diff --git a/Billing.Shared/Billing.Shared.projitems b/Billing.Shared/Billing.Shared.projitems
index cab1ba6..a25db1d 100644
--- a/Billing.Shared/Billing.Shared.projitems
+++ b/Billing.Shared/Billing.Shared.projitems
@@ -36,12 +36,13 @@
+
+
AccountPage.xaml
AddAccountPage.xaml
- Code
AddBillPage.xaml
@@ -67,6 +68,10 @@
Designer
MSBuild:UpdateDesignTimeXaml
+
+ Designer
+ MSBuild:UpdateDesignTimeXaml
+
Designer
MSBuild:UpdateDesignTimeXaml
@@ -80,9 +85,4 @@
MSBuild:UpdateDesignTimeXaml
-
-
- MSBuild:UpdateDesignTimeXaml
-
-
\ No newline at end of file
diff --git a/Billing.Shared/Models/Account.cs b/Billing.Shared/Models/Account.cs
index bc2a069..3dadad5 100644
--- a/Billing.Shared/Models/Account.cs
+++ b/Billing.Shared/Models/Account.cs
@@ -8,6 +8,7 @@ namespace Billing.Models
public string Icon { get; set; } = ICON_DEFAULT;
public AccountCategory Category { get; set; }
public string Name { get; set; }
+ public decimal Initial { get; set; }
public decimal Balance { get; set; }
public string Memo { get; set; }
@@ -17,6 +18,7 @@ namespace Billing.Models
Icon = Read(node, nameof(Icon), ICON_DEFAULT);
Category = (AccountCategory)Read(node, nameof(Category), 0);
Name = Read(node, nameof(Name), string.Empty);
+ Initial = Read(node, nameof(Initial), 0m);
Balance = Read(node, nameof(Balance), 0m);
Memo = Read(node, nameof(Memo), null);
}
@@ -27,6 +29,7 @@ namespace Billing.Models
Write(node, nameof(Icon), Icon);
Write(node, nameof(Category), (int)Category);
Write(node, nameof(Name), Name);
+ Write(node, nameof(Initial), Initial);
Write(node, nameof(Balance), Balance);
Write(node, nameof(Memo), Memo);
}
diff --git a/Billing.Shared/UI/BillingDate.xaml.cs b/Billing.Shared/UI/BillingDate.xaml.cs
index e205c79..a87ed25 100644
--- a/Billing.Shared/UI/BillingDate.xaml.cs
+++ b/Billing.Shared/UI/BillingDate.xaml.cs
@@ -7,13 +7,13 @@ 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 static readonly BindableProperty SundayProperty = BindableProperty.Create(nameof(Sunday), typeof(BillingDay), typeof(BillingDate));
+ public static readonly BindableProperty MondayProperty = BindableProperty.Create(nameof(Monday), typeof(BillingDay), typeof(BillingDate));
+ public static readonly BindableProperty TuesdayProperty = BindableProperty.Create(nameof(Tuesday), typeof(BillingDay), typeof(BillingDate));
+ public static readonly BindableProperty WednesdayProperty = BindableProperty.Create(nameof(Wednesday), typeof(BillingDay), typeof(BillingDate));
+ public static readonly BindableProperty ThursdayProperty = BindableProperty.Create(nameof(Thursday), typeof(BillingDay), typeof(BillingDate));
+ public static readonly BindableProperty FridayProperty = BindableProperty.Create(nameof(Friday), typeof(BillingDay), typeof(BillingDate));
+ public static readonly BindableProperty SaturdayProperty = BindableProperty.Create(nameof(Saturday), typeof(BillingDay), typeof(BillingDate));
public BillingDay Sunday => (BillingDay)GetValue(SundayProperty);
public BillingDay Monday => (BillingDay)GetValue(MondayProperty);
@@ -219,12 +219,12 @@ namespace Billing.UI
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);
+ public static readonly BindableProperty DateProperty = BindableProperty.Create(nameof(Date), typeof(DateTime), typeof(BillingDay), propertyChanged: OnDatePropertyChanged);
+ public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(BillingDay));
+ public static readonly BindableProperty FontFamilyProperty = BindableProperty.Create(nameof(FontFamily), typeof(string), typeof(BillingDay), defaultValue: Definition.GetCascadiaRegularFontFamily());
+ public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create(nameof(IsSelected), typeof(bool), typeof(BillingDay));
+ public static readonly BindableProperty OpacityProperty = BindableProperty.Create(nameof(Opacity), typeof(double), typeof(BillingDay), defaultValue: 1.0);
+ public 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)
{
diff --git a/Billing.Shared/UI/GroupStackLayout.cs b/Billing.Shared/UI/GroupStackLayout.cs
new file mode 100644
index 0000000..0ae2020
--- /dev/null
+++ b/Billing.Shared/UI/GroupStackLayout.cs
@@ -0,0 +1,159 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Linq;
+using Xamarin.Forms;
+
+namespace Billing.UI
+{
+ public class GroupStackLayout : Layout
+ {
+ public static readonly BindableProperty GroupHeaderTemplateProperty = BindableProperty.Create(nameof(GroupHeaderTemplate), typeof(DataTemplate), typeof(GroupStackLayout));
+ public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create(nameof(ItemTemplate), typeof(DataTemplate), typeof(GroupStackLayout));
+ public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(nameof(ItemsSource), typeof(IList), typeof(GroupStackLayout), propertyChanged: OnItemsSourcePropertyChanged);
+ public static readonly BindableProperty SpacingProperty = BindableProperty.Create(nameof(Spacing), typeof(double), typeof(GroupStackLayout), defaultValue: 4d);
+
+ public DataTemplate GroupHeaderTemplate
+ {
+ get => (DataTemplate)GetValue(GroupHeaderTemplateProperty);
+ set => SetValue(GroupHeaderTemplateProperty, value);
+ }
+ public DataTemplate ItemTemplate
+ {
+ get => (DataTemplate)GetValue(ItemTemplateProperty);
+ set => SetValue(ItemTemplateProperty, value);
+ }
+ public IList ItemsSource
+ {
+ get => (IList)GetValue(ItemsSourceProperty);
+ set => SetValue(ItemsSourceProperty, value);
+ }
+ public double Spacing
+ {
+ get => (double)GetValue(SpacingProperty);
+ set => SetValue(SpacingProperty, value);
+ }
+
+ private static void OnItemsSourcePropertyChanged(BindableObject obj, object old, object @new)
+ {
+ var stack = (GroupStackLayout)obj;
+ stack.lastWidth = -1;
+ if (@new == null)
+ {
+ stack.cachedLayout.Clear();
+ stack.Children.Clear();
+ stack.InvalidateLayout();
+ }
+ else if (@new is IList list)
+ {
+ stack.freezed = true;
+ stack.cachedLayout.Clear();
+ stack.Children.Clear();
+ var groupTemplate = stack.GroupHeaderTemplate;
+ var itemTemplate = stack.ItemTemplate;
+ for (var i = 0; i < list.Count; i++)
+ {
+ var item = list[i];
+ if (item is IList sublist)
+ {
+ if (groupTemplate != null)
+ {
+ var child = groupTemplate.CreateContent();
+ if (child is View view)
+ {
+ view.BindingContext = item;
+ stack.Children.Add(view);
+ }
+ }
+ foreach (var it in sublist)
+ {
+ var child = itemTemplate.CreateContent();
+ if (child is View view)
+ {
+ view.BindingContext = it;
+ stack.Children.Add(view);
+ }
+ }
+ }
+ else
+ {
+ var child = itemTemplate.CreateContent();
+ if (child is View view)
+ {
+ view.BindingContext = list[i];
+ stack.Children.Add(view);
+ }
+ }
+ }
+ stack.freezed = false;
+ stack.UpdateChildrenLayout();
+ stack.InvalidateLayout();
+ }
+ }
+
+ private readonly Dictionary cachedLayout = new();
+
+ private bool freezed;
+ private double lastWidth = -1;
+ private SizeRequest lastSizeRequest;
+
+ public void Refresh(IList list)
+ {
+ OnItemsSourcePropertyChanged(this, null, list);
+ }
+
+ protected override void LayoutChildren(double x, double y, double width, double height)
+ {
+ if (freezed)
+ {
+ return;
+ }
+ var source = ItemsSource;
+ if (source == null || source.Count <= 0)
+ {
+ return;
+ }
+ var spacing = Spacing;
+ var lastHeight = 0.0;
+ foreach (var item in Children)
+ {
+ var measured = item.Measure(width, height, MeasureFlags.IncludeMargins);
+ var rect = new Rectangle(
+ 0, lastHeight, width,
+ measured.Request.Height);
+ if (cachedLayout.TryGetValue(item, out var v))
+ {
+ if (v != rect)
+ {
+ cachedLayout[item] = rect;
+ item.Layout(rect);
+ }
+ }
+ else
+ {
+ cachedLayout.Add(item, rect);
+ item.Layout(rect);
+ }
+ lastHeight += rect.Height + spacing;
+ }
+ }
+
+ protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
+ {
+ if (lastWidth == widthConstraint)
+ {
+ return lastSizeRequest;
+ }
+ lastWidth = widthConstraint;
+ var spacing = Spacing;
+ var lastHeight = 0.0;
+ foreach (var item in Children)
+ {
+ var measured = item.Measure(widthConstraint, heightConstraint, MeasureFlags.IncludeMargins);
+ lastHeight += measured.Request.Height + spacing;
+ }
+ lastSizeRequest = new SizeRequest(new Size(widthConstraint, lastHeight));
+ return lastSizeRequest;
+ }
+ }
+}
diff --git a/Billing.Shared/UI/ItemSelectPage.cs b/Billing.Shared/UI/ItemSelectPage.cs
new file mode 100644
index 0000000..12c7446
--- /dev/null
+++ b/Billing.Shared/UI/ItemSelectPage.cs
@@ -0,0 +1,51 @@
+using Billing.Themes;
+using System.Collections;
+
+using Xamarin.Forms;
+
+namespace Billing.UI
+{
+ public class ItemSelectPage : ContentPage
+ {
+ public ItemSelectPage(IList source)
+ {
+ Content = new ListView
+ {
+ ItemsSource = source,
+ ItemTemplate = new DataTemplate(() => new StackLayout
+ {
+ Orientation = StackOrientation.Horizontal,
+ Padding = new Thickness(20, 0),
+ Spacing = 10,
+ Children =
+ {
+ new Image
+ {
+ WidthRequest = 22,
+ HeightRequest = 22,
+ Aspect = Aspect.AspectFit,
+ VerticalOptions = LayoutOptions.Center
+ }
+ .Binding(Image.SourceProperty, "Icon"),
+
+ new Label
+ {
+ VerticalOptions = LayoutOptions.Center,
+ LineBreakMode = LineBreakMode.TailTruncation
+ }
+ .Binding(Label.TextProperty, "Name")
+ .DynamicResource(Label.TextColorProperty, BaseTheme.TextColor)
+ }
+ })
+ }
+ .DynamicResource(BackgroundColorProperty, BaseTheme.WindowBackgroundColor);
+ }
+ }
+
+ public class SelectItem
+ {
+ public string Icon { get; set; }
+ public T Value { get; set; }
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Billing.Shared/UI/OptionsCells.cs b/Billing.Shared/UI/OptionsCells.cs
index f84dd11..a71167c 100644
--- a/Billing.Shared/UI/OptionsCells.cs
+++ b/Billing.Shared/UI/OptionsCells.cs
@@ -4,7 +4,6 @@ using Xamarin.Forms;
namespace Billing.UI
{
-
public class OptionEntry : Entry { }
public class OptionEditor : Editor { }
diff --git a/Billing.Shared/Views/AccountPage.xaml b/Billing.Shared/Views/AccountPage.xaml
index 598a4f7..86fb32c 100644
--- a/Billing.Shared/Views/AccountPage.xaml
+++ b/Billing.Shared/Views/AccountPage.xaml
@@ -13,7 +13,7 @@
-
+
@@ -42,8 +42,17 @@
Text="{Binding Liability, Converter={StaticResource moneyConverter}}"/>
-
-
+
+
+
+
+
+
+
+
+
+
@@ -56,8 +65,8 @@
-
-
+
+
\ No newline at end of file
diff --git a/Billing.Shared/Views/AccountPage.xaml.cs b/Billing.Shared/Views/AccountPage.xaml.cs
index d965a13..1c843dd 100644
--- a/Billing.Shared/Views/AccountPage.xaml.cs
+++ b/Billing.Shared/Views/AccountPage.xaml.cs
@@ -1,4 +1,6 @@
+using System.Collections.Generic;
using System.Collections.ObjectModel;
+using System.Linq;
using Billing.Models;
using Billing.UI;
using Xamarin.Forms;
@@ -10,21 +12,21 @@ 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));
- private static readonly BindableProperty AccountsProperty = BindableProperty.Create(nameof(Accounts), typeof(ObservableCollection), typeof(AccountPage));
+ private static readonly BindableProperty AccountsProperty = BindableProperty.Create(nameof(Accounts), typeof(List), typeof(AccountPage));
public decimal Balance => (decimal)GetValue(BalanceProperty);
public decimal Asset => (decimal)GetValue(AssetProperty);
public decimal Liability => (decimal)GetValue(LiabilityProperty);
- public ObservableCollection Accounts => (ObservableCollection)GetValue(AccountsProperty);
+ public List Accounts => (List)GetValue(AccountsProperty);
public Command AddAccount { get; }
- private readonly ObservableCollection accounts;
+ private readonly List accounts;
public AccountPage()
{
AddAccount = new Command(OnAddAccount);
- accounts = new ObservableCollection();
+ accounts = new List();
SetValue(AccountsProperty, accounts);
InitializeComponent();
@@ -47,7 +49,27 @@ namespace Billing.Views
private void AccountChecked(object sender, AccountEventArgs e)
{
Helper.Debug(e.Account.ToString());
- accounts.Add(e.Account);
+ var group = accounts.FirstOrDefault(g => g.Key == e.Account.Category);
+ if (group == null)
+ {
+ group = new AccountGrouping(e.Account.Category)
+ {
+ e.Account
+ };
+ accounts.Add(group);
+ }
+ else
+ {
+ group.Add(e.Account);
+ }
+ groupLayout.Refresh(accounts);
}
}
+
+ public class AccountGrouping : List, IGrouping
+ {
+ public AccountGrouping(AccountCategory key) : base() => Key = key;
+ public AccountCategory Key { get; }
+ public decimal Balance { get; set; }
+ }
}
\ No newline at end of file
diff --git a/Billing.Shared/Views/AddAccountPage.xaml b/Billing.Shared/Views/AddAccountPage.xaml
index 37761d7..07e1dae 100644
--- a/Billing.Shared/Views/AddAccountPage.xaml
+++ b/Billing.Shared/Views/AddAccountPage.xaml
@@ -13,7 +13,6 @@
-
@@ -23,14 +22,16 @@
-
-
+
-
@@ -38,20 +39,22 @@
-
-
+
-
+ Placeholder="{r:Text MemoPlaceholder}"/>
diff --git a/Billing.Shared/Views/AddAccountPage.xaml.cs b/Billing.Shared/Views/AddAccountPage.xaml.cs
index 6b365ab..87e93a6 100644
--- a/Billing.Shared/Views/AddAccountPage.xaml.cs
+++ b/Billing.Shared/Views/AddAccountPage.xaml.cs
@@ -1,6 +1,8 @@
-using Billing.Models;
+using Billing.Languages;
+using Billing.Models;
using Billing.UI;
using System;
+using System.Collections.Generic;
using Xamarin.Forms;
namespace Billing.Views
@@ -69,16 +71,6 @@ namespace Billing.Views
InitializeComponent();
}
- private void Balance_Unfocused(object sender, FocusEventArgs e)
- {
- if (sender is OptionEntry entry && decimal.TryParse(entry.Text, out decimal d))
- {
- var converter = (MoneyConverter)Resources["moneyConverter"];
- entry.Text = converter.Convert(d, null, null, null)?.ToString();
- //Balance = d;
- }
- }
-
private async void OnCheckAccount()
{
if (Tap.IsBusy)
@@ -108,9 +100,22 @@ namespace Billing.Views
}
- private void OnSelectCategory()
+ private async void OnSelectCategory()
{
-
+ if (Tap.IsBusy)
+ {
+ return;
+ }
+ using (Tap.Start())
+ {
+ await Navigation.PushAsync(new ItemSelectPage(new List>
+ {
+ new() { Icon = "sackdollar", Value = AccountCategory.Cash, Name = Resource.Cash },
+ new() { Icon = "creditcard", Value = AccountCategory.CreditCard, Name = Resource.CreditCard },
+ new() { Icon = "", Value = AccountCategory.DebitCard, Name = Resource.DebitCard },
+ new() { Icon = "", Value = AccountCategory.ElecAccount, Name = Resource.ElecAccount }
+ }));
+ }
}
}
diff --git a/Billing/Billing.Android/Resources/drawable-mdpi/creditcard.png b/Billing/Billing.Android/Resources/drawable-mdpi/creditcard.png
new file mode 100644
index 0000000..948d197
Binary files /dev/null and b/Billing/Billing.Android/Resources/drawable-mdpi/creditcard.png differ
diff --git a/Billing/Billing.Android/Resources/drawable-xhdpi/creditcard.png b/Billing/Billing.Android/Resources/drawable-xhdpi/creditcard.png
new file mode 100644
index 0000000..8bf47e4
Binary files /dev/null and b/Billing/Billing.Android/Resources/drawable-xhdpi/creditcard.png differ
diff --git a/Billing/Billing.Android/Resources/drawable-xxhdpi/creditcard.png b/Billing/Billing.Android/Resources/drawable-xxhdpi/creditcard.png
new file mode 100644
index 0000000..d8f2b29
Binary files /dev/null and b/Billing/Billing.Android/Resources/drawable-xxhdpi/creditcard.png differ
diff --git a/Billing/Billing.Android/Resources/drawable/creditcard.png b/Billing/Billing.Android/Resources/drawable/creditcard.png
new file mode 100644
index 0000000..e40b05d
Binary files /dev/null and b/Billing/Billing.Android/Resources/drawable/creditcard.png differ
diff --git a/Billing/Billing.iOS/Resources/creditcard.png b/Billing/Billing.iOS/Resources/creditcard.png
new file mode 100644
index 0000000..948d197
Binary files /dev/null and b/Billing/Billing.iOS/Resources/creditcard.png differ
diff --git a/Billing/Billing.iOS/Resources/creditcard@2x.png b/Billing/Billing.iOS/Resources/creditcard@2x.png
new file mode 100644
index 0000000..8bf47e4
Binary files /dev/null and b/Billing/Billing.iOS/Resources/creditcard@2x.png differ
diff --git a/Billing/Billing.iOS/Resources/creditcard@3x.png b/Billing/Billing.iOS/Resources/creditcard@3x.png
new file mode 100644
index 0000000..d8f2b29
Binary files /dev/null and b/Billing/Billing.iOS/Resources/creditcard@3x.png differ