diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Maui.FreakyControls.csproj b/MAUI.FreakyControls/MAUI.FreakyControls/Maui.FreakyControls.csproj
index 10b3ae6b..5a235799 100644
--- a/MAUI.FreakyControls/MAUI.FreakyControls/Maui.FreakyControls.csproj
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Maui.FreakyControls.csproj
@@ -12,9 +12,9 @@
10.0.17763.0
10.0.17763.0
Maui.FreakyControls
- 0.4.6
- 0.4.6
- 0.4.6-pre
+ 0.4.7
+ 0.4.7
+ 0.4.7-pre
en
FreakyControls
@@ -25,8 +25,9 @@
maui_toolkit.png
https://github.com/FreakyAli/MAUI.FreakyControls
https://github.com/FreakyAli/MAUI.FreakyControls
- Maui dotnet.Maui .net-Maui FreakyControls Switch AutoComplete JumpList Button Checkbox uikit Signature Radiobutton SignatureView Svg CircularImage TextInputLayout
- FreakySwitch is here!
+ Maui dotnet.Maui .net-Maui FreakyControls CodeView OTP PinCodeView Switch AutoComplete JumpList Button Checkbox uikit Signature Radiobutton SignatureView Svg CircularImage TextInputLayout
+ FreakyCodeView and FreakyPinCodeView are here!
+ readme.md
Copyright 2023
true
false
@@ -73,6 +74,7 @@
+
@@ -91,6 +93,8 @@
+
+
@@ -118,6 +122,8 @@
+
+
@@ -125,10 +131,6 @@
-
-
-
-
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Platforms/Windows/TouchAndPressEffect.cs b/MAUI.FreakyControls/MAUI.FreakyControls/Platforms/Windows/TouchAndPressEffect.cs
index c0d16df3..0a84ecd7 100644
--- a/MAUI.FreakyControls/MAUI.FreakyControls/Platforms/Windows/TouchAndPressEffect.cs
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Platforms/Windows/TouchAndPressEffect.cs
@@ -1,5 +1,4 @@
-using Microsoft.Maui.Controls.Platform;
-
+using Microsoft.Maui.Controls.Platform;
namespace Maui.FreakyControls.Platforms.Windows;
internal class TouchAndPressEffect : PlatformEffect
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Behaviors/BehaviorBase.cs b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Behaviors/BehaviorBase.cs
new file mode 100644
index 00000000..eec44094
--- /dev/null
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Behaviors/BehaviorBase.cs
@@ -0,0 +1,37 @@
+namespace Maui.FreakyControls.Shared.Behaviors;
+
+public abstract class BehaviorBase : Behavior where T : BindableObject
+{
+ public T AssociatedObject { get; private set; }
+
+ protected override void OnAttachedTo(T bindable)
+ {
+ base.OnAttachedTo(bindable);
+ AssociatedObject = bindable;
+
+ if (bindable.BindingContext != null)
+ {
+ BindingContext = bindable.BindingContext;
+ }
+
+ bindable.BindingContextChanged += OnBindingContextChanged;
+ }
+
+ protected override void OnDetachingFrom(T bindable)
+ {
+ base.OnDetachingFrom(bindable);
+ bindable.BindingContextChanged -= OnBindingContextChanged;
+ AssociatedObject = null;
+ }
+
+ private void OnBindingContextChanged(object sender, EventArgs e)
+ {
+ OnBindingContextChanged();
+ }
+
+ protected override void OnBindingContextChanged()
+ {
+ base.OnBindingContextChanged();
+ BindingContext = AssociatedObject.BindingContext;
+ }
+}
\ No newline at end of file
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Controls/BaseSKCanvas.cs b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Controls/BaseSKCanvas.cs
index c93ed534..b9dd1cfd 100644
--- a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Controls/BaseSKCanvas.cs
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Controls/BaseSKCanvas.cs
@@ -18,14 +18,9 @@ protected override sealed void OnPaintSurface(SKPaintSurfaceEventArgs e)
{
return;
}
-
e.Surface.Canvas.Clear(SKColors.Transparent);
-
- // make sure no previous transforms still apply
e.Surface.Canvas.ResetMatrix();
-
base.OnPaintSurface(e);
-
DoPaintSurface(e);
}
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Enums/FocusAnimation.cs b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Enums/FocusAnimation.cs
new file mode 100644
index 00000000..167b8e87
--- /dev/null
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Enums/FocusAnimation.cs
@@ -0,0 +1,8 @@
+namespace Maui.FreakyControls.Shared.Enums;
+
+public enum FocusAnimation
+{
+ Bounce,
+ Scale,
+ None
+}
\ No newline at end of file
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Enums/ItemShape.cs b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Enums/ItemShape.cs
new file mode 100644
index 00000000..d7bca82f
--- /dev/null
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Enums/ItemShape.cs
@@ -0,0 +1,8 @@
+namespace Maui.FreakyControls.Shared.Enums;
+
+public enum ItemShape
+{
+ Circle,
+ Square,
+ Squircle
+}
\ No newline at end of file
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Enums/KeyboardType.cs b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Enums/KeyboardType.cs
new file mode 100644
index 00000000..82acb84f
--- /dev/null
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Enums/KeyboardType.cs
@@ -0,0 +1,7 @@
+namespace Maui.FreakyControls.Shared.Enums;
+
+public enum KeyboardType
+{
+ Numeric,
+ AlphaNumeric
+}
\ No newline at end of file
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Enums/Shape.cs b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Enums/Shape.cs
index 0c34af87..a3aad6f1 100644
--- a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Enums/Shape.cs
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Enums/Shape.cs
@@ -2,13 +2,20 @@
public enum Shape
{
- ///
- /// Circular shape to your control
- ///
+ //
+ // a Circular shape to your control
+ //
Circle,
- ///
- /// Rectangular shape to your control
- ///
- Rectangle
+ [Obsolete("Please use Square instead, " +
+ "this option will be removed with the next stable release")]
+ //
+ // a Rectangular shape to your control
+ //
+ Rectangle,
+
+ //
+ // a Square shape to your control
+ //
+ Sqaure = Rectangle,
}
\ No newline at end of file
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/EventArgs/FreakyCodeCompletedEventArgs.cs b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/EventArgs/FreakyCodeCompletedEventArgs.cs
new file mode 100644
index 00000000..2d1c5287
--- /dev/null
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/EventArgs/FreakyCodeCompletedEventArgs.cs
@@ -0,0 +1,12 @@
+//Make sure .EventArgs is never created
+namespace Maui.FreakyControls;
+
+public class FreakyCodeCompletedEventArgs : EventArgs
+{
+ public string Code { get; set; }
+
+ public FreakyCodeCompletedEventArgs(string code)
+ {
+ this.Code = code;
+ }
+}
\ No newline at end of file
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Extensions/CollectionExtensions.cs b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Extensions/CollectionExtensions.cs
index 837a6bde..b8adef4f 100644
--- a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Extensions/CollectionExtensions.cs
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Extensions/CollectionExtensions.cs
@@ -1,4 +1,4 @@
-using System.Collections.ObjectModel;
+using System.Collections.ObjectModel;
namespace Maui.FreakyControls.Extensions;
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCheckbox/FreakyCheckbox.cs b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCheckbox/FreakyCheckbox.cs
index 9f25b2ee..c3a166c1 100644
--- a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCheckbox/FreakyCheckbox.cs
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCheckbox/FreakyCheckbox.cs
@@ -51,7 +51,7 @@ private void CheckBox_Tapped(object sender, EventArgs e)
private static readonly Shape shape =
DeviceInfo.Platform == DevicePlatform.iOS ?
Shared.Enums.Shape.Circle :
- Shared.Enums.Shape.Rectangle;
+ Shared.Enums.Shape.Sqaure;
private static readonly float outlineWidth = 6.0f;
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCodeView/CodeView.cs b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCodeView/CodeView.cs
new file mode 100644
index 00000000..c7b6e636
--- /dev/null
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCodeView/CodeView.cs
@@ -0,0 +1,157 @@
+using Maui.FreakyControls.Extensions;
+using Maui.FreakyControls.Shared.Enums;
+using Microsoft.Maui.Controls.Shapes;
+
+namespace Maui.FreakyControls;
+
+internal class CodeView : Border
+{
+ public const double DefaultItemSize = 50.0;
+ public const double DefaultDotSize = 20.0;
+ public const double DefaultItemSpacing = 5.0;
+ public const int DefaultCodeLength = 4;
+ public static Color DefaultColor = Colors.Black;
+ public static Color DefaultItemBackgroundColor = Colors.Transparent;
+
+ private string inputChar;
+ private Color color;
+ private Color ItemBorderColor;
+
+ public FocusAnimation FocusAnimationType { get; set; }
+ public Color ItemFocusColor { get; set; }
+ public Border Item => this;
+ public Border Dot { get; }
+ public Label CharLabel { get; }
+
+ public CodeView()
+ {
+ Padding = 0;
+ BackgroundColor = DefaultItemBackgroundColor;
+ StrokeShape = new Ellipse();
+ Stroke = DefaultColor;
+ HeightRequest = WidthRequest = DefaultItemSize;
+ VerticalOptions = LayoutOptions.Center;
+
+ Dot = new Border()
+ {
+ StrokeShape = new Ellipse() { Fill = DefaultColor },
+ Stroke = DefaultColor,
+ StrokeThickness = 1,
+ HorizontalOptions = LayoutOptions.Center,
+ VerticalOptions = LayoutOptions.Center,
+ HeightRequest = DefaultDotSize,
+ WidthRequest = DefaultDotSize,
+ Scale = 0,
+ Padding = 0
+ };
+
+ CharLabel = new Label()
+ {
+ HorizontalOptions = LayoutOptions.Center,
+ VerticalOptions = LayoutOptions.Center,
+ TextColor = DefaultColor,
+ FontAttributes = FontAttributes.Bold,
+ VerticalTextAlignment = TextAlignment.Center,
+ Scale = 0,
+ TextTransform = TextTransform.Uppercase
+ };
+
+ Content = Dot;
+ }
+
+ private async Task GrowAsync()
+ {
+ await Content.ScaleTo(1.0, 100);
+ }
+
+ private async Task ShrinkAsync()
+ {
+ await Content.ScaleTo(0, 100);
+ }
+
+ public void SetColor(Color color, Color ItemBorderColor)
+ {
+ this.color = color;
+ this.ItemBorderColor = ItemBorderColor;
+ SetBorderColor();
+ Dot.BackgroundColor = color;
+ CharLabel.TextColor = color;
+ }
+
+ public void SetRadius(ItemShape shapeType)
+ {
+ if (shapeType == ItemShape.Circle)
+ {
+ this.StrokeShape = new RoundRectangle() { CornerRadius = (float)HeightRequest / 2 };
+ }
+ else if (shapeType == ItemShape.Square)
+ {
+ this.StrokeShape = new RoundRectangle() { CornerRadius = 0 };
+ }
+ else if (shapeType == ItemShape.Squircle)
+ {
+ this.StrokeShape = new RoundRectangle() { CornerRadius = 10 };
+ }
+ }
+
+ public void SecureMode(bool isPassword)
+ {
+ if (isPassword)
+ {
+ Content = Dot;
+ }
+ else
+ {
+ Content = CharLabel;
+ }
+
+ if (!string.IsNullOrEmpty(inputChar))
+ {
+ GrowAsync().RunConcurrently();
+ }
+ else
+ {
+ ShrinkAsync().RunConcurrently();
+ }
+ }
+
+ public void ClearValueWithAnimation()
+ {
+ inputChar = null;
+ ShrinkAsync().RunConcurrently();
+ }
+
+ public void SetValueWithAnimation(char inputChar)
+ {
+ UnfocusAnimate();
+ CharLabel.Text = inputChar.ToString();
+ this.inputChar = inputChar.ToString();
+ GrowAsync().RunConcurrently();
+ }
+
+ public async void FocusAnimate()
+ {
+ Stroke = ItemFocusColor;
+
+ if (FocusAnimationType == FocusAnimation.Bounce)
+ {
+ await this.ScaleTo(1.2, 100);
+ await this.ScaleTo(1, 100);
+ }
+ else if (FocusAnimationType == FocusAnimation.Scale)
+ {
+ await this.ScaleTo(1.2, 100);
+ }
+ }
+
+ public async void UnfocusAnimate()
+ {
+ SetBorderColor();
+ await this.ScaleTo(1, 100);
+ }
+
+ private void SetBorderColor()
+ {
+ Stroke = ItemBorderColor == Colors.Black ? color : ItemBorderColor;
+ }
+}
\ No newline at end of file
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCodeView/FreakyCodeView.xaml b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCodeView/FreakyCodeView.xaml
new file mode 100644
index 00000000..3abdf704
--- /dev/null
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCodeView/FreakyCodeView.xaml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCodeView/FreakyCodeView.xaml.cs b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCodeView/FreakyCodeView.xaml.cs
new file mode 100644
index 00000000..2c44a785
--- /dev/null
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCodeView/FreakyCodeView.xaml.cs
@@ -0,0 +1,632 @@
+using Maui.FreakyControls.Shared.Enums;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Windows.Input;
+
+namespace Maui.FreakyControls;
+
+public partial class FreakyCodeView : ContentView
+{
+ #region Events
+
+ public event EventHandler CodeEntryCompleted;
+
+ #endregion Events
+
+ #region Constructor and Initializations
+
+ public FreakyCodeView()
+ {
+ InitializeComponent();
+ hiddenTextEntry.TextChanged += FreakyCodeView_TextChanged;
+ hiddenTextEntry.Focused += HiddenTextEntry_Focused;
+ hiddenTextEntry.Unfocused += HiddenTextEntry_Unfocused;
+ Initialize();
+ }
+
+ private void HiddenTextEntry_Unfocused(object sender, FocusEventArgs e)
+ {
+ var CodeItemArray = CodeItemContainer.Children.Select(x => x as CodeView).ToList();
+ for (int i = 0; i < CodeLength; i++)
+ {
+ CodeItemArray[i].UnfocusAnimate();
+ }
+ }
+
+ private void HiddenTextEntry_Focused(object sender, FocusEventArgs e)
+ {
+ var length = CodeValue == null ? 0 : CodeValue.Length;
+ hiddenTextEntry.CursorPosition = length;
+
+ var CodeItemArray = CodeItemContainer.Children.Select(x => x as CodeView).ToArray();
+
+ if (length == CodeLength)
+ {
+ CodeItemArray[length - 1].FocusAnimate();
+ }
+ else
+ {
+ for (int i = 0; i < CodeLength; i++)
+ {
+ if (i == length)
+ {
+ CodeItemArray[i].FocusAnimate();
+ }
+ else
+ {
+ CodeItemArray[i].UnfocusAnimate();
+ }
+ }
+ }
+ }
+
+ #endregion Constructor and Initializations
+
+ #region Methods
+
+ public void Initialize()
+ {
+ hiddenTextEntry.MaxLength = CodeLength;
+ SetInputType(CodeInputType);
+
+ var count = CodeItemContainer.Children.Count;
+
+ if (count < CodeLength)
+ {
+ int newItemesToAdd = CodeLength - count;
+ char[] CodeCharsArray = CodeValue.ToCharArray();
+
+ for (int i = 1; i <= newItemesToAdd; i++)
+ {
+ CodeView container = CreateItem();
+ CodeItemContainer.Children.Add(container);
+ if (CodeValue.Length >= CodeLength)
+ {
+ container.SetValueWithAnimation(CodeCharsArray[CodeView.DefaultCodeLength + i - 1]);
+ }
+ }
+ }
+ else if (count > CodeLength)
+ {
+ int ItemesToRemove = count - CodeLength;
+ for (int i = 1; i <= ItemesToRemove; i++)
+ {
+ CodeItemContainer.Children.RemoveAt(CodeItemContainer.Children.Count - 1);
+ }
+ }
+ }
+
+ public new void Focus()
+ {
+ base.Focus();
+ hiddenTextEntry.Focus();
+ }
+
+ private CodeView CreateItem(char? charValue = null)
+ {
+ CodeView container = new()
+ {
+ HeightRequest = ItemSize,
+ WidthRequest = ItemSize,
+ ItemFocusColor = ItemFocusColor,
+ FocusAnimationType = ItemFocusAnimation,
+ StrokeThickness = ItemBorderWidth
+ };
+ container.Item.BackgroundColor = ItemBackgroundColor;
+ container.CharLabel.FontSize = ItemSize / 2;
+ container.SecureMode(IsPassword);
+ container.SetColor(Color, ItemBorderColor);
+ container.SetRadius(ItemShape);
+ if (charValue.HasValue)
+ {
+ container.SetValueWithAnimation(charValue.Value);
+ }
+ return container;
+ }
+
+ #endregion Methods
+
+ #region Events
+
+ private void FreakyCodeView_TextChanged(object sender, TextChangedEventArgs e)
+ {
+ CodeValue = e.NewTextValue;
+
+ if (e.NewTextValue.Length >= CodeLength)
+ {
+ if (ShouldAutoDismissKeyboard == true)
+ {
+ (sender as Entry).Unfocus();
+ }
+ CodeEntryCompleted?.Invoke(this, new FreakyCodeCompletedEventArgs(CodeValue));
+ CodeEntryCompletedCommand?.Execute(CodeValue);
+ }
+ }
+
+ #endregion Events
+
+ #region BindableProperties
+
+ public string CodeValue
+ {
+ get => (string)GetValue(CodeValueProperty);
+ set => SetValue(CodeValueProperty, value);
+ }
+
+ public static readonly BindableProperty CodeValueProperty =
+ BindableProperty.Create(
+ nameof(CodeValue),
+ typeof(string),
+ typeof(FreakyCodeView),
+ string.Empty,
+ defaultBindingMode: BindingMode.TwoWay,
+ propertyChanged: CodeValuePropertyChanged);
+
+ private static async void CodeValuePropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ try
+ {
+ var control = (FreakyCodeView)bindable;
+
+ string newCode = newValue.ToString();
+ string oldCode = oldValue.ToString();
+
+ int newCodeLength = newCode.Length;
+ int oldCodeLength = oldCode.Length;
+
+ if (newCodeLength == 0 && oldCodeLength == 0)
+ {
+ return;
+ }
+
+ char[] newCodeChars = newCode.ToCharArray();
+
+ control.hiddenTextEntry.Text = newCode;
+ var CodeItemArray = control.CodeItemContainer.Children.Select(x => x as CodeView).ToArray();
+
+ bool isCodeEnteredProgramatically = (oldCodeLength == 0 && newCodeLength == control.CodeLength) || newCodeLength == oldCodeLength;
+
+ if (isCodeEnteredProgramatically)
+ {
+ for (int i = 0; i < control.CodeLength; i++)
+ {
+ CodeItemArray[i].ClearValueWithAnimation();
+ }
+ }
+
+ for (int i = 0; i < control.CodeLength; i++)
+ {
+ if (i < newCodeLength)
+ {
+ if (isCodeEnteredProgramatically)
+ {
+ await Task.Delay(50);
+ }
+
+ CodeItemArray[i].SetValueWithAnimation(newCodeChars[i]);
+ }
+ else
+ {
+ if (CodeItemArray.Length >= control.CodeLength)
+ {
+ CodeItemArray[i].ClearValueWithAnimation();
+ CodeItemArray[i].UnfocusAnimate();
+ }
+ }
+ }
+
+ if (control.hiddenTextEntry.IsFocused)
+ {
+ if (newCodeLength < control.CodeLength)
+ {
+ CodeItemArray[newCodeLength].FocusAnimate();
+ }
+ else if (newCodeLength == control.CodeLength)
+ {
+ CodeItemArray[newCodeLength - 1].FocusAnimate();
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex.ToString());
+ }
+ }
+
+ public int CodeLength
+ {
+ get => (int)GetValue(CodeLengthProperty);
+ set => SetValue(CodeLengthProperty, value);
+ }
+
+ public static readonly BindableProperty CodeLengthProperty =
+ BindableProperty.Create(
+ nameof(CodeLength),
+ typeof(int),
+ typeof(FreakyCodeView),
+ CodeView.DefaultCodeLength,
+ defaultBindingMode: BindingMode.OneWay,
+ propertyChanged: CodeLengthPropertyChanged);
+
+ private static void CodeLengthPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ if ((int)newValue <= 0)
+ {
+ return;
+ }
+ ((FreakyCodeView)bindable).Initialize();
+ }
+
+ public KeyboardType CodeInputType
+ {
+ get => (KeyboardType)GetValue(CodeInputTypeProperty);
+ set => SetValue(CodeInputTypeProperty, value);
+ }
+
+ public static readonly BindableProperty CodeInputTypeProperty =
+ BindableProperty.Create(
+ nameof(CodeInputType),
+ typeof(KeyboardType),
+ typeof(FreakyCodeView),
+ KeyboardType.Numeric,
+ defaultBindingMode: BindingMode.OneWay,
+ propertyChanged: CodeInputTypePropertyChanged);
+
+ private static void CodeInputTypePropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ var control = ((FreakyCodeView)bindable);
+ control.SetInputType((KeyboardType)newValue);
+ }
+
+ public void SetInputType(KeyboardType inputKeyboardType)
+ {
+ if (inputKeyboardType == KeyboardType.Numeric)
+ {
+ hiddenTextEntry.Keyboard = Keyboard.Numeric;
+ }
+ else if (inputKeyboardType == KeyboardType.AlphaNumeric)
+ {
+ hiddenTextEntry.Keyboard = Keyboard.Create(0);
+ }
+ }
+
+ public ICommand CodeEntryCompletedCommand
+ {
+ get { return (ICommand)GetValue(CodeEntryCompletedCommandProperty); }
+ set { SetValue(CodeEntryCompletedCommandProperty, value); }
+ }
+
+ public static readonly BindableProperty CodeEntryCompletedCommandProperty =
+ BindableProperty.Create(
+ nameof(CodeEntryCompletedCommand),
+ typeof(ICommand),
+ typeof(FreakyCodeView),
+ null);
+
+ public bool IsPassword
+ {
+ get => (bool)GetValue(IsPasswordProperty);
+ set => SetValue(IsPasswordProperty, value);
+ }
+
+ public static readonly BindableProperty IsPasswordProperty =
+ BindableProperty.Create(
+ nameof(IsPassword),
+ typeof(bool),
+ typeof(FreakyCodeView),
+ true,
+ defaultBindingMode: BindingMode.OneWay,
+ propertyChanged: IsPasswordPropertyChanged);
+
+ private static void IsPasswordPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ var control = ((FreakyCodeView)bindable);
+ foreach (var x in control.CodeItemContainer.Children)
+ {
+ var container = (CodeView)x;
+ container.SecureMode((bool)newValue);
+ }
+ }
+
+ public Color Color
+ {
+ get => (Color)GetValue(ColorProperty);
+ set => SetValue(ColorProperty, value);
+ }
+
+ public static readonly BindableProperty ColorProperty =
+ BindableProperty.Create(
+ nameof(Color),
+ typeof(Color),
+ typeof(FreakyCodeView),
+ Colors.Black,
+ defaultBindingMode: BindingMode.OneWay,
+ propertyChanged: ColorPropertyChanged);
+
+ private static void ColorPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ var control = ((FreakyCodeView)bindable);
+ foreach (var x in control.CodeItemContainer.Children)
+ {
+ var container = (CodeView)x;
+ container.SetColor(color: (Color)newValue, ItemBorderColor: control.ItemBorderColor);
+ }
+ }
+
+ public double ItemSpacing
+ {
+ get => (double)GetValue(ItemSpacingProperty);
+ set => SetValue(ItemSpacingProperty, value);
+ }
+
+ public static readonly BindableProperty ItemSpacingProperty =
+ BindableProperty.Create(
+ nameof(ItemSpacing),
+ typeof(double),
+ typeof(FreakyCodeView),
+ CodeView.DefaultItemSpacing,
+ defaultBindingMode: BindingMode.OneWay,
+ propertyChanged: ItemSpacingPropertyChanged);
+
+ private static void ItemSpacingPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ if ((double)newValue < 0)
+ {
+ return;
+ }
+ var control = ((FreakyCodeView)bindable);
+ control.CodeItemContainer.Spacing = (double)newValue;
+ }
+
+ public double ItemSize
+ {
+ get => (double)GetValue(ItemSizeProperty);
+ set => SetValue(ItemSizeProperty, value);
+ }
+
+ public static readonly BindableProperty ItemSizeProperty =
+ BindableProperty.Create(
+ nameof(ItemSize),
+ typeof(double),
+ typeof(FreakyCodeView),
+ CodeView.DefaultItemSize,
+ defaultBindingMode: BindingMode.OneWay,
+ propertyChanged: ItemSizePropertyChanged);
+
+ private static void ItemSizePropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ if ((double)newValue < 0)
+ {
+ return;
+ }
+
+ var control = ((FreakyCodeView)bindable);
+ foreach (var x in control.CodeItemContainer.Children)
+ {
+ var container = (CodeView)x;
+ container.HeightRequest = (double)newValue;
+ container.WidthRequest = (double)newValue;
+ container.SetRadius(control.ItemShape);
+ }
+ }
+
+ public ItemShape ItemShape
+ {
+ get => (ItemShape)GetValue(ItemShapeProperty);
+ set => SetValue(ItemShapeProperty, value);
+ }
+
+ public static readonly BindableProperty ItemShapeProperty =
+ BindableProperty.Create(
+ nameof(ItemShape),
+ typeof(ItemShape),
+ typeof(FreakyCodeView),
+ ItemShape.Circle,
+ defaultBindingMode: BindingMode.OneWay,
+ propertyChanged: ItemShapePropertyChanged);
+
+ private static void ItemShapePropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ var control = ((FreakyCodeView)bindable);
+ foreach (var x in control.CodeItemContainer.Children)
+ {
+ var container = (CodeView)x;
+ container.SetRadius((ItemShape)newValue);
+ }
+ }
+
+ public Color ItemFocusColor
+ {
+ get => (Color)GetValue(ItemFocusColorProperty);
+ set => SetValue(ItemFocusColorProperty, value);
+ }
+
+ public static readonly BindableProperty ItemFocusColorProperty =
+ BindableProperty.Create(
+ nameof(ItemFocusColor),
+ typeof(Color),
+ typeof(FreakyCodeView),
+ Colors.Black,
+ defaultBindingMode: BindingMode.OneWay,
+ propertyChanged: ItemFocusColorPropertyChanged);
+
+ private static void ItemFocusColorPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ var control = ((FreakyCodeView)bindable);
+ foreach (var x in control.CodeItemContainer.Children)
+ {
+ var container = (CodeView)x;
+ container.ItemFocusColor = (Color)newValue;
+ }
+ }
+
+ public FocusAnimation ItemFocusAnimation
+ {
+ get => (FocusAnimation)GetValue(ItemFocusAnimationProperty);
+ set => SetValue(ItemFocusAnimationProperty, value);
+ }
+
+ public static readonly BindableProperty ItemFocusAnimationProperty =
+ BindableProperty.Create(
+ nameof(ItemFocusAnimation),
+ typeof(FocusAnimation),
+ typeof(FreakyCodeView),
+ default(FocusAnimation),
+ defaultBindingMode: BindingMode.OneWay,
+ propertyChanged: ItemFocusAnimationPropertyChanged);
+
+ private static void ItemFocusAnimationPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ var control = ((FreakyCodeView)bindable);
+ foreach (var x in control.CodeItemContainer.Children)
+ {
+ var container = (CodeView)x;
+ container.FocusAnimationType = (FocusAnimation)newValue;
+ }
+ }
+
+ public Color ItemBorderColor
+ {
+ get => (Color)GetValue(ItemBorderColorProperty);
+ set => SetValue(ItemBorderColorProperty, value);
+ }
+
+ public static readonly BindableProperty ItemBorderColorProperty =
+ BindableProperty.Create(
+ nameof(ItemBorderColor),
+ typeof(Color),
+ typeof(FreakyCodeView),
+ Colors.Black,
+ defaultBindingMode: BindingMode.OneWay,
+ propertyChanged: ItemBorderColorPropertyChanged);
+
+ private static void ItemBorderColorPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ var control = (FreakyCodeView)bindable;
+ if (control.Color != (Color)newValue)
+ {
+ foreach (var x in ((FreakyCodeView)bindable).CodeItemContainer.Children)
+ {
+ var container = (CodeView)x;
+ container.SetColor(color: control.Color, ItemBorderColor: (Color)newValue);
+ }
+ }
+ }
+
+ public Color ItemBackgroundColor
+ {
+ get => (Color)GetValue(ItemBackgroundColorProperty);
+ set => SetValue(ItemBackgroundColorProperty, value);
+ }
+
+ public static readonly BindableProperty ItemBackgroundColorProperty =
+ BindableProperty.Create(
+ nameof(ItemBackgroundColor),
+ typeof(Color),
+ typeof(FreakyCodeView),
+ default(Color),
+ defaultBindingMode: BindingMode.OneWay,
+ propertyChanged: ItemBackgroundColorPropertyChanged);
+
+ private static void ItemBackgroundColorPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ foreach (var x in ((FreakyCodeView)bindable).CodeItemContainer.Children)
+ {
+ var container = (CodeView)x;
+ container.Item.BackgroundColor = (Color)newValue;
+ }
+ }
+
+ public bool ShouldAutoDismissKeyboard
+ {
+ get => (bool)GetValue(ShouldAutoDismissKeyboardProperty);
+ set => SetValue(ShouldAutoDismissKeyboardProperty, value);
+ }
+
+ public static readonly BindableProperty ShouldAutoDismissKeyboardProperty =
+ BindableProperty.Create(
+ nameof(ShouldAutoDismissKeyboard),
+ typeof(bool),
+ typeof(FreakyCodeView),
+ true,
+ defaultBindingMode: BindingMode.OneWay);
+
+ private void TapGestureRecognizer_Tapped(object sender, TappedEventArgs e)
+ {
+ if (IsEnabled)
+ {
+ this.Focus();
+ }
+ }
+
+ public double ItemBorderWidth
+ {
+ get => (double)GetValue(ItemBorderWidthProperty);
+ set => SetValue(ItemBorderWidthProperty, value);
+ }
+
+ public static readonly BindableProperty ItemBorderWidthProperty =
+ BindableProperty.Create(
+ nameof(ItemBorderWidth),
+ typeof(double),
+ typeof(FreakyCodeView),
+ 5.0,
+ defaultBindingMode: BindingMode.OneWay);
+
+ [TypeConverter(typeof(FontSizeConverter))]
+ public double FontSize
+ {
+ get => (double)GetValue(FontSizeProperty);
+ set => SetValue(FontSizeProperty, value);
+ }
+
+ public static readonly BindableProperty FontSizeProperty =
+ BindableProperty.Create(
+ nameof(FontSize),
+ typeof(double),
+ typeof(FreakyCodeView),
+ defaultValueCreator: FontSizeDefaultValueCreator,
+ defaultBindingMode: BindingMode.OneWay,
+ propertyChanged: OnFontSizeChanged);
+
+ private static object FontSizeDefaultValueCreator(BindableObject bindable)
+ {
+ var itemSize = (double)ItemSizeProperty.DefaultValue;
+ double fontSize = itemSize / 2.0;
+ return fontSize;
+ }
+
+ private static void OnFontSizeChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ var control = ((FreakyCodeView)bindable);
+ foreach (var x in control.CodeItemContainer.Children)
+ {
+ var container = (CodeView)x;
+ container.CharLabel.FontSize = (double)newValue;
+ }
+ }
+
+ public string FontFamily
+ {
+ get => (string)GetValue(FontFamilyProperty);
+ set => SetValue(FontFamilyProperty, value);
+ }
+
+ public static readonly BindableProperty FontFamilyProperty = BindableProperty.Create(
+ nameof(FontFamily),
+ typeof(string),
+ typeof(FreakyCodeView),
+ propertyChanged: OnFontFamilyChanged);
+
+ private static void OnFontFamilyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ var control = ((FreakyCodeView)bindable);
+ foreach (var x in control.CodeItemContainer.Children)
+ {
+ var container = (CodeView)x;
+ container.CharLabel.FontFamily = newValue?.ToString();
+ }
+ }
+
+ #endregion BindableProperties
+}
\ No newline at end of file
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCodeView/FreakyPinCodeControl.xaml b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCodeView/FreakyPinCodeControl.xaml
new file mode 100644
index 00000000..3cb1daf9
--- /dev/null
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCodeView/FreakyPinCodeControl.xaml
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCodeView/FreakyPinCodeControl.xaml.cs b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCodeView/FreakyPinCodeControl.xaml.cs
new file mode 100644
index 00000000..b90afd85
--- /dev/null
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyCodeView/FreakyPinCodeControl.xaml.cs
@@ -0,0 +1,343 @@
+using Maui.FreakyControls.Shared.Enums;
+using System.ComponentModel;
+using System.Windows.Input;
+
+namespace Maui.FreakyControls;
+
+public partial class FreakyPinCodeControl : ContentView
+{
+ public event EventHandler CodeEntryCompleted;
+
+ public FreakyPinCodeControl()
+ {
+ InitializeComponent();
+ }
+
+ #region BindableProperties
+
+ public string CodeValue
+ {
+ get => (string)GetValue(CodeValueProperty);
+ set => SetValue(CodeValueProperty, value);
+ }
+
+ public static readonly BindableProperty CodeValueProperty =
+ BindableProperty.Create(
+ nameof(CodeValue),
+ typeof(string),
+ typeof(FreakyPinCodeControl),
+ string.Empty,
+ defaultBindingMode: BindingMode.TwoWay);
+
+ public int CodeLength
+ {
+ get => (int)GetValue(CodeLengthProperty);
+ set => SetValue(CodeLengthProperty, value);
+ }
+
+ public static readonly BindableProperty CodeLengthProperty =
+ BindableProperty.Create(
+ nameof(CodeLength),
+ typeof(int),
+ typeof(FreakyPinCodeControl),
+ CodeView.DefaultCodeLength,
+ defaultBindingMode: BindingMode.OneWay);
+
+ public ICommand CodeEntryCompletedCommand
+ {
+ get { return (ICommand)GetValue(CodeEntryCompletedCommandProperty); }
+ set { SetValue(CodeEntryCompletedCommandProperty, value); }
+ }
+
+ public static readonly BindableProperty CodeEntryCompletedCommandProperty =
+ BindableProperty.Create(
+ nameof(CodeEntryCompletedCommand),
+ typeof(ICommand),
+ typeof(FreakyPinCodeControl),
+ null);
+
+ public bool IsPassword
+ {
+ get => (bool)GetValue(IsPasswordProperty);
+ set => SetValue(IsPasswordProperty, value);
+ }
+
+ public static readonly BindableProperty IsPasswordProperty =
+ BindableProperty.Create(
+ nameof(IsPassword),
+ typeof(bool),
+ typeof(FreakyPinCodeControl),
+ true,
+ defaultBindingMode: BindingMode.OneWay);
+
+ public Color Color
+ {
+ get => (Color)GetValue(ColorProperty);
+ set => SetValue(ColorProperty, value);
+ }
+
+ public static readonly BindableProperty ColorProperty =
+ BindableProperty.Create(
+ nameof(Color),
+ typeof(Color),
+ typeof(FreakyPinCodeControl),
+ Colors.Black,
+ defaultBindingMode: BindingMode.OneWay);
+
+ public double ItemSpacing
+ {
+ get => (double)GetValue(ItemSpacingProperty);
+ set => SetValue(ItemSpacingProperty, value);
+ }
+
+ public static readonly BindableProperty ItemSpacingProperty =
+ BindableProperty.Create(
+ nameof(ItemSpacing),
+ typeof(double),
+ typeof(FreakyPinCodeControl),
+ CodeView.DefaultItemSpacing,
+ defaultBindingMode: BindingMode.OneWay);
+
+ public double ItemSize
+ {
+ get => (double)GetValue(ItemSizeProperty);
+ set => SetValue(ItemSizeProperty, value);
+ }
+
+ public static readonly BindableProperty ItemSizeProperty =
+ BindableProperty.Create(
+ nameof(ItemSize),
+ typeof(double),
+ typeof(FreakyPinCodeControl),
+ CodeView.DefaultItemSize,
+ defaultBindingMode: BindingMode.OneWay);
+
+ public ItemShape ItemShape
+ {
+ get => (ItemShape)GetValue(ItemShapeProperty);
+ set => SetValue(ItemShapeProperty, value);
+ }
+
+ public static readonly BindableProperty ItemShapeProperty =
+ BindableProperty.Create(
+ nameof(ItemShape),
+ typeof(ItemShape),
+ typeof(FreakyPinCodeControl),
+ ItemShape.Circle,
+ defaultBindingMode: BindingMode.OneWay);
+
+ public Color ItemFocusColor
+ {
+ get => (Color)GetValue(ItemFocusColorProperty);
+ set => SetValue(ItemFocusColorProperty, value);
+ }
+
+ public static readonly BindableProperty ItemFocusColorProperty =
+ BindableProperty.Create(
+ nameof(ItemFocusColor),
+ typeof(Color),
+ typeof(FreakyPinCodeControl),
+ Colors.Black,
+ defaultBindingMode: BindingMode.OneWay);
+
+ public FocusAnimation ItemFocusAnimation
+ {
+ get => (FocusAnimation)GetValue(ItemFocusAnimationProperty);
+ set => SetValue(ItemFocusAnimationProperty, value);
+ }
+
+ public static readonly BindableProperty ItemFocusAnimationProperty =
+ BindableProperty.Create(
+ nameof(ItemFocusAnimation),
+ typeof(FocusAnimation),
+ typeof(FreakyPinCodeControl),
+ default(FocusAnimation),
+ defaultBindingMode: BindingMode.OneWay);
+
+ public Color ItemBorderColor
+ {
+ get => (Color)GetValue(ItemBorderColorProperty);
+ set => SetValue(ItemBorderColorProperty, value);
+ }
+
+ public static readonly BindableProperty ItemBorderColorProperty =
+ BindableProperty.Create(
+ nameof(ItemBorderColor),
+ typeof(Color),
+ typeof(FreakyPinCodeControl),
+ Colors.Black,
+ defaultBindingMode: BindingMode.OneWay);
+
+ public Color ItemBackgroundColor
+ {
+ get => (Color)GetValue(ItemBackgroundColorProperty);
+ set => SetValue(ItemBackgroundColorProperty, value);
+ }
+
+ public static readonly BindableProperty ItemBackgroundColorProperty =
+ BindableProperty.Create(
+ nameof(ItemBackgroundColor),
+ typeof(Color),
+ typeof(FreakyPinCodeControl),
+ default(Color),
+ defaultBindingMode: BindingMode.OneWay);
+
+ public double ItemBorderWidth
+ {
+ get => (double)GetValue(ItemBorderWidthProperty);
+ set => SetValue(ItemBorderWidthProperty, value);
+ }
+
+ public static readonly BindableProperty ItemBorderWidthProperty =
+ BindableProperty.Create(
+ nameof(ItemBorderWidth),
+ typeof(double),
+ typeof(FreakyPinCodeControl),
+ 5.0,
+ defaultBindingMode: BindingMode.OneWay);
+
+ [TypeConverter(typeof(FontSizeConverter))]
+ public double FontSize
+ {
+ get => (double)GetValue(FontSizeProperty);
+ set => SetValue(FontSizeProperty, value);
+ }
+
+ public static readonly BindableProperty FontSizeProperty =
+ BindableProperty.Create(
+ nameof(FontSize),
+ typeof(double),
+ typeof(FreakyPinCodeControl),
+ FreakyCodeView.FontSizeProperty.DefaultValue,
+ defaultBindingMode: BindingMode.OneWay);
+
+ public string FontFamily
+ {
+ get => (string)GetValue(FontFamilyProperty);
+ set => SetValue(FontFamilyProperty, value);
+ }
+
+ public static readonly BindableProperty FontFamilyProperty = BindableProperty.Create(
+ nameof(FontFamily),
+ typeof(string),
+ typeof(FreakyPinCodeControl));
+
+ private void FreakyCodeView_CodeEntryCompleted(object sender, FreakyCodeCompletedEventArgs e)
+ {
+ CodeEntryCompleted?.Invoke(this, e);
+ }
+
+ public ImageSource BackspaceButtonSource
+ {
+ get => (ImageSource)GetValue(BackspaceButtonSourceProperty);
+ set => SetValue(BackspaceButtonSourceProperty, value);
+ }
+
+ public static readonly BindableProperty BackspaceButtonSourceProperty = BindableProperty.Create(
+ nameof(BackspaceButtonSource),
+ typeof(ImageSource),
+ typeof(FreakyPinCodeControl),
+ default(ImageSource));
+
+ public Color KeyboardBackgroundColor
+ {
+ get => (Color)GetValue(KeyboardBackgroundColorProperty);
+ set => SetValue(KeyboardBackgroundColorProperty, value);
+ }
+
+ public static readonly BindableProperty KeyboardBackgroundColorProperty = BindableProperty.Create(
+ nameof(KeyboardBackgroundColor),
+ typeof(Color),
+ typeof(FreakyPinCodeControl),
+ Colors.White);
+
+ public Color CancelBackgroundColor
+ {
+ get => (Color)GetValue(CancelBackgroundColorProperty);
+ set => SetValue(CancelBackgroundColorProperty, value);
+ }
+
+ public static readonly BindableProperty CancelBackgroundColorProperty = BindableProperty.Create(
+ nameof(CancelBackgroundColor),
+ typeof(Color),
+ typeof(FreakyPinCodeControl),
+ Colors.White);
+
+ public Color BackspaceBackgroundColor
+ {
+ get => (Color)GetValue(BackspaceBackgroundColorProperty);
+ set => SetValue(BackspaceBackgroundColorProperty, value);
+ }
+
+ public static readonly BindableProperty BackspaceBackgroundColorProperty = BindableProperty.Create(
+ nameof(BackspaceBackgroundColor),
+ typeof(Color),
+ typeof(FreakyPinCodeControl),
+ Colors.White);
+
+ public Color KeyboardTextColor
+ {
+ get => (Color)GetValue(KeyboardTextColorProperty);
+ set => SetValue(KeyboardTextColorProperty, value);
+ }
+
+ public static readonly BindableProperty KeyboardTextColorProperty = BindableProperty.Create(
+ nameof(KeyboardTextColor),
+ typeof(Color),
+ typeof(FreakyPinCodeControl),
+ Colors.Black);
+
+ public double KeyboardButtonSizeRequest
+ {
+ get => (double)GetValue(KeyboardButtonSizeRequestProperty);
+ set => SetValue(KeyboardButtonSizeRequestProperty, value);
+ }
+
+ public static readonly BindableProperty KeyboardButtonSizeRequestProperty = BindableProperty.Create(
+ nameof(BackspaceBackgroundColor),
+ typeof(double),
+ typeof(FreakyPinCodeControl),
+ 100.0);
+
+ public int KeyboardButtonCornerRadius
+ {
+ get => (int)GetValue(KeyboardButtonCornerRadiusProperty);
+ set => SetValue(KeyboardButtonCornerRadiusProperty, value);
+ }
+
+ public static readonly BindableProperty KeyboardButtonCornerRadiusProperty = BindableProperty.Create(
+ nameof(KeyboardButtonCornerRadius),
+ typeof(int),
+ typeof(FreakyPinCodeControl),
+ 10);
+
+ public Thickness CancelButtonPadding
+ {
+ get => (Thickness)GetValue(CancelButtonPaddingProperty);
+ set => SetValue(CancelButtonPaddingProperty, value);
+ }
+
+ public static readonly BindableProperty CancelButtonPaddingProperty = BindableProperty.Create(
+ nameof(CancelButtonPadding),
+ typeof(Thickness),
+ typeof(FreakyPinCodeControl),
+ new Thickness(20));
+
+ private void Keyboard_Clicked(object sender, System.EventArgs e)
+ {
+ var button = (Button)sender;
+ var text = button.Text;
+ this.CodeValue += text;
+ }
+
+ private void Cancel_Clicked(object sender, System.EventArgs e)
+ {
+ }
+
+ void ImageButton_Clicked(System.Object sender, System.EventArgs e)
+ {
+ if (CodeValue.Length != 0)
+ CodeValue = CodeValue[..^1];
+ }
+ #endregion BindableProperties
+}
\ No newline at end of file
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakySvgImageView/FreakySvgImageView.xaml.cs b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakySvgImageView/FreakySvgImageView.cs
similarity index 51%
rename from MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakySvgImageView/FreakySvgImageView.xaml.cs
rename to MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakySvgImageView/FreakySvgImageView.cs
index 60b34f63..34fabbd2 100644
--- a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakySvgImageView/FreakySvgImageView.xaml.cs
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakySvgImageView/FreakySvgImageView.cs
@@ -1,40 +1,97 @@
-using Maui.FreakyControls.Extensions;
-using SkiaSharp;
-using SkiaSharp.Views.Maui;
-using System.Diagnostics;
+using System.Diagnostics;
using System.Reflection;
using System.Windows.Input;
+using Maui.FreakyControls.Extensions;
+using Maui.FreakyControls.Shared.Helpers;
+using SkiaSharp;
+using SkiaSharp.Views.Maui;
+using SKPaintSurfaceEventArgs = SkiaSharp.Views.Maui.SKPaintSurfaceEventArgs;
using SKSvg = SkiaSharp.Extended.Svg.SKSvg;
+using Color = Microsoft.Maui.Graphics.Color;
namespace Maui.FreakyControls;
-public partial class FreakySvgImageView : BaseSKCanvas
+public class FreakySvgImageView : BaseSKCanvas, IDisposable
{
- private DateTime firstTap;
- public const int TAP_TIME_TRESHOLD = 200;
-
- public event EventHandler Tapped;
-
- private SKCanvas canvas;
private SKImageInfo info;
private SKSurface surface;
+ private SKCanvas canvas;
+ private readonly TapGestureRecognizer tapGestureRecognizer;
+
+ private SKSvg Svg { get; }
+
+ private SKCanvas Canvas
+ {
+ get => canvas;
+ set
+ {
+ canvas = value;
+ OnPropertyChanged(nameof(this.SvgMode));
+ OnPropertyChanged(nameof(this.ImageColor));
+ }
+ }
+
+ ///
+ /// Tapped event for our control
+ ///
+ public event EventHandler Tapped;
+
+ #region Constructor, Destructor, Disposal and Assignments
- #region bindable properties
+ public FreakySvgImageView()
+ {
+ tapGestureRecognizer = new TapGestureRecognizer();
+ tapGestureRecognizer.SetBinding(TapGestureRecognizer.CommandProperty, new Binding("BindingContext.Command", source: this));
+ tapGestureRecognizer.SetBinding(TapGestureRecognizer.CommandParameterProperty, new Binding("BindingContext.CommandParameter", source: this));
+ GestureRecognizers.Add(tapGestureRecognizer);
+ tapGestureRecognizer.Tapped += TapGestureRecognizer_Tapped;
+ SizeChanged += FreakySvgImageView_SizeChanged;
+ this.Svg = new SKSvg();
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ~FreakySvgImageView()
+ {
+ Dispose(false);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ SizeChanged -= FreakySvgImageView_SizeChanged;
+ tapGestureRecognizer.Tapped -= TapGestureRecognizer_Tapped;
+ GestureRecognizers.Clear();
+ }
+
+ protected override void DoPaintSurface(SKPaintSurfaceEventArgs e)
+ {
+ info = e.Info;
+ surface = e.Surface;
+ Canvas = surface.Canvas;
+ Canvas.Clear();
+ if (Svg != null && Svg?.Picture != null)
+ Canvas.DrawPicture(Svg?.Picture);
+ }
+
+ #endregion
public static readonly BindableProperty ImageColorProperty = BindableProperty.Create(
- nameof(ImageColor),
- typeof(Color),
- typeof(FreakySvgImageView),
- Colors.Transparent,
- propertyChanged: OnColorChangedPropertyChanged
- );
+ nameof(ImageColor),
+ typeof(Color),
+ typeof(FreakySvgImageView),
+ Colors.Transparent
+ );
public static readonly BindableProperty SvgAssemblyProperty = BindableProperty.Create(
- nameof(SvgAssembly),
- typeof(Assembly),
- typeof(FreakySvgImageView),
- default(Assembly)
- );
+ nameof(SvgAssembly),
+ typeof(Assembly),
+ typeof(FreakySvgImageView),
+ default(Assembly)
+ );
public static readonly BindableProperty CommandProperty = BindableProperty.Create(
nameof(Command),
@@ -59,22 +116,30 @@ public partial class FreakySvgImageView : BaseSKCanvas
nameof(ResourceId),
typeof(string),
typeof(FreakySvgImageView),
- default(string),
- propertyChanged: RedrawCanvas
+ default(string)
);
public static readonly BindableProperty Base64StringProperty = BindableProperty.Create(
nameof(Base64String),
typeof(string),
typeof(FreakySvgImageView),
- default(string),
- propertyChanged: RedrawCanvas
+ default(string)
);
- private static void OnColorChangedPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ public static readonly BindableProperty UriProperty = BindableProperty.Create(
+ nameof(Uri),
+ typeof(Uri),
+ typeof(FreakySvgImageView),
+ default(Uri)
+ );
+
+ ///
+ /// of type , specifies the Assembly for your Uri
+ ///
+ public Uri Uri
{
- var view = bindable as FreakySvgImageView;
- view.InvalidateSurface();
+ get => (Uri)GetValue(UriProperty);
+ set => SetValue(UriProperty, value);
}
///
@@ -140,51 +205,28 @@ public Aspect SvgMode
set { SetValue(SvgModeProperty, value); }
}
- #endregion bindable properties
-
- public FreakySvgImageView()
+ private void TapGestureRecognizer_Tapped(object sender, TappedEventArgs e)
{
- InitializeComponent();
+ Tapped?.Invoke(this, e);
}
- private void TapGestureRecognizer_OnTapped(object sender, EventArgs e)
+ private void FreakySvgImageView_SizeChanged(object sender, EventArgs e)
{
- var time = Math.Round((DateTime.Now - firstTap).TotalMilliseconds, MidpointRounding.AwayFromZero);
-
- //Check to avoid handling multiple tap events at same time using threshold
- if (time > TAP_TIME_TRESHOLD)
- {
- firstTap = DateTime.Now;
- Tapped?.Invoke(this, e);
- }
+ InvalidateSurface();
}
- protected override void DoPaintSurface(SKPaintSurfaceEventArgs skPaintSurfaceEventArgs)
+ private void SetResourceId()
{
try
{
- info = skPaintSurfaceEventArgs.Info;
- surface = skPaintSurfaceEventArgs.Surface;
- canvas = surface.Canvas;
- canvas.Clear();
- //TODO: Figure out why drawing on coachmark is leading to surface being null
- if (skPaintSurfaceEventArgs.Surface == null)
- {
- return;
- }
-
- if (!string.IsNullOrWhiteSpace(ResourceId) && this.SvgAssembly != null)
- {
- UpdateResourceId();
- }
- else if (!string.IsNullOrWhiteSpace(Base64String))
- {
- UpdateBase64();
- }
- else
+ Stream svgStream;
+ svgStream = SvgAssembly?.GetManifestResourceStream(ResourceId);
+ if (svgStream == null)
{
+ Trace.TraceError($"{nameof(FreakySvgImageView)}: Embedded Resource not found for Svg: {ResourceId}");
return;
}
+ Svg?.Load(svgStream);
}
catch (KeyNotFoundException ex)
{
@@ -197,29 +239,40 @@ protected override void DoPaintSurface(SKPaintSurfaceEventArgs skPaintSurfaceEve
}
}
- private void SKCanvasView_OnSizeChanged(object sender, EventArgs e)
- {
- InvalidateSurface();
- }
-
- private static void RedrawCanvas(BindableObject bindable, object oldvalue, object newvalue)
+ private void SetImageColor()
{
- FreakySvgImageView svgIcon = bindable as FreakySvgImageView;
- svgIcon?.InvalidateSurface();
+ if (ImageColor != Colors.Transparent)
+ {
+ using var paint = new SKPaint
+ {
+ ColorFilter = SKColorFilter.CreateBlendMode(ImageColor.ToSKColor(), SKBlendMode.SrcIn),
+ Style = SKPaintStyle.StrokeAndFill
+ };
+ Canvas.DrawPicture(Svg.Picture, paint);
+ return;
+ }
+ Canvas.DrawPicture(Svg.Picture);
}
- private void UpdateBase64()
+ private void SetBase64String()
{
- var svg = new SKSvg();
- string base64 = Base64String.Substring(Base64String.IndexOf(',') + 1);
- var byteArray = Convert.FromBase64String(base64);
- using (var stream = new MemoryStream(byteArray))
+ try
{
- svg.Load(stream);
+ string base64 = Base64String.Substring(Base64String.IndexOf(',') + 1);
+ var byteArray = Convert.FromBase64String(base64);
+ using var stream = new MemoryStream(byteArray);
+ Svg.Load(stream);
}
+ catch (Exception ex)
+ {
+ ex.TraceException();
+ }
+ }
- canvas.Translate(info.Width / 2f, info.Height / 2f);
- var bounds = svg.Picture.CullRect;
+ private void SetSvgMode()
+ {
+ Canvas.Translate(info.Width / 2f, info.Height / 2f);
+ var bounds = Svg.Picture.CullRect;
var xRatio = info.Width / bounds.Width;
var yRatio = info.Height / bounds.Height;
xRatio *= .95f;
@@ -227,109 +280,69 @@ private void UpdateBase64()
float ratio;
switch (SvgMode)
{
- case Aspect.Center:
- case Aspect.AspectFit:
- ratio = Math.Min(xRatio, yRatio);
- canvas.Scale(ratio);
- break;
-
case Aspect.AspectFill:
ratio = Math.Max(xRatio, yRatio);
- canvas.Scale(ratio);
+ Canvas.Scale(ratio);
break;
case Aspect.Fill:
- canvas.Scale(xRatio, yRatio);
+ Canvas.Scale(xRatio, yRatio);
break;
+ case Aspect.Center:
+ case Aspect.AspectFit:
default:
- throw new ArgumentOutOfRangeException();
+ ratio = Math.Min(xRatio, yRatio);
+ Canvas.Scale(ratio);
+ break;
}
+ Canvas.Translate(-bounds.MidX, -bounds.MidY);
+ }
- canvas.Translate(-bounds.MidX, -bounds.MidY);
-
- if (ImageColor != Colors.Transparent)
+ protected async override void OnPropertyChanged(string propertyName = null)
+ {
+ base.OnPropertyChanged(propertyName);
+ if (propertyName == nameof(ResourceId) || propertyName == nameof(SvgAssembly))
{
- using (var paint = new SKPaint
- {
- ColorFilter = SKColorFilter.CreateBlendMode(ImageColor.ToSKColor(), SKBlendMode.SrcIn),
- Style = SKPaintStyle.StrokeAndFill
- })
- {
- canvas.DrawPicture(svg.Picture, paint);
+ if (string.IsNullOrWhiteSpace(ResourceId) || SvgAssembly == null)
return;
- }
+ SetResourceId();
}
-
- canvas.DrawPicture(svg.Picture);
- }
-
- private void UpdateResourceId()
- {
- Stream svgStream;
- var svg = new SKSvg();
- svgStream = this.SvgAssembly.GetManifestResourceStream(ResourceId);
- if (svgStream == null)
+ else if (propertyName == nameof(ImageColor))
{
- // TODO: write log entry notifying that this Svg does not have a matching EmbeddedResource
- Trace.TraceError($"SKSvgImage: Embedded Resource not found for Svg: {ResourceId}");
- return;
+ if (Canvas == null || Svg == null || Svg.Picture == null)
+ return;
+ SetImageColor();
}
- svg.Load(svgStream);
-
- canvas.Translate(info.Width / 2f, info.Height / 2f);
- var bounds = svg.Picture.CullRect;
- var xRatio = info.Width / bounds.Width;
- var yRatio = info.Height / bounds.Height;
- xRatio *= .95f;
- yRatio *= .95f;
- float ratio;
- switch (SvgMode)
+ else if (propertyName == nameof(Base64String))
{
- case Aspect.Center:
- case Aspect.AspectFit:
- ratio = Math.Min(xRatio, yRatio);
- canvas.Scale(ratio);
- break;
-
- case Aspect.AspectFill:
- ratio = Math.Max(xRatio, yRatio);
- canvas.Scale(ratio);
- break;
-
- case Aspect.Fill:
- canvas.Scale(xRatio, yRatio);
- break;
-
- default:
- throw new ArgumentOutOfRangeException();
+ if (string.IsNullOrWhiteSpace(Base64String) && Svg != null)
+ return;
+ SetBase64String();
}
- canvas.Translate(-bounds.MidX, -bounds.MidY);
-
- if (ImageColor != Colors.Transparent)
+ else if (propertyName == nameof(SvgMode))
{
- using (var paint = new SKPaint
- {
- ColorFilter = SKColorFilter.CreateBlendMode(ImageColor.ToSKColor(), SKBlendMode.SrcIn),
- Style = SKPaintStyle.StrokeAndFill
- })
+ if (Canvas == null || Svg == null || Svg.Picture == null)
+ return;
+ SetSvgMode();
+ }
+ else if (propertyName == nameof(Uri))
+ {
+ if (Uri == default)
{
- canvas.DrawPicture(svg.Picture, paint);
return;
}
- }
- canvas.DrawPicture(svg.Picture);
- }
- protected override void OnPropertyChanged(string propertyName = null)
- {
- base.OnPropertyChanged(propertyName);
-
- if (propertyName != nameof(ResourceId) &&
- propertyName != nameof(SvgMode))
- {
- return;
+ try
+ {
+ var stream = await DownloadHelper.GetStreamAsync(Uri);
+ Svg.Load(stream);
+ InvalidateSurface();
+ }
+ catch (Exception ex)
+ {
+ ex.TraceException();
+ }
}
- InvalidateSurface();
}
}
\ No newline at end of file
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakySvgImageView/FreakySvgImageView.xaml b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakySvgImageView/FreakySvgImageView.xaml
deleted file mode 100644
index 634dfa51..00000000
--- a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakySvgImageView/FreakySvgImageView.xaml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyTimePicker/FreakyTimePickerHandler.cs b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyTimePicker/FreakyTimePickerHandler.cs
index d2655dde..4bf59b14 100644
--- a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyTimePicker/FreakyTimePickerHandler.cs
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/FreakyTimePicker/FreakyTimePickerHandler.cs
@@ -15,14 +15,14 @@ private void MapTimePicker(ITimePickerHandler timePickerHandler, ITimePicker tim
{
if (timePicker is FreakyTimePicker freakyTimePicker &&
timePickerHandler is FreakyTimePickerHandler freakyTimePickerHandler)
- {
+ {
if (PlatformView != null && VirtualView != null)
- {
- if (freakyTimePicker.ImageSource != default(ImageSource))
- {
- freakyTimePickerHandler.HandleAndAlignImageSourceAsync(freakyTimePicker).RunConcurrently();
- }
- }
+ {
+ if (freakyTimePicker.ImageSource != default(ImageSource))
+ {
+ freakyTimePickerHandler.HandleAndAlignImageSourceAsync(freakyTimePicker).RunConcurrently();
+ }
+ }
}
}
}
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Helpers/DownloadHelper.cs b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Helpers/DownloadHelper.cs
index 28156123..e461ec73 100644
--- a/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Helpers/DownloadHelper.cs
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/Shared/Helpers/DownloadHelper.cs
@@ -1,4 +1,5 @@
-using Maui.FreakyControls.Shared.Wrappers;
+using Maui.FreakyControls.Extensions;
+using Maui.FreakyControls.Shared.Wrappers;
using System.Diagnostics;
namespace Maui.FreakyControls.Shared.Helpers;
@@ -24,10 +25,7 @@ private static async Task DownloadStreamAsync(Uri uri, CancellationToken
}
catch (Exception ex)
{
- Trace.TraceError(ex.Message);
- Trace.TraceError(ex.StackTrace);
- Trace.TraceError(ex.Source);
- Trace.WriteLine(ex.InnerException);
+ ex.TraceException();
return null;
}
}
diff --git a/MAUI.FreakyControls/MAUI.FreakyControls/readme.md b/MAUI.FreakyControls/MAUI.FreakyControls/readme.md
new file mode 100644
index 00000000..0c84fc80
--- /dev/null
+++ b/MAUI.FreakyControls/MAUI.FreakyControls/readme.md
@@ -0,0 +1,32 @@
+## Installation
+
+Add our [NuGet](https://www.nuget.org/packages/FreakyControls) package or
+
+Run the following command to add our Nuget to your .Net MAUI app:
+
+Install-Package FreakyControls -Version xx.xx.xx
+
+Add the following using statement and Initialization in your MauiProgram:
+
+using MAUI.FreakyControls.Extensions;
+namespace Samples;
+
+public static class MauiProgram
+{
+public static MauiApp CreateMauiApp()
+{
+var builder = MauiApp.CreateBuilder();
+builder
+.UseMauiApp()
+ .ConfigureFonts(fonts =>
+ {
+ fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
+ fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
+ });
+ //Takes one argument if you would like to init Skiasharp through FreakyControls or not. (Used for RadioButton, Checkbox & SVGImageView)
+ builder.InitializeFreakyControls();
+ return builder.Build();
+ }
+ }
+
+Now you can use the controls in your app.
diff --git a/MAUI.FreakyControls/Samples/AppShell.xaml.cs b/MAUI.FreakyControls/Samples/AppShell.xaml.cs
index 34b4f2f3..83aab788 100644
--- a/MAUI.FreakyControls/Samples/AppShell.xaml.cs
+++ b/MAUI.FreakyControls/Samples/AppShell.xaml.cs
@@ -12,6 +12,7 @@ public partial class AppShell : Shell
internal const string signatureView = "SignatureView";
internal const string textInputLayout = "TextInputLayouts";
internal const string jumpList = "JumpList";
+ internal const string pinView = "PinView";
public AppShell()
{
@@ -26,5 +27,6 @@ public AppShell()
Routing.RegisterRoute(radioButtons, typeof(RadioButtons.RadioButtonsView));
Routing.RegisterRoute(buttons, typeof(ButtonsView.ButtonsView));
Routing.RegisterRoute(jumpList, typeof(JumpList.JumpListView));
+ Routing.RegisterRoute(pinView, typeof(PinView.PinView));
}
}
\ No newline at end of file
diff --git a/MAUI.FreakyControls/Samples/Checkboxes/CheckboxesView.xaml b/MAUI.FreakyControls/Samples/Checkboxes/CheckboxesView.xaml
index e9a28971..94775e58 100644
--- a/MAUI.FreakyControls/Samples/Checkboxes/CheckboxesView.xaml
+++ b/MAUI.FreakyControls/Samples/Checkboxes/CheckboxesView.xaml
@@ -35,7 +35,7 @@
Shape="Circle" />
@@ -48,10 +48,10 @@
Design="Unified"
FillColor="{StaticResource Primary}"
OutlineColor="{StaticResource Primary}"
- Shape="Rectangle" />
+ Shape="Sqaure" />
@@ -64,7 +64,7 @@
Design="Unified"
FillColor="{StaticResource Primary}"
OutlineColor="{StaticResource Primary}"
- Shape="Rectangle" />
+ Shape="Sqaure" />
+ Shape="Sqaure" />
@@ -99,7 +99,7 @@
Shape="Circle" />
@@ -112,10 +112,10 @@
Design="Unified"
FillColor="Transparent"
OutlineColor="{StaticResource Primary}"
- Shape="Rectangle" />
+ Shape="Sqaure" />
@@ -128,10 +128,10 @@
Design="Unified"
FillColor="{StaticResource Primary}"
OutlineColor="{StaticResource Primary}"
- Shape="Rectangle" />
+ Shape="Sqaure" />
@@ -144,10 +144,10 @@
Design="Unified"
FillColor="{StaticResource Primary}"
OutlineColor="{StaticResource Primary}"
- Shape="Rectangle" />
+ Shape="Sqaure" />
@@ -157,10 +157,10 @@
Design="Unified"
FillColor="{StaticResource Primary}"
OutlineColor="{StaticResource Primary}"
- Shape="Rectangle" />
+ Shape="Sqaure" />
diff --git a/MAUI.FreakyControls/Samples/Constants.cs b/MAUI.FreakyControls/Samples/Constants.cs
index 3dd921dc..68a87c32 100644
--- a/MAUI.FreakyControls/Samples/Constants.cs
+++ b/MAUI.FreakyControls/Samples/Constants.cs
@@ -9,6 +9,6 @@ public static class Constants
public static readonly string DotnetBot = ResourcePath + "dotnet_bot.svg";
public static readonly string Profile = "https://images.pexels.com/photos/1704488/pexels-photo-1704488.jpeg?cs=srgb&dl=pexels-suliman-sallehi-1704488.jpg&fm=jpg";
public static readonly string Profile2 = "https://i.stack.imgur.com/HOUoK.jpg?s=256&g=1";
- public static readonly string SvgUrl = "https://storage.googleapis.com/draw-svg/home/img/board.svg";
+ public static readonly Uri SvgUrl = new( "https://storage.googleapis.com/draw-svg/home/img/board.svg");
public static readonly string SvgBase64 = "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iNTA5cHgiIGhlaWdodD0iNDYwcHgiIHZpZXdCb3g9IjE5MCAxMDAgMjIwIDIwMCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgbWVldCIgID48cmVjdCBpZD0ic3ZnRWRpdG9yQmFja2dyb3VuZCIgeD0iMTkwIiB5PSIxMDAiIHdpZHRoPSIyMjAiIGhlaWdodD0iMjAwIiBzdHlsZT0iZmlsbDpub25lOyBzdHJva2U6IG5vbmU7Ii8+PGRlZnMgaWQ9InN2Z0VkaXRvckRlZnMiPjxwb2x5Z29uIGlkPSJzdmdFZGl0b3JTaGFwZURlZnMiIHN0eWxlPSJmaWxsOmtoYWtpO3N0cm9rZTpibGFjazt2ZWN0b3ItZWZmZWN0Om5vbi1zY2FsaW5nLXN0cm9rZTtzdHJva2Utd2lkdGg6MXB4OyIvPjwvZGVmcz48ZyBzdHJva2U9Im5vbmUiIHRyYW5zZm9ybT0ibWF0cml4KDQuNzYxOSAwIDAgNC43NjE5IDE4NS43MTQgNzUuMTkwNSkiIGlkPSJlMV9zaGFwZSI+PGcgZmlsbD0iIzM3NDc0RiI+PHJlY3QgaGVpZ2h0PSIzNiIgd2lkdGg9IjIiIHg9IjIzIiB5PSI1Ii8+PHJlY3QgaGVpZ2h0PSIxNC4yIiB0cmFuc2Zvcm09Im1hdHJpeCguNzA3IC43MDcgLS43MDcgLjcwNyAzMy41MjMgLTMuOTIxKSIgd2lkdGg9IjIiIHg9IjIwLjUiIHk9IjMxLjQiLz48cmVjdCBoZWlnaHQ9IjE0LjIiIHRyYW5zZm9ybT0ibWF0cml4KC0uNzA3IC43MDcgLS43MDcgLS43MDcgNzIuNDg3IDQ2Ljk5NSkiIHdpZHRoPSIyIiB4PSIyNS41IiB5PSIzMS40Ii8+PC9nPjxyZWN0IGZpbGw9IiNDRkQ4REMiIGhlaWdodD0iMjgiIHdpZHRoPSI0MCIgeD0iNCIgeT0iOCIvPjxnIGZpbGw9IiM2MDdEOEIiPjxyZWN0IGhlaWdodD0iNCIgd2lkdGg9IjQyIiB4PSIzIiB5PSI3Ii8+PHJlY3QgaGVpZ2h0PSIyIiB3aWR0aD0iNDIiIHg9IjMiIHk9IjM1Ii8+PGNpcmNsZSBjeD0iMzEuNSIgY3k9IjQzLjUiIHI9IjEuNSIvPjxjaXJjbGUgY3g9IjE2LjUiIGN5PSI0My41IiByPSIxLjUiLz48L2c+PGcgZmlsbD0iI0M1MTE2MiIvPjwvZz48ZyBzdHJva2U9Im5vbmUiIHRyYW5zZm9ybT0ibWF0cml4KDIuNzUgMCAwIDIuNzUgMjM1IDEyMC43NSkiIGlkPSJlMl9zaGFwZSI+PHBhdGggZD0iTTQwLDQxSDhjLTIuMiwwLTQtMS44LTQtNFYxMWMwLTIuMiwxLjgtNCw0LTRoMzJjMi4yLDAsNCwxLjgsNCw0djI2QzQ0LDM5LjIsNDIuMiw0MSw0MCw0MXoiIGZpbGw9IiNGNTdDMDAiLz48Y2lyY2xlIGN4PSIzNSIgY3k9IjE2IiBmaWxsPSIjRkZGOUM0IiByPSIzIi8+PHBvbHlnb24gZmlsbD0iIzk0MkEwOSIgcG9pbnRzPSIyMCwxNiA5LDMyIDMxLDMyIi8+PHBvbHlnb24gZmlsbD0iI0JGMzYwQyIgcG9pbnRzPSIzMSwyMiAyMywzMiAzOSwzMiIvPjwvZz48L3N2Zz4=";
}
\ No newline at end of file
diff --git a/MAUI.FreakyControls/Samples/ImageViews/ImagesPage.xaml b/MAUI.FreakyControls/Samples/ImageViews/ImagesPage.xaml
index 4cb2974d..fac02ad4 100644
--- a/MAUI.FreakyControls/Samples/ImageViews/ImagesPage.xaml
+++ b/MAUI.FreakyControls/Samples/ImageViews/ImagesPage.xaml
@@ -25,6 +25,12 @@
Base64String="{x:Static samples:Constants.SvgBase64}"
HeightRequest="300"
SvgMode="AspectFit" />
+
+
+
\ No newline at end of file
diff --git a/MAUI.FreakyControls/Samples/InputViews/InputViewModel.cs b/MAUI.FreakyControls/Samples/InputViews/InputViewModel.cs
index faee58a7..337104e6 100644
--- a/MAUI.FreakyControls/Samples/InputViews/InputViewModel.cs
+++ b/MAUI.FreakyControls/Samples/InputViews/InputViewModel.cs
@@ -1,4 +1,4 @@
-using Maui.FreakyControls.Extensions;
+using Maui.FreakyControls.Extensions;
using System.Collections.ObjectModel;
namespace Samples.InputViews;
diff --git a/MAUI.FreakyControls/Samples/InputViews/InputViews.xaml b/MAUI.FreakyControls/Samples/InputViews/InputViews.xaml
index 7142cd15..b8f084eb 100644
--- a/MAUI.FreakyControls/Samples/InputViews/InputViews.xaml
+++ b/MAUI.FreakyControls/Samples/InputViews/InputViews.xaml
@@ -53,6 +53,7 @@
+
+
+
+
();
diff --git a/MAUI.FreakyControls/Samples/MainViewModel.cs b/MAUI.FreakyControls/Samples/MainViewModel.cs
index 533901d9..3727cc10 100644
--- a/MAUI.FreakyControls/Samples/MainViewModel.cs
+++ b/MAUI.FreakyControls/Samples/MainViewModel.cs
@@ -54,7 +54,8 @@ public MainViewModel()
AppShell.checkboxes,
AppShell.radioButtons,
AppShell.buttons,
- AppShell.jumpList
+ AppShell.jumpList,
+ AppShell.pinView
};
}
diff --git a/MAUI.FreakyControls/Samples/MauiProgram.cs b/MAUI.FreakyControls/Samples/MauiProgram.cs
index ad70a1e9..d68bc9cd 100644
--- a/MAUI.FreakyControls/Samples/MauiProgram.cs
+++ b/MAUI.FreakyControls/Samples/MauiProgram.cs
@@ -1,4 +1,5 @@
-using Maui.FreakyControls.Extensions;
+using CommunityToolkit.Maui;
+using Maui.FreakyControls.Extensions;
// this is to avoid the following https://docs.microsoft.com/en-us/dotnet/maui/xaml/xamlc
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
@@ -17,6 +18,7 @@ public static MauiApp CreateMauiApp()
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
+ builder.UseMauiCommunityToolkit();
builder.InitializeFreakyControls();
return builder.Build();
}
diff --git a/MAUI.FreakyControls/Samples/PinView/PinView.xaml b/MAUI.FreakyControls/Samples/PinView/PinView.xaml
new file mode 100644
index 00000000..bba594b9
--- /dev/null
+++ b/MAUI.FreakyControls/Samples/PinView/PinView.xaml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MAUI.FreakyControls/Samples/PinView/PinView.xaml.cs b/MAUI.FreakyControls/Samples/PinView/PinView.xaml.cs
new file mode 100644
index 00000000..fbb6e48e
--- /dev/null
+++ b/MAUI.FreakyControls/Samples/PinView/PinView.xaml.cs
@@ -0,0 +1,9 @@
+namespace Samples.PinView;
+
+public partial class PinView : ContentPage
+{
+ public PinView()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/MAUI.FreakyControls/Samples/PinView/PinViewModel.cs b/MAUI.FreakyControls/Samples/PinView/PinViewModel.cs
new file mode 100644
index 00000000..90081e9a
--- /dev/null
+++ b/MAUI.FreakyControls/Samples/PinView/PinViewModel.cs
@@ -0,0 +1,5 @@
+namespace Samples.PinView;
+
+public class PinViewModel : BaseViewModel
+{
+}
\ No newline at end of file
diff --git a/MAUI.FreakyControls/Samples/Resources/Images/backspace.svg b/MAUI.FreakyControls/Samples/Resources/Images/backspace.svg
new file mode 100644
index 00000000..d721b8ff
--- /dev/null
+++ b/MAUI.FreakyControls/Samples/Resources/Images/backspace.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/MAUI.FreakyControls/Samples/Resources/Images/panda.jpg b/MAUI.FreakyControls/Samples/Resources/Images/panda.jpg
new file mode 100644
index 00000000..752ce855
Binary files /dev/null and b/MAUI.FreakyControls/Samples/Resources/Images/panda.jpg differ
diff --git a/MAUI.FreakyControls/Samples/Resources/Styles/Colors.xaml b/MAUI.FreakyControls/Samples/Resources/Styles/Colors.xaml
index edb91bc1..f0489776 100644
--- a/MAUI.FreakyControls/Samples/Resources/Styles/Colors.xaml
+++ b/MAUI.FreakyControls/Samples/Resources/Styles/Colors.xaml
@@ -2,9 +2,9 @@
- #512BD4
- #DFD8F7
- #2B0B98
+ Black
+ White
+ Gray
White
Black
#E1E1E1
@@ -28,7 +28,6 @@
-
#F7B548
#FFD590
#FFE5B9
diff --git a/MAUI.FreakyControls/Samples/Samples.csproj b/MAUI.FreakyControls/Samples/Samples.csproj
index 5bdd2269..b6f9bcb4 100644
--- a/MAUI.FreakyControls/Samples/Samples.csproj
+++ b/MAUI.FreakyControls/Samples/Samples.csproj
@@ -65,6 +65,11 @@
+
+
+
+
+
@@ -80,9 +85,11 @@
+
+
@@ -113,4 +120,8 @@
+
+
+
+