From c3640e4ffcd27d6db86e56245330d5064bffde33 Mon Sep 17 00:00:00 2001 From: "viet.to" Date: Fri, 30 Jun 2023 14:07:18 +0700 Subject: [PATCH] #138 Add maui switch --- .../DayAndNightSwitchContentView.xaml | 78 +++++++++ .../DayAndNightSwitchContentView.xaml.cs | 67 +++++++ .../CustomSwitches/IosSwitchContentView.xaml | 53 ++++++ .../IosSwitchContentView.xaml.cs | 63 +++++++ .../MauiSwitch/MauiSwitchControlInfo.cs | 15 ++ .../Community/MauiSwitch/MauiSwitchPage.xaml | 164 ++++++++++++++++++ .../MauiSwitch/MauiSwitchPage.xaml.cs | 12 ++ .../MauiSwitch/MauiSwitchPageViewModel.cs | 35 ++++ .../MauiSwitch/SwitchViews/BorderSwitch.xaml | 24 +++ .../SwitchViews/BorderSwitch.xaml.cs | 125 +++++++++++++ .../MauiSwitch/SwitchViews/ImageSwitch.xaml | 14 ++ .../SwitchViews/ImageSwitch.xaml.cs | 29 ++++ .../HomeService.cs | 0 .../IHomeService.cs | 0 src/MAUIsland.csproj | 15 +- src/MauiProgram.cs | 4 +- 16 files changed, 695 insertions(+), 3 deletions(-) create mode 100644 src/Features/Gallery/Pages/Community/MauiSwitch/ContentViews/CustomSwitches/DayAndNightSwitchContentView.xaml create mode 100644 src/Features/Gallery/Pages/Community/MauiSwitch/ContentViews/CustomSwitches/DayAndNightSwitchContentView.xaml.cs create mode 100644 src/Features/Gallery/Pages/Community/MauiSwitch/ContentViews/CustomSwitches/IosSwitchContentView.xaml create mode 100644 src/Features/Gallery/Pages/Community/MauiSwitch/ContentViews/CustomSwitches/IosSwitchContentView.xaml.cs create mode 100644 src/Features/Gallery/Pages/Community/MauiSwitch/MauiSwitchControlInfo.cs create mode 100644 src/Features/Gallery/Pages/Community/MauiSwitch/MauiSwitchPage.xaml create mode 100644 src/Features/Gallery/Pages/Community/MauiSwitch/MauiSwitchPage.xaml.cs create mode 100644 src/Features/Gallery/Pages/Community/MauiSwitch/MauiSwitchPageViewModel.cs create mode 100644 src/Features/Gallery/Pages/Community/MauiSwitch/SwitchViews/BorderSwitch.xaml create mode 100644 src/Features/Gallery/Pages/Community/MauiSwitch/SwitchViews/BorderSwitch.xaml.cs create mode 100644 src/Features/Gallery/Pages/Community/MauiSwitch/SwitchViews/ImageSwitch.xaml create mode 100644 src/Features/Gallery/Pages/Community/MauiSwitch/SwitchViews/ImageSwitch.xaml.cs rename src/Features/Home/Services/{Interfaces => Implementations}/HomeService.cs (100%) rename src/Features/Home/Services/{Implementations => Interfaces}/IHomeService.cs (100%) diff --git a/src/Features/Gallery/Pages/Community/MauiSwitch/ContentViews/CustomSwitches/DayAndNightSwitchContentView.xaml b/src/Features/Gallery/Pages/Community/MauiSwitch/ContentViews/CustomSwitches/DayAndNightSwitchContentView.xaml new file mode 100644 index 00000000..69a5937e --- /dev/null +++ b/src/Features/Gallery/Pages/Community/MauiSwitch/ContentViews/CustomSwitches/DayAndNightSwitchContentView.xaml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + diff --git a/src/Features/Gallery/Pages/Community/MauiSwitch/ContentViews/CustomSwitches/DayAndNightSwitchContentView.xaml.cs b/src/Features/Gallery/Pages/Community/MauiSwitch/ContentViews/CustomSwitches/DayAndNightSwitchContentView.xaml.cs new file mode 100644 index 00000000..cdce1cc5 --- /dev/null +++ b/src/Features/Gallery/Pages/Community/MauiSwitch/ContentViews/CustomSwitches/DayAndNightSwitchContentView.xaml.cs @@ -0,0 +1,67 @@ +using IeuanWalker.Maui.Switch; +using IeuanWalker.Maui.Switch.Events; +using IeuanWalker.Maui.Switch.Helpers; +using Microsoft.Maui.Controls.Shapes; + +namespace MAUIsland; + +[XamlCompilation(XamlCompilationOptions.Compile)] +public partial class DayAndNightSwitchContentView : ContentView +{ + public DayAndNightSwitchContentView() + { + InitializeComponent(); + } + public event EventHandler? Toggled = null; + + public static readonly BindableProperty IsToggledProperty = BindableProperty.Create(nameof(IsToggled), typeof(bool), typeof(DayAndNightSwitchContentView), false, BindingMode.TwoWay); + + public bool IsToggled + { + get => (bool)GetValue(IsToggledProperty); + set => SetValue(IsToggledProperty, value); + } + + public static readonly BindableProperty ToggledCommandProperty = BindableProperty.Create(nameof(ToggledCommand), typeof(ICommand), typeof(DayAndNightSwitchContentView)); + + public ICommand ToggledCommand + { + get => (ICommand)GetValue(ToggledCommandProperty); + set => SetValue(ToggledCommandProperty, value); + } + + void CustomSwitch_SwitchPanUpdate(CustomSwitch customSwitch, SwitchPanUpdatedEventArgs e) + { + KnobContent.TranslationX = -(e.TranslateX + e.XRef); + + Color fromColorLight = e.IsToggled ? Color.FromArgb("#cdf4cc") : Color.FromArgb("#f7cccc"); + Color toColorLight = e.IsToggled ? Color.FromArgb("#f7cccc") : Color.FromArgb("#cdf4cc"); + + Color fromColorDark = e.IsToggled ? Color.FromArgb("#46d744") : Color.FromArgb("#dd2424"); + Color toColorDark = e.IsToggled ? Color.FromArgb("#dd2424") : Color.FromArgb("#46d744"); + + double t = e.Percentage * 0.01; + + double zeroToFive = Calculate(0, 5, t); + double fiveToZero = Calculate(5, 0, t); + + customSwitch.KnobStrokeShape = new RoundRectangle + { + CornerRadius = e.IsToggled ? + new CornerRadius(zeroToFive, fiveToZero, zeroToFive, fiveToZero) : + new CornerRadius(fiveToZero, zeroToFive, fiveToZero, zeroToFive) + }; + customSwitch.KnobBackgroundColor = ColorAnimationUtil.ColorAnimation(fromColorLight, toColorLight, t); + customSwitch.KnobStroke = ColorAnimationUtil.ColorAnimation(fromColorDark, toColorDark, t); + } + + void CustomSwitch_Toggled(object sender, ToggledEventArgs e) + { + Toggled?.Invoke(sender, e); + } + + public static double Calculate(double from, double to, double percentage) + { + return from + ((to - from) * percentage); + } +} \ No newline at end of file diff --git a/src/Features/Gallery/Pages/Community/MauiSwitch/ContentViews/CustomSwitches/IosSwitchContentView.xaml b/src/Features/Gallery/Pages/Community/MauiSwitch/ContentViews/CustomSwitches/IosSwitchContentView.xaml new file mode 100644 index 00000000..ee7ab22f --- /dev/null +++ b/src/Features/Gallery/Pages/Community/MauiSwitch/ContentViews/CustomSwitches/IosSwitchContentView.xaml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + diff --git a/src/Features/Gallery/Pages/Community/MauiSwitch/ContentViews/CustomSwitches/IosSwitchContentView.xaml.cs b/src/Features/Gallery/Pages/Community/MauiSwitch/ContentViews/CustomSwitches/IosSwitchContentView.xaml.cs new file mode 100644 index 00000000..c0473e4c --- /dev/null +++ b/src/Features/Gallery/Pages/Community/MauiSwitch/ContentViews/CustomSwitches/IosSwitchContentView.xaml.cs @@ -0,0 +1,63 @@ +using IeuanWalker.Maui.Switch; +using IeuanWalker.Maui.Switch.Events; +using IeuanWalker.Maui.Switch.Helpers; + +namespace MAUIsland; + +[XamlCompilation(XamlCompilationOptions.Compile)] +public partial class IosSwitchContentView : ContentView +{ + #region [ CTor ] + + public IosSwitchContentView() + { + InitializeComponent(); + } + #endregion + + #region [ Properties ] + public static readonly BindableProperty IsToggledProperty = BindableProperty.Create(nameof(IsToggled), typeof(bool), typeof(IosSwitchContentView), false, BindingMode.TwoWay); + + public bool IsToggled + { + get => (bool)GetValue(IsToggledProperty); + set => SetValue(IsToggledProperty, value); + } + + public static readonly BindableProperty AccessibilityHintProperty = BindableProperty.Create(nameof(AccessibilityHint), typeof(string), typeof(IosSwitchContentView), string.Empty); + + public string AccessibilityHint + { + get => (string)GetValue(AccessibilityHintProperty); + set => SetValue(AccessibilityHintProperty, value); + } + + public static readonly BindableProperty ToggledCommandProperty = BindableProperty.Create(nameof(ToggledCommand), typeof(ICommand), typeof(IosSwitchContentView)); + + public ICommand ToggledCommand + { + get => (ICommand)GetValue(ToggledCommandProperty); + set => SetValue(ToggledCommandProperty, value); + } + #endregion + + #region [ Event Handlers ] + public event EventHandler? Toggled = null; + + void CustomSwitch_SwitchPanUpdate(CustomSwitch customSwitch, SwitchPanUpdatedEventArgs e) + { + //Color Animation + Color fromColor = e.IsToggled ? Color.FromArgb("#4ACC64") : Color.FromArgb("#EBECEC"); + Color toColor = e.IsToggled ? Color.FromArgb("#EBECEC") : Color.FromArgb("#4ACC64"); + + double t = e.Percentage * 0.01; + + customSwitch.BackgroundColor = ColorAnimationUtil.ColorAnimation(fromColor, toColor, t); + } + + void CustomSwitch_Toggled(object sender, ToggledEventArgs e) + { + Toggled?.Invoke(sender, e); + } + #endregion +} \ No newline at end of file diff --git a/src/Features/Gallery/Pages/Community/MauiSwitch/MauiSwitchControlInfo.cs b/src/Features/Gallery/Pages/Community/MauiSwitch/MauiSwitchControlInfo.cs new file mode 100644 index 00000000..42015582 --- /dev/null +++ b/src/Features/Gallery/Pages/Community/MauiSwitch/MauiSwitchControlInfo.cs @@ -0,0 +1,15 @@ +namespace MAUIsland.Gallery.Community; +class MauiSwitchControlInfo : IControlInfo +{ + public string ControlName => nameof(IeuanWalker.Maui.Switch); + public string ControlRoute => typeof(MauiSwitchPage).FullName; + public ImageSource ControlIcon => new FontImageSource() + { + FontFamily = FontNames.FluentSystemIconsRegular, + Glyph = FluentUIIcon.Ic_fluent_toggle_left_24_regular + }; + public string ControlDetail => "This is a switch/ toggle control that would allow you to create any style switch you'd like. This component is built on top/ from this great libary - Global.InputForms. Fixes a few issues, adds more options for styling and improved accessibility."; + public string GitHubUrl => $"https://github.com/Strypper/mauisland/tree/main/src/Features/Gallery/Pages/Community/{ControlName}"; + public string DocumentUrl => $"https://github.com/IeuanWalker/Maui.Switch"; + public string GroupName => ControlGroupInfo.GitHubCommunity; +} \ No newline at end of file diff --git a/src/Features/Gallery/Pages/Community/MauiSwitch/MauiSwitchPage.xaml b/src/Features/Gallery/Pages/Community/MauiSwitch/MauiSwitchPage.xaml new file mode 100644 index 00000000..efeea133 --- /dev/null +++ b/src/Features/Gallery/Pages/Community/MauiSwitch/MauiSwitchPage.xaml @@ -0,0 +1,164 @@ + + + + + + + + + + + + MauiSwitch defines the following properties: + + + + These properties are backed by BindableProperty objects, which means that they can be targets of data bindings, and styled. + + + + + IsToggle, of type bool, to indicate the toggled status of the switch. + ]]> + + + ToggleAnimationDuration, of type int, Used to set the duration of the toggle animation. + ]]> + + + HeightRequest, of type double, the Height of the switch. + ]]> + + + WidthRequest, of type double, the width of the switch. + ]]> + + + StrokeShape, is of type IShape, describes the shape of the switch. Learn more on MS docs. + ]]> + + + Stroke, of type Brush, indicates the brush used to paint the border. Learn more on MS docs. + ]]> + + + StrokeThickness, is of type double, indicates the width of the border. + ]]> + + + BackgroundColor, of type Color, the solid color of the switch. + ]]> + + + Background, of type Brush, the background for the switch, learn more on MS docs. + ]]> + + + BackgroundContent, sets the content of the switch. See examples for an idea how to utilise it. + ]]> + + + KnobHeight, of type double, the height of the knob on the switch. + ]]> + + + KnobWidth, of type double, the width of the knob on the switch. + ]]> + + + KnobBackground, of type Brush, the background for the knob, learn more on MS docs. + ]]> + + + KnobBackgroundColor, of type Color, the solid color of the knob. + ]]> + + + KnobStrokeShape, is of type IShape, describes the shape of the knob. Learn more on MS docs. + ]]> + + + KnobStroke, of type Brush, indicates the brush used to paint the border. Learn more on MS docs. + ]]> + + + KnobStrokeThickness, is of type double, indicates the width of the border. + ]]> + + + KnobContent, sets the content of the knob. See examples for an idea how to utilise it. + ]]> + + + HorizontalKnobMargin, of type double, adds a margin to the max distance the knob can travel. + ]]> + + + KnobLimit, used to calculate the knob position. See examples for an idea how to utilise it. + ]]> + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Features/Gallery/Pages/Community/MauiSwitch/MauiSwitchPage.xaml.cs b/src/Features/Gallery/Pages/Community/MauiSwitch/MauiSwitchPage.xaml.cs new file mode 100644 index 00000000..85da4691 --- /dev/null +++ b/src/Features/Gallery/Pages/Community/MauiSwitch/MauiSwitchPage.xaml.cs @@ -0,0 +1,12 @@ +namespace MAUIsland; +public partial class MauiSwitchPage : IControlPage +{ + #region [CTor] + public MauiSwitchPage(MauiSwitchPageViewModel vm) + { + InitializeComponent(); + + BindingContext = vm; + } + #endregion +} \ No newline at end of file diff --git a/src/Features/Gallery/Pages/Community/MauiSwitch/MauiSwitchPageViewModel.cs b/src/Features/Gallery/Pages/Community/MauiSwitch/MauiSwitchPageViewModel.cs new file mode 100644 index 00000000..9cac3713 --- /dev/null +++ b/src/Features/Gallery/Pages/Community/MauiSwitch/MauiSwitchPageViewModel.cs @@ -0,0 +1,35 @@ +namespace MAUIsland; +public partial class MauiSwitchPageViewModel : NavigationAwareBaseViewModel +{ + #region [CTor] + public MauiSwitchPageViewModel( + IAppNavigator appNavigator + ) : base(appNavigator) + { + } + #endregion + + #region [Properties] + [ObservableProperty] + IControlInfo controlInformation; + + [ObservableProperty] + string switchXamlCode = ""; + #endregion + + #region [Overrides] + protected override void OnInit(IDictionary query) + { + base.OnInit(query); + + ControlInformation = query.GetData(); + + } + #endregion + + #region [ Relay Commands ] + [RelayCommand] + Task OpenUrlAsync(string url) + => AppNavigator.OpenUrlAsync(url); + #endregion +} \ No newline at end of file diff --git a/src/Features/Gallery/Pages/Community/MauiSwitch/SwitchViews/BorderSwitch.xaml b/src/Features/Gallery/Pages/Community/MauiSwitch/SwitchViews/BorderSwitch.xaml new file mode 100644 index 00000000..1210946e --- /dev/null +++ b/src/Features/Gallery/Pages/Community/MauiSwitch/SwitchViews/BorderSwitch.xaml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/src/Features/Gallery/Pages/Community/MauiSwitch/SwitchViews/BorderSwitch.xaml.cs b/src/Features/Gallery/Pages/Community/MauiSwitch/SwitchViews/BorderSwitch.xaml.cs new file mode 100644 index 00000000..584b1a4b --- /dev/null +++ b/src/Features/Gallery/Pages/Community/MauiSwitch/SwitchViews/BorderSwitch.xaml.cs @@ -0,0 +1,125 @@ +using IeuanWalker.Maui.Switch; +using Microsoft.Maui.Controls.Shapes; + +namespace MAUIsland; + +public partial class BorderSwitch : SwitchView +{ + public BorderSwitch() + { + InitializeComponent(); + + Loaded += (sender, args) => StyleSwitch(); + } + + void TapGestureRecognizer_Tapped(object sender, TappedEventArgs e) + { + IsToggled = !IsToggled; + } + + protected override void IsToggledChanged() + { + base.IsToggledChanged(); + + StyleSwitch(); + InvokeToggled(); + } + + void StyleSwitch() + { + if (IsToggled) + { + SwitchBackground.StrokeShape = new RoundRectangle + { + CornerRadius = new CornerRadius(40, 0, 40, 0) + }; + SwitchBackground.Stroke = new LinearGradientBrush() + { + EndPoint = new Point(1, 0), + GradientStops = new GradientStopCollection + { + new GradientStop + { + Offset = 0.1f, + Color = Colors.Transparent + }, + new GradientStop + { + Offset = 1f, + Color = Color.FromArgb("#a8ff78") + } + } + }; + SwitchBackground.Background = new LinearGradientBrush() + { + EndPoint = new Point(1, 0), + GradientStops = new GradientStopCollection + { + new GradientStop + { + Offset = 0.1f, + Color = Colors.Transparent + }, + new GradientStop + { + Offset = 0.5f, + Color = Color.FromArgb("#78ffd6") + }, + new GradientStop + { + Offset = 1f, + Color = Color.FromArgb("#a8ff78") + } + } + }; + SwitchText.Text = "On"; + } + else + { + SwitchBackground.StrokeShape = new RoundRectangle + { + CornerRadius = new CornerRadius(0, 40, 0, 40) + }; + SwitchBackground.Stroke = new LinearGradientBrush() + { + EndPoint = new Point(1, 0), + GradientStops = new GradientStopCollection + { + new GradientStop + { + Offset = 0.1f, + Color = Color.FromArgb("#FF512F") + }, + new GradientStop + { + Offset = 1f, + Color = Colors.Transparent + } + } + }; + SwitchBackground.Background = new LinearGradientBrush() + { + EndPoint = new Point(1, 0), + GradientStops = new GradientStopCollection + { + new GradientStop + { + Offset = 0.1f, + Color = Color.FromArgb("#DD2476") + }, + new GradientStop + { + Offset = 0.5f, + Color = Color.FromArgb("#FF512F") + }, + new GradientStop + { + Offset = 1f, + Color = Colors.Transparent + } + } + }; + SwitchText.Text = "Off"; + } + } +} \ No newline at end of file diff --git a/src/Features/Gallery/Pages/Community/MauiSwitch/SwitchViews/ImageSwitch.xaml b/src/Features/Gallery/Pages/Community/MauiSwitch/SwitchViews/ImageSwitch.xaml new file mode 100644 index 00000000..0bb64f47 --- /dev/null +++ b/src/Features/Gallery/Pages/Community/MauiSwitch/SwitchViews/ImageSwitch.xaml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/src/Features/Gallery/Pages/Community/MauiSwitch/SwitchViews/ImageSwitch.xaml.cs b/src/Features/Gallery/Pages/Community/MauiSwitch/SwitchViews/ImageSwitch.xaml.cs new file mode 100644 index 00000000..30ea576f --- /dev/null +++ b/src/Features/Gallery/Pages/Community/MauiSwitch/SwitchViews/ImageSwitch.xaml.cs @@ -0,0 +1,29 @@ +using IeuanWalker.Maui.Switch; + +namespace MAUIsland; + +public partial class ImageSwitch : SwitchView +{ + public ImageSwitch() + { + InitializeComponent(); + + Loaded += (sender, args) => StyleSwitch(); + } + + void TapGestureRecognizer_Tapped(object sender, TappedEventArgs e) + { + IsToggled = !IsToggled; + } + + protected override void IsToggledChanged() + { + StyleSwitch(); + InvokeToggled(); + } + + void StyleSwitch() + { + SwitchImage.Source = ImageSource.FromFile(IsToggled ? "ioslogo" : "androidlogo"); + } +} \ No newline at end of file diff --git a/src/Features/Home/Services/Interfaces/HomeService.cs b/src/Features/Home/Services/Implementations/HomeService.cs similarity index 100% rename from src/Features/Home/Services/Interfaces/HomeService.cs rename to src/Features/Home/Services/Implementations/HomeService.cs diff --git a/src/Features/Home/Services/Implementations/IHomeService.cs b/src/Features/Home/Services/Interfaces/IHomeService.cs similarity index 100% rename from src/Features/Home/Services/Implementations/IHomeService.cs rename to src/Features/Home/Services/Interfaces/IHomeService.cs diff --git a/src/MAUIsland.csproj b/src/MAUIsland.csproj index 28cbdab9..c2a9e125 100644 --- a/src/MAUIsland.csproj +++ b/src/MAUIsland.csproj @@ -130,6 +130,7 @@ + @@ -166,7 +167,6 @@ - @@ -260,6 +260,18 @@ MSBuild:Compile + + MSBuild:Compile + + + MSBuild:Compile + + + MSBuild:Compile + + + MSBuild:Compile + MSBuild:Compile @@ -428,7 +440,6 @@ - diff --git a/src/MauiProgram.cs b/src/MauiProgram.cs index 77220232..69e67496 100644 --- a/src/MauiProgram.cs +++ b/src/MauiProgram.cs @@ -2,6 +2,7 @@ using CommunityToolkit.Maui.Alerts; using CommunityToolkit.Maui.Core; using CommunityToolkit.Maui.Storage; +using IeuanWalker.Maui.Switch; using Material.Components.Maui.Extensions; using Microsoft.AspNetCore.SignalR.Client; using Microsoft.Extensions.Configuration; @@ -30,6 +31,7 @@ public static MauiApp CreateMauiApp() .UseMauiCommunityToolkitCore() .UseMauiCommunityToolkitMediaElement() .UseSkiaSharp() + .UseSwitch() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); @@ -38,7 +40,7 @@ public static MauiApp CreateMauiApp() }) .UseMaterialComponents(new List { - "OpenSans-Regular.ttf" + //"OpenSans-Regular.ttf" }) .ConfigureEssentials(essentials => {