Skip to content

Commit 1f0858b

Browse files
committed
Refactor SfOtpInput and update unit tests
Enhanced `SfOtpInput.cs` with new using directives, restructured event handlers, and added `ApplyEntrySize` method for better dimension management. Improved code readability and updated comments for clarity. Updated `SfOtpInputUnitTests.cs` for consistent formatting and added tests to verify `BoxWidth` and `BoxHeight` changes. Overall improvements enhance clarity and maintainability of both implementation and tests. Refactor SfOtpInput for clarity and add unit tests Improved code structure in `SfOtpInput.cs` by reorganizing `using` directives, updating documentation, and encapsulating entry dimension logic in a new `ApplyEntrySize` method. Enhanced focus event handling for consistency across input types. Added unit tests in `SfOtpInputUnitTests.cs` to verify updates to `BoxWidth` and `BoxHeight`, ensuring correct entry dimensions. Improved existing tests for clarity and maintainability, enhancing overall test coverage for the `SfOtpInput` class.
1 parent bf9accc commit 1f0858b

File tree

2 files changed

+101
-54
lines changed

2 files changed

+101
-54
lines changed

maui/src/OtpInput/SfOtpInput.cs

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
using Syncfusion.Maui.Toolkit.Internals;
2-
using Syncfusion.Maui.Toolkit.Graphics.Internals;
3-
using Rect = Microsoft.Maui.Graphics.Rect; // Alias for Maui's Rect
4-
using TextAlignment = Microsoft.Maui.TextAlignment; // Alias for Maui's TextAlignment
5-
using ResourceDictionary = Microsoft.Maui.Controls.ResourceDictionary; // Alias for Maui's ResourceDictionary
1+
using Syncfusion.Maui.Toolkit.Graphics.Internals;
62
using Syncfusion.Maui.Toolkit.Helper;
3+
using Syncfusion.Maui.Toolkit.Internals;
74
using Syncfusion.Maui.Toolkit.Themes;
5+
using Rect = Microsoft.Maui.Graphics.Rect;
6+
using ResourceDictionary = Microsoft.Maui.Controls.ResourceDictionary;
7+
using TextAlignment = Microsoft.Maui.TextAlignment;
88
using System.Globalization;
99
#if WINDOWS
1010
using Microsoft.UI.Xaml;
@@ -1057,10 +1057,10 @@ static void OnAutoFocusPropertyChanged(BindableObject bindable, object oldValue,
10571057
if ((bool)newValue)
10581058
{
10591059
#if !(MACCATALYST || IOS)
1060-
otpInput.Loaded += (s, e) =>
1061-
{
1062-
otpInput._otpEntries[0].Focus();
1063-
};
1060+
otpInput.Loaded += (s, e) =>
1061+
{
1062+
otpInput._otpEntries[0].Focus();
1063+
};
10641064
#else
10651065
Task.Run(() =>
10661066
{
@@ -1154,7 +1154,7 @@ static void OnStrokePropertyChanged(BindableObject bindable, object oldValue, ob
11541154
}
11551155

11561156
/// <summary>
1157-
/// Add this property changed handler
1157+
/// Updates all OTP entry dimensions when BoxWidth or BoxHeight changes.
11581158
/// </summary>
11591159
static void OnBoxSizePropertyChanged(BindableObject bindable, object oldValue, object newValue)
11601160
{
@@ -1166,10 +1166,7 @@ static void OnBoxSizePropertyChanged(BindableObject bindable, object oldValue, o
11661166
{
11671167
foreach (var entry in otpInput._otpEntries)
11681168
{
1169-
entry.MinimumWidthRequest = otpInput._entryWidth;
1170-
entry.MinimumHeightRequest = otpInput._entryHeight;
1171-
entry.WidthRequest = otpInput._entryWidth;
1172-
entry.HeightRequest = otpInput._entryHeight;
1169+
otpInput.ApplyEntrySize(entry);
11731170
}
11741171
}
11751172
otpInput.InvalidateMeasure();
@@ -1411,23 +1408,31 @@ OTPEntry InitializeEntry()
14111408
{
14121409
OTPEntry otpEntry = new OTPEntry
14131410
{
1414-
MinimumWidthRequest = _entryWidth,
1415-
MinimumHeightRequest = _entryHeight,
1416-
WidthRequest = _entryWidth,
1417-
HeightRequest = _entryHeight,
14181411
FontSize = 16,
14191412
HorizontalTextAlignment = TextAlignment.Center,
14201413
VerticalTextAlignment = TextAlignment.Center,
14211414
Keyboard = Type is OtpInputType.Number ? Keyboard.Numeric : Keyboard.Text,
14221415
};
14231416

1417+
ApplyEntrySize(otpEntry);
14241418
otpEntry.BindingContext = this;
14251419
otpEntry.SetBinding(OTPEntry.PlaceholderColorProperty, BindingHelper.CreateBinding(nameof(PlaceholderColor), getter: static (SfOtpInput otpInput) => otpInput.PlaceholderColor));
14261420
otpEntry.SetBinding(OTPEntry.TextColorProperty, BindingHelper.CreateBinding(nameof(TextColor), getter: static (SfOtpInput otpInput) => otpInput.TextColor));
14271421

14281422
return otpEntry;
14291423
}
14301424

1425+
/// <summary>
1426+
/// Applies the current entry size to the given OTPEntry.
1427+
/// </summary>
1428+
void ApplyEntrySize(OTPEntry entry)
1429+
{
1430+
entry.MinimumWidthRequest = _entryWidth;
1431+
entry.MinimumHeightRequest = _entryHeight;
1432+
entry.WidthRequest = _entryWidth;
1433+
entry.HeightRequest = _entryHeight;
1434+
}
1435+
14311436
/// <summary>
14321437
/// Handles the event when an OTP input field receives focus.
14331438
/// Updates the focused index and redraws the control.
@@ -1533,19 +1538,19 @@ void OnEntryTextChanged(object? sender, Microsoft.Maui.Controls.TextChangedEvent
15331538
});
15341539
}
15351540
#else
1541+
{
1542+
if (Type is OtpInputType.Password && e.NewTextValue is not "")
15361543
{
1537-
if (Type is OtpInputType.Password && e.NewTextValue is not "")
1538-
{
1539-
_otpEntries[index].Text = MaskCharacter.ToString();
1540-
}
1541-
1542-
if (isValidText)
1543-
{
1544-
Value = new string(valueArray);
1545-
}
1544+
_otpEntries[index].Text = MaskCharacter.ToString();
1545+
}
15461546

1547-
HandleFocus(index, hasText);
1547+
if (isValidText)
1548+
{
1549+
Value = new string(valueArray);
15481550
}
1551+
1552+
HandleFocus(index, hasText);
1553+
}
15491554
#endif
15501555

15511556
#if ANDROID || WINDOWS

maui/tests/Syncfusion.Maui.Toolkit.UnitTest/Editors/SfOtpInputUnitTests.cs

Lines changed: 68 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public void GetVisualState_Filled(bool enabled, bool hovered, string stroke, str
120120
[InlineData(OtpInputStyle.Outlined, 13, false, OtpInputState.Error, "#008000", "#FF0000", "#1C1B1F", "#611c1b1f")]
121121
public void UpdateParameters(OtpInputStyle otpInputStyle, double cornerRadius, bool isEnabled, OtpInputState otpInputState, string stroke, string background, string textColor, string disabledTextColor)
122122
{
123-
OTPEntry otpEntry = new OTPEntry();
123+
OTPEntry otpEntry = new OTPEntry();
124124
otpEntry.UpdateParameters(otpInputStyle, cornerRadius, new PointF(10, 10), new PointF(30, 30), new SfOtpInput(),isEnabled, otpInputState, Color.FromArgb(stroke), Color.FromArgb(background), Color.FromArgb(textColor), Color.FromArgb(disabledTextColor));
125125
OtpInputStyle? resultInputStyle = (OtpInputStyle?)GetPrivateField(otpEntry, "_styleMode");
126126
double? resultCornerRadius = (double?)GetPrivateField(otpEntry, "_cornerRadius");
@@ -292,6 +292,48 @@ public void InputBackground(Color input, Color expected)
292292
Assert.Equal(expected, actual);
293293
}
294294

295+
296+
297+
[Theory]
298+
[InlineData(40)]
299+
[InlineData(60)]
300+
[InlineData(100)]
301+
public void BoxWidth_UpdatesEntryDimensions(double newWidth)
302+
{
303+
var otpInput = new SfOtpInput();
304+
otpInput.BoxWidth = newWidth;
305+
var _otpEntries = (OTPEntry[]?)GetPrivateField(otpInput, "_otpEntries");
306+
if (_otpEntries != null)
307+
{
308+
foreach (var entry in _otpEntries)
309+
{
310+
Assert.Equal(newWidth, entry.MinimumWidthRequest);
311+
Assert.Equal(newWidth, entry.WidthRequest);
312+
}
313+
}
314+
}
315+
316+
317+
318+
[Theory]
319+
[InlineData(40)]
320+
[InlineData(55)]
321+
[InlineData(80)]
322+
public void BoxHeight_UpdatesEntryDimensions(double newHeight)
323+
{
324+
var otpInput = new SfOtpInput();
325+
otpInput.BoxHeight = newHeight;
326+
var _otpEntries = (OTPEntry[]?)GetPrivateField(otpInput, "_otpEntries");
327+
if (_otpEntries != null)
328+
{
329+
foreach (var entry in _otpEntries)
330+
{
331+
Assert.Equal(newHeight, entry.MinimumHeightRequest);
332+
Assert.Equal(newHeight, entry.HeightRequest);
333+
}
334+
}
335+
}
336+
295337
#endregion
296338

297339
#region Internal Properties
@@ -548,11 +590,11 @@ public void FocusAsync()
548590
var otpInput = new SfOtpInput();
549591
OTPEntry[]? otpEntries = (OTPEntry[]?)GetPrivateField(otpInput, "_otpEntries");
550592
SetPrivateField(otpInput, "_otpEntries", otpEntries);
551-
var sender = otpEntries?[2];
593+
var sender = otpEntries?[2];
552594
var focusEventArgs = new FocusEventArgs(otpInput,true);
553595
InvokePrivateMethod(otpInput, "FocusAsync", sender, focusEventArgs);
554596
var focusedIndex = (int?)GetPrivateField(otpInput, "_focusedIndex");
555-
Assert.Equal(2, focusedIndex);
597+
Assert.Equal(2, focusedIndex);
556598
}
557599

558600

@@ -567,14 +609,14 @@ public void FocusOutAsync()
567609
}
568610

569611
[Theory]
570-
[InlineData(0, true, 0)]
612+
[InlineData(0, true, 0)]
571613
[InlineData(1, false, 1)]
572614
public void FocusEntry(int index, bool setCursorToStart, int expectedCursorPosition)
573615
{
574616
var otpInput = new SfOtpInput();
575617
OTPEntry[]? otpEntries = (OTPEntry[]?)GetPrivateField(otpInput, "_otpEntries");
576618
SetPrivateField(otpInput, "_otpEntries", otpEntries);
577-
SetPrivateField(otpInput, "_focusedIndex", 0);
619+
SetPrivateField(otpInput, "_focusedIndex", 0);
578620
otpEntries?[0].Focus();
579621
InvokePrivateMethod(otpInput, "FocusEntry", index, setCursorToStart);
580622
int? resultFocusedIndex = (int?)GetPrivateField(otpInput, "_focusedIndex");
@@ -584,9 +626,9 @@ public void FocusEntry(int index, bool setCursorToStart, int expectedCursorPosit
584626
}
585627

586628
[Theory]
587-
[InlineData(3, true, 3)]
629+
[InlineData(3, true, 3)]
588630
[InlineData(0, false, 0)]
589-
[InlineData(3, false, 3)]
631+
[InlineData(3, false, 3)]
590632
public void HandleFocus(int index, bool hasText, int expectedFocusIndex)
591633
{
592634
var otpInput = new SfOtpInput ();
@@ -596,26 +638,26 @@ public void HandleFocus(int index, bool hasText, int expectedFocusIndex)
596638
SetPrivateField(otpInput, "_focusedIndex", index);
597639
InvokePrivateMethod(otpInput,"HandleFocus", index, hasText);
598640
focusedIndex = GetPrivateField(otpInput, "_focusedIndex");
599-
Assert.Equal(expectedFocusIndex, focusedIndex);
641+
Assert.Equal(expectedFocusIndex, focusedIndex);
600642
}
601643

602644
[Theory]
603-
[InlineData(0, 1)]
645+
[InlineData(0, 1)]
604646
[InlineData(1, 1)]
605-
[InlineData(2,1)]
606-
[InlineData(3, 1)]
647+
[InlineData(2,1)]
648+
[InlineData(3, 1)]
607649
public void GetStrokeThickness(int index, float expectedStrokeThickness)
608650
{
609651
var otpInput = new SfOtpInput();
610652
OTPEntry[]? otpEntries = (OTPEntry[]?)GetPrivateField(otpInput, "_otpEntries");
611653
SetPrivateField(otpInput,"_otpEntries", otpEntries);
612654
float? strokeThickness =(float?) InvokePrivateMethod(otpInput, "GetStrokeThickness", index);
613-
Assert.Equal(expectedStrokeThickness, strokeThickness);
655+
Assert.Equal(expectedStrokeThickness, strokeThickness);
614656
}
615657

616658

617659
[Theory]
618-
[InlineData(0, 30f, 40f, 5f, 3f, 50f, false, 300f)]
660+
[InlineData(0, 30f, 40f, 5f, 3f, 50f, false, 300f)]
619661
[InlineData(1, 35f, 45f, 10f, 5f, 60f, false, 300f)]
620662
public void UpdateDrawingParameters(int index, float entryWidth, float entryHeight, float spacing, float extraSpacing, float lineLength, bool isRTL, float controlWidth)
621663
{
@@ -667,14 +709,14 @@ public void UpdateValue()
667709
var otpInput = new SfOtpInput();
668710
OTPEntry[]? _otpEntries = (OTPEntry[]?)GetPrivateField(otpInput, "_otpEntries");
669711

670-
string invalidInput = "12A4";
671-
InvokePrivateMethod(otpInput, "UpdateValue", otpInput, invalidInput);
712+
string invalidInput = "12A4";
713+
InvokePrivateMethod(otpInput, "UpdateValue", otpInput, invalidInput);
672714
Assert.Equal("1", _otpEntries?[0].Text);
673715
Assert.Equal("2", _otpEntries?[1].Text);
674-
Assert.Equal("", _otpEntries?[2].Text);
716+
Assert.Equal("", _otpEntries?[2].Text);
675717
Assert.Equal("4", _otpEntries?[3].Text);
676718

677-
otpInput.Type = OtpInputType.Password;
719+
otpInput.Type = OtpInputType.Password;
678720
string passwordInput = "1234";
679721
InvokePrivateMethod(otpInput, "UpdateValue", otpInput, passwordInput);
680722
if (_otpEntries != null)
@@ -696,7 +738,7 @@ public void UpdateEntriesLength(int initialLength, int newLength)
696738
InvokePrivateMethod(otpInput, "UpdateEntriesLength", initialLength, newLength);
697739
OTPEntry[]? _otpEntries = (OTPEntry[]?)GetPrivateField(otpInput, "_otpEntries");
698740
SetPrivateField(otpInput, "_otpEntries", _otpEntries);
699-
Assert.Equal(newLength, _otpEntries?.Length);
741+
Assert.Equal(newLength, _otpEntries?.Length);
700742
}
701743

702744
[Theory]
@@ -753,14 +795,14 @@ public void AddEntry(int initialLength,int newLength)
753795
int expectedSeparatorCount = newLength - 1;
754796
int actualSeparatorCount = layout.Children.OfType<SfLabel>().Count();
755797
Assert.Equal(expectedSeparatorCount, actualSeparatorCount);
756-
int expectedTotalChildren = newLength + expectedSeparatorCount;
798+
int expectedTotalChildren = newLength + expectedSeparatorCount;
757799
Assert.Equal(expectedTotalChildren, layout.Children.Count);
758800
}
759801

760802

761803
[Theory]
762-
[InlineData(0, 50f, 30f, 5f, 5f)]
763-
[InlineData(0, 60f, 40f, 10f, 10f)]
804+
[InlineData(0, 50f, 30f, 5f, 5f)]
805+
[InlineData(0, 60f, 40f, 10f, 10f)]
764806
public void SetInputFieldPosition(int index, float entryWidth, float entryHeight, float spacing, float extraSpacing)
765807
{
766808

@@ -777,22 +819,22 @@ public void SetInputFieldPosition(int index, float entryWidth, float entryHeight
777819
InvokePrivateMethod(otpInput, "SetInputFieldPosition", index, otpEntry);
778820

779821
RectF[]? entryBounds = (RectF[]?)GetPrivateField(otpInput, "_entryBounds");
780-
Assert.Equal(index + 1, entryBounds?.Length);
822+
Assert.Equal(index + 1, entryBounds?.Length);
781823

782824
var layoutBounds = AbsoluteLayout.GetLayoutBounds(otpEntry);
783825

784826
float expectedX = (entryWidth + spacing) * index + extraSpacing;
785827
float expectedY = extraSpacing;
786828

787-
Assert.Equal(expectedX, layoutBounds.X);
829+
Assert.Equal(expectedX, layoutBounds.X);
788830
Assert.Equal(expectedY, layoutBounds.Y);
789831
Assert.Equal(entryWidth, layoutBounds.Width);
790-
Assert.Equal(entryHeight, layoutBounds.Height);
832+
Assert.Equal(entryHeight, layoutBounds.Height);
791833
}
792834

793835
[Theory]
794-
[InlineData(0, 50f, 30f, 5f, 5f)]
795-
[InlineData(1, 60f, 40f, 10f, 10f)]
836+
[InlineData(0, 50f, 30f, 5f, 5f)]
837+
[InlineData(1, 60f, 40f, 10f, 10f)]
796838
public void SetSeparatorPosition(int index, float entryWidth, float entryHeight, float spacing, float separatorWidth)
797839
{
798840
var otpInput = new SfOtpInput();

0 commit comments

Comments
 (0)