using Billing.Themes; using System; using Xamarin.Forms; namespace Billing.UI { public class OptionEntry : Entry { } public class OptionEditor : Editor { } 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 static readonly BindableProperty IconProperty = BindableProperty.Create(nameof(Icon), typeof(ImageSource), typeof(OptionCell)); public string Title { get => (string)GetValue(TitleProperty); set => SetValue(TitleProperty, value); } public Color BackgroundColor { get => (Color)GetValue(BackgroundColorProperty); set => SetValue(BackgroundColorProperty, value); } [TypeConverter(typeof(ImageSourceConverter))] public ImageSource Icon { get => (ImageSource)GetValue(IconProperty); set => SetValue(IconProperty, value); } protected abstract View Content { get; } public OptionCell() { View = new Grid { BindingContext = this, Padding = new Thickness(20, 0), ColumnDefinitions = { new ColumnDefinition { Width = GridLength.Auto }, new ColumnDefinition { Width = new GridLength(.3, GridUnitType.Star) }, new ColumnDefinition { Width = new GridLength(.7, GridUnitType.Star) } }, Children = { new TintImage { WidthRequest = 20, HeightRequest = 20, Aspect = Aspect.AspectFit, VerticalOptions = LayoutOptions.Center, Margin = new Thickness(6, 0) } .Binding(VisualElement.IsVisibleProperty, nameof(Icon), converter: new NotNullConverter()) .Binding(Image.SourceProperty, nameof(Icon)), new Label { LineBreakMode = LineBreakMode.TailTruncation, VerticalOptions = LayoutOptions.Center } .GridColumn(1) .Binding(Label.TextProperty, nameof(Title)) .DynamicResource(Label.TextColorProperty, BaseTheme.TextColor), Content.GridColumn(2) } } .DynamicResource(VisualElement.BackgroundColorProperty, BaseTheme.OptionTintColor); } } public abstract class OptionVerticalCell : OptionCell { public OptionVerticalCell() { View = new Grid { BindingContext = this, Padding = new Thickness(20, 0), ColumnDefinitions = { new ColumnDefinition { Width = GridLength.Auto }, new ColumnDefinition { Width = GridLength.Star } }, RowDefinitions = { new RowDefinition { Height = new GridLength(40) }, new RowDefinition { Height = GridLength.Star } }, Children = { new TintImage { WidthRequest = 20, HeightRequest = 20, Aspect = Aspect.AspectFit, VerticalOptions = LayoutOptions.Center, Margin = new Thickness(6, 0) } .Binding(VisualElement.IsVisibleProperty, nameof(Icon), converter: new NotNullConverter()) .Binding(Image.SourceProperty, nameof(Icon)), new Label { LineBreakMode = LineBreakMode.TailTruncation, VerticalOptions = LayoutOptions.Center } .GridColumn(1) .Binding(Label.TextProperty, nameof(Title)) .DynamicResource(Label.TextColorProperty, BaseTheme.TextColor), Content.GridRow(1).GridColumnSpan(2) } } .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 OptionSelectCell : OptionTextCell { public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(Command), typeof(OptionSelectCell)); public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create(nameof(CommandParameter), typeof(object), typeof(OptionSelectCell)); public Command Command { get => (Command)GetValue(CommandProperty); set => SetValue(CommandProperty, value); } public object CommandParameter { get => GetValue(CommandParameterProperty); set => SetValue(CommandParameterProperty, value); } protected override View Content => new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.End, Children = { new Label { HorizontalOptions = LayoutOptions.End, VerticalOptions = LayoutOptions.Center } .Binding(Label.TextProperty, nameof(Detail)) .DynamicResource(Label.TextColorProperty, BaseTheme.SecondaryTextColor), new TintImage { HeightRequest = 20, VerticalOptions = LayoutOptions.Center, Margin = new Thickness(6, 0), Source = "right.png" } }, GestureRecognizers = { new TapGestureRecognizer() .Binding(TapGestureRecognizer.CommandProperty, nameof(Command)) .Binding(TapGestureRecognizer.CommandParameterProperty, nameof(CommandParameter)) } }; } public class OptionImageCell : OptionSelectCell { public static readonly BindableProperty ImageSourceProperty = BindableProperty.Create(nameof(ImageSource), typeof(ImageSource), typeof(OptionImageCell)); [TypeConverter(typeof(ImageSourceConverter))] public ImageSource ImageSource { get => (ImageSource)GetValue(ImageSourceProperty); set => SetValue(ImageSourceProperty, value); } protected override View Content => new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.End, Children = { new TintImage { WidthRequest = 26, HeightRequest = 20, HorizontalOptions = LayoutOptions.End, VerticalOptions = LayoutOptions.Center, Margin = new Thickness(6, 0) } .Binding(Image.SourceProperty, nameof(ImageSource)), new TintImage { HeightRequest = 20, VerticalOptions = LayoutOptions.Center, Margin = new Thickness(6, 0), Source = "right.png" } }, GestureRecognizers = { new TapGestureRecognizer() .Binding(TapGestureRecognizer.CommandProperty, nameof(Command)) .Binding(TapGestureRecognizer.CommandParameterProperty, nameof(CommandParameter)) } }; } 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), mode: 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); } public event EventHandler Unfocused; protected override View Content { get { var content = new OptionEntry { HorizontalOptions = LayoutOptions.Fill, HorizontalTextAlignment = TextAlignment.End, VerticalOptions = LayoutOptions.Center, ReturnType = ReturnType.Next } .Binding(Entry.TextProperty, nameof(Text), mode: 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); content.Unfocused += Content_Unfocused; return content; } } private void Content_Unfocused(object sender, FocusEventArgs e) { Unfocused?.Invoke(sender, e); } } public class OptionEditorCell : OptionVerticalCell { public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(OptionEditorCell)); public static readonly BindableProperty FontSizeProperty = BindableProperty.Create(nameof(FontSize), typeof(double), typeof(OptionEditorCell), defaultValue: Device.GetNamedSize(NamedSize.Default, typeof(Editor))); public static readonly BindableProperty KeyboardProperty = BindableProperty.Create(nameof(Keyboard), typeof(Keyboard), typeof(OptionEditorCell), defaultValue: Keyboard.Default); public static readonly BindableProperty PlaceholderProperty = BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(OptionEditorCell)); public string Text { get => (string)GetValue(TextProperty); set => SetValue(TextProperty, value); } [TypeConverter(typeof(FontSizeConverter))] public double FontSize { get => (double)GetValue(FontSizeProperty); set => SetValue(FontSizeProperty, 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 OptionEditor { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill } .Binding(Editor.TextProperty, nameof(Text), mode: BindingMode.TwoWay) .Binding(Editor.FontSizeProperty, nameof(FontSize)) .Binding(InputView.KeyboardProperty, nameof(Keyboard)) .Binding(Editor.PlaceholderProperty, nameof(Placeholder)) .DynamicResource(Editor.TextColorProperty, BaseTheme.TextColor) .DynamicResource(Editor.PlaceholderColorProperty, BaseTheme.SecondaryTextColor) .DynamicResource(VisualElement.BackgroundColorProperty, BaseTheme.OptionTintColor); } }