2023-08-02 23:45:04 +08:00

352 lines
11 KiB
C#

using System.ComponentModel;
using static Blahblah.FlowerApp.Extensions;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace Blahblah.FlowerApp.Controls;
public class TitleLabel : Label { }
public class SecondaryLabel : Label { }
public class IconLabel : Label { }
public class OptionEntry : Entry { }
public class OptionEditor : Editor { }
public class OptionDatePicker : DatePicker { }
public class OptionTimePicker : TimePicker { }
public abstract class OptionCell : ViewCell
{
public static readonly BindableProperty IconProperty = CreateProperty<ImageSource, OptionCell>(nameof(Icon));
public static readonly BindableProperty TitleProperty = CreateProperty<string, OptionCell>(nameof(Title));
public static readonly BindableProperty IsRequiredProperty = CreateProperty<bool, OptionCell>(nameof(IsRequired));
[TypeConverter(typeof(ImageSourceConverter))]
public ImageSource Icon
{
get => (ImageSource)GetValue(IconProperty);
set => SetValue(IconProperty, value);
}
public string Title
{
get => (string)GetValue(TitleProperty);
set => SetValue(TitleProperty, value);
}
public bool IsRequired
{
get => (bool)GetValue(IsRequiredProperty);
set => SetValue(IsRequiredProperty, value);
}
protected abstract View Content { get; }
public OptionCell()
{
View = new Grid
{
BindingContext = this,
Padding = new Thickness(20, 0),
ColumnSpacing = 12,
ColumnDefinitions =
{
new(GridLength.Auto),
new(new GridLength(.35, GridUnitType.Star)),
new(new GridLength(.65, GridUnitType.Star))
},
RowDefinitions = { new(44) },
Children =
{
new Image
{
WidthRequest = 20,
HeightRequest = 20,
Aspect = Aspect.AspectFit,
VerticalOptions = LayoutOptions.Center
}
.Binding(VisualElement.IsVisibleProperty, nameof(Icon), converter: new VisibleIfNotNullConverter())
.Binding(Image.SourceProperty, nameof(Icon)),
new Grid
{
ColumnDefinitions =
{
new(GridLength.Auto),
new(GridLength.Star)
},
Children =
{
new TitleLabel
{
LineBreakMode = LineBreakMode.TailTruncation,
VerticalOptions = LayoutOptions.Center
}
.Binding(Label.TextProperty, nameof(Title)),
new SecondaryLabel
{
VerticalOptions = LayoutOptions.Center,
Text = "*"
}
.GridColumn(1)
.AppThemeBinding(Label.TextColorProperty, Res.Red100, Res.Red300)
.Binding(VisualElement.IsVisibleProperty, nameof(IsRequired)),
}
}
.GridColumn(1),
Content.GridColumn(2)
}
}
.AppThemeBinding(VisualElement.BackgroundColorProperty, Colors.White, Res.Gray900);
}
}
public abstract class OptionVerticalCell : OptionCell
{
public OptionVerticalCell()
{
View = new Grid
{
BindingContext = this,
Padding = new Thickness(20, 0),
ColumnSpacing = 12,
ColumnDefinitions =
{
new(GridLength.Auto),
new(GridLength.Star)
},
RowDefinitions =
{
new(44),
new(GridLength.Star)
},
Children =
{
new Image
{
WidthRequest = 20,
HeightRequest = 20,
Aspect = Aspect.AspectFit,
VerticalOptions = LayoutOptions.Center
}
.Binding(VisualElement.IsVisibleProperty, nameof(Icon), converter: new VisibleIfNotNullConverter())
.Binding(Image.SourceProperty, nameof(Icon)),
new TitleLabel
{
LineBreakMode = LineBreakMode.TailTruncation,
VerticalOptions = LayoutOptions.Center
}
.GridColumn(1)
.Binding(Label.TextProperty, nameof(Title)),
Content.GridRow(1).GridColumn(1)
}
}
.AppThemeBinding(VisualElement.BackgroundColorProperty, Colors.White, Res.Gray900);
}
}
public class OptionTextCell : OptionCell
{
public static readonly BindableProperty DetailProperty = CreateProperty<string, OptionTextCell>(nameof(Detail));
public string Detail
{
get => (string)GetValue(DetailProperty);
set => SetValue(DetailProperty, value);
}
protected override View Content => new SecondaryLabel
{
HorizontalOptions = LayoutOptions.End,
VerticalOptions = LayoutOptions.Center
}
.Binding(Label.TextProperty, nameof(Detail));
}
public class OptionEntryCell : OptionCell
{
public static readonly BindableProperty TextProperty = CreateProperty<string, OptionEntryCell>(nameof(Text), defaultBindingMode: BindingMode.TwoWay);
public static readonly BindableProperty KeyboardProperty = CreateProperty<Keyboard, OptionEntryCell>(nameof(Keyboard), defaultValue: Keyboard.Default);
public static readonly BindableProperty PlaceholderProperty = CreateProperty<string, OptionEntryCell>(nameof(Placeholder));
public event EventHandler<FocusEventArgs>? Unfocused;
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
{
get
{
var entry = new OptionEntry()
.Binding(Entry.TextProperty, nameof(Text))
.Binding(InputView.KeyboardProperty, nameof(Keyboard))
.Binding(Entry.PlaceholderProperty, nameof(Placeholder));
entry.Unfocused += Entry_Unfocused;
return entry;
}
}
private void Entry_Unfocused(object? sender, FocusEventArgs e)
{
Unfocused?.Invoke(this, e);
}
}
public class OptionEditorCell : OptionVerticalCell
{
public static readonly BindableProperty TextProperty = CreateProperty<string, OptionEditorCell>(nameof(Text), defaultBindingMode: BindingMode.TwoWay);
public static readonly BindableProperty KeyboardProperty = CreateProperty<Keyboard, OptionEditorCell>(nameof(Keyboard), defaultValue: Keyboard.Default);
public static readonly BindableProperty PlaceholderProperty = CreateProperty<string, OptionEditorCell>(nameof(Placeholder));
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 OptionEditor()
.Binding(Editor.TextProperty, nameof(Text))
.Binding(InputView.KeyboardProperty, nameof(Keyboard))
.Binding(Editor.PlaceholderProperty, nameof(Placeholder));
}
public class OptionSwitchCell : OptionCell
{
public static readonly BindableProperty IsToggledProperty = CreateProperty<bool, OptionSwitchCell>(nameof(IsToggled), defaultBindingMode: BindingMode.TwoWay);
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));
}
public class OptionSelectCell : OptionTextCell
{
public static readonly BindableProperty CommandProperty = CreateProperty<Command, OptionSelectCell>(nameof(Command));
public static readonly BindableProperty CommandParameterProperty = CreateProperty<object, OptionSelectCell>(nameof(CommandParameter));
public Command Command
{
get => (Command)GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
public object CommandParameter
{
get => GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value);
}
public event EventHandler? DetailTapped;
protected override View Content
{
get
{
var tap = new TapGestureRecognizer();
tap.Tapped += OnTapped;
return new StackLayout
{
Orientation = StackOrientation.Horizontal,
HorizontalOptions = LayoutOptions.End,
Children =
{
new SecondaryLabel
{
VerticalOptions = LayoutOptions.Center,
}
.Binding(Label.TextProperty, nameof(Detail)),
new IconLabel
{
VerticalOptions = LayoutOptions.Center,
Margin = new Thickness(6, 0),
Text = Res.Right
}
},
GestureRecognizers = { tap }
};
}
}
private void OnTapped(object? sender, TappedEventArgs e)
{
DetailTapped?.Invoke(this, e);
}
}
public class OptionDateTimePickerCell : OptionCell
{
public static readonly BindableProperty DateProperty = CreateProperty<DateTime, OptionDateTimePickerCell>(nameof(Date), defaultBindingMode: BindingMode.TwoWay);
public static readonly BindableProperty TimeProperty = CreateProperty<TimeSpan, OptionDateTimePickerCell>(nameof(Time), defaultBindingMode: BindingMode.TwoWay);
public DateTime Date
{
get => (DateTime)GetValue(DateProperty);
set => SetValue(DateProperty, value);
}
public TimeSpan Time
{
get => (TimeSpan)GetValue(TimeProperty);
set => SetValue(TimeProperty, value);
}
protected override View Content => new Grid
{
ColumnDefinitions =
{
new(GridLength.Star),
new(GridLength.Auto),
new(GridLength.Auto)
},
ColumnSpacing = 6,
Children =
{
new OptionDatePicker()
.Binding(DatePicker.DateProperty, nameof(Date))
.GridColumn(1),
new OptionTimePicker()
.Binding(TimePicker.TimeProperty, nameof(Time))
.GridColumn(2)
}
};
}