Billing/Billing.Shared/Views/CategoryPage.xaml.cs
2022-03-07 21:31:27 +08:00

250 lines
8.5 KiB
C#

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<CategoryGrouping>
{
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<UICategory>, IGrouping<string, UICategory>
{
public string Key { get; }
public CategoryGrouping(string key, IEnumerable<UICategory> categories) : base(categories)
{
Key = key;
}
}
}