From e012110b00a338de98193df74c6ab83b0087ef93 Mon Sep 17 00:00:00 2001 From: Tsanie Lily Date: Fri, 25 Feb 2022 13:38:42 +0800 Subject: [PATCH] language version degraded to 9.0 --- Billing.Shared/App.cs | 93 ++-- Billing.Shared/Helper.cs | 33 +- Billing.Shared/Languages/Resource.cs | 2 +- Billing.Shared/MainShell.xaml.cs | 13 +- Billing.Shared/Models/Account.cs | 67 +-- Billing.Shared/Models/BaseModel.cs | 305 +++++------ Billing.Shared/Models/Billing.cs | 55 +- Billing.Shared/Models/Category.cs | 55 +- Billing.Shared/Themes/BaseTheme.cs | 127 ++--- Billing.Shared/Themes/Dark.cs | 82 +-- Billing.Shared/Themes/Light.cs | 82 +-- Billing.Shared/UI/BillingDate.xaml.cs | 485 +++++++++--------- Billing.Shared/UI/BillingPage.cs | 13 +- Billing.Shared/UI/Converters.cs | 49 +- Billing.Shared/UI/CustomControl.cs | 285 +++++----- Billing.Shared/UI/CustomEffect.cs | 21 +- Billing.Shared/UI/Definition.cs | 109 ++-- Billing.Shared/Views/AccountPage.xaml.cs | 64 +-- Billing.Shared/Views/AddAccountPage.xaml.cs | 155 +++--- Billing.Shared/Views/AddBillPage.xaml.cs | 13 +- Billing.Shared/Views/BillPage.xaml.cs | 75 +-- Billing.Shared/Views/SettingPage.xaml.cs | 13 +- .../Billing.Android/Billing.Android.csproj | 7 +- Billing/Billing.iOS/AppDelegate.cs | 39 +- Billing/Billing.iOS/Billing.iOS.csproj | 6 +- Billing/Billing.iOS/Definition.cs | 17 +- .../Effects/ShadowEffectPlatform.cs | 49 +- Billing/Billing.iOS/Main.cs | 19 +- Billing/Billing.iOS/PlatformCulture.cs | 105 ++-- .../Renderers/LongPressButtonRenderer.cs | 53 +- .../Renderers/OptionEntryRenderer.cs | 21 +- .../Renderers/TintImageRenderer.cs | 37 +- 32 files changed, 1287 insertions(+), 1262 deletions(-) diff --git a/Billing.Shared/App.cs b/Billing.Shared/App.cs index 5cc2213..6fb0e23 100644 --- a/Billing.Shared/App.cs +++ b/Billing.Shared/App.cs @@ -3,59 +3,60 @@ using Billing.Themes; using Xamarin.Essentials; using Xamarin.Forms; -namespace Billing; - -public class App : Application +namespace Billing { - public static AppTheme CurrentTheme { get; private set; } - public static PlatformCulture CurrentCulture { get; private set; } - - public App() + public class App : Application { - CurrentCulture = new PlatformCulture(); - InitResources(); + public static AppTheme CurrentTheme { get; private set; } + public static PlatformCulture CurrentCulture { get; private set; } - MainPage = new MainShell(); - Shell.Current.GoToAsync("//Bills"); - } - - protected override void OnStart() - { - } - - protected override void OnResume() - { - SetTheme(AppInfo.RequestedTheme); - } - - private void InitResources() - { - var theme = AppInfo.RequestedTheme; - SetTheme(theme, true); - } - - private void SetTheme(AppTheme theme, bool force = false) - { - if (force || theme != CurrentTheme) + public App() { - CurrentTheme = theme; - } - else - { - return; - } - Helper.Debug($"application theme: {theme}"); + CurrentCulture = new PlatformCulture(); + InitResources(); - BaseTheme instance; - if (theme == AppTheme.Dark) - { - instance = Dark.Instance; + MainPage = new MainShell(); + Shell.Current.GoToAsync("//Bills"); } - else + + protected override void OnStart() { - instance = Light.Instance; } - // TODO: status bar - Resources = instance; + + protected override void OnResume() + { + SetTheme(AppInfo.RequestedTheme); + } + + private void InitResources() + { + var theme = AppInfo.RequestedTheme; + SetTheme(theme, true); + } + + private void SetTheme(AppTheme theme, bool force = false) + { + if (force || theme != CurrentTheme) + { + CurrentTheme = theme; + } + else + { + return; + } + Helper.Debug($"application theme: {theme}"); + + BaseTheme instance; + if (theme == AppTheme.Dark) + { + instance = Dark.Instance; + } + else + { + instance = Light.Instance; + } + // TODO: status bar + Resources = instance; + } } } \ No newline at end of file diff --git a/Billing.Shared/Helper.cs b/Billing.Shared/Helper.cs index e0b69b1..b8a20ee 100644 --- a/Billing.Shared/Helper.cs +++ b/Billing.Shared/Helper.cs @@ -1,23 +1,24 @@ using System; -namespace Billing; - -internal static class Helper +namespace Billing { - public static void Debug(string message) + internal static class Helper { - var time = DateTime.Now.ToString("HH:mm:ss.fff"); - System.Diagnostics.Debug.WriteLine($"[{time}] - {message}"); - } + public static void Debug(string message) + { + var time = DateTime.Now.ToString("HH:mm:ss.fff"); + System.Diagnostics.Debug.WriteLine($"[{time}] - {message}"); + } - public static void Error(string category, Exception ex) - { - Error(category, ex?.Message ?? "unknown error"); - } + public static void Error(string category, Exception ex) + { + Error(category, ex?.Message ?? "unknown error"); + } - public static void Error(string category, string message) - { - var time = DateTime.Now.ToString("HH:mm:ss.fff"); - System.Diagnostics.Debug.Fail($"[{time}] - {category}", message); + public static void Error(string category, string message) + { + var time = DateTime.Now.ToString("HH:mm:ss.fff"); + System.Diagnostics.Debug.Fail($"[{time}] - {category}", message); + } } -} +} \ No newline at end of file diff --git a/Billing.Shared/Languages/Resource.cs b/Billing.Shared/Languages/Resource.cs index 5a59b23..7747641 100644 --- a/Billing.Shared/Languages/Resource.cs +++ b/Billing.Shared/Languages/Resource.cs @@ -36,7 +36,7 @@ namespace Billing.Languages { get { - if (strings?.TryGetValue(key, out string val) == true) + if (strings != null && strings.TryGetValue(key, out string val)) { return val; } diff --git a/Billing.Shared/MainShell.xaml.cs b/Billing.Shared/MainShell.xaml.cs index 220a4d7..8146bcc 100644 --- a/Billing.Shared/MainShell.xaml.cs +++ b/Billing.Shared/MainShell.xaml.cs @@ -1,11 +1,12 @@ using Xamarin.Forms; -namespace Billing; - -public partial class MainShell : Shell +namespace Billing { - public MainShell() + public partial class MainShell : Shell { - InitializeComponent(); + public MainShell() + { + InitializeComponent(); + } } -} +} \ No newline at end of file diff --git a/Billing.Shared/Models/Account.cs b/Billing.Shared/Models/Account.cs index b7d57a6..bc2a069 100644 --- a/Billing.Shared/Models/Account.cs +++ b/Billing.Shared/Models/Account.cs @@ -1,41 +1,42 @@ using System.Xml.Linq; -namespace Billing.Models; - -public class Account : BaseModel +namespace Billing.Models { - public int Id { get; set; } - public string Icon { get; set; } = ICON_DEFAULT; - public AccountCategory Category { get; set; } - public string Name { get; set; } - public decimal Balance { get; set; } - public string Memo { get; set; } - - public override void OnXmlDeserialize(XElement node) + public class Account : BaseModel { - Id = Read(node, nameof(Id), 0); - Icon = Read(node, nameof(Icon), ICON_DEFAULT); - Category = (AccountCategory)Read(node, nameof(Category), 0); - Name = Read(node, nameof(Name), string.Empty); - Balance = Read(node, nameof(Balance), 0m); - Memo = Read(node, nameof(Memo), null); + public int Id { get; set; } + public string Icon { get; set; } = ICON_DEFAULT; + public AccountCategory Category { get; set; } + public string Name { get; set; } + public decimal Balance { get; set; } + public string Memo { get; set; } + + public override void OnXmlDeserialize(XElement node) + { + Id = Read(node, nameof(Id), 0); + Icon = Read(node, nameof(Icon), ICON_DEFAULT); + Category = (AccountCategory)Read(node, nameof(Category), 0); + Name = Read(node, nameof(Name), string.Empty); + Balance = Read(node, nameof(Balance), 0m); + Memo = Read(node, nameof(Memo), null); + } + + public override void OnXmlSerialize(XElement node) + { + Write(node, nameof(Id), Id); + Write(node, nameof(Icon), Icon); + Write(node, nameof(Category), (int)Category); + Write(node, nameof(Name), Name); + Write(node, nameof(Balance), Balance); + Write(node, nameof(Memo), Memo); + } } - public override void OnXmlSerialize(XElement node) + public enum AccountCategory { - Write(node, nameof(Id), Id); - Write(node, nameof(Icon), Icon); - Write(node, nameof(Category), (int)Category); - Write(node, nameof(Name), Name); - Write(node, nameof(Balance), Balance); - Write(node, nameof(Memo), Memo); + Cash = 0, + CreditCard, + DebitCard, + ElecAccount } -} - -public enum AccountCategory -{ - Cash = 0, - CreditCard, - DebitCard, - ElecAccount -} +} \ No newline at end of file diff --git a/Billing.Shared/Models/BaseModel.cs b/Billing.Shared/Models/BaseModel.cs index 410765b..53ed0f9 100644 --- a/Billing.Shared/Models/BaseModel.cs +++ b/Billing.Shared/Models/BaseModel.cs @@ -5,180 +5,181 @@ using System.Linq; using System.Text; using System.Xml.Linq; -namespace Billing.Models; - -public interface IModel +namespace Billing.Models { - void OnXmlSerialize(XElement node); - - void OnXmlDeserialize(XElement node); -} - -public abstract class BaseModel : IModel, IDisposable -{ - protected const string ICON_DEFAULT = "ic_default"; - - private bool disposed = false; - - public static T ParseXml(string xml) where T : BaseModel, new() + public interface IModel { - XDocument doc = XDocument.Parse(xml); - T model = new(); - model.OnXmlDeserialize(doc.Root); - return model; + void OnXmlSerialize(XElement node); + + void OnXmlDeserialize(XElement node); } - protected static string ToString(IFormattable v) => v.ToString(null, CultureInfo.InvariantCulture); - protected static double ParseDouble(string s) => double.Parse(s, CultureInfo.InvariantCulture); - protected static decimal ParseDecimal(string s) => decimal.Parse(s, CultureInfo.InvariantCulture); - protected static int ParseInt(string s) => int.Parse(s, CultureInfo.InvariantCulture); - protected static long ParseLong(string s) => long.Parse(s, CultureInfo.InvariantCulture); - - protected static bool IsTrue(string s) => - string.Equals(s, "true", StringComparison.OrdinalIgnoreCase) || - string.Equals(s, "yes", StringComparison.OrdinalIgnoreCase) || - s == "1"; - - #region Private Methods - - private static XElement WriteString(XElement parent, string name, string val, Action action = null) + public abstract class BaseModel : IModel, IDisposable { - XElement ele; - if (val == null) + protected const string ICON_DEFAULT = "ic_default"; + + private bool disposed = false; + + public static T ParseXml(string xml) where T : BaseModel, new() { - ele = new XElement(name); + XDocument doc = XDocument.Parse(xml); + T model = new(); + model.OnXmlDeserialize(doc.Root); + return model; } - else + + protected static string ToString(IFormattable v) => v.ToString(null, CultureInfo.InvariantCulture); + protected static double ParseDouble(string s) => double.Parse(s, CultureInfo.InvariantCulture); + protected static decimal ParseDecimal(string s) => decimal.Parse(s, CultureInfo.InvariantCulture); + protected static int ParseInt(string s) => int.Parse(s, CultureInfo.InvariantCulture); + protected static long ParseLong(string s) => long.Parse(s, CultureInfo.InvariantCulture); + + protected static bool IsTrue(string s) => + string.Equals(s, "true", StringComparison.OrdinalIgnoreCase) || + string.Equals(s, "yes", StringComparison.OrdinalIgnoreCase) || + s == "1"; + + #region Private Methods + + private static XElement WriteString(XElement parent, string name, string val, Action action = null) { - ele = new XElement(name, val); - } - action?.Invoke(ele); - parent.Add(ele); - return ele; - } - - private static T ReadSubnode(XElement node, string subname, Func func) - { - var ele = node.Elements().FirstOrDefault(e => string.Equals(e.Name.ToString(), subname, StringComparison.OrdinalIgnoreCase)); - return func(ele); - } - - private static T ReadObject(XElement node) where T : IModel, new() - { - if (IsTrue(node.Attribute("null")?.Value)) - { - return default; - } - T value = new(); - value.OnXmlDeserialize(node); - return value; - } - - private static T[] ReadArray(XElement node) where T : IModel, new() - { - if (IsTrue(node.Attribute("null")?.Value)) - { - return default; - } - int count = ParseInt(node.Attribute("count").Value); - T[] array = new T[count]; - foreach (XElement ele in node.Elements("item")) - { - int index = ParseInt(ele.Attribute("index").Value); - array[index] = ReadObject(ele); - } - return array; - } - - #endregion - - #region Read/Write Helper - - protected static XElement Write(XElement parent, string name, string val) => WriteString(parent, name, val); - protected static XElement Write(XElement parent, string name, DateTime date) => WriteString(parent, name, ToString(date.Ticks)); - protected static XElement Write(XElement parent, string name, T value) where T : IFormattable => WriteString(parent, name, ToString(value)); - protected static XElement WriteObject(XElement parent, string name, T value) where T : IModel => WriteString(parent, name, null, - action: ele => - { - if (value == null) + XElement ele; + if (val == null) { - ele.Add(new XAttribute("null", 1)); + ele = new XElement(name); } else { - value.OnXmlSerialize(ele); + ele = new XElement(name, val); } - }); - protected static XElement WriteArray(XElement parent, string name, T[] value) where T : IModel => WriteString(parent, name, null, - action: ele => + action?.Invoke(ele); + parent.Add(ele); + return ele; + } + + private static T ReadSubnode(XElement node, string subname, Func func) { - if (value == null) + var ele = node.Elements().FirstOrDefault(e => string.Equals(e.Name.ToString(), subname, StringComparison.OrdinalIgnoreCase)); + return func(ele); + } + + private static T ReadObject(XElement node) where T : IModel, new() + { + if (IsTrue(node.Attribute("null")?.Value)) { - ele.Add(new XAttribute("null", 1)); + return default; } - else + T value = new(); + value.OnXmlDeserialize(node); + return value; + } + + private static T[] ReadArray(XElement node) where T : IModel, new() + { + if (IsTrue(node.Attribute("null")?.Value)) { - ele.Add(new XAttribute("count", value.Length)); - for (var i = 0; i < value.Length; i++) + return default; + } + int count = ParseInt(node.Attribute("count").Value); + T[] array = new T[count]; + foreach (XElement ele in node.Elements("item")) + { + int index = ParseInt(ele.Attribute("index").Value); + array[index] = ReadObject(ele); + } + return array; + } + + #endregion + + #region Read/Write Helper + + protected static XElement Write(XElement parent, string name, string val) => WriteString(parent, name, val); + protected static XElement Write(XElement parent, string name, DateTime date) => WriteString(parent, name, ToString(date.Ticks)); + protected static XElement Write(XElement parent, string name, T value) where T : IFormattable => WriteString(parent, name, ToString(value)); + protected static XElement WriteObject(XElement parent, string name, T value) where T : IModel => WriteString(parent, name, null, + action: ele => + { + if (value == null) { - XElement item = WriteObject(ele, "item", value[i]); - item.Add(new XAttribute("index", i)); + ele.Add(new XAttribute("null", 1)); } - } - }); + else + { + value.OnXmlSerialize(ele); + } + }); + protected static XElement WriteArray(XElement parent, string name, T[] value) where T : IModel => WriteString(parent, name, null, + action: ele => + { + if (value == null) + { + ele.Add(new XAttribute("null", 1)); + } + else + { + ele.Add(new XAttribute("count", value.Length)); + for (var i = 0; i < value.Length; i++) + { + XElement item = WriteObject(ele, "item", value[i]); + item.Add(new XAttribute("index", i)); + } + } + }); - protected static string Read(XElement node, string subname, string def) => ReadSubnode(node, subname, e => e?.Value ?? def); - protected static int Read(XElement node, string subname, int def) => ReadSubnode(node, subname, e => e == null ? def : ParseInt(e.Value)); - protected static long Read(XElement node, string subname, long def) => ReadSubnode(node, subname, e => e == null ? def : ParseLong(e.Value)); - protected static double Read(XElement node, string subname, double def) => ReadSubnode(node, subname, e => e == null ? def : ParseDouble(e.Value)); - protected static decimal Read(XElement node, string subname, decimal def) => ReadSubnode(node, subname, e => e == null ? def : ParseDecimal(e.Value)); - protected static DateTime Read(XElement node, string subname, DateTime def) => ReadSubnode(node, subname, e => e == null ? def : new DateTime(ParseLong(e.Value))); - protected static T ReadObject(XElement node, string subname, T def = default) where T : IModel, new() => ReadSubnode(node, subname, e => e == null ? def : ReadObject(e)); - protected static T[] ReadArray(XElement node, string subname, T[] def = null) where T : IModel, new() => ReadSubnode(node, subname, e => e == null ? def : ReadArray(e)); + protected static string Read(XElement node, string subname, string def) => ReadSubnode(node, subname, e => e?.Value ?? def); + protected static int Read(XElement node, string subname, int def) => ReadSubnode(node, subname, e => e == null ? def : ParseInt(e.Value)); + protected static long Read(XElement node, string subname, long def) => ReadSubnode(node, subname, e => e == null ? def : ParseLong(e.Value)); + protected static double Read(XElement node, string subname, double def) => ReadSubnode(node, subname, e => e == null ? def : ParseDouble(e.Value)); + protected static decimal Read(XElement node, string subname, decimal def) => ReadSubnode(node, subname, e => e == null ? def : ParseDecimal(e.Value)); + protected static DateTime Read(XElement node, string subname, DateTime def) => ReadSubnode(node, subname, e => e == null ? def : new DateTime(ParseLong(e.Value))); + protected static T ReadObject(XElement node, string subname, T def = default) where T : IModel, new() => ReadSubnode(node, subname, e => e == null ? def : ReadObject(e)); + protected static T[] ReadArray(XElement node, string subname, T[] def = null) where T : IModel, new() => ReadSubnode(node, subname, e => e == null ? def : ReadArray(e)); - #endregion + #endregion - public XDocument ToXml() - { - XDocument xdoc = new(new XDeclaration("1.0", "utf-8", "yes"), new XElement("root")); - ToXml(xdoc.Root); - return xdoc; - } - - public void ToXml(XElement node) - { - OnXmlSerialize(node); - } - - public void SaveToStream(Stream stream) - { - ToXml().Save(stream, SaveOptions.DisableFormatting); - } - - public abstract void OnXmlSerialize(XElement node); - public abstract void OnXmlDeserialize(XElement node); - - - public override string ToString() - { - XDocument xdoc = ToXml(); - using MemoryStream ms = new(); - using StreamWriter writer = new(ms, Encoding.UTF8); - xdoc.Save(writer, SaveOptions.DisableFormatting); - writer.Flush(); - ms.Seek(0, SeekOrigin.Begin); - using StreamReader reader = new(ms, Encoding.UTF8); - return reader.ReadToEnd(); - } - - protected virtual void Dispose(bool dispose) { } - - public void Dispose() - { - if (!disposed) + public XDocument ToXml() { - Dispose(true); - disposed = true; + XDocument xdoc = new(new XDeclaration("1.0", "utf-8", "yes"), new XElement("root")); + ToXml(xdoc.Root); + return xdoc; + } + + public void ToXml(XElement node) + { + OnXmlSerialize(node); + } + + public void SaveToStream(Stream stream) + { + ToXml().Save(stream, SaveOptions.DisableFormatting); + } + + public abstract void OnXmlSerialize(XElement node); + public abstract void OnXmlDeserialize(XElement node); + + + public override string ToString() + { + XDocument xdoc = ToXml(); + using MemoryStream ms = new(); + using StreamWriter writer = new(ms, Encoding.UTF8); + xdoc.Save(writer, SaveOptions.DisableFormatting); + writer.Flush(); + ms.Seek(0, SeekOrigin.Begin); + using StreamReader reader = new(ms, Encoding.UTF8); + return reader.ReadToEnd(); + } + + protected virtual void Dispose(bool dispose) { } + + public void Dispose() + { + if (!disposed) + { + Dispose(true); + disposed = true; + } } } -} +} \ No newline at end of file diff --git a/Billing.Shared/Models/Billing.cs b/Billing.Shared/Models/Billing.cs index 2dbc676..bc17f1d 100644 --- a/Billing.Shared/Models/Billing.cs +++ b/Billing.Shared/Models/Billing.cs @@ -1,34 +1,35 @@ using System; using System.Xml.Linq; -namespace Billing.Models; - -public class Billing : BaseModel +namespace Billing.Models { - public decimal Amount { get; set; } - public string Name { get; set; } - public int CategoryId { get; set; } - public int WalletId { get; set; } - public string Store { get; set; } - public DateTime CreateTime { get; set; } - - public override void OnXmlDeserialize(XElement node) + public class Billing : BaseModel { - Amount = Read(node, nameof(Amount), 0m); - Name = Read(node, nameof(Name), string.Empty); - CategoryId = Read(node, nameof(CategoryId), -1); - WalletId = Read(node, nameof(WalletId), -1); - Store = Read(node, nameof(Store), string.Empty); - CreateTime = Read(node, nameof(CreateTime), default(DateTime)); - } + public decimal Amount { get; set; } + public string Name { get; set; } + public int CategoryId { get; set; } + public int WalletId { get; set; } + public string Store { get; set; } + public DateTime CreateTime { get; set; } - public override void OnXmlSerialize(XElement node) - { - Write(node, nameof(Amount), Amount); - Write(node, nameof(Name), Name); - Write(node, nameof(CategoryId), CategoryId); - Write(node, nameof(WalletId), WalletId); - Write(node, nameof(Store), Store); - Write(node, nameof(CreateTime), CreateTime); + public override void OnXmlDeserialize(XElement node) + { + Amount = Read(node, nameof(Amount), 0m); + Name = Read(node, nameof(Name), string.Empty); + CategoryId = Read(node, nameof(CategoryId), -1); + WalletId = Read(node, nameof(WalletId), -1); + Store = Read(node, nameof(Store), string.Empty); + CreateTime = Read(node, nameof(CreateTime), default(DateTime)); + } + + public override void OnXmlSerialize(XElement node) + { + Write(node, nameof(Amount), Amount); + Write(node, nameof(Name), Name); + Write(node, nameof(CategoryId), CategoryId); + Write(node, nameof(WalletId), WalletId); + Write(node, nameof(Store), Store); + Write(node, nameof(CreateTime), CreateTime); + } } -} +} \ No newline at end of file diff --git a/Billing.Shared/Models/Category.cs b/Billing.Shared/Models/Category.cs index b6d44d3..4be6366 100644 --- a/Billing.Shared/Models/Category.cs +++ b/Billing.Shared/Models/Category.cs @@ -1,34 +1,35 @@ using System.Xml.Linq; -namespace Billing.Models; - -public class Category : BaseModel +namespace Billing.Models { - public int Id { get; set; } - public string Icon { get; set; } = ICON_DEFAULT; - public string Name { get; set; } - public int? ParentId { get; set; } - - public override void OnXmlDeserialize(XElement node) + public class Category : BaseModel { - Id = Read(node, nameof(Id), 0); - Icon = Read(node, nameof(Icon), ICON_DEFAULT); - Name = Read(node, nameof(Name), string.Empty); - var parentId = Read(node, nameof(ParentId), -1); - if (parentId >= 0) + public int Id { get; set; } + public string Icon { get; set; } = ICON_DEFAULT; + public string Name { get; set; } + public int? ParentId { get; set; } + + public override void OnXmlDeserialize(XElement node) { - ParentId = parentId; + Id = Read(node, nameof(Id), 0); + Icon = Read(node, nameof(Icon), ICON_DEFAULT); + Name = Read(node, nameof(Name), string.Empty); + var parentId = Read(node, nameof(ParentId), -1); + if (parentId >= 0) + { + ParentId = parentId; + } + } + + public override void OnXmlSerialize(XElement node) + { + Write(node, nameof(Id), Id); + Write(node, nameof(Icon), Icon); + Write(node, nameof(Name), Name); + if (ParentId != null) + { + Write(node, nameof(ParentId), ParentId.Value); + } } } - - public override void OnXmlSerialize(XElement node) - { - Write(node, nameof(Id), Id); - Write(node, nameof(Icon), Icon); - Write(node, nameof(Name), Name); - if (ParentId != null) - { - Write(node, nameof(ParentId), ParentId.Value); - } - } -} +} \ No newline at end of file diff --git a/Billing.Shared/Themes/BaseTheme.cs b/Billing.Shared/Themes/BaseTheme.cs index 13b9baf..fec3db4 100644 --- a/Billing.Shared/Themes/BaseTheme.cs +++ b/Billing.Shared/Themes/BaseTheme.cs @@ -1,76 +1,77 @@ using Billing.UI; using Xamarin.Forms; -namespace Billing.Themes; - -public abstract class BaseTheme : ResourceDictionary +namespace Billing.Themes { - public const string CascadiaFontRegular = nameof(CascadiaFontRegular); - public const string CascadiaFontBold = nameof(CascadiaFontBold); - public const string RobotoCondensedFontRegular = nameof(RobotoCondensedFontRegular); - public const string RobotoCondensedFontBold = nameof(RobotoCondensedFontBold); - - public const string WindowBackgroundColor = nameof(WindowBackgroundColor); - public const string OptionTintColor = nameof(OptionTintColor); - public const string PromptBackgroundColor = nameof(PromptBackgroundColor); - public const string PrimaryColor = nameof(PrimaryColor); - public const string SecondaryColor = nameof(SecondaryColor); - public const string TabBarBackgroundColor = nameof(TabBarBackgroundColor); - public const string TabBarTitleColor = nameof(TabBarTitleColor); - public const string TabBarUnselectedColor = nameof(TabBarUnselectedColor); - public const string OutRangeDayColor = nameof(OutRangeDayColor); - public const string TextColor = nameof(TextColor); - public const string SecondaryTextColor = nameof(SecondaryTextColor); - public const string RedColor = nameof(RedColor); - - protected abstract Color PrimaryMauiColor { get; } - protected abstract Color SecondaryMauiColor { get; } - - protected void InitResources() + public abstract class BaseTheme : ResourceDictionary { - var robotoRegularFontFamily = Definition.GetRobotoCondensedRegularFontFamily(); - Add(CascadiaFontRegular, Definition.GetCascadiaRegularFontFamily()); - Add(CascadiaFontBold, Definition.GetCascadiaBoldFontFamily()); - Add(RobotoCondensedFontRegular, Definition.GetRobotoCondensedRegularFontFamily()); - Add(RobotoCondensedFontBold, Definition.GetRobotoCondensedBoldFontFamily()); + public const string CascadiaFontRegular = nameof(CascadiaFontRegular); + public const string CascadiaFontBold = nameof(CascadiaFontBold); + public const string RobotoCondensedFontRegular = nameof(RobotoCondensedFontRegular); + public const string RobotoCondensedFontBold = nameof(RobotoCondensedFontBold); - Add(PrimaryColor, PrimaryMauiColor); - Add(SecondaryColor, SecondaryMauiColor); - Add(TabBarTitleColor, PrimaryMauiColor); + public const string WindowBackgroundColor = nameof(WindowBackgroundColor); + public const string OptionTintColor = nameof(OptionTintColor); + public const string PromptBackgroundColor = nameof(PromptBackgroundColor); + public const string PrimaryColor = nameof(PrimaryColor); + public const string SecondaryColor = nameof(SecondaryColor); + public const string TabBarBackgroundColor = nameof(TabBarBackgroundColor); + public const string TabBarTitleColor = nameof(TabBarTitleColor); + public const string TabBarUnselectedColor = nameof(TabBarUnselectedColor); + public const string OutRangeDayColor = nameof(OutRangeDayColor); + public const string TextColor = nameof(TextColor); + public const string SecondaryTextColor = nameof(SecondaryTextColor); + public const string RedColor = nameof(RedColor); - Add(new Style(typeof(Label)) + protected abstract Color PrimaryMauiColor { get; } + protected abstract Color SecondaryMauiColor { get; } + + protected void InitResources() { - Setters = + var robotoRegularFontFamily = Definition.GetRobotoCondensedRegularFontFamily(); + Add(CascadiaFontRegular, Definition.GetCascadiaRegularFontFamily()); + Add(CascadiaFontBold, Definition.GetCascadiaBoldFontFamily()); + Add(RobotoCondensedFontRegular, Definition.GetRobotoCondensedRegularFontFamily()); + Add(RobotoCondensedFontBold, Definition.GetRobotoCondensedBoldFontFamily()); + + Add(PrimaryColor, PrimaryMauiColor); + Add(SecondaryColor, SecondaryMauiColor); + Add(TabBarTitleColor, PrimaryMauiColor); + + Add(new Style(typeof(Label)) { - new Setter { Property = Label.FontSizeProperty, Value = Device.GetNamedSize(NamedSize.Small, typeof(Label)) }, - new Setter { Property = Label.TextColorProperty, Value = PrimaryMauiColor }, - new Setter { Property = Label.FontFamilyProperty, Value = robotoRegularFontFamily } - } - }); - Add(new Style(typeof(OptionEntry)) - { - Setters = + Setters = + { + new Setter { Property = Label.FontSizeProperty, Value = Device.GetNamedSize(NamedSize.Small, typeof(Label)) }, + new Setter { Property = Label.TextColorProperty, Value = PrimaryMauiColor }, + new Setter { Property = Label.FontFamilyProperty, Value = robotoRegularFontFamily } + } + }); + Add(new Style(typeof(OptionEntry)) { - new Setter { Property = Entry.FontSizeProperty, Value = Device.GetNamedSize(NamedSize.Small, typeof(Entry)) }, - new Setter { Property = Entry.FontFamilyProperty, Value = robotoRegularFontFamily } - } - }); - Add(new Style(typeof(Button)) - { - Setters = + Setters = + { + new Setter { Property = Entry.FontSizeProperty, Value = Device.GetNamedSize(NamedSize.Small, typeof(Entry)) }, + new Setter { Property = Entry.FontFamilyProperty, Value = robotoRegularFontFamily } + } + }); + Add(new Style(typeof(Button)) { - new Setter { Property = Button.TextColorProperty, Value = SecondaryMauiColor }, - new Setter { Property = Button.FontFamilyProperty, Value = robotoRegularFontFamily }, - new Setter { Property = VisualElement.BackgroundColorProperty, Value = PrimaryMauiColor }, - new Setter { Property = Button.PaddingProperty, Value = new Thickness(14, 10) } - } - }); - Add(new Style(typeof(TintImage)) - { - Setters = + Setters = + { + new Setter { Property = Button.TextColorProperty, Value = SecondaryMauiColor }, + new Setter { Property = Button.FontFamilyProperty, Value = robotoRegularFontFamily }, + new Setter { Property = VisualElement.BackgroundColorProperty, Value = PrimaryMauiColor }, + new Setter { Property = Button.PaddingProperty, Value = new Thickness(14, 10) } + } + }); + Add(new Style(typeof(TintImage)) { - new Setter { Property = TintImage.PrimaryColorProperty, Value = PrimaryMauiColor } - } - }); + Setters = + { + new Setter { Property = TintImage.PrimaryColorProperty, Value = PrimaryMauiColor } + } + }); + } } -} +} \ No newline at end of file diff --git a/Billing.Shared/Themes/Dark.cs b/Billing.Shared/Themes/Dark.cs index b99a16f..736470c 100644 --- a/Billing.Shared/Themes/Dark.cs +++ b/Billing.Shared/Themes/Dark.cs @@ -1,50 +1,50 @@ -using Billing.UI; -using Xamarin.Forms; +using Xamarin.Forms; -namespace Billing.Themes; - -public class Dark : BaseTheme +namespace Billing.Themes { - private static Dark _instance; - - public static Dark Instance => _instance ??= new Dark(); - - protected override Color PrimaryMauiColor => Color.White; - protected override Color SecondaryMauiColor => Color.LightGray; - - public Dark() + public class Dark : BaseTheme { - InitColors(); - InitResources(); - } + private static Dark _instance; - private void InitColors() - { - Add(WindowBackgroundColor, Color.Black); - Add(OptionTintColor, Color.FromRgb(28, 28, 28)); - Add(PromptBackgroundColor, Color.FromRgb(0x1f, 0x1f, 0x1f)); - Add(TabBarBackgroundColor, Color.Black); - Add(TabBarUnselectedColor, Color.FromRgb(0x82, 0x82, 0x82)); - Add(OutRangeDayColor, Color.DarkGray); - Add(TextColor, Color.FromRgb(0xcc, 0xcc, 0xcc)); - Add(SecondaryTextColor, Color.LightGray); - Add(RedColor, Color.FromRgb(211, 5, 5)); + public static Dark Instance => _instance ??= new Dark(); - Add(new Style(typeof(TabBar)) + protected override Color PrimaryMauiColor => Color.White; + protected override Color SecondaryMauiColor => Color.LightGray; + + public Dark() { - Setters = - { - new Setter { Property = Shell.TabBarBackgroundColorProperty, Value = Color.Black }, - new Setter { Property = Shell.TabBarTitleColorProperty, Value = PrimaryMauiColor }, - new Setter { Property = Shell.TabBarUnselectedColorProperty, Value = Color.FromRgb(0x82, 0x82, 0x82) } - } - }); - Add(new Style(typeof(TableView)) + InitColors(); + InitResources(); + } + + private void InitColors() { - Setters = + Add(WindowBackgroundColor, Color.Black); + Add(OptionTintColor, Color.FromRgb(28, 28, 28)); + Add(PromptBackgroundColor, Color.FromRgb(0x1f, 0x1f, 0x1f)); + Add(TabBarBackgroundColor, Color.Black); + Add(TabBarUnselectedColor, Color.FromRgb(0x82, 0x82, 0x82)); + Add(OutRangeDayColor, Color.DarkGray); + Add(TextColor, Color.FromRgb(0xcc, 0xcc, 0xcc)); + Add(SecondaryTextColor, Color.LightGray); + Add(RedColor, Color.FromRgb(211, 5, 5)); + + Add(new Style(typeof(TabBar)) { - new Setter { Property = VisualElement.BackgroundColorProperty, Value = Color.Black } - } - }); + Setters = + { + new Setter { Property = Shell.TabBarBackgroundColorProperty, Value = Color.Black }, + new Setter { Property = Shell.TabBarTitleColorProperty, Value = PrimaryMauiColor }, + new Setter { Property = Shell.TabBarUnselectedColorProperty, Value = Color.FromRgb(0x82, 0x82, 0x82) } + } + }); + Add(new Style(typeof(TableView)) + { + Setters = + { + new Setter { Property = VisualElement.BackgroundColorProperty, Value = Color.Black } + } + }); + } } -} +} \ No newline at end of file diff --git a/Billing.Shared/Themes/Light.cs b/Billing.Shared/Themes/Light.cs index d05b3a7..b3ad5ba 100644 --- a/Billing.Shared/Themes/Light.cs +++ b/Billing.Shared/Themes/Light.cs @@ -1,50 +1,50 @@ -using Billing.UI; -using Xamarin.Forms; +using Xamarin.Forms; -namespace Billing.Themes; - -public class Light : BaseTheme +namespace Billing.Themes { - private static Light _instance; - - public static Light Instance => _instance ??= new Light(); - - protected override Color PrimaryMauiColor => Color.FromRgb(0x18, 0x31, 0x53); - protected override Color SecondaryMauiColor => Color.White; - - public Light() + public class Light : BaseTheme { - InitColors(); - InitResources(); - } + private static Light _instance; - private void InitColors() - { - Add(WindowBackgroundColor, Color.White); - Add(OptionTintColor, Color.White); - Add(PromptBackgroundColor, Color.FromRgb(0xe0, 0xe0, 0xe0)); - Add(TabBarBackgroundColor, Color.White); - Add(TabBarUnselectedColor, Color.FromRgb(0x82, 0x82, 0x82)); - Add(OutRangeDayColor, Color.LightGray); - Add(TextColor, Color.FromRgb(0x33, 0x33, 0x33)); - Add(SecondaryTextColor, Color.DimGray); - Add(RedColor, Color.FromRgb(211, 64, 85)); + public static Light Instance => _instance ??= new Light(); - Add(new Style(typeof(TabBar)) + protected override Color PrimaryMauiColor => Color.FromRgb(0x18, 0x31, 0x53); + protected override Color SecondaryMauiColor => Color.White; + + public Light() { - Setters = - { - new Setter { Property = Shell.TabBarBackgroundColorProperty, Value = Color.White }, - new Setter { Property = Shell.TabBarTitleColorProperty, Value = PrimaryMauiColor }, - new Setter { Property = Shell.TabBarUnselectedColorProperty, Value = Color.FromRgb(0x82, 0x82, 0x82) } - } - }); - Add(new Style(typeof(TableView)) + InitColors(); + InitResources(); + } + + private void InitColors() { - Setters = + Add(WindowBackgroundColor, Color.White); + Add(OptionTintColor, Color.White); + Add(PromptBackgroundColor, Color.FromRgb(0xe0, 0xe0, 0xe0)); + Add(TabBarBackgroundColor, Color.White); + Add(TabBarUnselectedColor, Color.FromRgb(0x82, 0x82, 0x82)); + Add(OutRangeDayColor, Color.LightGray); + Add(TextColor, Color.FromRgb(0x33, 0x33, 0x33)); + Add(SecondaryTextColor, Color.DimGray); + Add(RedColor, Color.FromRgb(211, 64, 85)); + + Add(new Style(typeof(TabBar)) { - new Setter { Property = VisualElement.BackgroundColorProperty, Value = Color.FromRgb(242, 241, 245) } - } - }); + Setters = + { + new Setter { Property = Shell.TabBarBackgroundColorProperty, Value = Color.White }, + new Setter { Property = Shell.TabBarTitleColorProperty, Value = PrimaryMauiColor }, + new Setter { Property = Shell.TabBarUnselectedColorProperty, Value = Color.FromRgb(0x82, 0x82, 0x82) } + } + }); + Add(new Style(typeof(TableView)) + { + Setters = + { + new Setter { Property = VisualElement.BackgroundColorProperty, Value = Color.FromRgb(242, 241, 245) } + } + }); + } } -} +} \ No newline at end of file diff --git a/Billing.Shared/UI/BillingDate.xaml.cs b/Billing.Shared/UI/BillingDate.xaml.cs index ad68fb1..e205c79 100644 --- a/Billing.Shared/UI/BillingDate.xaml.cs +++ b/Billing.Shared/UI/BillingDate.xaml.cs @@ -1,289 +1,290 @@ using System; using Xamarin.Forms; -namespace Billing.UI; - -public partial class BillingDate : ContentView +namespace Billing.UI { - #region UI Properties - - private static readonly BindableProperty SundayProperty = BindableProperty.Create(nameof(Sunday), typeof(BillingDay), typeof(BillingDate)); - private static readonly BindableProperty MondayProperty = BindableProperty.Create(nameof(Monday), typeof(BillingDay), typeof(BillingDate)); - private static readonly BindableProperty TuesdayProperty = BindableProperty.Create(nameof(Tuesday), typeof(BillingDay), typeof(BillingDate)); - private static readonly BindableProperty WednesdayProperty = BindableProperty.Create(nameof(Wednesday), typeof(BillingDay), typeof(BillingDate)); - private static readonly BindableProperty ThursdayProperty = BindableProperty.Create(nameof(Thursday), typeof(BillingDay), typeof(BillingDate)); - private static readonly BindableProperty FridayProperty = BindableProperty.Create(nameof(Friday), typeof(BillingDay), typeof(BillingDate)); - private static readonly BindableProperty SaturdayProperty = BindableProperty.Create(nameof(Saturday), typeof(BillingDay), typeof(BillingDate)); - - public BillingDay Sunday => (BillingDay)GetValue(SundayProperty); - public BillingDay Monday => (BillingDay)GetValue(MondayProperty); - public BillingDay Tuesday => (BillingDay)GetValue(TuesdayProperty); - public BillingDay Wednesday => (BillingDay)GetValue(WednesdayProperty); - public BillingDay Thursday => (BillingDay)GetValue(ThursdayProperty); - public BillingDay Friday => (BillingDay)GetValue(FridayProperty); - public BillingDay Saturday => (BillingDay)GetValue(SaturdayProperty); - - #endregion - - private static BindableProperty GetWeekProperty(int week) + public partial class BillingDate : ContentView { - return (DayOfWeek)week switch - { - DayOfWeek.Monday => MondayProperty, - DayOfWeek.Tuesday => TuesdayProperty, - DayOfWeek.Wednesday => WednesdayProperty, - DayOfWeek.Thursday => ThursdayProperty, - DayOfWeek.Friday => FridayProperty, - DayOfWeek.Saturday => SaturdayProperty, - _ => SundayProperty - }; - } + #region UI Properties - public static readonly BindableProperty LocatedDateProperty = BindableProperty.Create(nameof(LocatedDate), typeof(DateTime), typeof(BillingDate), propertyChanged: OnLocatedDatePropertyChanged); - public static readonly BindableProperty SelectedDateProperty = BindableProperty.Create(nameof(SelectedDate), typeof(DateTime), typeof(BillingDate), propertyChanged: OnSelectedDatePropertyChanged); + private static readonly BindableProperty SundayProperty = BindableProperty.Create(nameof(Sunday), typeof(BillingDay), typeof(BillingDate)); + private static readonly BindableProperty MondayProperty = BindableProperty.Create(nameof(Monday), typeof(BillingDay), typeof(BillingDate)); + private static readonly BindableProperty TuesdayProperty = BindableProperty.Create(nameof(Tuesday), typeof(BillingDay), typeof(BillingDate)); + private static readonly BindableProperty WednesdayProperty = BindableProperty.Create(nameof(Wednesday), typeof(BillingDay), typeof(BillingDate)); + private static readonly BindableProperty ThursdayProperty = BindableProperty.Create(nameof(Thursday), typeof(BillingDay), typeof(BillingDate)); + private static readonly BindableProperty FridayProperty = BindableProperty.Create(nameof(Friday), typeof(BillingDay), typeof(BillingDate)); + private static readonly BindableProperty SaturdayProperty = BindableProperty.Create(nameof(Saturday), typeof(BillingDay), typeof(BillingDate)); - private static void OnLocatedDatePropertyChanged(BindableObject obj, object old, object @new) - { - if (obj is BillingDate billingDate && @new is DateTime date) + public BillingDay Sunday => (BillingDay)GetValue(SundayProperty); + public BillingDay Monday => (BillingDay)GetValue(MondayProperty); + public BillingDay Tuesday => (BillingDay)GetValue(TuesdayProperty); + public BillingDay Wednesday => (BillingDay)GetValue(WednesdayProperty); + public BillingDay Thursday => (BillingDay)GetValue(ThursdayProperty); + public BillingDay Friday => (BillingDay)GetValue(FridayProperty); + public BillingDay Saturday => (BillingDay)GetValue(SaturdayProperty); + + #endregion + + private static BindableProperty GetWeekProperty(int week) { - var week = (int)date.DayOfWeek; - var tmpDate = date.AddDays(-week); - for (var i = 0; i < 7; i++) + return (DayOfWeek)week switch { - var prop = GetWeekProperty(i); - var day = new BillingDay(tmpDate); - billingDate.SetValue(prop, day); - tmpDate = tmpDate.AddDays(1); - } + DayOfWeek.Monday => MondayProperty, + DayOfWeek.Tuesday => TuesdayProperty, + DayOfWeek.Wednesday => WednesdayProperty, + DayOfWeek.Thursday => ThursdayProperty, + DayOfWeek.Friday => FridayProperty, + DayOfWeek.Saturday => SaturdayProperty, + _ => SundayProperty + }; } - } - private static void OnSelectedDatePropertyChanged(BindableObject obj, object old, object @new) - { - if (obj is BillingDate billingDate && @new is DateTime selected) + public static readonly BindableProperty LocatedDateProperty = BindableProperty.Create(nameof(LocatedDate), typeof(DateTime), typeof(BillingDate), propertyChanged: OnLocatedDatePropertyChanged); + public static readonly BindableProperty SelectedDateProperty = BindableProperty.Create(nameof(SelectedDate), typeof(DateTime), typeof(BillingDate), propertyChanged: OnSelectedDatePropertyChanged); + + private static void OnLocatedDatePropertyChanged(BindableObject obj, object old, object @new) { - for (var i = 0; i < 7; i++) + if (obj is BillingDate billingDate && @new is DateTime date) { - var prop = GetWeekProperty(i); - var day = (BillingDay)billingDate.GetValue(prop); - day.Refresh(selected); - } - } - } - - public DateTime LocatedDate - { - get => (DateTime)GetValue(LocatedDateProperty); - set => SetValue(LocatedDateProperty, value); - } - public DateTime SelectedDate - { - get => (DateTime)GetValue(SelectedDateProperty); - set => SetValue(SelectedDateProperty, value); - } - - public Command OnDayTapped { get; } - - public event EventHandler DateSelected; - - private DateTime lastDate; - private double? x1; - private double x2; - - public BillingDate() - { - OnDayTapped = new Command(OnDayChanged); - - InitializeComponent(); - } - - public void SetDateTime(DateTime selectedDate, DateTime? locatedDate = null) - { - if (locatedDate != null) - { - LocatedDate = locatedDate.Value; - } - else - { - LocatedDate = selectedDate; - } - SelectedDate = selectedDate; - DateSelected?.Invoke(this, new DateEventArgs(selectedDate)); - } - - private void OnDayChanged(object o) - { - var selected = SelectedDate; - if (o is BillingDay day && (selected.Year != day.Date.Year || selected.DayOfYear != day.Date.DayOfYear)) - { - for (var i = 0; i < 7; i++) - { - var d = (BillingDay)GetValue(GetWeekProperty(i)); - if (d.IsSelected) + var week = (int)date.DayOfWeek; + var tmpDate = date.AddDays(-week); + for (var i = 0; i < 7; i++) { - this.AbortAnimation("unselected"); - this.Animate("unselected", v => - { - d.Opacity = v; - }, - start: 1, end: 0, - easing: Easing.CubicOut, - finished: (v, b) => - { - d.Opacity = 0; - d.IsSelected = false; - }); + var prop = GetWeekProperty(i); + var day = new BillingDay(tmpDate); + billingDate.SetValue(prop, day); + tmpDate = tmpDate.AddDays(1); } } - SelectedDate = day.Date; - this.AbortAnimation("selected"); - this.Animate("selected", v => - { - day.Opacity = v; - }, - start: 0, end: 1, - easing: Easing.CubicOut, - finished: (v, b) => - { - day.Opacity = 1; - }); - DateSelected?.Invoke(this, new DateEventArgs(day.Date)); } - } - private void OnPanUpdated(object sender, PanUpdatedEventArgs e) - { - if (e.StatusType == GestureStatus.Started) + private static void OnSelectedDatePropertyChanged(BindableObject obj, object old, object @new) { - lastDate = DateTime.Now; - x1 = null; + if (obj is BillingDate billingDate && @new is DateTime selected) + { + for (var i = 0; i < 7; i++) + { + var prop = GetWeekProperty(i); + var day = (BillingDay)billingDate.GetValue(prop); + day.Refresh(selected); + } + } } - else if (e.StatusType == GestureStatus.Running) + + public DateTime LocatedDate { - if (x1 == null) - { - x1 = e.TotalX; - } - x2 = e.TotalX; + get => (DateTime)GetValue(LocatedDateProperty); + set => SetValue(LocatedDateProperty, value); } - else if (e.StatusType == GestureStatus.Completed) + public DateTime SelectedDate { - if (x1 == null) - { - return; - } - var totalX = x2 - x1.Value; - x1 = null; - var ms = (DateTime.Now - lastDate).TotalMilliseconds; - var speed = totalX / ms; - Helper.Debug($"completed, speed: {speed}"); - if (speed < -0.7) - { - LocatedDate = LocatedDate.AddDays(7); - } - else if (speed > 0.7) - { - LocatedDate = LocatedDate.AddDays(-7); - } - OnSelectedDatePropertyChanged(this, null, SelectedDate); + get => (DateTime)GetValue(SelectedDateProperty); + set => SetValue(SelectedDateProperty, value); } - } -} -public class DateEventArgs : EventArgs -{ - public DateTime Date { get; } + public Command OnDayTapped { get; } - public DateEventArgs(DateTime date) - { - Date = date; - } -} + public event EventHandler DateSelected; -public class BillingDayView : ContentView -{ - public static readonly BindableProperty BillingDayProperty = BindableProperty.Create(nameof(BillingDay), typeof(BillingDay), typeof(BillingDayView)); - public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(Command), typeof(BillingDayView)); + private DateTime lastDate; + private double? x1; + private double x2; - public BillingDay BillingDay - { - get => (BillingDay)GetValue(BillingDayProperty); - set => SetValue(BillingDayProperty, value); - } - public Command Command - { - get => (Command)GetValue(CommandProperty); - set => SetValue(CommandProperty, value); - } -} - -public class BillingDay : BindableObject -{ - private static readonly BindableProperty DateProperty = BindableProperty.Create(nameof(Date), typeof(DateTime), typeof(BillingDay), propertyChanged: OnDatePropertyChanged); - private static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(BillingDay)); - private static readonly BindableProperty FontFamilyProperty = BindableProperty.Create(nameof(FontFamily), typeof(string), typeof(BillingDay), defaultValue: Definition.GetCascadiaRegularFontFamily()); - private static readonly BindableProperty IsSelectedProperty = BindableProperty.Create(nameof(IsSelected), typeof(bool), typeof(BillingDay)); - private static readonly BindableProperty OpacityProperty = BindableProperty.Create(nameof(Opacity), typeof(double), typeof(BillingDay), defaultValue: 1.0); - private static readonly BindableProperty TextOpacityProperty = BindableProperty.Create(nameof(TextOpacity), typeof(double), typeof(BillingDay), defaultValue: 1.0); - - private static void OnDatePropertyChanged(BindableObject obj, object old, object @new) - { - if (obj is BillingDay day && @new is DateTime date) + public BillingDate() { - if (date.Day == 1) + OnDayTapped = new Command(OnDayChanged); + + InitializeComponent(); + } + + public void SetDateTime(DateTime selectedDate, DateTime? locatedDate = null) + { + if (locatedDate != null) { - day.SetValue(TextProperty, date.ToString("MMM")); + LocatedDate = locatedDate.Value; } else { - day.SetValue(TextProperty, date.Day.ToString()); + LocatedDate = selectedDate; + } + SelectedDate = selectedDate; + DateSelected?.Invoke(this, new DateEventArgs(selectedDate)); + } + + private void OnDayChanged(object o) + { + var selected = SelectedDate; + if (o is BillingDay day && (selected.Year != day.Date.Year || selected.DayOfYear != day.Date.DayOfYear)) + { + for (var i = 0; i < 7; i++) + { + var d = (BillingDay)GetValue(GetWeekProperty(i)); + if (d.IsSelected) + { + this.AbortAnimation("unselected"); + this.Animate("unselected", v => + { + d.Opacity = v; + }, + start: 1, end: 0, + easing: Easing.CubicOut, + finished: (v, b) => + { + d.Opacity = 0; + d.IsSelected = false; + }); + } + } + SelectedDate = day.Date; + this.AbortAnimation("selected"); + this.Animate("selected", v => + { + day.Opacity = v; + }, + start: 0, end: 1, + easing: Easing.CubicOut, + finished: (v, b) => + { + day.Opacity = 1; + }); + DateSelected?.Invoke(this, new DateEventArgs(day.Date)); + } + } + + private void OnPanUpdated(object sender, PanUpdatedEventArgs e) + { + if (e.StatusType == GestureStatus.Started) + { + lastDate = DateTime.Now; + x1 = null; + } + else if (e.StatusType == GestureStatus.Running) + { + if (x1 == null) + { + x1 = e.TotalX; + } + x2 = e.TotalX; + } + else if (e.StatusType == GestureStatus.Completed) + { + if (x1 == null) + { + return; + } + var totalX = x2 - x1.Value; + x1 = null; + var ms = (DateTime.Now - lastDate).TotalMilliseconds; + var speed = totalX / ms; + Helper.Debug($"completed, speed: {speed}"); + if (speed < -0.7) + { + LocatedDate = LocatedDate.AddDays(7); + } + else if (speed > 0.7) + { + LocatedDate = LocatedDate.AddDays(-7); + } + OnSelectedDatePropertyChanged(this, null, SelectedDate); } } } - public DateTime Date + public class DateEventArgs : EventArgs { - get => (DateTime)GetValue(DateProperty); - set => SetValue(DateProperty, value); - } - public string Text => (string)GetValue(TextProperty); - public string FontFamily => (string)GetValue(FontFamilyProperty); - public bool IsSelected - { - get => (bool)GetValue(IsSelectedProperty); - set => SetValue(IsSelectedProperty, value); - } - public double Opacity - { - get => (double)GetValue(OpacityProperty); - set => SetValue(OpacityProperty, value); - } - public double TextOpacity => (double)GetValue(TextOpacityProperty); + public DateTime Date { get; } - public BillingDay(DateTime date) - { - Date = date; + public DateEventArgs(DateTime date) + { + Date = date; + } } - public void Refresh(DateTime selected) + public class BillingDayView : ContentView { - var date = Date; - if (date.Year == selected.Year && date.DayOfYear == selected.DayOfYear) + public static readonly BindableProperty BillingDayProperty = BindableProperty.Create(nameof(BillingDay), typeof(BillingDay), typeof(BillingDayView)); + public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(Command), typeof(BillingDayView)); + + public BillingDay BillingDay { - SetValue(IsSelectedProperty, true); - SetValue(FontFamilyProperty, Definition.GetCascadiaBoldFontFamily()); + get => (BillingDay)GetValue(BillingDayProperty); + set => SetValue(BillingDayProperty, value); } - else + public Command Command { - SetValue(FontFamilyProperty, Definition.GetCascadiaRegularFontFamily()); - } - if (date.Year == selected.Year && date.Month == selected.Month) - { - SetValue(TextOpacityProperty, 1.0); - } - else - { - SetValue(TextOpacityProperty, .4); + get => (Command)GetValue(CommandProperty); + set => SetValue(CommandProperty, value); } } -} + + public class BillingDay : BindableObject + { + private static readonly BindableProperty DateProperty = BindableProperty.Create(nameof(Date), typeof(DateTime), typeof(BillingDay), propertyChanged: OnDatePropertyChanged); + private static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(BillingDay)); + private static readonly BindableProperty FontFamilyProperty = BindableProperty.Create(nameof(FontFamily), typeof(string), typeof(BillingDay), defaultValue: Definition.GetCascadiaRegularFontFamily()); + private static readonly BindableProperty IsSelectedProperty = BindableProperty.Create(nameof(IsSelected), typeof(bool), typeof(BillingDay)); + private static readonly BindableProperty OpacityProperty = BindableProperty.Create(nameof(Opacity), typeof(double), typeof(BillingDay), defaultValue: 1.0); + private static readonly BindableProperty TextOpacityProperty = BindableProperty.Create(nameof(TextOpacity), typeof(double), typeof(BillingDay), defaultValue: 1.0); + + private static void OnDatePropertyChanged(BindableObject obj, object old, object @new) + { + if (obj is BillingDay day && @new is DateTime date) + { + if (date.Day == 1) + { + day.SetValue(TextProperty, date.ToString("MMM")); + } + else + { + day.SetValue(TextProperty, date.Day.ToString()); + } + } + } + + public DateTime Date + { + get => (DateTime)GetValue(DateProperty); + set => SetValue(DateProperty, value); + } + public string Text => (string)GetValue(TextProperty); + public string FontFamily => (string)GetValue(FontFamilyProperty); + public bool IsSelected + { + get => (bool)GetValue(IsSelectedProperty); + set => SetValue(IsSelectedProperty, value); + } + public double Opacity + { + get => (double)GetValue(OpacityProperty); + set => SetValue(OpacityProperty, value); + } + public double TextOpacity => (double)GetValue(TextOpacityProperty); + + public BillingDay(DateTime date) + { + Date = date; + } + + public void Refresh(DateTime selected) + { + var date = Date; + if (date.Year == selected.Year && date.DayOfYear == selected.DayOfYear) + { + SetValue(IsSelectedProperty, true); + SetValue(FontFamilyProperty, Definition.GetCascadiaBoldFontFamily()); + } + else + { + SetValue(FontFamilyProperty, Definition.GetCascadiaRegularFontFamily()); + } + if (date.Year == selected.Year && date.Month == selected.Month) + { + SetValue(TextOpacityProperty, 1.0); + } + else + { + SetValue(TextOpacityProperty, .4); + } + } + } +} \ No newline at end of file diff --git a/Billing.Shared/UI/BillingPage.cs b/Billing.Shared/UI/BillingPage.cs index 0ebcdd7..07d9068 100644 --- a/Billing.Shared/UI/BillingPage.cs +++ b/Billing.Shared/UI/BillingPage.cs @@ -1,12 +1,13 @@ using Billing.Themes; using Xamarin.Forms; -namespace Billing.UI; - -public abstract class BillingPage : ContentPage +namespace Billing.UI { - public BillingPage() + public abstract class BillingPage : ContentPage { - SetDynamicResource(BackgroundColorProperty, BaseTheme.WindowBackgroundColor); + public BillingPage() + { + SetDynamicResource(BackgroundColorProperty, BaseTheme.WindowBackgroundColor); + } } -} +} \ No newline at end of file diff --git a/Billing.Shared/UI/Converters.cs b/Billing.Shared/UI/Converters.cs index b79a195..e5dfbdb 100644 --- a/Billing.Shared/UI/Converters.cs +++ b/Billing.Shared/UI/Converters.cs @@ -3,38 +3,39 @@ using System; using System.Globalization; using Xamarin.Forms; -namespace Billing.UI; - -public class TitleDateConverter : IValueConverter +namespace Billing.UI { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public class TitleDateConverter : IValueConverter { - if (value is DateTime date) + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return date.ToString(Resource.TitleDateFormat); + if (value is DateTime date) + { + return date.ToString(Resource.TitleDateFormat); + } + return value; } - return value; - } - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return value; - } -} - -public class MoneyConverter : IValueConverter -{ - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is decimal d) + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - return "¥ " + d.ToString("n2", CultureInfo.InvariantCulture); + return value; } - return value; } - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + public class MoneyConverter : IValueConverter { - return value; + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is decimal d) + { + return "¥ " + d.ToString("n2", CultureInfo.InvariantCulture); + } + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return value; + } } -} +} \ No newline at end of file diff --git a/Billing.Shared/UI/CustomControl.cs b/Billing.Shared/UI/CustomControl.cs index 79fae10..e92985a 100644 --- a/Billing.Shared/UI/CustomControl.cs +++ b/Billing.Shared/UI/CustomControl.cs @@ -2,153 +2,154 @@ using System; using Xamarin.Forms; -namespace Billing.UI; - -public class TintImage : Image +namespace Billing.UI { - public static readonly BindableProperty PrimaryColorProperty = BindableProperty.Create(nameof(PrimaryColor), typeof(Color?), typeof(TintImage)); - - public Color? PrimaryColor + public class TintImage : Image { - get => (Color?)GetValue(PrimaryColorProperty); - set => SetValue(PrimaryColorProperty, value); - } -} + public static readonly BindableProperty PrimaryColorProperty = BindableProperty.Create(nameof(PrimaryColor), typeof(Color?), typeof(TintImage)); -public class LongPressButton : Button -{ - public event EventHandler LongPressed; - - public LongPressButton() - { - Padding = 0; - BackgroundColor = Color.Transparent; - } - - public void TriggerLongPress() - { - LongPressed?.Invoke(this, EventArgs.Empty); - } -} - -public class OptionEntry : Entry { } - -public abstract class OptionCell : ViewCell -{ - public static readonly BindableProperty TitleProperty = BindableProperty.Create(nameof(Title), typeof(string), typeof(OptionCell)); - public static readonly BindableProperty BackgroundColorProperty = BindableProperty.Create(nameof(BackgroundColor), typeof(Color), typeof(OptionCell)); - - public string Title - { - get => (string)GetValue(TitleProperty); - set => SetValue(TitleProperty, value); - } - public Color BackgroundColor - { - get => (Color)GetValue(BackgroundColorProperty); - set => SetValue(BackgroundColorProperty, value); - } - - protected abstract View Content { get; } - - public OptionCell() - { - View = new Grid + public Color? PrimaryColor { - BindingContext = this, - Padding = new Thickness(20, 0), - ColumnDefinitions = - { - new ColumnDefinition { Width = new GridLength(.3, GridUnitType.Star) }, - new ColumnDefinition { Width = new GridLength(.7, GridUnitType.Star) } - }, - Children = - { - new Label - { - LineBreakMode = LineBreakMode.TailTruncation, - VerticalOptions = LayoutOptions.Center - } - .Binding(Label.TextProperty, nameof(Title)) - .DynamicResource(Label.TextColorProperty, BaseTheme.TextColor), - - Content.GridColumn(1) - } + get => (Color?)GetValue(PrimaryColorProperty); + set => SetValue(PrimaryColorProperty, value); } + } + + public class LongPressButton : Button + { + public event EventHandler LongPressed; + + public LongPressButton() + { + Padding = 0; + BackgroundColor = Color.Transparent; + } + + public void TriggerLongPress() + { + LongPressed?.Invoke(this, EventArgs.Empty); + } + } + + public class OptionEntry : Entry { } + + public abstract class OptionCell : ViewCell + { + public static readonly BindableProperty TitleProperty = BindableProperty.Create(nameof(Title), typeof(string), typeof(OptionCell)); + public static readonly BindableProperty BackgroundColorProperty = BindableProperty.Create(nameof(BackgroundColor), typeof(Color), typeof(OptionCell)); + + public string Title + { + get => (string)GetValue(TitleProperty); + set => SetValue(TitleProperty, value); + } + public Color BackgroundColor + { + get => (Color)GetValue(BackgroundColorProperty); + set => SetValue(BackgroundColorProperty, value); + } + + protected abstract View Content { get; } + + public OptionCell() + { + View = new Grid + { + BindingContext = this, + Padding = new Thickness(20, 0), + ColumnDefinitions = + { + new ColumnDefinition { Width = new GridLength(.3, GridUnitType.Star) }, + new ColumnDefinition { Width = new GridLength(.7, GridUnitType.Star) } + }, + Children = + { + new Label + { + LineBreakMode = LineBreakMode.TailTruncation, + VerticalOptions = LayoutOptions.Center + } + .Binding(Label.TextProperty, nameof(Title)) + .DynamicResource(Label.TextColorProperty, BaseTheme.TextColor), + + Content.GridColumn(1) + } + } + .DynamicResource(VisualElement.BackgroundColorProperty, BaseTheme.OptionTintColor); + } + } + + public class OptionTextCell : OptionCell + { + public static readonly BindableProperty DetailProperty = BindableProperty.Create(nameof(Detail), typeof(string), typeof(OptionTextCell)); + + public string Detail + { + get => (string)GetValue(DetailProperty); + set => SetValue(DetailProperty, value); + } + + protected override View Content => new Label + { + HorizontalOptions = LayoutOptions.End, + VerticalOptions = LayoutOptions.Center + } + .Binding(Label.TextProperty, nameof(Detail)) + .DynamicResource(Label.TextColorProperty, BaseTheme.SecondaryTextColor); + } + + public class OptionSwitchCell : OptionCell + { + public static readonly BindableProperty IsToggledProperty = BindableProperty.Create(nameof(IsToggled), typeof(bool), typeof(OptionSwitchCell)); + + public bool IsToggled + { + get => (bool)GetValue(IsToggledProperty); + set => SetValue(IsToggledProperty, value); + } + + protected override View Content => new Switch + { + HorizontalOptions = LayoutOptions.End, + VerticalOptions = LayoutOptions.Center + } + .Binding(Switch.IsToggledProperty, nameof(IsToggled), BindingMode.TwoWay); + } + + public class OptionEntryCell : OptionCell + { + public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(OptionEntryCell)); + public static readonly BindableProperty KeyboardProperty = BindableProperty.Create(nameof(Keyboard), typeof(Keyboard), typeof(OptionEntryCell)); + public static readonly BindableProperty PlaceholderProperty = BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(OptionEntryCell)); + + public string Text + { + get => (string)GetValue(TextProperty); + set => SetValue(TextProperty, value); + } + public Keyboard Keyboard + { + get => (Keyboard)GetValue(KeyboardProperty); + set => SetValue(KeyboardProperty, value); + } + public string Placeholder + { + get => (string)GetValue(PlaceholderProperty); + set => SetValue(PlaceholderProperty, value); + } + + protected override View Content => new OptionEntry + { + HorizontalOptions = LayoutOptions.Fill, + HorizontalTextAlignment = TextAlignment.End, + VerticalOptions = LayoutOptions.Center, + ReturnType = ReturnType.Next + } + .Binding(Entry.TextProperty, nameof(Text), BindingMode.TwoWay) + .Binding(InputView.KeyboardProperty, nameof(Keyboard)) + .Binding(Entry.PlaceholderProperty, nameof(Placeholder)) + .DynamicResource(Entry.TextColorProperty, BaseTheme.TextColor) + .DynamicResource(Entry.PlaceholderColorProperty, BaseTheme.SecondaryTextColor) .DynamicResource(VisualElement.BackgroundColorProperty, BaseTheme.OptionTintColor); } -} - -public class OptionTextCell : OptionCell -{ - public static readonly BindableProperty DetailProperty = BindableProperty.Create(nameof(Detail), typeof(string), typeof(OptionTextCell)); - - public string Detail - { - get => (string)GetValue(DetailProperty); - set => SetValue(DetailProperty, value); - } - - protected override View Content => new Label - { - HorizontalOptions = LayoutOptions.End, - VerticalOptions = LayoutOptions.Center - } - .Binding(Label.TextProperty, nameof(Detail)) - .DynamicResource(Label.TextColorProperty, BaseTheme.SecondaryTextColor); -} - -public class OptionSwitchCell : OptionCell -{ - public static readonly BindableProperty IsToggledProperty = BindableProperty.Create(nameof(IsToggled), typeof(bool), typeof(OptionSwitchCell)); - - public bool IsToggled - { - get => (bool)GetValue(IsToggledProperty); - set => SetValue(IsToggledProperty, value); - } - - protected override View Content => new Switch - { - HorizontalOptions = LayoutOptions.End, - VerticalOptions = LayoutOptions.Center - } - .Binding(Switch.IsToggledProperty, nameof(IsToggled), BindingMode.TwoWay); -} - -public class OptionEntryCell : OptionCell -{ - public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(OptionEntryCell)); - public static readonly BindableProperty KeyboardProperty = BindableProperty.Create(nameof(Keyboard), typeof(Keyboard), typeof(OptionEntryCell)); - public static readonly BindableProperty PlaceholderProperty = BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(OptionEntryCell)); - - public string Text - { - get => (string)GetValue(TextProperty); - set => SetValue(TextProperty, value); - } - public Keyboard Keyboard - { - get => (Keyboard)GetValue(KeyboardProperty); - set => SetValue(KeyboardProperty, value); - } - public string Placeholder - { - get => (string)GetValue(PlaceholderProperty); - set => SetValue(PlaceholderProperty, value); - } - - protected override View Content => new OptionEntry - { - HorizontalOptions = LayoutOptions.Fill, - HorizontalTextAlignment = TextAlignment.End, - VerticalOptions = LayoutOptions.Center, - ReturnType = ReturnType.Next - } - .Binding(Entry.TextProperty, nameof(Text), BindingMode.TwoWay) - .Binding(InputView.KeyboardProperty, nameof(Keyboard)) - .Binding(Entry.PlaceholderProperty, nameof(Placeholder)) - .DynamicResource(Entry.TextColorProperty, BaseTheme.TextColor) - .DynamicResource(Entry.PlaceholderColorProperty, BaseTheme.SecondaryTextColor) - .DynamicResource(VisualElement.BackgroundColorProperty, BaseTheme.OptionTintColor); } \ No newline at end of file diff --git a/Billing.Shared/UI/CustomEffect.cs b/Billing.Shared/UI/CustomEffect.cs index 2be1af0..5c5a9f8 100644 --- a/Billing.Shared/UI/CustomEffect.cs +++ b/Billing.Shared/UI/CustomEffect.cs @@ -1,15 +1,16 @@ using Xamarin.Forms; -namespace Billing.UI; - -public class ShadowEffect : RoutingEffect +namespace Billing.UI { - public float Radius { get; set; } - public Color Color { get; set; } - public Size Offect { get; set; } - public float Opacity { get; set; } - - public ShadowEffect() : base($"Org.Tsanie.{nameof(ShadowEffect)}") + public class ShadowEffect : RoutingEffect { + public float Radius { get; set; } + public Color Color { get; set; } + public Size Offect { get; set; } + public float Opacity { get; set; } + + public ShadowEffect() : base($"Org.Tsanie.{nameof(ShadowEffect)}") + { + } } -} +} \ No newline at end of file diff --git a/Billing.Shared/UI/Definition.cs b/Billing.Shared/UI/Definition.cs index 392eb12..9fc42e5 100644 --- a/Billing.Shared/UI/Definition.cs +++ b/Billing.Shared/UI/Definition.cs @@ -1,68 +1,69 @@ using System; using Xamarin.Forms; -namespace Billing.UI; - -public static partial class Definition +namespace Billing.UI { - public static partial string GetCascadiaRegularFontFamily(); - public static partial string GetCascadiaBoldFontFamily(); - public static partial string GetRobotoCondensedRegularFontFamily(); - public static partial string GetRobotoCondensedBoldFontFamily(); -} - -public static class ExtensionHelper -{ - public static View Binding(this View view, BindableProperty property, string path, BindingMode mode = BindingMode.Default, IValueConverter converter = null) + public static partial class Definition { - view.SetBinding(property, path, mode, converter); - return view; + public static partial string GetCascadiaRegularFontFamily(); + public static partial string GetCascadiaBoldFontFamily(); + public static partial string GetRobotoCondensedRegularFontFamily(); + public static partial string GetRobotoCondensedBoldFontFamily(); } - public static View DynamicResource(this View view, BindableProperty property, string key) + public static class ExtensionHelper { - view.SetDynamicResource(property, key); - return view; - } - - public static View GridColumn(this View view, int column) - { - Grid.SetColumn(view, column); - return view; - } - - public static View GridRow(this View view, int row) - { - Grid.SetRow(view, row); - return view; - } -} - -public class Tap : IDisposable -{ - private readonly static object sync = new(); - private static Tap instance; - - private bool busy = false; - - private Tap() { } - - public static bool IsBusy => instance?.busy ?? false; - - public static Tap Start() - { - lock (sync) + public static View Binding(this View view, BindableProperty property, string path, BindingMode mode = BindingMode.Default, IValueConverter converter = null) { - (instance ??= new Tap()).busy = true; + view.SetBinding(property, path, mode, converter); + return view; } - return instance; - } - public void Dispose() - { - lock (sync) + public static View DynamicResource(this View view, BindableProperty property, string key) { - busy = false; + view.SetDynamicResource(property, key); + return view; + } + + public static View GridColumn(this View view, int column) + { + Grid.SetColumn(view, column); + return view; + } + + public static View GridRow(this View view, int row) + { + Grid.SetRow(view, row); + return view; } } -} + + public class Tap : IDisposable + { + private readonly static object sync = new(); + private static Tap instance; + + private bool busy = false; + + private Tap() { } + + public static bool IsBusy => instance?.busy ?? false; + + public static Tap Start() + { + lock (sync) + { + (instance ??= new Tap()).busy = true; + } + return instance; + } + + public void Dispose() + { + lock (sync) + { + busy = false; + } + } + } +} \ No newline at end of file diff --git a/Billing.Shared/Views/AccountPage.xaml.cs b/Billing.Shared/Views/AccountPage.xaml.cs index 28a5064..848a37d 100644 --- a/Billing.Shared/Views/AccountPage.xaml.cs +++ b/Billing.Shared/Views/AccountPage.xaml.cs @@ -1,44 +1,44 @@ using Billing.UI; -using System; using Xamarin.Forms; -namespace Billing.Views; - -public partial class AccountPage : BillingPage +namespace Billing.Views { - private static readonly BindableProperty BalanceProperty = BindableProperty.Create(nameof(Balance), typeof(decimal), typeof(AccountPage)); - private static readonly BindableProperty AssetProperty = BindableProperty.Create(nameof(Asset), typeof(decimal), typeof(AccountPage)); - private static readonly BindableProperty LiabilityProperty = BindableProperty.Create(nameof(Liability), typeof(decimal), typeof(AccountPage)); - - public decimal Balance => (decimal)GetValue(BalanceProperty); - public decimal Asset => (decimal)GetValue(AssetProperty); - public decimal Liability => (decimal)GetValue(LiabilityProperty); - - public Command AddAccount { get; } - - public AccountPage() + public partial class AccountPage : BillingPage { - AddAccount = new Command(OnAddAccount); + private static readonly BindableProperty BalanceProperty = BindableProperty.Create(nameof(Balance), typeof(decimal), typeof(AccountPage)); + private static readonly BindableProperty AssetProperty = BindableProperty.Create(nameof(Asset), typeof(decimal), typeof(AccountPage)); + private static readonly BindableProperty LiabilityProperty = BindableProperty.Create(nameof(Liability), typeof(decimal), typeof(AccountPage)); - InitializeComponent(); - } + public decimal Balance => (decimal)GetValue(BalanceProperty); + public decimal Asset => (decimal)GetValue(AssetProperty); + public decimal Liability => (decimal)GetValue(LiabilityProperty); - private async void OnAddAccount() - { - if (Tap.IsBusy) + public Command AddAccount { get; } + + public AccountPage() { - return; + AddAccount = new Command(OnAddAccount); + + InitializeComponent(); } - using (Tap.Start()) + + private async void OnAddAccount() { - var page = new AddAccountPage(); - page.AccountChecked += AccountChecked; - await Navigation.PushAsync(page); + if (Tap.IsBusy) + { + return; + } + using (Tap.Start()) + { + var page = new AddAccountPage(); + page.AccountChecked += AccountChecked; + await Navigation.PushAsync(page); + } + } + + private void AccountChecked(object sender, AccountEventArgs e) + { + Helper.Debug(e.Account.ToString()); } } - - private void AccountChecked(object sender, AccountEventArgs e) - { - Helper.Debug(e.Account.ToString()); - } -} +} \ No newline at end of file diff --git a/Billing.Shared/Views/AddAccountPage.xaml.cs b/Billing.Shared/Views/AddAccountPage.xaml.cs index 93c5ed9..0caa427 100644 --- a/Billing.Shared/Views/AddAccountPage.xaml.cs +++ b/Billing.Shared/Views/AddAccountPage.xaml.cs @@ -3,84 +3,85 @@ using Billing.UI; using System; using Xamarin.Forms; -namespace Billing.Views; - -public partial class AddAccountPage : BillingPage +namespace Billing.Views { - private static readonly BindableProperty AccountNameProperty = BindableProperty.Create(nameof(AccountName), typeof(string), typeof(AddAccountPage)); - private static readonly BindableProperty AccountIconProperty = BindableProperty.Create(nameof(AccountIcon), typeof(string), typeof(AddAccountPage)); - private static readonly BindableProperty CategoryProperty = BindableProperty.Create(nameof(Category), typeof(string), typeof(AddAccountPage)); - private static readonly BindableProperty BalanceProperty = BindableProperty.Create(nameof(Balance), typeof(decimal), typeof(AddAccountPage)); - private static readonly BindableProperty MemoProperty = BindableProperty.Create(nameof(Memo), typeof(string), typeof(AddAccountPage)); + public partial class AddAccountPage : BillingPage + { + private static readonly BindableProperty AccountNameProperty = BindableProperty.Create(nameof(AccountName), typeof(string), typeof(AddAccountPage)); + private static readonly BindableProperty AccountIconProperty = BindableProperty.Create(nameof(AccountIcon), typeof(string), typeof(AddAccountPage)); + private static readonly BindableProperty CategoryProperty = BindableProperty.Create(nameof(Category), typeof(string), typeof(AddAccountPage)); + private static readonly BindableProperty BalanceProperty = BindableProperty.Create(nameof(Balance), typeof(decimal), typeof(AddAccountPage)); + private static readonly BindableProperty MemoProperty = BindableProperty.Create(nameof(Memo), typeof(string), typeof(AddAccountPage)); - public string AccountName - { - get => (string)GetValue(AccountNameProperty); - set => SetValue(AccountNameProperty, value); - } - public string AccountIcon - { - get => (string)GetValue(AccountIconProperty); - set => SetValue(AccountIconProperty, value); - } - public string Category - { - get => (string)GetValue(CategoryProperty); - set => SetValue(CategoryProperty, value); - } - public decimal Balance - { - get => (decimal)GetValue(BalanceProperty); - set => SetValue(BalanceProperty, value); - } - public string Memo - { - get => (string)GetValue(MemoProperty); - set => SetValue(MemoProperty, value); - } - - private readonly Account account; - - public Command CheckAccount { get; } - - public event EventHandler AccountChecked; - - public AddAccountPage() - { - CheckAccount = new Command(OnCheckAccount); - InitializeComponent(); - } - - public AddAccountPage(Account account) - { - this.account = account; - AccountName = account.Name; - AccountIcon = account.Icon; - Category = account.Category.ToString(); - Balance = account.Balance; - Memo = account.Memo; - CheckAccount = new Command(OnCheckAccount); - InitializeComponent(); - } - - private void OnCheckAccount() - { - AccountChecked?.Invoke(this, new AccountEventArgs + public string AccountName { - Account = new Account - { - Id = account?.Id ?? -1, - Name = AccountName, - Icon = AccountIcon, - //Category = Category, - Balance = Balance, - Memo = Memo - } - }); - } -} + get => (string)GetValue(AccountNameProperty); + set => SetValue(AccountNameProperty, value); + } + public string AccountIcon + { + get => (string)GetValue(AccountIconProperty); + set => SetValue(AccountIconProperty, value); + } + public string Category + { + get => (string)GetValue(CategoryProperty); + set => SetValue(CategoryProperty, value); + } + public decimal Balance + { + get => (decimal)GetValue(BalanceProperty); + set => SetValue(BalanceProperty, value); + } + public string Memo + { + get => (string)GetValue(MemoProperty); + set => SetValue(MemoProperty, value); + } -public class AccountEventArgs : EventArgs -{ - public Account Account { get; set; } -} + private readonly Account account; + + public Command CheckAccount { get; } + + public event EventHandler AccountChecked; + + public AddAccountPage() + { + CheckAccount = new Command(OnCheckAccount); + InitializeComponent(); + } + + public AddAccountPage(Account account) + { + this.account = account; + AccountName = account.Name; + AccountIcon = account.Icon; + Category = account.Category.ToString(); + Balance = account.Balance; + Memo = account.Memo; + CheckAccount = new Command(OnCheckAccount); + InitializeComponent(); + } + + private void OnCheckAccount() + { + AccountChecked?.Invoke(this, new AccountEventArgs + { + Account = new Account + { + Id = account?.Id ?? -1, + Name = AccountName, + Icon = AccountIcon, + //Category = Category, + Balance = Balance, + Memo = Memo + } + }); + } + } + + public class AccountEventArgs : EventArgs + { + public Account Account { get; set; } + } +} \ No newline at end of file diff --git a/Billing.Shared/Views/AddBillPage.xaml.cs b/Billing.Shared/Views/AddBillPage.xaml.cs index 436ceb2..1cdab90 100644 --- a/Billing.Shared/Views/AddBillPage.xaml.cs +++ b/Billing.Shared/Views/AddBillPage.xaml.cs @@ -1,11 +1,12 @@ using Billing.UI; -namespace Billing.Views; - -public partial class AddBillPage : BillingPage +namespace Billing.Views { - public AddBillPage() + public partial class AddBillPage : BillingPage { - InitializeComponent(); + public AddBillPage() + { + InitializeComponent(); + } } -} +} \ No newline at end of file diff --git a/Billing.Shared/Views/BillPage.xaml.cs b/Billing.Shared/Views/BillPage.xaml.cs index b2d80e2..ed20a80 100644 --- a/Billing.Shared/Views/BillPage.xaml.cs +++ b/Billing.Shared/Views/BillPage.xaml.cs @@ -2,43 +2,44 @@ using Billing.UI; using System; using Xamarin.Forms; -namespace Billing.Views; - -public partial class BillPage : BillingPage +namespace Billing.Views { - private static readonly BindableProperty SelectedDateProperty = BindableProperty.Create(nameof(SelectedDate), typeof(DateTime), typeof(BillPage)); - - public DateTime SelectedDate + public partial class BillPage : BillingPage { - get => (DateTime)GetValue(SelectedDateProperty); - set => SetValue(SelectedDateProperty, value); + private static readonly BindableProperty SelectedDateProperty = BindableProperty.Create(nameof(SelectedDate), typeof(DateTime), typeof(BillPage)); + + public DateTime SelectedDate + { + get => (DateTime)GetValue(SelectedDateProperty); + set => SetValue(SelectedDateProperty, value); + } + + public Command AddBilling { get; } + + public BillPage() + { + AddBilling = new Command(OnAddBilling); + + InitializeComponent(); + + billingDate.SetDateTime(DateTime.Now); + } + + private void OnDateSelected(object sender, DateEventArgs e) + { + SelectedDate = e.Date; + + // TODO: while selecting date + } + + private void OnTitleDateLongPressed(object sender, EventArgs e) + { + billingDate.SetDateTime(DateTime.Now); + } + + private async void OnAddBilling() + { + await Navigation.PushAsync(new AddBillPage()); + } } - - public Command AddBilling { get; } - - public BillPage() - { - AddBilling = new Command(OnAddBilling); - - InitializeComponent(); - - billingDate.SetDateTime(DateTime.Now); - } - - private void OnDateSelected(object sender, DateEventArgs e) - { - SelectedDate = e.Date; - - // TODO: while selecting date - } - - private void OnTitleDateLongPressed(object sender, EventArgs e) - { - billingDate.SetDateTime(DateTime.Now); - } - - private async void OnAddBilling() - { - await Navigation.PushAsync(new AddBillPage()); - } -} +} \ No newline at end of file diff --git a/Billing.Shared/Views/SettingPage.xaml.cs b/Billing.Shared/Views/SettingPage.xaml.cs index b1d085a..a6d9bbe 100644 --- a/Billing.Shared/Views/SettingPage.xaml.cs +++ b/Billing.Shared/Views/SettingPage.xaml.cs @@ -1,11 +1,12 @@ using Billing.UI; -namespace Billing.Views; - -public partial class SettingPage : BillingPage +namespace Billing.Views { - public SettingPage() + public partial class SettingPage : BillingPage { - InitializeComponent(); + public SettingPage() + { + InitializeComponent(); + } } -} +} \ No newline at end of file diff --git a/Billing/Billing.Android/Billing.Android.csproj b/Billing/Billing.Android/Billing.Android.csproj index f727a1b..5f2f729 100644 --- a/Billing/Billing.Android/Billing.Android.csproj +++ b/Billing/Billing.Android/Billing.Android.csproj @@ -16,14 +16,13 @@ Properties\AndroidManifest.xml Resources Assets - false v12.0 true true Xamarin.Android.Net.AndroidClientHandler - 10.0 + 9.0 true @@ -65,8 +64,8 @@ - - + + diff --git a/Billing/Billing.iOS/AppDelegate.cs b/Billing/Billing.iOS/AppDelegate.cs index 7f2229a..c0f57ad 100644 --- a/Billing/Billing.iOS/AppDelegate.cs +++ b/Billing/Billing.iOS/AppDelegate.cs @@ -1,26 +1,27 @@ using Foundation; using UIKit; -namespace Billing.iOS; - -// The UIApplicationDelegate for the application. This class is responsible for launching the -// User Interface of the application, as well as listening (and optionally responding) to -// application events from iOS. -[Register(nameof(AppDelegate))] -public partial class AppDelegate : Xamarin.Forms.Platform.iOS.FormsApplicationDelegate +namespace Billing.iOS { - // - // This method is invoked when the application has loaded and is ready to run. In this - // method you should instantiate the window, load the UI into it and then make the window - // visible. - // - // You have 17 seconds to return from this method, or iOS will terminate your application. - // - public override bool FinishedLaunching(UIApplication app, NSDictionary options) + // The UIApplicationDelegate for the application. This class is responsible for launching the + // User Interface of the application, as well as listening (and optionally responding) to + // application events from iOS. + [Register(nameof(AppDelegate))] + public partial class AppDelegate : Xamarin.Forms.Platform.iOS.FormsApplicationDelegate { - Xamarin.Forms.Forms.Init(); - LoadApplication(new App()); + // + // This method is invoked when the application has loaded and is ready to run. In this + // method you should instantiate the window, load the UI into it and then make the window + // visible. + // + // You have 17 seconds to return from this method, or iOS will terminate your application. + // + public override bool FinishedLaunching(UIApplication app, NSDictionary options) + { + Xamarin.Forms.Forms.Init(); + LoadApplication(new App()); - return base.FinishedLaunching(app, options); + return base.FinishedLaunching(app, options); + } } -} +} \ No newline at end of file diff --git a/Billing/Billing.iOS/Billing.iOS.csproj b/Billing/Billing.iOS/Billing.iOS.csproj index 3e47e60..481de8d 100644 --- a/Billing/Billing.iOS/Billing.iOS.csproj +++ b/Billing/Billing.iOS/Billing.iOS.csproj @@ -15,7 +15,7 @@ true NSUrlSessionHandler automatic - 10.0 + 9.0 true @@ -138,8 +138,8 @@ - - + + diff --git a/Billing/Billing.iOS/Definition.cs b/Billing/Billing.iOS/Definition.cs index 4621151..e162438 100644 --- a/Billing/Billing.iOS/Definition.cs +++ b/Billing/Billing.iOS/Definition.cs @@ -1,9 +1,10 @@ -namespace Billing.UI; - -public static partial class Definition +namespace Billing.UI { - public static partial string GetCascadiaRegularFontFamily() => "CascadiaCode-Regular"; - public static partial string GetCascadiaBoldFontFamily() => "CascadiaCode-Bold"; - public static partial string GetRobotoCondensedRegularFontFamily() => "RobotoCondensed-Regular"; - public static partial string GetRobotoCondensedBoldFontFamily() => "RobotoCondensed-Bold"; -} + public static partial class Definition + { + public static partial string GetCascadiaRegularFontFamily() => "CascadiaCode-Regular"; + public static partial string GetCascadiaBoldFontFamily() => "CascadiaCode-Bold"; + public static partial string GetRobotoCondensedRegularFontFamily() => "RobotoCondensed-Regular"; + public static partial string GetRobotoCondensedBoldFontFamily() => "RobotoCondensed-Bold"; + } +} \ No newline at end of file diff --git a/Billing/Billing.iOS/Effects/ShadowEffectPlatform.cs b/Billing/Billing.iOS/Effects/ShadowEffectPlatform.cs index 3e5616b..5308b28 100644 --- a/Billing/Billing.iOS/Effects/ShadowEffectPlatform.cs +++ b/Billing/Billing.iOS/Effects/ShadowEffectPlatform.cs @@ -7,37 +7,38 @@ using Xamarin.Forms.Platform.iOS; [assembly: ResolutionGroupName("Org.Tsanie")] [assembly: ExportEffect(typeof(ShadowEffectPlatform), nameof(ShadowEffect))] -namespace Billing.iOS.Effects; - -public class ShadowEffectPlatform : PlatformEffect +namespace Billing.iOS.Effects { - protected override void OnAttached() + public class ShadowEffectPlatform : PlatformEffect { - try + protected override void OnAttached() { - var effect = (ShadowEffect)Element.Effects.FirstOrDefault(e => e is ShadowEffect); - if (effect != null) + try { - var layer = Control.Layer; - layer.ShadowRadius = effect.Radius; - layer.ShadowColor = effect.Color.ToCGColor(); - layer.ShadowOffset = effect.Offect.ToSizeF(); - layer.ShadowOpacity = effect.Opacity; + var effect = (ShadowEffect)Element.Effects.FirstOrDefault(e => e is ShadowEffect); + if (effect != null) + { + var layer = Control.Layer; + layer.ShadowRadius = effect.Radius; + layer.ShadowColor = effect.Color.ToCGColor(); + layer.ShadowOffset = effect.Offect.ToSizeF(); + layer.ShadowOpacity = effect.Opacity; + } + } + catch (Exception ex) + { + Helper.Error("shadow.effect.attached", $"Cannot set property on attached control, error: {ex.Message}"); } } - catch (Exception ex) - { - Helper.Error("shadow.effect.attached", $"Cannot set property on attached control, error: {ex.Message}"); - } - } - protected override void OnDetached() - { - var layer = Control?.Layer; - if (layer != null) + protected override void OnDetached() { - layer.ShadowColor = Color.Transparent.ToCGColor(); - layer.ShadowOpacity = 0; + var layer = Control?.Layer; + if (layer != null) + { + layer.ShadowColor = Color.Transparent.ToCGColor(); + layer.ShadowOpacity = 0; + } } } -} +} \ No newline at end of file diff --git a/Billing/Billing.iOS/Main.cs b/Billing/Billing.iOS/Main.cs index 4a10d03..4e61eb4 100644 --- a/Billing/Billing.iOS/Main.cs +++ b/Billing/Billing.iOS/Main.cs @@ -1,14 +1,15 @@ using UIKit; -namespace Billing.iOS; - -public class Application +namespace Billing.iOS { - // This is the main entry point of the application. - static void Main(string[] args) + public class Application { - // if you want to use a different Application Delegate class from "AppDelegate" - // you can specify it here. - UIApplication.Main(args, null, typeof(AppDelegate)); + // This is the main entry point of the application. + static void Main(string[] args) + { + // if you want to use a different Application Delegate class from "AppDelegate" + // you can specify it here. + UIApplication.Main(args, null, typeof(AppDelegate)); + } } -} +} \ No newline at end of file diff --git a/Billing/Billing.iOS/PlatformCulture.cs b/Billing/Billing.iOS/PlatformCulture.cs index 1f1ddca..188897a 100644 --- a/Billing/Billing.iOS/PlatformCulture.cs +++ b/Billing/Billing.iOS/PlatformCulture.cs @@ -4,72 +4,73 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Threading; -namespace Billing.Languages; - -public partial class PlatformCulture +namespace Billing.Languages { - public partial string GetNamespace() + public partial class PlatformCulture { - return typeof(AppDelegate).Namespace; - } - - public partial void Init() - { - string lang; - if (NSLocale.PreferredLanguages.Length > 0) + public partial string GetNamespace() { - var pref = NSLocale.PreferredLanguages[0]; - lang = iOSToDotnetLanguage(pref); - } - else - { - lang = "zh-CN"; + return typeof(AppDelegate).Namespace; } - CultureInfo ci; - Init(lang); - try - { - ci = new CultureInfo(Language); - } - catch (CultureNotFoundException e) + public partial void Init() { + string lang; + if (NSLocale.PreferredLanguages.Length > 0) + { + var pref = NSLocale.PreferredLanguages[0]; + lang = iOSToDotnetLanguage(pref); + } + else + { + lang = "zh-CN"; + } + + CultureInfo ci; + Init(lang); try { - var fallback = ToDotnetFallbackLanguage(); - Helper.Debug($"{lang} failed, trying {fallback} ({e.Message})"); - ci = new CultureInfo(fallback); + ci = new CultureInfo(Language); } - catch (CultureNotFoundException e1) + catch (CultureNotFoundException e) { - Helper.Error("culture.get", $"{lang} couldn't be set, using 'zh-CN' ({e1.Message})"); - ci = new CultureInfo("zh-CN"); + try + { + var fallback = ToDotnetFallbackLanguage(); + Helper.Debug($"{lang} failed, trying {fallback} ({e.Message})"); + ci = new CultureInfo(fallback); + } + catch (CultureNotFoundException e1) + { + Helper.Error("culture.get", $"{lang} couldn't be set, using 'zh-CN' ({e1.Message})"); + ci = new CultureInfo("zh-CN"); + } } + + Thread.CurrentThread.CurrentCulture = ci; + Thread.CurrentThread.CurrentUICulture = ci; + + Helper.Debug($"CurrentCulture set: {ci.Name}"); } - Thread.CurrentThread.CurrentCulture = ci; - Thread.CurrentThread.CurrentUICulture = ci; - - Helper.Debug($"CurrentCulture set: {ci.Name}"); - } - - [SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "")] - private static string iOSToDotnetLanguage(string iOSLanguage) - { - //certain languages need to be converted to CultureInfo equivalent - string netLanguage = iOSLanguage switch + [SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "")] + private static string iOSToDotnetLanguage(string iOSLanguage) { - // Not supported .NET culture - "ms-MY" or "ms-SG" => "ms", // closest supported - // "Schwiizertüütsch (Swiss German)" not supported .NET culture - "gsw-CH" => "de-CH", // closest supported + //certain languages need to be converted to CultureInfo equivalent + string netLanguage = iOSLanguage switch + { + // Not supported .NET culture + "ms-MY" or "ms-SG" => "ms", // closest supported + // "Schwiizertüütsch (Swiss German)" not supported .NET culture + "gsw-CH" => "de-CH", // closest supported - // add more application-specific cases here (if required) - // ONLY use cultures that have been tested and known to work + // add more application-specific cases here (if required) + // ONLY use cultures that have been tested and known to work - _ => iOSLanguage, - }; - Helper.Debug($"iOS Language: {iOSLanguage}, .NET Language/Locale: {netLanguage}"); - return netLanguage; + _ => iOSLanguage, + }; + Helper.Debug($"iOS Language: {iOSLanguage}, .NET Language/Locale: {netLanguage}"); + return netLanguage; + } } -} +} \ No newline at end of file diff --git a/Billing/Billing.iOS/Renderers/LongPressButtonRenderer.cs b/Billing/Billing.iOS/Renderers/LongPressButtonRenderer.cs index e9ed67a..8397006 100644 --- a/Billing/Billing.iOS/Renderers/LongPressButtonRenderer.cs +++ b/Billing/Billing.iOS/Renderers/LongPressButtonRenderer.cs @@ -5,39 +5,40 @@ using Xamarin.Forms; using Xamarin.Forms.Platform.iOS; [assembly: ExportRenderer(typeof(LongPressButton), typeof(LongPressButtonRenderer))] -namespace Billing.iOS.Renderers; - -public class LongPressButtonRenderer : ButtonRenderer +namespace Billing.iOS.Renderers { - private UILongPressGestureRecognizer longGesture; - - protected override void OnElementChanged(ElementChangedEventArgs