using Billing.Languages; using Billing.Models; using Billing.Themes; using Billing.UI; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Xamarin.Forms; namespace Billing.Views { public partial class CategoryPage : BillingPage { private static readonly BindableProperty CategoriesProperty = BindableProperty.Create(nameof(Categories), typeof(IList), typeof(CategoryPage)); private static readonly BindableProperty IsTopCategoryProperty = BindableProperty.Create(nameof(IsTopCategory), typeof(bool), typeof(CategoryPage)); public IList Categories { get => (IList)GetValue(CategoriesProperty); set => SetValue(CategoriesProperty, value); } public bool IsTopCategory => (bool)GetValue(IsTopCategoryProperty); public Command LongPressed { get; } public Command Tapped { get; } private readonly int parentId; private readonly Category parent; public CategoryPage(int pid = -1) { parentId = pid; parent = App.Categories.FirstOrDefault(c => c.Id == pid); Title = parent?.Name ?? Resource.CategoryManage; if (parent != null) { SetValue(IsTopCategoryProperty, false); Categories = App.Categories.Where(c => c.ParentId == pid).Select(c => WrapCategory(c)).ToList(); ToolbarItems.Add(new ToolbarItem { Order = ToolbarItemOrder.Primary, IconImageSource = "plus.png", Command = new Command(OnAddCategory) }); } else { SetValue(IsTopCategoryProperty, true); Categories = new List { new(Resource.Spending, App.Categories.Where(c => c.Type == CategoryType.Spending && c.ParentId == null).Select(c => WrapCategory(c))), new(Resource.Income, App.Categories.Where(c => c.Type == CategoryType.Income && c.ParentId == null).Select(c => WrapCategory(c))) }; } LongPressed = new Command(OnLongPressed); Tapped = new Command(OnTapped); InitializeComponent(); } private UICategory WrapCategory(Category category) { return new UICategory(category) { Icon = category.Icon, Name = category.Name, IsTopCategory = IsTopCategory, TintColor = category.TintColor == Color.Transparent || category.TintColor == default ? BaseTheme.CurrentPrimaryColor : category.TintColor }; } private async void OnAddCategory() { if (Tap.IsBusy) { return; } using (Tap.Start()) { var page = new AddCategoryPage(parent: parent); page.CategoryChecked += OnCategoryChecked; await Navigation.PushAsync(page); } } private async void OnLongPressed(object o) { if (Tap.IsBusy) { return; } using (Tap.Start()) { if (o is UICategory c) { if (parentId < 0) { var page = new AddCategoryPage(c.Category.Id); page.CategoryChecked += OnCategoryChecked; await Navigation.PushAsync(page); } else { var result = await this.ShowConfirm(string.Format(Resource.ConfirmDeleteCategory, c.Category.Name)); if (result) { Categories.Remove(c); groupLayout.Refresh(Categories); App.Categories.Remove(c.Category); _ = Task.Run(App.WriteCategories); } } } } } private async void OnTapped(object o) { if (Tap.IsBusy) { return; } using (Tap.Start()) { if (o is UICategory c) { if (parentId < 0) { var page = new CategoryPage(c.Category.Id); await Navigation.PushAsync(page); } else { var page = new AddCategoryPage(c.Category.Id); page.CategoryChecked += OnCategoryChecked; await Navigation.PushAsync(page); } } } } private void OnCategoryChecked(object sender, Category category) { if (category.Id < 0) { // add int maxId; if (App.Categories.Count > 0) { maxId = App.Categories.Max(b => b.Id); } else { maxId = -1; } category.Id = maxId + 1; App.Categories.Add(category); Categories.Add(WrapCategory(category)); } else { foreach (var o in Categories) { if (o is CategoryGrouping grouping) { var c = grouping.FirstOrDefault(c => c.Category == category); if (c != null) { UpdateCategory(c); } } else if (o is UICategory c && c.Category == category) { UpdateCategory(c); break; } } } groupLayout.Refresh(Categories); Task.Run(App.WriteCategories); } private void UpdateCategory(UICategory c) { c.Name = c.Category.Name; c.Icon = c.Category.Icon; c.TintColor = c.Category.TintColor == Color.Transparent || c.Category.TintColor == default ? BaseTheme.CurrentPrimaryColor : c.Category.TintColor; } } public class UICategory : BindableObject { public static readonly BindableProperty IsCheckedProperty = BindableProperty.Create(nameof(IsChecked), typeof(bool), typeof(UICategory)); public static readonly BindableProperty IconProperty = BindableProperty.Create(nameof(Icon), typeof(string), typeof(UICategory)); public static readonly BindableProperty NameProperty = BindableProperty.Create(nameof(Name), typeof(string), typeof(UICategory)); public static readonly BindableProperty TintColorProperty = BindableProperty.Create(nameof(TintColor), typeof(Color), typeof(UICategory)); public static readonly BindableProperty IsTopCategoryProperty = BindableProperty.Create(nameof(IsTopCategory), typeof(bool), typeof(UICategory)); public bool IsChecked { get => (bool)GetValue(IsCheckedProperty); set => SetValue(IsCheckedProperty, value); } public string Icon { get => (string)GetValue(IconProperty); set => SetValue(IconProperty, value); } public string Name { get => (string)GetValue(NameProperty); set => SetValue(NameProperty, value); } public Color TintColor { get => (Color)GetValue(TintColorProperty); set => SetValue(TintColorProperty, value); } public bool IsTopCategory { get => (bool)GetValue(IsTopCategoryProperty); set => SetValue(IsTopCategoryProperty, value); } public Category Category { get; } public UICategory(Category category) { Category = category; } } public class CategoryGrouping : List, IGrouping { public string Key { get; } public CategoryGrouping(string key, IEnumerable categories) : base(categories) { Key = key; } } }