filter conditions
This commit is contained in:
		@@ -20,6 +20,14 @@
 | 
			
		||||
	<TapToMemo>Click here to record</TapToMemo>
 | 
			
		||||
	<TitleDateFormat>MM/dd/yyyy</TitleDateFormat>
 | 
			
		||||
	<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>
 | 
			
		||||
	<Assets>Assets</Assets>
 | 
			
		||||
	<Liability>Liability</Liability>
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,14 @@
 | 
			
		||||
	<TapToMemo>点此记录</TapToMemo>
 | 
			
		||||
	<TitleDateFormat>yyyy年MM月dd日</TitleDateFormat>
 | 
			
		||||
	<DateRangeFormat>MM月dd日</DateRangeFormat>
 | 
			
		||||
	<To>至</To>
 | 
			
		||||
	<Monthly>当月</Monthly>
 | 
			
		||||
	<Today>今日</Today>
 | 
			
		||||
	<PastMonth>一个月</PastMonth>
 | 
			
		||||
	<PastQuarter>一个季度</PastQuarter>
 | 
			
		||||
	<PastSixMonths>六个月</PastSixMonths>
 | 
			
		||||
	<PastYear>一年</PastYear>
 | 
			
		||||
	<Total>全部</Total>
 | 
			
		||||
	<Balance>余额</Balance>
 | 
			
		||||
	<Assets>资产</Assets>
 | 
			
		||||
	<Liability>负债</Liability>
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,8 @@ namespace Billing.UI
 | 
			
		||||
    {
 | 
			
		||||
        public event EventHandler Loaded;
 | 
			
		||||
 | 
			
		||||
        private bool loaded;
 | 
			
		||||
 | 
			
		||||
        public BillingPage()
 | 
			
		||||
        {
 | 
			
		||||
            SetDynamicResource(BackgroundColorProperty, BaseTheme.WindowBackgroundColor);
 | 
			
		||||
@@ -18,5 +20,14 @@ namespace Billing.UI
 | 
			
		||||
        {
 | 
			
		||||
            Loaded?.Invoke(this, EventArgs.Empty);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void TriggerLoad()
 | 
			
		||||
        {
 | 
			
		||||
            if (!loaded)
 | 
			
		||||
            {
 | 
			
		||||
                loaded = true;
 | 
			
		||||
                OnLoaded();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -8,15 +8,19 @@ namespace Billing.UI
 | 
			
		||||
{
 | 
			
		||||
    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
 | 
			
		||||
        {
 | 
			
		||||
            get => (Color)GetValue(ColorProperty);
 | 
			
		||||
            set => SetValue(ColorProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public event EventHandler<Color> ColorChanged;
 | 
			
		||||
        public Command Command
 | 
			
		||||
        {
 | 
			
		||||
            get => (Command)GetValue(CommandProperty);
 | 
			
		||||
            set => SetValue(CommandProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private SKPoint? lastTouch;
 | 
			
		||||
 | 
			
		||||
@@ -116,7 +120,7 @@ namespace Billing.UI
 | 
			
		||||
 | 
			
		||||
                var color = touchColor.ToFormsColor();
 | 
			
		||||
                Color = color;
 | 
			
		||||
                ColorChanged?.Invoke(this, color);
 | 
			
		||||
                Command?.Execute(color);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -126,8 +130,8 @@ namespace Billing.UI
 | 
			
		||||
            lastTouch = e.Location;
 | 
			
		||||
 | 
			
		||||
            var size = CanvasSize;
 | 
			
		||||
            if ((e.Location.X > 0 && e.Location.X < size.Width) &&
 | 
			
		||||
                (e.Location.Y > 0 && e.Location.Y < size.Height))
 | 
			
		||||
            if (e.Location.X > 0 && e.Location.X < size.Width &&
 | 
			
		||||
                e.Location.Y > 0 && e.Location.Y < size.Height)
 | 
			
		||||
            {
 | 
			
		||||
                e.Handled = true;
 | 
			
		||||
                InvalidateSurface();
 | 
			
		||||
 
 | 
			
		||||
@@ -92,6 +92,12 @@ namespace Billing.UI
 | 
			
		||||
            var result = await page.DisplayActionSheet(message, Resource.No, yes);
 | 
			
		||||
            return result == yes;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static DateTime LastMoment(this DateTime date)
 | 
			
		||||
        {
 | 
			
		||||
            // add 23:59:59.999...
 | 
			
		||||
            return date.AddTicks(863999999999);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class ModelExtensionHelper
 | 
			
		||||
 
 | 
			
		||||
@@ -73,15 +73,9 @@ namespace Billing.Views
 | 
			
		||||
            InitializeComponent();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool focused;
 | 
			
		||||
 | 
			
		||||
        public override void OnLoaded()
 | 
			
		||||
        {
 | 
			
		||||
            if (!focused)
 | 
			
		||||
            {
 | 
			
		||||
                focused = true;
 | 
			
		||||
                editorName.SetFocus();
 | 
			
		||||
            }
 | 
			
		||||
            editorName.SetFocus();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async void OnCheckAccount()
 | 
			
		||||
 
 | 
			
		||||
@@ -116,15 +116,9 @@ namespace Billing.Views
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool focused;
 | 
			
		||||
 | 
			
		||||
        public override void OnLoaded()
 | 
			
		||||
        {
 | 
			
		||||
            if (!focused)
 | 
			
		||||
            {
 | 
			
		||||
                focused = true;
 | 
			
		||||
                editorAmount.SetFocus();
 | 
			
		||||
            }
 | 
			
		||||
            editorAmount.SetFocus();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async void OnCheckBill()
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@
 | 
			
		||||
                <ViewCell Height="120">
 | 
			
		||||
                    <Grid BackgroundColor="{DynamicResource OptionTintColor}"
 | 
			
		||||
                          ColumnDefinitions=".35*, .65*" Padding="10">
 | 
			
		||||
                        <ui:ColorPicker Grid.Column="1" ColorChanged="ColorPicker_ColorChanged"/>
 | 
			
		||||
                        <ui:ColorPicker Grid.Column="1" Command="{Binding ColorPickerCommand}"/>
 | 
			
		||||
                    </Grid>
 | 
			
		||||
                </ViewCell>
 | 
			
		||||
            </TableSection>
 | 
			
		||||
 
 | 
			
		||||
@@ -38,6 +38,7 @@ namespace Billing.Views
 | 
			
		||||
 | 
			
		||||
        public Command CheckCategory { get; }
 | 
			
		||||
        public Command SelectIcon { get; }
 | 
			
		||||
        public Command ColorPickerCommand { get; }
 | 
			
		||||
 | 
			
		||||
        public event EventHandler<Category> CategoryChecked;
 | 
			
		||||
 | 
			
		||||
@@ -73,25 +74,23 @@ namespace Billing.Views
 | 
			
		||||
 | 
			
		||||
            CheckCategory = new Command(OnCheckCategory);
 | 
			
		||||
            SelectIcon = new Command(OnSelectIcon);
 | 
			
		||||
            ColorPickerCommand = new Command(OnColorPickerCommand);
 | 
			
		||||
 | 
			
		||||
            InitializeComponent();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool focused;
 | 
			
		||||
 | 
			
		||||
        public override void OnLoaded()
 | 
			
		||||
        {
 | 
			
		||||
            if (!focused)
 | 
			
		||||
            {
 | 
			
		||||
                focused = true;
 | 
			
		||||
                editorName.SetFocus();
 | 
			
		||||
            }
 | 
			
		||||
            editorName.SetFocus();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ColorPicker_ColorChanged(object sender, Color e)
 | 
			
		||||
        private void OnColorPickerCommand(object o)
 | 
			
		||||
        {
 | 
			
		||||
            TintColor = e;
 | 
			
		||||
            TintColorString = Helper.WrapColorString(e.ToHex());
 | 
			
		||||
            if (o is Color color)
 | 
			
		||||
            {
 | 
			
		||||
                TintColor = color;
 | 
			
		||||
                TintColorString = Helper.WrapColorString(color.ToHex());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async void OnCheckCategory()
 | 
			
		||||
 
 | 
			
		||||
@@ -44,8 +44,6 @@ namespace Billing.Views
 | 
			
		||||
        public Command EditBilling { get; }
 | 
			
		||||
        public Command DeleteBilling { get; }
 | 
			
		||||
 | 
			
		||||
        private bool initialized;
 | 
			
		||||
 | 
			
		||||
        public BillPage()
 | 
			
		||||
        {
 | 
			
		||||
            TitleDateTap = new Command(OnTitleDateTapped);
 | 
			
		||||
@@ -58,11 +56,7 @@ namespace Billing.Views
 | 
			
		||||
 | 
			
		||||
        public override void OnLoaded()
 | 
			
		||||
        {
 | 
			
		||||
            if (!initialized)
 | 
			
		||||
            {
 | 
			
		||||
                initialized = true;
 | 
			
		||||
                billingDate.SetDateTime(DateTime.Today);
 | 
			
		||||
            }
 | 
			
		||||
            billingDate.SetDateTime(DateTime.Today);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void OnDateSelected(object sender, DateEventArgs e)
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@
 | 
			
		||||
                xmlns:ui="clr-namespace:Billing.UI"
 | 
			
		||||
                xmlns:v="clr-namespace:Billing.Views"
 | 
			
		||||
                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"
 | 
			
		||||
                x:Class="Billing.Views.RankPage"
 | 
			
		||||
                x:Name="rankPage"
 | 
			
		||||
@@ -13,7 +14,7 @@
 | 
			
		||||
 | 
			
		||||
    <Shell.TitleView>
 | 
			
		||||
        <Grid>
 | 
			
		||||
            <StackLayout Margin="30, 0, 0, 0" HorizontalOptions="Center" VerticalOptions="Center"
 | 
			
		||||
            <StackLayout HorizontalOptions="Center" VerticalOptions="Center"
 | 
			
		||||
                         Orientation="Horizontal" Spacing="10">
 | 
			
		||||
                <ui:TintImageButton Source="left.png" WidthRequest="20" HeightRequest="20"
 | 
			
		||||
                                    VerticalOptions="Center" HorizontalOptions="Start"
 | 
			
		||||
@@ -21,6 +22,9 @@
 | 
			
		||||
                <Label Text="{Binding Title}"
 | 
			
		||||
                       TextColor="{DynamicResource PrimaryColor}"
 | 
			
		||||
                       FontSize="{OnPlatform Android=20, iOS=18}">
 | 
			
		||||
                    <Label.GestureRecognizers>
 | 
			
		||||
                        <TapGestureRecognizer Command="{Binding FilterCommand}"/>
 | 
			
		||||
                    </Label.GestureRecognizers>
 | 
			
		||||
                    <Label.FontFamily>
 | 
			
		||||
                        <OnPlatform x:TypeArguments="x:String"
 | 
			
		||||
                                    Android="OpenSans-SemiBold.ttf#OpenSans-SemiBold"
 | 
			
		||||
@@ -34,9 +38,9 @@
 | 
			
		||||
        </Grid>
 | 
			
		||||
    </Shell.TitleView>
 | 
			
		||||
 | 
			
		||||
    <ContentPage.ToolbarItems>
 | 
			
		||||
    <!--<ContentPage.ToolbarItems>
 | 
			
		||||
        <ToolbarItem Order="Primary" IconImageSource="filter.png" Command="{Binding FilterCommand}"/>
 | 
			
		||||
    </ContentPage.ToolbarItems>
 | 
			
		||||
    </ContentPage.ToolbarItems>-->
 | 
			
		||||
 | 
			
		||||
    <ContentPage.Resources>
 | 
			
		||||
        <ui:NegativeConverter x:Key="negativeConverter"/>
 | 
			
		||||
@@ -48,7 +52,7 @@
 | 
			
		||||
        <Style x:Key="titleLabel" TargetType="Label">
 | 
			
		||||
            <Setter Property="FontSize" Value="16"/>
 | 
			
		||||
            <Setter Property="Margin" Value="10, 20, 10, 10"/>
 | 
			
		||||
            <!--<Setter Property="TextColor" Value="{DynamicResource SecondaryTextColor}"/>-->
 | 
			
		||||
            <Setter Property="TextColor" Value="{DynamicResource TextColor}"/>
 | 
			
		||||
        </Style>
 | 
			
		||||
        <Style x:Key="promptLabel" TargetType="Label">
 | 
			
		||||
            <Setter Property="HeightRequest" Value="240"/>
 | 
			
		||||
@@ -58,12 +62,16 @@
 | 
			
		||||
            <Setter Property="VerticalTextAlignment" Value="Center"/>
 | 
			
		||||
            <Setter Property="TextColor" Value="{DynamicResource SecondaryTextColor}"/>
 | 
			
		||||
        </Style>
 | 
			
		||||
        <Style TargetType="Button">
 | 
			
		||||
            <Setter Property="TextColor" Value="{DynamicResource TextColor}"/>
 | 
			
		||||
            <Setter Property="FontSize" Value="14"/>
 | 
			
		||||
        </Style>
 | 
			
		||||
    </ContentPage.Resources>
 | 
			
		||||
 | 
			
		||||
    <Grid>
 | 
			
		||||
        <ScrollView x:Name="scroller">
 | 
			
		||||
        <ScrollView x:Name="scroller" Scrolled="Scroller_Scrolled">
 | 
			
		||||
            <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}">
 | 
			
		||||
                    <StackLayout Grid.Column="1" Orientation="Horizontal" Spacing="6">
 | 
			
		||||
                        <Label Text="{r:Text Income}" TextColor="{DynamicResource GreenColor}"
 | 
			
		||||
@@ -133,7 +141,7 @@
 | 
			
		||||
        <ui:BlurryPanel x:Name="panelFilter" VerticalOptions="Start" Opacity="0"
 | 
			
		||||
                        BackgroundColor="{DynamicResource WindowBackgroundColor}"
 | 
			
		||||
                        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"
 | 
			
		||||
                                 SelectedSegmentIndex="{Binding SegmentType, Mode=TwoWay}"
 | 
			
		||||
                                 SelectedTextColor="{DynamicResource TextColor}"
 | 
			
		||||
@@ -143,6 +151,33 @@
 | 
			
		||||
                    <ui:SegmentedControlOption Text="{r:Text Income}"/>
 | 
			
		||||
                </ui:SegmentedControl.Children>
 | 
			
		||||
            </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>
 | 
			
		||||
</ui:BillingPage>
 | 
			
		||||
@@ -16,7 +16,22 @@ namespace Billing.Views
 | 
			
		||||
{
 | 
			
		||||
    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 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 CategoryChartProperty = Helper.Create<Chart, RankPage>(nameof(CategoryChart));
 | 
			
		||||
        private static readonly BindableProperty TopBillsProperty = Helper.Create<IList<UIBill>, RankPage>(nameof(TopBills));
 | 
			
		||||
@@ -34,8 +49,40 @@ namespace Billing.Views
 | 
			
		||||
                1 => CategoryType.Income,
 | 
			
		||||
                _ => CategoryType.Spending
 | 
			
		||||
            };
 | 
			
		||||
            page.OnFilterCommand(false);
 | 
			
		||||
            page.SetMonth(page.current);
 | 
			
		||||
            page.LoadData();
 | 
			
		||||
        }
 | 
			
		||||
        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
 | 
			
		||||
@@ -43,6 +90,31 @@ namespace Billing.Views
 | 
			
		||||
            get => (int)GetValue(SegmentTypeProperty);
 | 
			
		||||
            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
 | 
			
		||||
        {
 | 
			
		||||
            get => (Chart)GetValue(ChartProperty);
 | 
			
		||||
@@ -82,11 +154,11 @@ namespace Billing.Views
 | 
			
		||||
        public Command FilterCommand { get; }
 | 
			
		||||
        public Command EditBilling { get; }
 | 
			
		||||
 | 
			
		||||
        private DateTime current;
 | 
			
		||||
        private DateTime end;
 | 
			
		||||
        private IEnumerable<Bill> bills;
 | 
			
		||||
        private CategoryType type = CategoryType.Spending;
 | 
			
		||||
        private bool isFilterToggled;
 | 
			
		||||
        private bool isFreezed;
 | 
			
		||||
        private bool isLocked;
 | 
			
		||||
 | 
			
		||||
        private readonly SKTypeface font;
 | 
			
		||||
 | 
			
		||||
@@ -111,7 +183,76 @@ namespace Billing.Views
 | 
			
		||||
 | 
			
		||||
        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()
 | 
			
		||||
@@ -120,7 +261,29 @@ namespace Billing.Views
 | 
			
		||||
            {
 | 
			
		||||
                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()
 | 
			
		||||
@@ -129,7 +292,29 @@ namespace Billing.Views
 | 
			
		||||
            {
 | 
			
		||||
                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)
 | 
			
		||||
@@ -146,6 +331,7 @@ namespace Billing.Views
 | 
			
		||||
            ViewExtensions.CancelAnimations(panelFilter);
 | 
			
		||||
            if (isFilterToggled)
 | 
			
		||||
            {
 | 
			
		||||
                await scroller.ScrollToAsync(scroller.ScrollX, scroller.ScrollY, false);
 | 
			
		||||
                await Task.WhenAll(
 | 
			
		||||
                    gridFilter.TranslateTo(0, 0, easing: Easing.CubicOut),
 | 
			
		||||
                    gridFilter.FadeTo(1, easing: Easing.CubicOut),
 | 
			
		||||
@@ -179,18 +365,9 @@ namespace Billing.Views
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void UpdateBill(UIBill bill)
 | 
			
		||||
        {
 | 
			
		||||
            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()
 | 
			
		||||
        private async void RefreshBalance(DateTime start, DateTime end)
 | 
			
		||||
        {
 | 
			
		||||
            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 spending = -bills.Where(b => b.Amount < 0).Sum(b => b.Amount);
 | 
			
		||||
            SetValue(IncomeProperty, income);
 | 
			
		||||
@@ -198,43 +375,33 @@ namespace Billing.Views
 | 
			
		||||
            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);
 | 
			
		||||
            if (bill != null)
 | 
			
		||||
            {
 | 
			
		||||
                UpdateBill(bill);
 | 
			
		||||
            }
 | 
			
		||||
            RefreshBalance();
 | 
			
		||||
 | 
			
		||||
            Task.Run(App.WriteBills);
 | 
			
		||||
            await Task.Run(App.WriteBills);
 | 
			
		||||
            LoadData();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async void SetMonth(DateTime date)
 | 
			
		||||
        private async void LoadData()
 | 
			
		||||
        {
 | 
			
		||||
            current = date.AddDays(1 - date.Day);
 | 
			
		||||
            end = current.AddDays(DateTime.DaysInMonth(current.Year, current.Month));
 | 
			
		||||
 | 
			
		||||
            var format = Resource.DateRangeFormat;
 | 
			
		||||
            Title = current.ToString(format) + " ~ " + end.AddDays(-1).ToString(format);
 | 
			
		||||
 | 
			
		||||
            var start = StartDate;
 | 
			
		||||
            var end = EndDate;
 | 
			
		||||
            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 textColor = BaseTheme.CurrentSecondaryTextColor.ToSKColor();
 | 
			
		||||
 | 
			
		||||
            _ = Task.Run(() => LoadReportChart(primaryColor, textColor));
 | 
			
		||||
            _ = Task.Run(() => LoadReportChart(primaryColor, textColor, start, end));
 | 
			
		||||
            _ = Task.Run(() => LoadCategoryChart(primaryColor, textColor));
 | 
			
		||||
            _ = 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>();
 | 
			
		||||
            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));
 | 
			
		||||
                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);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -31,7 +31,7 @@
 | 
			
		||||
                    <!--<Label Text="" LineBreakMode="TailTruncation"
 | 
			
		||||
                           VerticalOptions="Center"
 | 
			
		||||
                           TextColor="{DynamicResource TextColor}"/>-->
 | 
			
		||||
                    <ui:ColorPicker Grid.Column="1" ColorChanged="ColorPicker_ColorChanged"/>
 | 
			
		||||
                    <ui:ColorPicker Grid.Column="1" Command="{Binding ColorPickerCommand}"/>
 | 
			
		||||
                </Grid>
 | 
			
		||||
            </ViewCell>
 | 
			
		||||
        </TableSection>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
using Billing.Themes;
 | 
			
		||||
using Billing.UI;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using Xamarin.Essentials;
 | 
			
		||||
using Xamarin.Forms;
 | 
			
		||||
 | 
			
		||||
@@ -8,8 +7,8 @@ namespace Billing.Views
 | 
			
		||||
{
 | 
			
		||||
    public partial class SettingPage : BillingPage
 | 
			
		||||
    {
 | 
			
		||||
        private static readonly BindableProperty VersionProperty = BindableProperty.Create(nameof(Version), typeof(string), typeof(SettingPage));
 | 
			
		||||
        private static readonly BindableProperty PrimaryColorProperty = BindableProperty.Create(nameof(PrimaryColor), typeof(string), typeof(SettingPage));
 | 
			
		||||
        private static readonly BindableProperty VersionProperty = Helper.Create<string, SettingPage>(nameof(Version));
 | 
			
		||||
        private static readonly BindableProperty PrimaryColorProperty = Helper.Create<string, SettingPage>(nameof(PrimaryColor));
 | 
			
		||||
 | 
			
		||||
        public string Version => (string)GetValue(VersionProperty);
 | 
			
		||||
        public string PrimaryColor
 | 
			
		||||
@@ -19,10 +18,12 @@ namespace Billing.Views
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Command CategoryCommand { get; }
 | 
			
		||||
        public Command ColorPickerCommand { get; }
 | 
			
		||||
 | 
			
		||||
        public SettingPage()
 | 
			
		||||
        {
 | 
			
		||||
            CategoryCommand = new Command(OnCategoryCommand);
 | 
			
		||||
            ColorPickerCommand = new Command(OnColorPickerCommand);
 | 
			
		||||
            InitializeComponent();
 | 
			
		||||
 | 
			
		||||
            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());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -18,7 +18,7 @@ namespace Billing.Droid.Renderers
 | 
			
		||||
            base.OnAttachedToWindow();
 | 
			
		||||
            if (Element is BillingPage page)
 | 
			
		||||
            {
 | 
			
		||||
                page.OnLoaded();
 | 
			
		||||
                page.TriggerLoad();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -18,10 +18,12 @@ namespace Billing.Droid.Renderers
 | 
			
		||||
        {
 | 
			
		||||
            base.OnElementChanged(e);
 | 
			
		||||
 | 
			
		||||
            if (e.NewElement != null)
 | 
			
		||||
            var control = Control;
 | 
			
		||||
            if (e.NewElement != null && control != null)
 | 
			
		||||
            {
 | 
			
		||||
                var drawable = new ColorDrawable(e.NewElement.BackgroundColor.ToAndroid());
 | 
			
		||||
                Control.SetBackground(drawable);
 | 
			
		||||
                control.SetBackground(drawable);
 | 
			
		||||
                control.Gravity = Android.Views.GravityFlags.CenterHorizontal;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,7 @@ namespace Billing.iOS.Renderers
 | 
			
		||||
            base.ViewDidAppear(animated);
 | 
			
		||||
            if (Element is BillingPage page)
 | 
			
		||||
            {
 | 
			
		||||
                page.OnLoaded();
 | 
			
		||||
                page.TriggerLoad();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,10 @@ namespace Billing.iOS.Renderers
 | 
			
		||||
            base.OnElementChanged(e);
 | 
			
		||||
 | 
			
		||||
            var control = Control;
 | 
			
		||||
            if (control != null)
 | 
			
		||||
            if (e.NewElement != null && control != null)
 | 
			
		||||
            {
 | 
			
		||||
                control.BorderStyle = UITextBorderStyle.None;
 | 
			
		||||
                control.TextAlignment = UITextAlignment.Center;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user