filter conditions

This commit is contained in:
Tsanie 2022-03-10 17:27:49 +08:00
parent 84ec2df987
commit 74053a328e
18 changed files with 330 additions and 95 deletions

View File

@ -20,6 +20,14 @@
<TapToMemo>Click here to record</TapToMemo> <TapToMemo>Click here to record</TapToMemo>
<TitleDateFormat>MM/dd/yyyy</TitleDateFormat> <TitleDateFormat>MM/dd/yyyy</TitleDateFormat>
<DateRangeFormat>MM/dd</DateRangeFormat> <DateRangeFormat>MM/dd</DateRangeFormat>
<To>To</To>
<Monthly>Monthly</Monthly>
<Today>Today</Today>
<PastMonth>Past Month</PastMonth>
<PastQuarter>Past Quarter</PastQuarter>
<PastSixMonths>Past Six Months</PastSixMonths>
<PastYear>Past Year</PastYear>
<Total>Total</Total>
<Balance>Balance</Balance> <Balance>Balance</Balance>
<Assets>Assets</Assets> <Assets>Assets</Assets>
<Liability>Liability</Liability> <Liability>Liability</Liability>

View File

@ -20,6 +20,14 @@
<TapToMemo>点此记录</TapToMemo> <TapToMemo>点此记录</TapToMemo>
<TitleDateFormat>yyyy年MM月dd日</TitleDateFormat> <TitleDateFormat>yyyy年MM月dd日</TitleDateFormat>
<DateRangeFormat>MM月dd日</DateRangeFormat> <DateRangeFormat>MM月dd日</DateRangeFormat>
<To></To>
<Monthly>当月</Monthly>
<Today>今日</Today>
<PastMonth>一个月</PastMonth>
<PastQuarter>一个季度</PastQuarter>
<PastSixMonths>六个月</PastSixMonths>
<PastYear>一年</PastYear>
<Total>全部</Total>
<Balance>余额</Balance> <Balance>余额</Balance>
<Assets>资产</Assets> <Assets>资产</Assets>
<Liability>负债</Liability> <Liability>负债</Liability>

View File

@ -8,6 +8,8 @@ namespace Billing.UI
{ {
public event EventHandler Loaded; public event EventHandler Loaded;
private bool loaded;
public BillingPage() public BillingPage()
{ {
SetDynamicResource(BackgroundColorProperty, BaseTheme.WindowBackgroundColor); SetDynamicResource(BackgroundColorProperty, BaseTheme.WindowBackgroundColor);
@ -18,5 +20,14 @@ namespace Billing.UI
{ {
Loaded?.Invoke(this, EventArgs.Empty); Loaded?.Invoke(this, EventArgs.Empty);
} }
public void TriggerLoad()
{
if (!loaded)
{
loaded = true;
OnLoaded();
}
}
} }
} }

View File

@ -8,15 +8,19 @@ namespace Billing.UI
{ {
public class ColorPicker : SKCanvasView public class ColorPicker : SKCanvasView
{ {
public static readonly BindableProperty ColorProperty = BindableProperty.Create(nameof(Color), typeof(Color), typeof(ColorPicker)); public static readonly BindableProperty ColorProperty = Helper.Create<Color, ColorPicker>(nameof(Color));
public static readonly BindableProperty CommandProperty = Helper.Create<Command, ColorPicker>(nameof(Command));
public Color Color public Color Color
{ {
get => (Color)GetValue(ColorProperty); get => (Color)GetValue(ColorProperty);
set => SetValue(ColorProperty, value); set => SetValue(ColorProperty, value);
} }
public Command Command
public event EventHandler<Color> ColorChanged; {
get => (Command)GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
private SKPoint? lastTouch; private SKPoint? lastTouch;
@ -116,7 +120,7 @@ namespace Billing.UI
var color = touchColor.ToFormsColor(); var color = touchColor.ToFormsColor();
Color = color; Color = color;
ColorChanged?.Invoke(this, color); Command?.Execute(color);
} }
} }
@ -126,8 +130,8 @@ namespace Billing.UI
lastTouch = e.Location; lastTouch = e.Location;
var size = CanvasSize; var size = CanvasSize;
if ((e.Location.X > 0 && e.Location.X < size.Width) && if (e.Location.X > 0 && e.Location.X < size.Width &&
(e.Location.Y > 0 && e.Location.Y < size.Height)) e.Location.Y > 0 && e.Location.Y < size.Height)
{ {
e.Handled = true; e.Handled = true;
InvalidateSurface(); InvalidateSurface();

View File

@ -92,6 +92,12 @@ namespace Billing.UI
var result = await page.DisplayActionSheet(message, Resource.No, yes); var result = await page.DisplayActionSheet(message, Resource.No, yes);
return result == yes; return result == yes;
} }
public static DateTime LastMoment(this DateTime date)
{
// add 23:59:59.999...
return date.AddTicks(863999999999);
}
} }
public static class ModelExtensionHelper public static class ModelExtensionHelper

View File

@ -73,15 +73,9 @@ namespace Billing.Views
InitializeComponent(); InitializeComponent();
} }
private bool focused;
public override void OnLoaded() public override void OnLoaded()
{ {
if (!focused) editorName.SetFocus();
{
focused = true;
editorName.SetFocus();
}
} }
private async void OnCheckAccount() private async void OnCheckAccount()

View File

@ -116,15 +116,9 @@ namespace Billing.Views
} }
} }
private bool focused;
public override void OnLoaded() public override void OnLoaded()
{ {
if (!focused) editorAmount.SetFocus();
{
focused = true;
editorAmount.SetFocus();
}
} }
private async void OnCheckBill() private async void OnCheckBill()

View File

@ -41,7 +41,7 @@
<ViewCell Height="120"> <ViewCell Height="120">
<Grid BackgroundColor="{DynamicResource OptionTintColor}" <Grid BackgroundColor="{DynamicResource OptionTintColor}"
ColumnDefinitions=".35*, .65*" Padding="10"> ColumnDefinitions=".35*, .65*" Padding="10">
<ui:ColorPicker Grid.Column="1" ColorChanged="ColorPicker_ColorChanged"/> <ui:ColorPicker Grid.Column="1" Command="{Binding ColorPickerCommand}"/>
</Grid> </Grid>
</ViewCell> </ViewCell>
</TableSection> </TableSection>

View File

@ -38,6 +38,7 @@ namespace Billing.Views
public Command CheckCategory { get; } public Command CheckCategory { get; }
public Command SelectIcon { get; } public Command SelectIcon { get; }
public Command ColorPickerCommand { get; }
public event EventHandler<Category> CategoryChecked; public event EventHandler<Category> CategoryChecked;
@ -73,25 +74,23 @@ namespace Billing.Views
CheckCategory = new Command(OnCheckCategory); CheckCategory = new Command(OnCheckCategory);
SelectIcon = new Command(OnSelectIcon); SelectIcon = new Command(OnSelectIcon);
ColorPickerCommand = new Command(OnColorPickerCommand);
InitializeComponent(); InitializeComponent();
} }
private bool focused;
public override void OnLoaded() public override void OnLoaded()
{ {
if (!focused) editorName.SetFocus();
{
focused = true;
editorName.SetFocus();
}
} }
private void ColorPicker_ColorChanged(object sender, Color e) private void OnColorPickerCommand(object o)
{ {
TintColor = e; if (o is Color color)
TintColorString = Helper.WrapColorString(e.ToHex()); {
TintColor = color;
TintColorString = Helper.WrapColorString(color.ToHex());
}
} }
private async void OnCheckCategory() private async void OnCheckCategory()

View File

@ -44,8 +44,6 @@ namespace Billing.Views
public Command EditBilling { get; } public Command EditBilling { get; }
public Command DeleteBilling { get; } public Command DeleteBilling { get; }
private bool initialized;
public BillPage() public BillPage()
{ {
TitleDateTap = new Command(OnTitleDateTapped); TitleDateTap = new Command(OnTitleDateTapped);
@ -58,11 +56,7 @@ namespace Billing.Views
public override void OnLoaded() public override void OnLoaded()
{ {
if (!initialized) billingDate.SetDateTime(DateTime.Today);
{
initialized = true;
billingDate.SetDateTime(DateTime.Today);
}
} }
private void OnDateSelected(object sender, DateEventArgs e) private void OnDateSelected(object sender, DateEventArgs e)

View File

@ -4,6 +4,7 @@
xmlns:ui="clr-namespace:Billing.UI" xmlns:ui="clr-namespace:Billing.UI"
xmlns:v="clr-namespace:Billing.Views" xmlns:v="clr-namespace:Billing.Views"
xmlns:chart="clr-namespace:Microcharts.Forms;assembly=Microcharts.Forms" xmlns:chart="clr-namespace:Microcharts.Forms;assembly=Microcharts.Forms"
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Billing.Views.RankPage" x:Class="Billing.Views.RankPage"
x:Name="rankPage" x:Name="rankPage"
@ -13,7 +14,7 @@
<Shell.TitleView> <Shell.TitleView>
<Grid> <Grid>
<StackLayout Margin="30, 0, 0, 0" HorizontalOptions="Center" VerticalOptions="Center" <StackLayout HorizontalOptions="Center" VerticalOptions="Center"
Orientation="Horizontal" Spacing="10"> Orientation="Horizontal" Spacing="10">
<ui:TintImageButton Source="left.png" WidthRequest="20" HeightRequest="20" <ui:TintImageButton Source="left.png" WidthRequest="20" HeightRequest="20"
VerticalOptions="Center" HorizontalOptions="Start" VerticalOptions="Center" HorizontalOptions="Start"
@ -21,6 +22,9 @@
<Label Text="{Binding Title}" <Label Text="{Binding Title}"
TextColor="{DynamicResource PrimaryColor}" TextColor="{DynamicResource PrimaryColor}"
FontSize="{OnPlatform Android=20, iOS=18}"> FontSize="{OnPlatform Android=20, iOS=18}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding FilterCommand}"/>
</Label.GestureRecognizers>
<Label.FontFamily> <Label.FontFamily>
<OnPlatform x:TypeArguments="x:String" <OnPlatform x:TypeArguments="x:String"
Android="OpenSans-SemiBold.ttf#OpenSans-SemiBold" Android="OpenSans-SemiBold.ttf#OpenSans-SemiBold"
@ -34,9 +38,9 @@
</Grid> </Grid>
</Shell.TitleView> </Shell.TitleView>
<ContentPage.ToolbarItems> <!--<ContentPage.ToolbarItems>
<ToolbarItem Order="Primary" IconImageSource="filter.png" Command="{Binding FilterCommand}"/> <ToolbarItem Order="Primary" IconImageSource="filter.png" Command="{Binding FilterCommand}"/>
</ContentPage.ToolbarItems> </ContentPage.ToolbarItems>-->
<ContentPage.Resources> <ContentPage.Resources>
<ui:NegativeConverter x:Key="negativeConverter"/> <ui:NegativeConverter x:Key="negativeConverter"/>
@ -48,7 +52,7 @@
<Style x:Key="titleLabel" TargetType="Label"> <Style x:Key="titleLabel" TargetType="Label">
<Setter Property="FontSize" Value="16"/> <Setter Property="FontSize" Value="16"/>
<Setter Property="Margin" Value="10, 20, 10, 10"/> <Setter Property="Margin" Value="10, 20, 10, 10"/>
<!--<Setter Property="TextColor" Value="{DynamicResource SecondaryTextColor}"/>--> <Setter Property="TextColor" Value="{DynamicResource TextColor}"/>
</Style> </Style>
<Style x:Key="promptLabel" TargetType="Label"> <Style x:Key="promptLabel" TargetType="Label">
<Setter Property="HeightRequest" Value="240"/> <Setter Property="HeightRequest" Value="240"/>
@ -58,12 +62,16 @@
<Setter Property="VerticalTextAlignment" Value="Center"/> <Setter Property="VerticalTextAlignment" Value="Center"/>
<Setter Property="TextColor" Value="{DynamicResource SecondaryTextColor}"/> <Setter Property="TextColor" Value="{DynamicResource SecondaryTextColor}"/>
</Style> </Style>
<Style TargetType="Button">
<Setter Property="TextColor" Value="{DynamicResource TextColor}"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</ContentPage.Resources> </ContentPage.Resources>
<Grid> <Grid>
<ScrollView x:Name="scroller"> <ScrollView x:Name="scroller" Scrolled="Scroller_Scrolled">
<StackLayout> <StackLayout>
<Grid Margin="0, 10, 0, 0" Padding="8" ColumnSpacing="8" ColumnDefinitions="*, Auto" HeightRequest="24" <Grid Padding="8" ColumnSpacing="8" ColumnDefinitions="*, Auto" HeightRequest="24"
BackgroundColor="{DynamicResource PromptBackgroundColor}"> BackgroundColor="{DynamicResource PromptBackgroundColor}">
<StackLayout Grid.Column="1" Orientation="Horizontal" Spacing="6"> <StackLayout Grid.Column="1" Orientation="Horizontal" Spacing="6">
<Label Text="{r:Text Income}" TextColor="{DynamicResource GreenColor}" <Label Text="{r:Text Income}" TextColor="{DynamicResource GreenColor}"
@ -133,7 +141,7 @@
<ui:BlurryPanel x:Name="panelFilter" VerticalOptions="Start" Opacity="0" <ui:BlurryPanel x:Name="panelFilter" VerticalOptions="Start" Opacity="0"
BackgroundColor="{DynamicResource WindowBackgroundColor}" BackgroundColor="{DynamicResource WindowBackgroundColor}"
HeightRequest="{Binding Height, Source={x:Reference gridFilter}}"/> HeightRequest="{Binding Height, Source={x:Reference gridFilter}}"/>
<Grid x:Name="gridFilter" VerticalOptions="Start" Opacity="0" Padding="10"> <Grid x:Name="gridFilter" VerticalOptions="Start" Opacity="0" Padding="10" RowDefinitions="Auto, Auto, Auto">
<ui:SegmentedControl Margin="6, 6, 6, 3" VerticalOptions="Center" <ui:SegmentedControl Margin="6, 6, 6, 3" VerticalOptions="Center"
SelectedSegmentIndex="{Binding SegmentType, Mode=TwoWay}" SelectedSegmentIndex="{Binding SegmentType, Mode=TwoWay}"
SelectedTextColor="{DynamicResource TextColor}" SelectedTextColor="{DynamicResource TextColor}"
@ -143,6 +151,33 @@
<ui:SegmentedControlOption Text="{r:Text Income}"/> <ui:SegmentedControlOption Text="{r:Text Income}"/>
</ui:SegmentedControl.Children> </ui:SegmentedControl.Children>
</ui:SegmentedControl> </ui:SegmentedControl>
<ScrollView Grid.Row="1" Margin="6, 6, 6, 3">
<ui:SegmentedControl SelectedSegmentIndex="{Binding SegmentDate, Mode=TwoWay}"
SelectedTextColor="{DynamicResource TextColor}"
TintColor="{DynamicResource PromptBackgroundColor}">
<ui:SegmentedControl.Children>
<ui:SegmentedControlOption Text="{r:Text Monthly}"/>
<ui:SegmentedControlOption Text="{r:Text Today}"/>
<ui:SegmentedControlOption Text="{r:Text PastMonth}"/>
<ui:SegmentedControlOption Text="{r:Text PastQuarter}"/>
<ui:SegmentedControlOption Text="{r:Text PastSixMonths}"/>
<ui:SegmentedControlOption Text="{r:Text PastYear}"/>
<ui:SegmentedControlOption Text="{r:Text Total}"/>
</ui:SegmentedControl.Children>
</ui:SegmentedControl>
</ScrollView>
<Grid Grid.Row="2" ColumnDefinitions="*, Auto, *" Margin="0, 10">
<ui:OptionDatePicker Date="{Binding StartPickerDate, Mode=TwoWay}"
FontSize="16" TextColor="{DynamicResource TextColor}"
VerticalOptions="Center"
ios:DatePicker.UpdateMode="WhenFinished"/>
<Label Grid.Column="1" Text="{r:Text To}" TextColor="{DynamicResource SecondaryTextColor}"
VerticalOptions="Center"/>
<ui:OptionDatePicker Grid.Column="2" Date="{Binding EndPickerDate, Mode=TwoWay}"
FontSize="16" TextColor="{DynamicResource TextColor}"
VerticalOptions="Center"
ios:DatePicker.UpdateMode="WhenFinished"/>
</Grid>
</Grid> </Grid>
</Grid> </Grid>
</ui:BillingPage> </ui:BillingPage>

View File

@ -16,7 +16,22 @@ namespace Billing.Views
{ {
public partial class RankPage : BillingPage public partial class RankPage : BillingPage
{ {
private static readonly DateTime today = DateTime.Today;
private static readonly BindableProperty SegmentTypeProperty = Helper.Create<int, RankPage>(nameof(SegmentType), defaultValue: 0, propertyChanged: OnSegmentTypeChanged); private static readonly BindableProperty SegmentTypeProperty = Helper.Create<int, RankPage>(nameof(SegmentType), defaultValue: 0, propertyChanged: OnSegmentTypeChanged);
private static readonly BindableProperty SegmentDateProperty = Helper.Create<int, RankPage>(nameof(SegmentDate), defaultValue: 0, propertyChanged: OnSegmentDateChanged);
private static readonly BindableProperty StartDateProperty = Helper.Create<DateTime, RankPage>(nameof(StartDate),
defaultValue: today.AddDays(1 - today.Day),
propertyChanged: OnDateChanged);
private static readonly BindableProperty EndDateProperty = Helper.Create<DateTime, RankPage>(nameof(EndDate),
defaultValue: today.AddDays(DateTime.DaysInMonth(today.Year, today.Month) - today.Day).LastMoment(),
propertyChanged: OnDateChanged);
private static readonly BindableProperty StartPickerDateProperty = Helper.Create<DateTime, RankPage>(nameof(StartPickerDate),
defaultValue: today.AddDays(1 - today.Day),
propertyChanged: OnPickerStartDateChanged);
private static readonly BindableProperty EndPickerDateProperty = Helper.Create<DateTime, RankPage>(nameof(EndPickerDate),
defaultValue: today.AddDays(DateTime.DaysInMonth(today.Year, today.Month) - today.Day),
propertyChanged: OnPickerEndDateChanged);
private static readonly BindableProperty ChartProperty = Helper.Create<Chart, RankPage>(nameof(Chart)); private static readonly BindableProperty ChartProperty = Helper.Create<Chart, RankPage>(nameof(Chart));
private static readonly BindableProperty CategoryChartProperty = Helper.Create<Chart, RankPage>(nameof(CategoryChart)); private static readonly BindableProperty CategoryChartProperty = Helper.Create<Chart, RankPage>(nameof(CategoryChart));
private static readonly BindableProperty TopBillsProperty = Helper.Create<IList<UIBill>, RankPage>(nameof(TopBills)); private static readonly BindableProperty TopBillsProperty = Helper.Create<IList<UIBill>, RankPage>(nameof(TopBills));
@ -34,8 +49,40 @@ namespace Billing.Views
1 => CategoryType.Income, 1 => CategoryType.Income,
_ => CategoryType.Spending _ => CategoryType.Spending
}; };
page.OnFilterCommand(false); page.LoadData();
page.SetMonth(page.current); }
private static void OnSegmentDateChanged(RankPage page, int old, int @new)
{
page.OnDateTypeCommand(@new);
}
private static void OnDateChanged(RankPage page, DateTime old = default, DateTime @new = default)
{
page.isLocked = true;
page.StartPickerDate = page.StartDate;
page.EndPickerDate = page.EndDate;
page.isLocked = false;
if (!page.isFreezed)
{
var format = Resource.TitleDateFormat;
page.Title = page.StartDate.ToString(format) + " ~ " + page.EndDate.ToString(format);
page.LoadData();
}
}
private static void OnPickerStartDateChanged(RankPage page, DateTime _, DateTime @new)
{
if (!page.isLocked)
{
page.SegmentDate = -1;
page.StartDate = @new;
}
}
private static void OnPickerEndDateChanged(RankPage page, DateTime _, DateTime @new)
{
if (!page.isLocked)
{
page.SegmentDate = -1;
page.EndDate = @new;
}
} }
public int SegmentType public int SegmentType
@ -43,6 +90,31 @@ namespace Billing.Views
get => (int)GetValue(SegmentTypeProperty); get => (int)GetValue(SegmentTypeProperty);
set => SetValue(SegmentTypeProperty, value); set => SetValue(SegmentTypeProperty, value);
} }
public int SegmentDate
{
get => (int)GetValue(SegmentDateProperty);
set => SetValue(SegmentDateProperty, value);
}
public DateTime StartDate
{
get => (DateTime)GetValue(StartDateProperty);
set => SetValue(StartDateProperty, value);
}
public DateTime EndDate
{
get => (DateTime)GetValue(EndDateProperty);
set => SetValue(EndDateProperty, value);
}
public DateTime StartPickerDate
{
get => (DateTime)GetValue(StartPickerDateProperty);
set => SetValue(StartPickerDateProperty, value);
}
public DateTime EndPickerDate
{
get => (DateTime)GetValue(EndPickerDateProperty);
set => SetValue(EndPickerDateProperty, value);
}
public Chart Chart public Chart Chart
{ {
get => (Chart)GetValue(ChartProperty); get => (Chart)GetValue(ChartProperty);
@ -82,11 +154,11 @@ namespace Billing.Views
public Command FilterCommand { get; } public Command FilterCommand { get; }
public Command EditBilling { get; } public Command EditBilling { get; }
private DateTime current;
private DateTime end;
private IEnumerable<Bill> bills; private IEnumerable<Bill> bills;
private CategoryType type = CategoryType.Spending; private CategoryType type = CategoryType.Spending;
private bool isFilterToggled; private bool isFilterToggled;
private bool isFreezed;
private bool isLocked;
private readonly SKTypeface font; private readonly SKTypeface font;
@ -111,7 +183,76 @@ namespace Billing.Views
public override void OnLoaded() public override void OnLoaded()
{ {
SetMonth(DateTime.Today); OnDateChanged(this);
}
private void OnDateTypeCommand(int index)
{
if (index < 0)
{
return;
}
if (scroller.ScrollY > 0)
{
scroller.ScrollToAsync(0, 0, true);
}
isFreezed = true;
var today = DateTime.Today;
switch (index)
{
case 0: // monthly
StartDate = today.AddDays(1 - today.Day);
EndDate = today.AddDays(DateTime.DaysInMonth(today.Year, today.Month) - today.Day).LastMoment();
break;
case 1: // today
StartDate = today;
EndDate = today.LastMoment();
break;
case 2: // past month
StartDate = today.AddMonths(-1).AddDays(1);
EndDate = today.LastMoment();
break;
case 3: // past quarter
StartDate = today.AddMonths(-3).AddDays(1);
EndDate = today.LastMoment();
break;
case 4: // past six months
StartDate = today.AddMonths(-6).AddDays(1);
EndDate = today.LastMoment();
break;
case 5: // past year
StartDate = today.AddYears(-1).AddDays(1);
EndDate = today.LastMoment();
break;
case 6: // total
//StartDate = App.Bills.Min(b => b.CreateTime).Date;
//EndDate = App.Bills.Max(b => b.CreateTime).Date.LastMoment();
DateTime min = DateTime.MaxValue;
DateTime max = DateTime.MinValue;
App.Bills.ForEach(b =>
{
if (b.CreateTime < min)
{
min = b.CreateTime;
}
if (b.CreateTime > max)
{
max = b.CreateTime;
}
});
StartDate = min.Date;
EndDate = max.Date.LastMoment();
break;
}
isFreezed = false;
OnDateChanged(this);
}
private bool IsPreset(DateTime start, DateTime end)
{
return start.Month == end.Month &&
start.Day == 1 &&
end.Day == DateTime.DaysInMonth(end.Year, end.Month);
} }
private void OnLeftCommand() private void OnLeftCommand()
@ -120,7 +261,29 @@ namespace Billing.Views
{ {
scroller.ScrollToAsync(0, 0, true); scroller.ScrollToAsync(0, 0, true);
} }
SetMonth(current.AddMonths(-1)); isFreezed = true;
var start = StartDate;
var end = EndDate;
if (IsPreset(start, end))
{
start = start.AddMonths(-1);
end = start.AddDays(DateTime.DaysInMonth(start.Year, start.Month) - 1).LastMoment();
}
else
{
var days = (end.Date - start.Date).TotalDays + 1;
start = start.AddDays(-days);
end = end.AddDays(-days);
}
if (start.Year < 1900)
{
isFreezed = false;
return;
}
StartDate = start;
EndDate = end;
isFreezed = false;
OnDateChanged(this);
} }
private void OnRightCommand() private void OnRightCommand()
@ -129,7 +292,29 @@ namespace Billing.Views
{ {
scroller.ScrollToAsync(0, 0, true); scroller.ScrollToAsync(0, 0, true);
} }
SetMonth(current.AddMonths(1)); isFreezed = true;
var start = StartDate;
var end = EndDate;
if (IsPreset(start, end))
{
start = start.AddMonths(1);
end = start.AddDays(DateTime.DaysInMonth(start.Year, start.Month) - 1).LastMoment();
}
else
{
var days = (end.Date - start.Date).TotalDays + 1;
start = start.AddDays(days);
end = end.AddDays(days);
}
if (end.Year > DateTime.Today.Year + 100)
{
isFreezed = false;
return;
}
StartDate = start;
EndDate = end;
isFreezed = false;
OnDateChanged(this);
} }
private async void OnFilterCommand(object o) private async void OnFilterCommand(object o)
@ -146,6 +331,7 @@ namespace Billing.Views
ViewExtensions.CancelAnimations(panelFilter); ViewExtensions.CancelAnimations(panelFilter);
if (isFilterToggled) if (isFilterToggled)
{ {
await scroller.ScrollToAsync(scroller.ScrollX, scroller.ScrollY, false);
await Task.WhenAll( await Task.WhenAll(
gridFilter.TranslateTo(0, 0, easing: Easing.CubicOut), gridFilter.TranslateTo(0, 0, easing: Easing.CubicOut),
gridFilter.FadeTo(1, easing: Easing.CubicOut), gridFilter.FadeTo(1, easing: Easing.CubicOut),
@ -179,18 +365,9 @@ namespace Billing.Views
} }
} }
private void UpdateBill(UIBill bill) private async void RefreshBalance(DateTime start, DateTime end)
{
bill.Icon = App.Categories.FirstOrDefault(c => c.Id == bill.Bill.CategoryId)?.Icon ?? BaseModel.ICON_DEFAULT;
bill.Name = bill.Bill.Name;
bill.DateCreation = bill.Bill.CreateTime;
bill.Amount = bill.Bill.Amount;
bill.Wallet = App.Accounts.FirstOrDefault(a => a.Id == bill.Bill.WalletId)?.Name;
}
private async void RefreshBalance()
{ {
var bills = await Task.Run(() => App.Bills.Where(b => b.CreateTime >= current && b.CreateTime <= end)); var bills = await Task.Run(() => App.Bills.Where(b => b.CreateTime >= start && b.CreateTime <= end));
var income = bills.Where(b => b.Amount > 0).Sum(b => b.Amount); var income = bills.Where(b => b.Amount > 0).Sum(b => b.Amount);
var spending = -bills.Where(b => b.Amount < 0).Sum(b => b.Amount); var spending = -bills.Where(b => b.Amount < 0).Sum(b => b.Amount);
SetValue(IncomeProperty, income); SetValue(IncomeProperty, income);
@ -198,43 +375,33 @@ namespace Billing.Views
SetValue(BalanceProperty, income - spending); SetValue(BalanceProperty, income - spending);
} }
private void OnBillChecked(object sender, Bill e) private async void OnBillChecked(object sender, Bill e)
{ {
var bill = TopBills.FirstOrDefault(b => b.Bill == e); await Task.Run(App.WriteBills);
if (bill != null) LoadData();
{
UpdateBill(bill);
}
RefreshBalance();
Task.Run(App.WriteBills);
} }
private async void SetMonth(DateTime date) private async void LoadData()
{ {
current = date.AddDays(1 - date.Day); var start = StartDate;
end = current.AddDays(DateTime.DaysInMonth(current.Year, current.Month)); var end = EndDate;
var format = Resource.DateRangeFormat;
Title = current.ToString(format) + " ~ " + end.AddDays(-1).ToString(format);
var spending = type == CategoryType.Spending; var spending = type == CategoryType.Spending;
bills = await Task.Run(() => App.Bills.Where(b => (b.Amount > 0 ^ spending) && b.CreateTime >= current && b.CreateTime <= end)); bills = await Task.Run(() => App.Bills.Where(b => (b.Amount > 0 ^ spending) && b.CreateTime >= start && b.CreateTime <= end));
var primaryColor = BaseTheme.CurrentPrimaryColor.ToSKColor(); var primaryColor = BaseTheme.CurrentPrimaryColor.ToSKColor();
var textColor = BaseTheme.CurrentSecondaryTextColor.ToSKColor(); var textColor = BaseTheme.CurrentSecondaryTextColor.ToSKColor();
_ = Task.Run(() => LoadReportChart(primaryColor, textColor)); _ = Task.Run(() => LoadReportChart(primaryColor, textColor, start, end));
_ = Task.Run(() => LoadCategoryChart(primaryColor, textColor)); _ = Task.Run(() => LoadCategoryChart(primaryColor, textColor));
_ = Task.Run(LoadTopBills); _ = Task.Run(LoadTopBills);
RefreshBalance(); RefreshBalance(start, end);
} }
private void LoadReportChart(SKColor primaryColor, SKColor textColor) private void LoadReportChart(SKColor primaryColor, SKColor textColor, DateTime start, DateTime end)
{ {
var entries = new List<ChartEntry>(); var entries = new List<ChartEntry>();
for (var day = current; day <= end; day = day.AddDays(1)) for (var day = start; day <= end; day = day.AddDays(1))
{ {
var daybills = bills.Where(b => Helper.IsSameDay(b.CreateTime, day)); var daybills = bills.Where(b => Helper.IsSameDay(b.CreateTime, day));
decimal amount = Math.Abs(daybills.Sum(b => b.Amount)); decimal amount = Math.Abs(daybills.Sum(b => b.Amount));
@ -350,5 +517,13 @@ namespace Billing.Views
} }
}); });
} }
private void Scroller_Scrolled(object sender, ScrolledEventArgs e)
{
if (isFilterToggled)
{
OnFilterCommand(false);
}
}
} }
} }

View File

@ -31,7 +31,7 @@
<!--<Label Text="" LineBreakMode="TailTruncation" <!--<Label Text="" LineBreakMode="TailTruncation"
VerticalOptions="Center" VerticalOptions="Center"
TextColor="{DynamicResource TextColor}"/>--> TextColor="{DynamicResource TextColor}"/>-->
<ui:ColorPicker Grid.Column="1" ColorChanged="ColorPicker_ColorChanged"/> <ui:ColorPicker Grid.Column="1" Command="{Binding ColorPickerCommand}"/>
</Grid> </Grid>
</ViewCell> </ViewCell>
</TableSection> </TableSection>

View File

@ -1,6 +1,5 @@
using Billing.Themes; using Billing.Themes;
using Billing.UI; using Billing.UI;
using System.Globalization;
using Xamarin.Essentials; using Xamarin.Essentials;
using Xamarin.Forms; using Xamarin.Forms;
@ -8,8 +7,8 @@ namespace Billing.Views
{ {
public partial class SettingPage : BillingPage public partial class SettingPage : BillingPage
{ {
private static readonly BindableProperty VersionProperty = BindableProperty.Create(nameof(Version), typeof(string), typeof(SettingPage)); private static readonly BindableProperty VersionProperty = Helper.Create<string, SettingPage>(nameof(Version));
private static readonly BindableProperty PrimaryColorProperty = BindableProperty.Create(nameof(PrimaryColor), typeof(string), typeof(SettingPage)); private static readonly BindableProperty PrimaryColorProperty = Helper.Create<string, SettingPage>(nameof(PrimaryColor));
public string Version => (string)GetValue(VersionProperty); public string Version => (string)GetValue(VersionProperty);
public string PrimaryColor public string PrimaryColor
@ -19,10 +18,12 @@ namespace Billing.Views
} }
public Command CategoryCommand { get; } public Command CategoryCommand { get; }
public Command ColorPickerCommand { get; }
public SettingPage() public SettingPage()
{ {
CategoryCommand = new Command(OnCategoryCommand); CategoryCommand = new Command(OnCategoryCommand);
ColorPickerCommand = new Command(OnColorPickerCommand);
InitializeComponent(); InitializeComponent();
var (main, build) = Definition.GetVersion(); var (main, build) = Definition.GetVersion();
@ -60,9 +61,12 @@ namespace Billing.Views
} }
} }
private void ColorPicker_ColorChanged(object sender, Color e) private void OnColorPickerCommand(object o)
{ {
PrimaryColor = Helper.WrapColorString(e.ToHex()); if (o is Color color)
{
PrimaryColor = Helper.WrapColorString(color.ToHex());
}
} }
} }
} }

View File

@ -18,7 +18,7 @@ namespace Billing.Droid.Renderers
base.OnAttachedToWindow(); base.OnAttachedToWindow();
if (Element is BillingPage page) if (Element is BillingPage page)
{ {
page.OnLoaded(); page.TriggerLoad();
} }
} }
} }

View File

@ -18,10 +18,12 @@ namespace Billing.Droid.Renderers
{ {
base.OnElementChanged(e); base.OnElementChanged(e);
if (e.NewElement != null) var control = Control;
if (e.NewElement != null && control != null)
{ {
var drawable = new ColorDrawable(e.NewElement.BackgroundColor.ToAndroid()); var drawable = new ColorDrawable(e.NewElement.BackgroundColor.ToAndroid());
Control.SetBackground(drawable); control.SetBackground(drawable);
control.Gravity = Android.Views.GravityFlags.CenterHorizontal;
} }
} }
} }

View File

@ -55,7 +55,7 @@ namespace Billing.iOS.Renderers
base.ViewDidAppear(animated); base.ViewDidAppear(animated);
if (Element is BillingPage page) if (Element is BillingPage page)
{ {
page.OnLoaded(); page.TriggerLoad();
} }
} }
} }

View File

@ -14,9 +14,10 @@ namespace Billing.iOS.Renderers
base.OnElementChanged(e); base.OnElementChanged(e);
var control = Control; var control = Control;
if (control != null) if (e.NewElement != null && control != null)
{ {
control.BorderStyle = UITextBorderStyle.None; control.BorderStyle = UITextBorderStyle.None;
control.TextAlignment = UITextAlignment.Center;
} }
} }
} }