- NumberWords helper: decimal → "about seventeen pounds", DateTime → "3 days ago"
- PhotoAnalysisView: after analysis shows a card preview with large verbal price,
photo dots, "Looks good ✓" to save instantly, "Change something ▼" to reveal
a price slider (snaps to 50p, updates verbally as you drag) and title bar
- Card preview updates when live eBay price lookup completes
- SavedListingsView cards: verbal price as primary, £x.xx small beneath,
relative date ("yesterday", "3 days ago") instead of raw timestamp
- Detail panel also shows relative date
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
80 lines
2.6 KiB
C#
80 lines
2.6 KiB
C#
namespace EbayListingTool.Helpers;
|
|
|
|
public static class NumberWords
|
|
{
|
|
private static readonly string[] Ones =
|
|
[
|
|
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
|
|
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen",
|
|
"seventeen", "eighteen", "nineteen"
|
|
];
|
|
|
|
private static readonly string[] Tens =
|
|
[
|
|
"", "", "twenty", "thirty", "forty", "fifty",
|
|
"sixty", "seventy", "eighty", "ninety"
|
|
];
|
|
|
|
/// <summary>
|
|
/// Converts a price to a friendly verbal string.
|
|
/// £17.49 → "about seventeen pounds"
|
|
/// £17.50 → "about seventeen pounds fifty"
|
|
/// £0.50 → "fifty pence"
|
|
/// </summary>
|
|
public static string ToVerbalPrice(decimal price)
|
|
{
|
|
if (price <= 0) return "no price set";
|
|
|
|
// Snap to nearest 50p
|
|
var rounded = Math.Round(price * 2) / 2m;
|
|
int pounds = (int)rounded;
|
|
bool hasFifty = (rounded - pounds) >= 0.5m;
|
|
|
|
if (pounds == 0)
|
|
return "fifty pence";
|
|
|
|
var poundsWord = IntToWords(pounds);
|
|
var poundsLabel = pounds == 1 ? "pound" : "pounds";
|
|
var suffix = hasFifty ? " fifty" : "";
|
|
|
|
return $"about {poundsWord} {poundsLabel}{suffix}";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts a UTC DateTime to a human-friendly relative string.
|
|
/// </summary>
|
|
public static string ToRelativeDate(DateTime utcTime)
|
|
{
|
|
var diff = DateTime.UtcNow - utcTime;
|
|
|
|
if (diff.TotalSeconds < 60) return "just now";
|
|
if (diff.TotalMinutes < 60) return $"{(int)diff.TotalMinutes} minutes ago";
|
|
if (diff.TotalHours < 2) return "about an hour ago";
|
|
if (diff.TotalHours < 24) return $"{(int)diff.TotalHours} hours ago";
|
|
if (diff.TotalDays < 2) return "yesterday";
|
|
if (diff.TotalDays < 7) return $"{(int)diff.TotalDays} days ago";
|
|
if (diff.TotalDays < 14) return "last week";
|
|
if (diff.TotalDays < 30) return $"{(int)(diff.TotalDays / 7)} weeks ago";
|
|
if (diff.TotalDays < 60) return "last month";
|
|
return $"{(int)(diff.TotalDays / 30)} months ago";
|
|
}
|
|
|
|
private static string IntToWords(int n)
|
|
{
|
|
if (n < 20) return Ones[n];
|
|
if (n < 100)
|
|
{
|
|
var t = Tens[n / 10];
|
|
var o = n % 10;
|
|
return o == 0 ? t : $"{t}-{Ones[o]}";
|
|
}
|
|
if (n < 1000)
|
|
{
|
|
var h = Ones[n / 100];
|
|
var rest = n % 100;
|
|
return rest == 0 ? $"{h} hundred" : $"{h} hundred and {IntToWords(rest)}";
|
|
}
|
|
return n.ToString(); // fallback for very large prices
|
|
}
|
|
}
|