language version degraded to 9.0
This commit is contained in:
		@@ -1,289 +1,290 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Xamarin.Forms;
 | 
			
		||||
 | 
			
		||||
namespace Billing.UI;
 | 
			
		||||
 | 
			
		||||
public partial class BillingDate : ContentView
 | 
			
		||||
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 BillingDay Sunday => (BillingDay)GetValue(SundayProperty);
 | 
			
		||||
    public BillingDay Monday => (BillingDay)GetValue(MondayProperty);
 | 
			
		||||
    public BillingDay Tuesday => (BillingDay)GetValue(TuesdayProperty);
 | 
			
		||||
    public BillingDay Wednesday => (BillingDay)GetValue(WednesdayProperty);
 | 
			
		||||
    public BillingDay Thursday => (BillingDay)GetValue(ThursdayProperty);
 | 
			
		||||
    public BillingDay Friday => (BillingDay)GetValue(FridayProperty);
 | 
			
		||||
    public BillingDay Saturday => (BillingDay)GetValue(SaturdayProperty);
 | 
			
		||||
 | 
			
		||||
    #endregion
 | 
			
		||||
 | 
			
		||||
    private static BindableProperty GetWeekProperty(int week)
 | 
			
		||||
    public partial class BillingDate : ContentView
 | 
			
		||||
    {
 | 
			
		||||
        return (DayOfWeek)week switch
 | 
			
		||||
        {
 | 
			
		||||
            DayOfWeek.Monday => MondayProperty,
 | 
			
		||||
            DayOfWeek.Tuesday => TuesdayProperty,
 | 
			
		||||
            DayOfWeek.Wednesday => WednesdayProperty,
 | 
			
		||||
            DayOfWeek.Thursday => ThursdayProperty,
 | 
			
		||||
            DayOfWeek.Friday => FridayProperty,
 | 
			
		||||
            DayOfWeek.Saturday => SaturdayProperty,
 | 
			
		||||
            _ => SundayProperty
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
        #region UI Properties
 | 
			
		||||
 | 
			
		||||
    public static readonly BindableProperty LocatedDateProperty = BindableProperty.Create(nameof(LocatedDate), typeof(DateTime), typeof(BillingDate), propertyChanged: OnLocatedDatePropertyChanged);
 | 
			
		||||
    public static readonly BindableProperty SelectedDateProperty = BindableProperty.Create(nameof(SelectedDate), typeof(DateTime), typeof(BillingDate), propertyChanged: OnSelectedDatePropertyChanged);
 | 
			
		||||
        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));
 | 
			
		||||
 | 
			
		||||
    private static void OnLocatedDatePropertyChanged(BindableObject obj, object old, object @new)
 | 
			
		||||
    {
 | 
			
		||||
        if (obj is BillingDate billingDate && @new is DateTime date)
 | 
			
		||||
        public BillingDay Sunday => (BillingDay)GetValue(SundayProperty);
 | 
			
		||||
        public BillingDay Monday => (BillingDay)GetValue(MondayProperty);
 | 
			
		||||
        public BillingDay Tuesday => (BillingDay)GetValue(TuesdayProperty);
 | 
			
		||||
        public BillingDay Wednesday => (BillingDay)GetValue(WednesdayProperty);
 | 
			
		||||
        public BillingDay Thursday => (BillingDay)GetValue(ThursdayProperty);
 | 
			
		||||
        public BillingDay Friday => (BillingDay)GetValue(FridayProperty);
 | 
			
		||||
        public BillingDay Saturday => (BillingDay)GetValue(SaturdayProperty);
 | 
			
		||||
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
        private static BindableProperty GetWeekProperty(int week)
 | 
			
		||||
        {
 | 
			
		||||
            var week = (int)date.DayOfWeek;
 | 
			
		||||
            var tmpDate = date.AddDays(-week);
 | 
			
		||||
            for (var i = 0; i < 7; i++)
 | 
			
		||||
            return (DayOfWeek)week switch
 | 
			
		||||
            {
 | 
			
		||||
                var prop = GetWeekProperty(i);
 | 
			
		||||
                var day = new BillingDay(tmpDate);
 | 
			
		||||
                billingDate.SetValue(prop, day);
 | 
			
		||||
                tmpDate = tmpDate.AddDays(1);
 | 
			
		||||
            }
 | 
			
		||||
                DayOfWeek.Monday => MondayProperty,
 | 
			
		||||
                DayOfWeek.Tuesday => TuesdayProperty,
 | 
			
		||||
                DayOfWeek.Wednesday => WednesdayProperty,
 | 
			
		||||
                DayOfWeek.Thursday => ThursdayProperty,
 | 
			
		||||
                DayOfWeek.Friday => FridayProperty,
 | 
			
		||||
                DayOfWeek.Saturday => SaturdayProperty,
 | 
			
		||||
                _ => SundayProperty
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void OnSelectedDatePropertyChanged(BindableObject obj, object old, object @new)
 | 
			
		||||
    {
 | 
			
		||||
        if (obj is BillingDate billingDate && @new is DateTime selected)
 | 
			
		||||
        public static readonly BindableProperty LocatedDateProperty = BindableProperty.Create(nameof(LocatedDate), typeof(DateTime), typeof(BillingDate), propertyChanged: OnLocatedDatePropertyChanged);
 | 
			
		||||
        public static readonly BindableProperty SelectedDateProperty = BindableProperty.Create(nameof(SelectedDate), typeof(DateTime), typeof(BillingDate), propertyChanged: OnSelectedDatePropertyChanged);
 | 
			
		||||
 | 
			
		||||
        private static void OnLocatedDatePropertyChanged(BindableObject obj, object old, object @new)
 | 
			
		||||
        {
 | 
			
		||||
            for (var i = 0; i < 7; i++)
 | 
			
		||||
            if (obj is BillingDate billingDate && @new is DateTime date)
 | 
			
		||||
            {
 | 
			
		||||
                var prop = GetWeekProperty(i);
 | 
			
		||||
                var day = (BillingDay)billingDate.GetValue(prop);
 | 
			
		||||
                day.Refresh(selected);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public DateTime LocatedDate
 | 
			
		||||
    {
 | 
			
		||||
        get => (DateTime)GetValue(LocatedDateProperty);
 | 
			
		||||
        set => SetValue(LocatedDateProperty, value);
 | 
			
		||||
    }
 | 
			
		||||
    public DateTime SelectedDate
 | 
			
		||||
    {
 | 
			
		||||
        get => (DateTime)GetValue(SelectedDateProperty);
 | 
			
		||||
        set => SetValue(SelectedDateProperty, value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Command OnDayTapped { get; }
 | 
			
		||||
 | 
			
		||||
    public event EventHandler<DateEventArgs> DateSelected;
 | 
			
		||||
 | 
			
		||||
    private DateTime lastDate;
 | 
			
		||||
    private double? x1;
 | 
			
		||||
    private double x2;
 | 
			
		||||
 | 
			
		||||
    public BillingDate()
 | 
			
		||||
    {
 | 
			
		||||
        OnDayTapped = new Command(OnDayChanged);
 | 
			
		||||
 | 
			
		||||
        InitializeComponent();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void SetDateTime(DateTime selectedDate, DateTime? locatedDate = null)
 | 
			
		||||
    {
 | 
			
		||||
        if (locatedDate != null)
 | 
			
		||||
        {
 | 
			
		||||
            LocatedDate = locatedDate.Value;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            LocatedDate = selectedDate;
 | 
			
		||||
        }
 | 
			
		||||
        SelectedDate = selectedDate;
 | 
			
		||||
        DateSelected?.Invoke(this, new DateEventArgs(selectedDate));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnDayChanged(object o)
 | 
			
		||||
    {
 | 
			
		||||
        var selected = SelectedDate;
 | 
			
		||||
        if (o is BillingDay day && (selected.Year != day.Date.Year || selected.DayOfYear != day.Date.DayOfYear))
 | 
			
		||||
        {
 | 
			
		||||
            for (var i = 0; i < 7; i++)
 | 
			
		||||
            {
 | 
			
		||||
                var d = (BillingDay)GetValue(GetWeekProperty(i));
 | 
			
		||||
                if (d.IsSelected)
 | 
			
		||||
                var week = (int)date.DayOfWeek;
 | 
			
		||||
                var tmpDate = date.AddDays(-week);
 | 
			
		||||
                for (var i = 0; i < 7; i++)
 | 
			
		||||
                {
 | 
			
		||||
                    this.AbortAnimation("unselected");
 | 
			
		||||
                    this.Animate("unselected", v =>
 | 
			
		||||
                    {
 | 
			
		||||
                        d.Opacity = v;
 | 
			
		||||
                    },
 | 
			
		||||
                    start: 1, end: 0,
 | 
			
		||||
                    easing: Easing.CubicOut,
 | 
			
		||||
                    finished: (v, b) =>
 | 
			
		||||
                    {
 | 
			
		||||
                        d.Opacity = 0;
 | 
			
		||||
                        d.IsSelected = false;
 | 
			
		||||
                    });
 | 
			
		||||
                    var prop = GetWeekProperty(i);
 | 
			
		||||
                    var day = new BillingDay(tmpDate);
 | 
			
		||||
                    billingDate.SetValue(prop, day);
 | 
			
		||||
                    tmpDate = tmpDate.AddDays(1);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            SelectedDate = day.Date;
 | 
			
		||||
            this.AbortAnimation("selected");
 | 
			
		||||
            this.Animate("selected", v =>
 | 
			
		||||
            {
 | 
			
		||||
                day.Opacity = v;
 | 
			
		||||
            },
 | 
			
		||||
            start: 0, end: 1,
 | 
			
		||||
            easing: Easing.CubicOut,
 | 
			
		||||
            finished: (v, b) =>
 | 
			
		||||
            {
 | 
			
		||||
                day.Opacity = 1;
 | 
			
		||||
            });
 | 
			
		||||
            DateSelected?.Invoke(this, new DateEventArgs(day.Date));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
 | 
			
		||||
    {
 | 
			
		||||
        if (e.StatusType == GestureStatus.Started)
 | 
			
		||||
        private static void OnSelectedDatePropertyChanged(BindableObject obj, object old, object @new)
 | 
			
		||||
        {
 | 
			
		||||
            lastDate = DateTime.Now;
 | 
			
		||||
            x1 = null;
 | 
			
		||||
            if (obj is BillingDate billingDate && @new is DateTime selected)
 | 
			
		||||
            {
 | 
			
		||||
                for (var i = 0; i < 7; i++)
 | 
			
		||||
                {
 | 
			
		||||
                    var prop = GetWeekProperty(i);
 | 
			
		||||
                    var day = (BillingDay)billingDate.GetValue(prop);
 | 
			
		||||
                    day.Refresh(selected);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (e.StatusType == GestureStatus.Running)
 | 
			
		||||
 | 
			
		||||
        public DateTime LocatedDate
 | 
			
		||||
        {
 | 
			
		||||
            if (x1 == null)
 | 
			
		||||
            {
 | 
			
		||||
                x1 = e.TotalX;
 | 
			
		||||
            }
 | 
			
		||||
            x2 = e.TotalX;
 | 
			
		||||
            get => (DateTime)GetValue(LocatedDateProperty);
 | 
			
		||||
            set => SetValue(LocatedDateProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
        else if (e.StatusType == GestureStatus.Completed)
 | 
			
		||||
        public DateTime SelectedDate
 | 
			
		||||
        {
 | 
			
		||||
            if (x1 == null)
 | 
			
		||||
            {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            var totalX = x2 - x1.Value;
 | 
			
		||||
            x1 = null;
 | 
			
		||||
            var ms = (DateTime.Now - lastDate).TotalMilliseconds;
 | 
			
		||||
            var speed = totalX / ms;
 | 
			
		||||
            Helper.Debug($"completed, speed: {speed}");
 | 
			
		||||
            if (speed < -0.7)
 | 
			
		||||
            {
 | 
			
		||||
                LocatedDate = LocatedDate.AddDays(7);
 | 
			
		||||
            }
 | 
			
		||||
            else if (speed > 0.7)
 | 
			
		||||
            {
 | 
			
		||||
                LocatedDate = LocatedDate.AddDays(-7);
 | 
			
		||||
            }
 | 
			
		||||
            OnSelectedDatePropertyChanged(this, null, SelectedDate);
 | 
			
		||||
            get => (DateTime)GetValue(SelectedDateProperty);
 | 
			
		||||
            set => SetValue(SelectedDateProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class DateEventArgs : EventArgs
 | 
			
		||||
{
 | 
			
		||||
    public DateTime Date { get; }
 | 
			
		||||
        public Command OnDayTapped { get; }
 | 
			
		||||
 | 
			
		||||
    public DateEventArgs(DateTime date)
 | 
			
		||||
    {
 | 
			
		||||
        Date = date;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
        public event EventHandler<DateEventArgs> DateSelected;
 | 
			
		||||
 | 
			
		||||
public class BillingDayView : ContentView
 | 
			
		||||
{
 | 
			
		||||
    public static readonly BindableProperty BillingDayProperty = BindableProperty.Create(nameof(BillingDay), typeof(BillingDay), typeof(BillingDayView));
 | 
			
		||||
    public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(Command), typeof(BillingDayView));
 | 
			
		||||
        private DateTime lastDate;
 | 
			
		||||
        private double? x1;
 | 
			
		||||
        private double x2;
 | 
			
		||||
 | 
			
		||||
    public BillingDay BillingDay
 | 
			
		||||
    {
 | 
			
		||||
        get => (BillingDay)GetValue(BillingDayProperty);
 | 
			
		||||
        set => SetValue(BillingDayProperty, value);
 | 
			
		||||
    }
 | 
			
		||||
    public Command Command
 | 
			
		||||
    {
 | 
			
		||||
        get => (Command)GetValue(CommandProperty);
 | 
			
		||||
        set => SetValue(CommandProperty, value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
    private static void OnDatePropertyChanged(BindableObject obj, object old, object @new)
 | 
			
		||||
    {
 | 
			
		||||
        if (obj is BillingDay day && @new is DateTime date)
 | 
			
		||||
        public BillingDate()
 | 
			
		||||
        {
 | 
			
		||||
            if (date.Day == 1)
 | 
			
		||||
            OnDayTapped = new Command(OnDayChanged);
 | 
			
		||||
 | 
			
		||||
            InitializeComponent();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetDateTime(DateTime selectedDate, DateTime? locatedDate = null)
 | 
			
		||||
        {
 | 
			
		||||
            if (locatedDate != null)
 | 
			
		||||
            {
 | 
			
		||||
                day.SetValue(TextProperty, date.ToString("MMM"));
 | 
			
		||||
                LocatedDate = locatedDate.Value;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                day.SetValue(TextProperty, date.Day.ToString());
 | 
			
		||||
                LocatedDate = selectedDate;
 | 
			
		||||
            }
 | 
			
		||||
            SelectedDate = selectedDate;
 | 
			
		||||
            DateSelected?.Invoke(this, new DateEventArgs(selectedDate));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void OnDayChanged(object o)
 | 
			
		||||
        {
 | 
			
		||||
            var selected = SelectedDate;
 | 
			
		||||
            if (o is BillingDay day && (selected.Year != day.Date.Year || selected.DayOfYear != day.Date.DayOfYear))
 | 
			
		||||
            {
 | 
			
		||||
                for (var i = 0; i < 7; i++)
 | 
			
		||||
                {
 | 
			
		||||
                    var d = (BillingDay)GetValue(GetWeekProperty(i));
 | 
			
		||||
                    if (d.IsSelected)
 | 
			
		||||
                    {
 | 
			
		||||
                        this.AbortAnimation("unselected");
 | 
			
		||||
                        this.Animate("unselected", v =>
 | 
			
		||||
                        {
 | 
			
		||||
                            d.Opacity = v;
 | 
			
		||||
                        },
 | 
			
		||||
                        start: 1, end: 0,
 | 
			
		||||
                        easing: Easing.CubicOut,
 | 
			
		||||
                        finished: (v, b) =>
 | 
			
		||||
                        {
 | 
			
		||||
                            d.Opacity = 0;
 | 
			
		||||
                            d.IsSelected = false;
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                SelectedDate = day.Date;
 | 
			
		||||
                this.AbortAnimation("selected");
 | 
			
		||||
                this.Animate("selected", v =>
 | 
			
		||||
                {
 | 
			
		||||
                    day.Opacity = v;
 | 
			
		||||
                },
 | 
			
		||||
                start: 0, end: 1,
 | 
			
		||||
                easing: Easing.CubicOut,
 | 
			
		||||
                finished: (v, b) =>
 | 
			
		||||
                {
 | 
			
		||||
                    day.Opacity = 1;
 | 
			
		||||
                });
 | 
			
		||||
                DateSelected?.Invoke(this, new DateEventArgs(day.Date));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
 | 
			
		||||
        {
 | 
			
		||||
            if (e.StatusType == GestureStatus.Started)
 | 
			
		||||
            {
 | 
			
		||||
                lastDate = DateTime.Now;
 | 
			
		||||
                x1 = null;
 | 
			
		||||
            }
 | 
			
		||||
            else if (e.StatusType == GestureStatus.Running)
 | 
			
		||||
            {
 | 
			
		||||
                if (x1 == null)
 | 
			
		||||
                {
 | 
			
		||||
                    x1 = e.TotalX;
 | 
			
		||||
                }
 | 
			
		||||
                x2 = e.TotalX;
 | 
			
		||||
            }
 | 
			
		||||
            else if (e.StatusType == GestureStatus.Completed)
 | 
			
		||||
            {
 | 
			
		||||
                if (x1 == null)
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                var totalX = x2 - x1.Value;
 | 
			
		||||
                x1 = null;
 | 
			
		||||
                var ms = (DateTime.Now - lastDate).TotalMilliseconds;
 | 
			
		||||
                var speed = totalX / ms;
 | 
			
		||||
                Helper.Debug($"completed, speed: {speed}");
 | 
			
		||||
                if (speed < -0.7)
 | 
			
		||||
                {
 | 
			
		||||
                    LocatedDate = LocatedDate.AddDays(7);
 | 
			
		||||
                }
 | 
			
		||||
                else if (speed > 0.7)
 | 
			
		||||
                {
 | 
			
		||||
                    LocatedDate = LocatedDate.AddDays(-7);
 | 
			
		||||
                }
 | 
			
		||||
                OnSelectedDatePropertyChanged(this, null, SelectedDate);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public DateTime Date
 | 
			
		||||
    public class DateEventArgs : EventArgs
 | 
			
		||||
    {
 | 
			
		||||
        get => (DateTime)GetValue(DateProperty);
 | 
			
		||||
        set => SetValue(DateProperty, value);
 | 
			
		||||
    }
 | 
			
		||||
    public string Text => (string)GetValue(TextProperty);
 | 
			
		||||
    public string FontFamily => (string)GetValue(FontFamilyProperty);
 | 
			
		||||
    public bool IsSelected
 | 
			
		||||
    {
 | 
			
		||||
        get => (bool)GetValue(IsSelectedProperty);
 | 
			
		||||
        set => SetValue(IsSelectedProperty, value);
 | 
			
		||||
    }
 | 
			
		||||
    public double Opacity
 | 
			
		||||
    {
 | 
			
		||||
        get => (double)GetValue(OpacityProperty);
 | 
			
		||||
        set => SetValue(OpacityProperty, value);
 | 
			
		||||
    }
 | 
			
		||||
    public double TextOpacity => (double)GetValue(TextOpacityProperty);
 | 
			
		||||
        public DateTime Date { get; }
 | 
			
		||||
 | 
			
		||||
    public BillingDay(DateTime date)
 | 
			
		||||
    {
 | 
			
		||||
        Date = date;
 | 
			
		||||
        public DateEventArgs(DateTime date)
 | 
			
		||||
        {
 | 
			
		||||
            Date = date;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Refresh(DateTime selected)
 | 
			
		||||
    public class BillingDayView : ContentView
 | 
			
		||||
    {
 | 
			
		||||
        var date = Date;
 | 
			
		||||
        if (date.Year == selected.Year && date.DayOfYear == selected.DayOfYear)
 | 
			
		||||
        public static readonly BindableProperty BillingDayProperty = BindableProperty.Create(nameof(BillingDay), typeof(BillingDay), typeof(BillingDayView));
 | 
			
		||||
        public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(Command), typeof(BillingDayView));
 | 
			
		||||
 | 
			
		||||
        public BillingDay BillingDay
 | 
			
		||||
        {
 | 
			
		||||
            SetValue(IsSelectedProperty, true);
 | 
			
		||||
            SetValue(FontFamilyProperty, Definition.GetCascadiaBoldFontFamily());
 | 
			
		||||
            get => (BillingDay)GetValue(BillingDayProperty);
 | 
			
		||||
            set => SetValue(BillingDayProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        public Command Command
 | 
			
		||||
        {
 | 
			
		||||
            SetValue(FontFamilyProperty, Definition.GetCascadiaRegularFontFamily());
 | 
			
		||||
        }
 | 
			
		||||
        if (date.Year == selected.Year && date.Month == selected.Month)
 | 
			
		||||
        {
 | 
			
		||||
            SetValue(TextOpacityProperty, 1.0);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            SetValue(TextOpacityProperty, .4);
 | 
			
		||||
            get => (Command)GetValue(CommandProperty);
 | 
			
		||||
            set => SetValue(CommandProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
        private static void OnDatePropertyChanged(BindableObject obj, object old, object @new)
 | 
			
		||||
        {
 | 
			
		||||
            if (obj is BillingDay day && @new is DateTime date)
 | 
			
		||||
            {
 | 
			
		||||
                if (date.Day == 1)
 | 
			
		||||
                {
 | 
			
		||||
                    day.SetValue(TextProperty, date.ToString("MMM"));
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    day.SetValue(TextProperty, date.Day.ToString());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public DateTime Date
 | 
			
		||||
        {
 | 
			
		||||
            get => (DateTime)GetValue(DateProperty);
 | 
			
		||||
            set => SetValue(DateProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
        public string Text => (string)GetValue(TextProperty);
 | 
			
		||||
        public string FontFamily => (string)GetValue(FontFamilyProperty);
 | 
			
		||||
        public bool IsSelected
 | 
			
		||||
        {
 | 
			
		||||
            get => (bool)GetValue(IsSelectedProperty);
 | 
			
		||||
            set => SetValue(IsSelectedProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
        public double Opacity
 | 
			
		||||
        {
 | 
			
		||||
            get => (double)GetValue(OpacityProperty);
 | 
			
		||||
            set => SetValue(OpacityProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
        public double TextOpacity => (double)GetValue(TextOpacityProperty);
 | 
			
		||||
 | 
			
		||||
        public BillingDay(DateTime date)
 | 
			
		||||
        {
 | 
			
		||||
            Date = date;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Refresh(DateTime selected)
 | 
			
		||||
        {
 | 
			
		||||
            var date = Date;
 | 
			
		||||
            if (date.Year == selected.Year && date.DayOfYear == selected.DayOfYear)
 | 
			
		||||
            {
 | 
			
		||||
                SetValue(IsSelectedProperty, true);
 | 
			
		||||
                SetValue(FontFamilyProperty, Definition.GetCascadiaBoldFontFamily());
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                SetValue(FontFamilyProperty, Definition.GetCascadiaRegularFontFamily());
 | 
			
		||||
            }
 | 
			
		||||
            if (date.Year == selected.Year && date.Month == selected.Month)
 | 
			
		||||
            {
 | 
			
		||||
                SetValue(TextOpacityProperty, 1.0);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                SetValue(TextOpacityProperty, .4);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,12 +1,13 @@
 | 
			
		||||
using Billing.Themes;
 | 
			
		||||
using Xamarin.Forms;
 | 
			
		||||
 | 
			
		||||
namespace Billing.UI;
 | 
			
		||||
 | 
			
		||||
public abstract class BillingPage : ContentPage
 | 
			
		||||
namespace Billing.UI
 | 
			
		||||
{
 | 
			
		||||
    public BillingPage()
 | 
			
		||||
    public abstract class BillingPage : ContentPage
 | 
			
		||||
    {
 | 
			
		||||
        SetDynamicResource(BackgroundColorProperty, BaseTheme.WindowBackgroundColor);
 | 
			
		||||
        public BillingPage()
 | 
			
		||||
        {
 | 
			
		||||
            SetDynamicResource(BackgroundColorProperty, BaseTheme.WindowBackgroundColor);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@@ -3,38 +3,39 @@ using System;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using Xamarin.Forms;
 | 
			
		||||
 | 
			
		||||
namespace Billing.UI;
 | 
			
		||||
 | 
			
		||||
public class TitleDateConverter : IValueConverter
 | 
			
		||||
namespace Billing.UI
 | 
			
		||||
{
 | 
			
		||||
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
 | 
			
		||||
    public class TitleDateConverter : IValueConverter
 | 
			
		||||
    {
 | 
			
		||||
        if (value is DateTime date)
 | 
			
		||||
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
 | 
			
		||||
        {
 | 
			
		||||
            return date.ToString(Resource.TitleDateFormat);
 | 
			
		||||
            if (value is DateTime date)
 | 
			
		||||
            {
 | 
			
		||||
                return date.ToString(Resource.TitleDateFormat);
 | 
			
		||||
            }
 | 
			
		||||
            return value;
 | 
			
		||||
        }
 | 
			
		||||
        return value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
 | 
			
		||||
    {
 | 
			
		||||
        return value;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class MoneyConverter : IValueConverter
 | 
			
		||||
{
 | 
			
		||||
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
 | 
			
		||||
    {
 | 
			
		||||
        if (value is decimal d)
 | 
			
		||||
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
 | 
			
		||||
        {
 | 
			
		||||
            return "¥ " + d.ToString("n2", CultureInfo.InvariantCulture);
 | 
			
		||||
            return value;
 | 
			
		||||
        }
 | 
			
		||||
        return value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
 | 
			
		||||
    public class MoneyConverter : IValueConverter
 | 
			
		||||
    {
 | 
			
		||||
        return value;
 | 
			
		||||
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
 | 
			
		||||
        {
 | 
			
		||||
            if (value is decimal d)
 | 
			
		||||
            {
 | 
			
		||||
                return "¥ " + d.ToString("n2", CultureInfo.InvariantCulture);
 | 
			
		||||
            }
 | 
			
		||||
            return value;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
 | 
			
		||||
        {
 | 
			
		||||
            return value;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@@ -2,153 +2,154 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Xamarin.Forms;
 | 
			
		||||
 | 
			
		||||
namespace Billing.UI;
 | 
			
		||||
 | 
			
		||||
public class TintImage : Image
 | 
			
		||||
namespace Billing.UI
 | 
			
		||||
{
 | 
			
		||||
    public static readonly BindableProperty PrimaryColorProperty = BindableProperty.Create(nameof(PrimaryColor), typeof(Color?), typeof(TintImage));
 | 
			
		||||
 | 
			
		||||
    public Color? PrimaryColor
 | 
			
		||||
    public class TintImage : Image
 | 
			
		||||
    {
 | 
			
		||||
        get => (Color?)GetValue(PrimaryColorProperty);
 | 
			
		||||
        set => SetValue(PrimaryColorProperty, value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
        public static readonly BindableProperty PrimaryColorProperty = BindableProperty.Create(nameof(PrimaryColor), typeof(Color?), typeof(TintImage));
 | 
			
		||||
 | 
			
		||||
public class LongPressButton : Button
 | 
			
		||||
{
 | 
			
		||||
    public event EventHandler LongPressed;
 | 
			
		||||
 | 
			
		||||
    public LongPressButton()
 | 
			
		||||
    {
 | 
			
		||||
        Padding = 0;
 | 
			
		||||
        BackgroundColor = Color.Transparent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void TriggerLongPress()
 | 
			
		||||
    {
 | 
			
		||||
        LongPressed?.Invoke(this, EventArgs.Empty);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class OptionEntry : Entry { }
 | 
			
		||||
 | 
			
		||||
public abstract class OptionCell : ViewCell
 | 
			
		||||
{
 | 
			
		||||
    public static readonly BindableProperty TitleProperty = BindableProperty.Create(nameof(Title), typeof(string), typeof(OptionCell));
 | 
			
		||||
    public static readonly BindableProperty BackgroundColorProperty = BindableProperty.Create(nameof(BackgroundColor), typeof(Color), typeof(OptionCell));
 | 
			
		||||
 | 
			
		||||
    public string Title
 | 
			
		||||
    {
 | 
			
		||||
        get => (string)GetValue(TitleProperty);
 | 
			
		||||
        set => SetValue(TitleProperty, value);
 | 
			
		||||
    }
 | 
			
		||||
    public Color BackgroundColor
 | 
			
		||||
    {
 | 
			
		||||
        get => (Color)GetValue(BackgroundColorProperty);
 | 
			
		||||
        set => SetValue(BackgroundColorProperty, value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected abstract View Content { get; }
 | 
			
		||||
 | 
			
		||||
    public OptionCell()
 | 
			
		||||
    {
 | 
			
		||||
        View = new Grid
 | 
			
		||||
        public Color? PrimaryColor
 | 
			
		||||
        {
 | 
			
		||||
            BindingContext = this,
 | 
			
		||||
            Padding = new Thickness(20, 0),
 | 
			
		||||
            ColumnDefinitions =
 | 
			
		||||
            {
 | 
			
		||||
                new ColumnDefinition { Width = new GridLength(.3, GridUnitType.Star) },
 | 
			
		||||
                new ColumnDefinition { Width = new GridLength(.7, GridUnitType.Star) }
 | 
			
		||||
            },
 | 
			
		||||
            Children =
 | 
			
		||||
            {
 | 
			
		||||
                new Label
 | 
			
		||||
                {
 | 
			
		||||
                    LineBreakMode = LineBreakMode.TailTruncation,
 | 
			
		||||
                    VerticalOptions = LayoutOptions.Center
 | 
			
		||||
                }
 | 
			
		||||
                .Binding(Label.TextProperty, nameof(Title))
 | 
			
		||||
                .DynamicResource(Label.TextColorProperty, BaseTheme.TextColor),
 | 
			
		||||
 | 
			
		||||
                Content.GridColumn(1)
 | 
			
		||||
            }
 | 
			
		||||
            get => (Color?)GetValue(PrimaryColorProperty);
 | 
			
		||||
            set => SetValue(PrimaryColorProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class LongPressButton : Button
 | 
			
		||||
    {
 | 
			
		||||
        public event EventHandler LongPressed;
 | 
			
		||||
 | 
			
		||||
        public LongPressButton()
 | 
			
		||||
        {
 | 
			
		||||
            Padding = 0;
 | 
			
		||||
            BackgroundColor = Color.Transparent;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void TriggerLongPress()
 | 
			
		||||
        {
 | 
			
		||||
            LongPressed?.Invoke(this, EventArgs.Empty);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class OptionEntry : Entry { }
 | 
			
		||||
 | 
			
		||||
    public abstract class OptionCell : ViewCell
 | 
			
		||||
    {
 | 
			
		||||
        public static readonly BindableProperty TitleProperty = BindableProperty.Create(nameof(Title), typeof(string), typeof(OptionCell));
 | 
			
		||||
        public static readonly BindableProperty BackgroundColorProperty = BindableProperty.Create(nameof(BackgroundColor), typeof(Color), typeof(OptionCell));
 | 
			
		||||
 | 
			
		||||
        public string Title
 | 
			
		||||
        {
 | 
			
		||||
            get => (string)GetValue(TitleProperty);
 | 
			
		||||
            set => SetValue(TitleProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
        public Color BackgroundColor
 | 
			
		||||
        {
 | 
			
		||||
            get => (Color)GetValue(BackgroundColorProperty);
 | 
			
		||||
            set => SetValue(BackgroundColorProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected abstract View Content { get; }
 | 
			
		||||
 | 
			
		||||
        public OptionCell()
 | 
			
		||||
        {
 | 
			
		||||
            View = new Grid
 | 
			
		||||
            {
 | 
			
		||||
                BindingContext = this,
 | 
			
		||||
                Padding = new Thickness(20, 0),
 | 
			
		||||
                ColumnDefinitions =
 | 
			
		||||
                {
 | 
			
		||||
                    new ColumnDefinition { Width = new GridLength(.3, GridUnitType.Star) },
 | 
			
		||||
                    new ColumnDefinition { Width = new GridLength(.7, GridUnitType.Star) }
 | 
			
		||||
                },
 | 
			
		||||
                Children =
 | 
			
		||||
                {
 | 
			
		||||
                    new Label
 | 
			
		||||
                    {
 | 
			
		||||
                        LineBreakMode = LineBreakMode.TailTruncation,
 | 
			
		||||
                        VerticalOptions = LayoutOptions.Center
 | 
			
		||||
                    }
 | 
			
		||||
                    .Binding(Label.TextProperty, nameof(Title))
 | 
			
		||||
                    .DynamicResource(Label.TextColorProperty, BaseTheme.TextColor),
 | 
			
		||||
 | 
			
		||||
                    Content.GridColumn(1)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .DynamicResource(VisualElement.BackgroundColorProperty, BaseTheme.OptionTintColor);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class OptionTextCell : OptionCell
 | 
			
		||||
    {
 | 
			
		||||
        public static readonly BindableProperty DetailProperty = BindableProperty.Create(nameof(Detail), typeof(string), typeof(OptionTextCell));
 | 
			
		||||
 | 
			
		||||
        public string Detail
 | 
			
		||||
        {
 | 
			
		||||
            get => (string)GetValue(DetailProperty);
 | 
			
		||||
            set => SetValue(DetailProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override View Content => new Label
 | 
			
		||||
        {
 | 
			
		||||
            HorizontalOptions = LayoutOptions.End,
 | 
			
		||||
            VerticalOptions = LayoutOptions.Center
 | 
			
		||||
        }
 | 
			
		||||
        .Binding(Label.TextProperty, nameof(Detail))
 | 
			
		||||
        .DynamicResource(Label.TextColorProperty, BaseTheme.SecondaryTextColor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class OptionSwitchCell : OptionCell
 | 
			
		||||
    {
 | 
			
		||||
        public static readonly BindableProperty IsToggledProperty = BindableProperty.Create(nameof(IsToggled), typeof(bool), typeof(OptionSwitchCell));
 | 
			
		||||
 | 
			
		||||
        public bool IsToggled
 | 
			
		||||
        {
 | 
			
		||||
            get => (bool)GetValue(IsToggledProperty);
 | 
			
		||||
            set => SetValue(IsToggledProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override View Content => new Switch
 | 
			
		||||
        {
 | 
			
		||||
            HorizontalOptions = LayoutOptions.End,
 | 
			
		||||
            VerticalOptions = LayoutOptions.Center
 | 
			
		||||
        }
 | 
			
		||||
        .Binding(Switch.IsToggledProperty, nameof(IsToggled), BindingMode.TwoWay);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class OptionEntryCell : OptionCell
 | 
			
		||||
    {
 | 
			
		||||
        public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(OptionEntryCell));
 | 
			
		||||
        public static readonly BindableProperty KeyboardProperty = BindableProperty.Create(nameof(Keyboard), typeof(Keyboard), typeof(OptionEntryCell));
 | 
			
		||||
        public static readonly BindableProperty PlaceholderProperty = BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(OptionEntryCell));
 | 
			
		||||
 | 
			
		||||
        public string Text
 | 
			
		||||
        {
 | 
			
		||||
            get => (string)GetValue(TextProperty);
 | 
			
		||||
            set => SetValue(TextProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
        public Keyboard Keyboard
 | 
			
		||||
        {
 | 
			
		||||
            get => (Keyboard)GetValue(KeyboardProperty);
 | 
			
		||||
            set => SetValue(KeyboardProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
        public string Placeholder
 | 
			
		||||
        {
 | 
			
		||||
            get => (string)GetValue(PlaceholderProperty);
 | 
			
		||||
            set => SetValue(PlaceholderProperty, value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override View Content => new OptionEntry
 | 
			
		||||
        {
 | 
			
		||||
            HorizontalOptions = LayoutOptions.Fill,
 | 
			
		||||
            HorizontalTextAlignment = TextAlignment.End,
 | 
			
		||||
            VerticalOptions = LayoutOptions.Center,
 | 
			
		||||
            ReturnType = ReturnType.Next
 | 
			
		||||
        }
 | 
			
		||||
        .Binding(Entry.TextProperty, nameof(Text), BindingMode.TwoWay)
 | 
			
		||||
        .Binding(InputView.KeyboardProperty, nameof(Keyboard))
 | 
			
		||||
        .Binding(Entry.PlaceholderProperty, nameof(Placeholder))
 | 
			
		||||
        .DynamicResource(Entry.TextColorProperty, BaseTheme.TextColor)
 | 
			
		||||
        .DynamicResource(Entry.PlaceholderColorProperty, BaseTheme.SecondaryTextColor)
 | 
			
		||||
        .DynamicResource(VisualElement.BackgroundColorProperty, BaseTheme.OptionTintColor);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class OptionTextCell : OptionCell
 | 
			
		||||
{
 | 
			
		||||
    public static readonly BindableProperty DetailProperty = BindableProperty.Create(nameof(Detail), typeof(string), typeof(OptionTextCell));
 | 
			
		||||
 | 
			
		||||
    public string Detail
 | 
			
		||||
    {
 | 
			
		||||
        get => (string)GetValue(DetailProperty);
 | 
			
		||||
        set => SetValue(DetailProperty, value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override View Content => new Label
 | 
			
		||||
    {
 | 
			
		||||
        HorizontalOptions = LayoutOptions.End,
 | 
			
		||||
        VerticalOptions = LayoutOptions.Center
 | 
			
		||||
    }
 | 
			
		||||
    .Binding(Label.TextProperty, nameof(Detail))
 | 
			
		||||
    .DynamicResource(Label.TextColorProperty, BaseTheme.SecondaryTextColor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class OptionSwitchCell : OptionCell
 | 
			
		||||
{
 | 
			
		||||
    public static readonly BindableProperty IsToggledProperty = BindableProperty.Create(nameof(IsToggled), typeof(bool), typeof(OptionSwitchCell));
 | 
			
		||||
 | 
			
		||||
    public bool IsToggled
 | 
			
		||||
    {
 | 
			
		||||
        get => (bool)GetValue(IsToggledProperty);
 | 
			
		||||
        set => SetValue(IsToggledProperty, value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override View Content => new Switch
 | 
			
		||||
    {
 | 
			
		||||
        HorizontalOptions = LayoutOptions.End,
 | 
			
		||||
        VerticalOptions = LayoutOptions.Center
 | 
			
		||||
    }
 | 
			
		||||
    .Binding(Switch.IsToggledProperty, nameof(IsToggled), BindingMode.TwoWay);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class OptionEntryCell : OptionCell
 | 
			
		||||
{
 | 
			
		||||
    public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(OptionEntryCell));
 | 
			
		||||
    public static readonly BindableProperty KeyboardProperty = BindableProperty.Create(nameof(Keyboard), typeof(Keyboard), typeof(OptionEntryCell));
 | 
			
		||||
    public static readonly BindableProperty PlaceholderProperty = BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(OptionEntryCell));
 | 
			
		||||
 | 
			
		||||
    public string Text
 | 
			
		||||
    {
 | 
			
		||||
        get => (string)GetValue(TextProperty);
 | 
			
		||||
        set => SetValue(TextProperty, value);
 | 
			
		||||
    }
 | 
			
		||||
    public Keyboard Keyboard
 | 
			
		||||
    {
 | 
			
		||||
        get => (Keyboard)GetValue(KeyboardProperty);
 | 
			
		||||
        set => SetValue(KeyboardProperty, value);
 | 
			
		||||
    }
 | 
			
		||||
    public string Placeholder
 | 
			
		||||
    {
 | 
			
		||||
        get => (string)GetValue(PlaceholderProperty);
 | 
			
		||||
        set => SetValue(PlaceholderProperty, value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override View Content => new OptionEntry
 | 
			
		||||
    {
 | 
			
		||||
        HorizontalOptions = LayoutOptions.Fill,
 | 
			
		||||
        HorizontalTextAlignment = TextAlignment.End,
 | 
			
		||||
        VerticalOptions = LayoutOptions.Center,
 | 
			
		||||
        ReturnType = ReturnType.Next
 | 
			
		||||
    }
 | 
			
		||||
    .Binding(Entry.TextProperty, nameof(Text), BindingMode.TwoWay)
 | 
			
		||||
    .Binding(InputView.KeyboardProperty, nameof(Keyboard))
 | 
			
		||||
    .Binding(Entry.PlaceholderProperty, nameof(Placeholder))
 | 
			
		||||
    .DynamicResource(Entry.TextColorProperty, BaseTheme.TextColor)
 | 
			
		||||
    .DynamicResource(Entry.PlaceholderColorProperty, BaseTheme.SecondaryTextColor)
 | 
			
		||||
    .DynamicResource(VisualElement.BackgroundColorProperty, BaseTheme.OptionTintColor);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,15 +1,16 @@
 | 
			
		||||
using Xamarin.Forms;
 | 
			
		||||
 | 
			
		||||
namespace Billing.UI;
 | 
			
		||||
 | 
			
		||||
public class ShadowEffect : RoutingEffect
 | 
			
		||||
namespace Billing.UI
 | 
			
		||||
{
 | 
			
		||||
    public float Radius { get; set; }
 | 
			
		||||
    public Color Color { get; set; }
 | 
			
		||||
    public Size Offect { get; set; }
 | 
			
		||||
    public float Opacity { get; set; }
 | 
			
		||||
 | 
			
		||||
    public ShadowEffect() : base($"Org.Tsanie.{nameof(ShadowEffect)}")
 | 
			
		||||
    public class ShadowEffect : RoutingEffect
 | 
			
		||||
    {
 | 
			
		||||
        public float Radius { get; set; }
 | 
			
		||||
        public Color Color { get; set; }
 | 
			
		||||
        public Size Offect { get; set; }
 | 
			
		||||
        public float Opacity { get; set; }
 | 
			
		||||
 | 
			
		||||
        public ShadowEffect() : base($"Org.Tsanie.{nameof(ShadowEffect)}")
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@@ -1,68 +1,69 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Xamarin.Forms;
 | 
			
		||||
 | 
			
		||||
namespace Billing.UI;
 | 
			
		||||
 | 
			
		||||
public static partial class Definition
 | 
			
		||||
namespace Billing.UI
 | 
			
		||||
{
 | 
			
		||||
    public static partial string GetCascadiaRegularFontFamily();
 | 
			
		||||
    public static partial string GetCascadiaBoldFontFamily();
 | 
			
		||||
    public static partial string GetRobotoCondensedRegularFontFamily();
 | 
			
		||||
    public static partial string GetRobotoCondensedBoldFontFamily();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public static class ExtensionHelper
 | 
			
		||||
{
 | 
			
		||||
    public static View Binding(this View view, BindableProperty property, string path, BindingMode mode = BindingMode.Default, IValueConverter converter = null)
 | 
			
		||||
    public static partial class Definition
 | 
			
		||||
    {
 | 
			
		||||
        view.SetBinding(property, path, mode, converter);
 | 
			
		||||
        return view;
 | 
			
		||||
        public static partial string GetCascadiaRegularFontFamily();
 | 
			
		||||
        public static partial string GetCascadiaBoldFontFamily();
 | 
			
		||||
        public static partial string GetRobotoCondensedRegularFontFamily();
 | 
			
		||||
        public static partial string GetRobotoCondensedBoldFontFamily();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static View DynamicResource(this View view, BindableProperty property, string key)
 | 
			
		||||
    public static class ExtensionHelper
 | 
			
		||||
    {
 | 
			
		||||
        view.SetDynamicResource(property, key);
 | 
			
		||||
        return view;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static View GridColumn(this View view, int column)
 | 
			
		||||
    {
 | 
			
		||||
        Grid.SetColumn(view, column);
 | 
			
		||||
        return view;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static View GridRow(this View view, int row)
 | 
			
		||||
    {
 | 
			
		||||
        Grid.SetRow(view, row);
 | 
			
		||||
        return view;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class Tap : IDisposable
 | 
			
		||||
{
 | 
			
		||||
    private readonly static object sync = new();
 | 
			
		||||
    private static Tap instance;
 | 
			
		||||
 | 
			
		||||
    private bool busy = false;
 | 
			
		||||
 | 
			
		||||
    private Tap() { }
 | 
			
		||||
 | 
			
		||||
    public static bool IsBusy => instance?.busy ?? false;
 | 
			
		||||
 | 
			
		||||
    public static Tap Start()
 | 
			
		||||
    {
 | 
			
		||||
        lock (sync)
 | 
			
		||||
        public static View Binding(this View view, BindableProperty property, string path, BindingMode mode = BindingMode.Default, IValueConverter converter = null)
 | 
			
		||||
        {
 | 
			
		||||
            (instance ??= new Tap()).busy = true;
 | 
			
		||||
            view.SetBinding(property, path, mode, converter);
 | 
			
		||||
            return view;
 | 
			
		||||
        }
 | 
			
		||||
        return instance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Dispose()
 | 
			
		||||
    {
 | 
			
		||||
        lock (sync)
 | 
			
		||||
        public static View DynamicResource(this View view, BindableProperty property, string key)
 | 
			
		||||
        {
 | 
			
		||||
            busy = false;
 | 
			
		||||
            view.SetDynamicResource(property, key);
 | 
			
		||||
            return view;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static View GridColumn(this View view, int column)
 | 
			
		||||
        {
 | 
			
		||||
            Grid.SetColumn(view, column);
 | 
			
		||||
            return view;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static View GridRow(this View view, int row)
 | 
			
		||||
        {
 | 
			
		||||
            Grid.SetRow(view, row);
 | 
			
		||||
            return view;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public class Tap : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly static object sync = new();
 | 
			
		||||
        private static Tap instance;
 | 
			
		||||
 | 
			
		||||
        private bool busy = false;
 | 
			
		||||
 | 
			
		||||
        private Tap() { }
 | 
			
		||||
 | 
			
		||||
        public static bool IsBusy => instance?.busy ?? false;
 | 
			
		||||
 | 
			
		||||
        public static Tap Start()
 | 
			
		||||
        {
 | 
			
		||||
            lock (sync)
 | 
			
		||||
            {
 | 
			
		||||
                (instance ??= new Tap()).busy = true;
 | 
			
		||||
            }
 | 
			
		||||
            return instance;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            lock (sync)
 | 
			
		||||
            {
 | 
			
		||||
                busy = false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user