diff --git a/src/Compatibility/Core/src/Android/Renderers/SearchBarRenderer.cs b/src/Compatibility/Core/src/Android/Renderers/SearchBarRenderer.cs index b19102fbcf0b..9bfc7433073c 100644 --- a/src/Compatibility/Core/src/Android/Renderers/SearchBarRenderer.cs +++ b/src/Compatibility/Core/src/Android/Renderers/SearchBarRenderer.cs @@ -253,6 +253,7 @@ void UpdatePlaceholderColor() _hintColorSwitcher?.UpdateTextColor(_editText, Element.PlaceholderColor, _editText.SetHintTextColor); } + [PortHandler] void UpdateText() { string query = Control.Query; diff --git a/src/Compatibility/Core/src/iOS/Renderers/SearchBarRenderer.cs b/src/Compatibility/Core/src/iOS/Renderers/SearchBarRenderer.cs index c2fc69df95b2..ae1875fdc416 100644 --- a/src/Compatibility/Core/src/iOS/Renderers/SearchBarRenderer.cs +++ b/src/Compatibility/Core/src/iOS/Renderers/SearchBarRenderer.cs @@ -332,6 +332,7 @@ void UpdatePlaceholder() } } + [PortHandler] void UpdateText() { // There is at least one scenario where modifying the Element's Text value from TextChanged diff --git a/src/Controls/samples/Controls.Sample/Pages/MainPage.cs b/src/Controls/samples/Controls.Sample/Pages/MainPage.cs index 9eccf3596909..040898142e5c 100644 --- a/src/Controls/samples/Controls.Sample/Pages/MainPage.cs +++ b/src/Controls/samples/Controls.Sample/Pages/MainPage.cs @@ -27,6 +27,10 @@ void SetupMauiLayout() var verticalStack = new VerticalStackLayout() { Spacing = 5, BackgroundColor = Color.AntiqueWhite }; var horizontalStack = new HorizontalStackLayout() { Spacing = 2, BackgroundColor = Color.CornflowerBlue }; + var searchBar = new SearchBar(); + searchBar.Text = "A search query"; + verticalStack.Add(searchBar); + var label = new Label { Text = "This will disappear in ~5 seconds", BackgroundColor = Color.Fuchsia }; label.Margin = new Thickness(15, 10, 20, 15); diff --git a/src/Core/src/Core/ISearchBar.cs b/src/Core/src/Core/ISearchBar.cs new file mode 100644 index 000000000000..13aad57093b5 --- /dev/null +++ b/src/Core/src/Core/ISearchBar.cs @@ -0,0 +1,7 @@ +namespace Microsoft.Maui +{ + public interface ISearchBar : IView + { + string Text { get; } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/Label/LabelHandler.Android.cs b/src/Core/src/Handlers/Label/LabelHandler.Android.cs index d3ab7caedfb4..2ffa4df38991 100644 --- a/src/Core/src/Handlers/Label/LabelHandler.Android.cs +++ b/src/Core/src/Handlers/Label/LabelHandler.Android.cs @@ -47,7 +47,7 @@ public static void MapTextDecorations(LabelHandler handler, ILabel label) handler.TypedNativeView?.UpdateTextDecorations(label); } - static void MapFont(LabelHandler handler, ILabel label) + public static void MapFont(LabelHandler handler, ILabel label) { var services = App.Current?.Services ?? throw new InvalidOperationException($"Unable to find service provider, the App.Current.Services was null."); diff --git a/src/Core/src/Handlers/Label/LabelHandler.iOS.cs b/src/Core/src/Handlers/Label/LabelHandler.iOS.cs index 9d01c73f8482..a32f2cb0435b 100644 --- a/src/Core/src/Handlers/Label/LabelHandler.iOS.cs +++ b/src/Core/src/Handlers/Label/LabelHandler.iOS.cs @@ -33,7 +33,7 @@ public static void MapTextDecorations(LabelHandler handler, ILabel label) handler.TypedNativeView?.UpdateTextDecorations(label); } - static void MapFont(LabelHandler handler, ILabel label) + public static void MapFont(LabelHandler handler, ILabel label) { var services = App.Current?.Services ?? throw new InvalidOperationException($"Unable to find service provider, the App.Current.Services was null."); diff --git a/src/Core/src/Handlers/SearchBar/SearchBarHandler.Android.cs b/src/Core/src/Handlers/SearchBar/SearchBarHandler.Android.cs new file mode 100644 index 000000000000..708f1756fa63 --- /dev/null +++ b/src/Core/src/Handlers/SearchBar/SearchBarHandler.Android.cs @@ -0,0 +1,17 @@ +using AndroidX.AppCompat.Widget; + +namespace Microsoft.Maui.Handlers +{ + public partial class SearchBarHandler : AbstractViewHandler + { + protected override SearchView CreateNativeView() + { + return new SearchView(Context); + } + + public static void MapText(SearchBarHandler handler, ISearchBar searchBar) + { + handler.TypedNativeView?.UpdateText(searchBar); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/SearchBar/SearchBarHandler.Standard.cs b/src/Core/src/Handlers/SearchBar/SearchBarHandler.Standard.cs new file mode 100644 index 000000000000..d92b9fa6876b --- /dev/null +++ b/src/Core/src/Handlers/SearchBar/SearchBarHandler.Standard.cs @@ -0,0 +1,11 @@ +using System; + +namespace Microsoft.Maui.Handlers +{ + public partial class SearchBarHandler : AbstractViewHandler + { + protected override object CreateNativeView() => throw new NotImplementedException(); + + public static void MapText(IViewHandler handler, ISearchBar searchBar) { } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/SearchBar/SearchBarHandler.cs b/src/Core/src/Handlers/SearchBar/SearchBarHandler.cs new file mode 100644 index 000000000000..7668efd77355 --- /dev/null +++ b/src/Core/src/Handlers/SearchBar/SearchBarHandler.cs @@ -0,0 +1,20 @@ +namespace Microsoft.Maui.Handlers +{ + public partial class SearchBarHandler + { + public static PropertyMapper SearchBarMapper = new PropertyMapper(ViewHandler.ViewMapper) + { + [nameof(ISearchBar.Text)] = MapText + }; + + public SearchBarHandler() : base(SearchBarMapper) + { + + } + + public SearchBarHandler(PropertyMapper mapper) : base(mapper ?? SearchBarMapper) + { + + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/SearchBar/SearchBarHandler.iOS.cs b/src/Core/src/Handlers/SearchBar/SearchBarHandler.iOS.cs new file mode 100644 index 000000000000..532e09eb7d7f --- /dev/null +++ b/src/Core/src/Handlers/SearchBar/SearchBarHandler.iOS.cs @@ -0,0 +1,15 @@ +using System; +using UIKit; + +namespace Microsoft.Maui.Handlers +{ + public partial class SearchBarHandler : AbstractViewHandler + { + protected override UISearchBar CreateNativeView() => new UISearchBar(); + + public static void MapText(SearchBarHandler handler, ISearchBar searchBar) + { + handler.TypedNativeView?.UpdateText(searchBar); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Android/SearchBarExtensions.cs b/src/Core/src/Platform/Android/SearchBarExtensions.cs new file mode 100644 index 000000000000..c4cbb9f57613 --- /dev/null +++ b/src/Core/src/Platform/Android/SearchBarExtensions.cs @@ -0,0 +1,12 @@ +using AndroidX.AppCompat.Widget; + +namespace Microsoft.Maui +{ + public static class SearchBarExtensions + { + public static void UpdateText(this SearchView searchView, ISearchBar searchBar) + { + searchView.SetQuery(searchBar.Text, false); + } + } +} diff --git a/src/Core/src/Platform/iOS/SearchBarExtensions.cs b/src/Core/src/Platform/iOS/SearchBarExtensions.cs new file mode 100644 index 000000000000..4cbed819a14f --- /dev/null +++ b/src/Core/src/Platform/iOS/SearchBarExtensions.cs @@ -0,0 +1,12 @@ +using UIKit; + +namespace Microsoft.Maui +{ + public static class SearchBarExtensions + { + public static void UpdateText(this UISearchBar uiSearchBar, ISearchBar searchBar) + { + uiSearchBar.Text = searchBar.Text; + } + } +} \ No newline at end of file diff --git a/src/Core/tests/DeviceTests/Handlers/SearchBar/SearchBarHandlerTests.Android.cs b/src/Core/tests/DeviceTests/Handlers/SearchBar/SearchBarHandlerTests.Android.cs new file mode 100644 index 000000000000..feb62e40be8a --- /dev/null +++ b/src/Core/tests/DeviceTests/Handlers/SearchBar/SearchBarHandlerTests.Android.cs @@ -0,0 +1,15 @@ +using Android.Widget; +using Microsoft.Maui.Handlers; +using SearchView = AndroidX.AppCompat.Widget.SearchView; + +namespace Microsoft.Maui.DeviceTests +{ + public partial class SearchBarHandlerTests + { + SearchView GetNativeSearchBar(SearchBarHandler searchBarHandler) => + (SearchView)searchBarHandler.View; + + string GetNativeText(SearchBarHandler searchBarHandler) => + GetNativeSearchBar(searchBarHandler).Query; + } +} \ No newline at end of file diff --git a/src/Core/tests/DeviceTests/Handlers/SearchBar/SearchBarHandlerTests.cs b/src/Core/tests/DeviceTests/Handlers/SearchBar/SearchBarHandlerTests.cs new file mode 100644 index 000000000000..ce5256f6e317 --- /dev/null +++ b/src/Core/tests/DeviceTests/Handlers/SearchBar/SearchBarHandlerTests.cs @@ -0,0 +1,49 @@ +using System.Threading.Tasks; +using Microsoft.Maui.DeviceTests.Stubs; +using Microsoft.Maui.Handlers; +using Xunit; + +namespace Microsoft.Maui.DeviceTests +{ + [Category(TestCategory.SearchBar)] + public partial class SearchBarHandlerTests : HandlerTestBase + { + public SearchBarHandlerTests(HandlerTestFixture fixture) : base(fixture) + { + } + + [Fact(DisplayName = "Text Initializes Correctly")] + public async Task TextInitializesCorrectly() + { + var searchBar = new SearchBarStub + { + Text = "Test" + }; + + await ValidatePropertyInitValue(searchBar, () => searchBar.Text, GetNativeText, searchBar.Text); + } + + [Theory(DisplayName = "Query Text Updates Correctly")] + [InlineData(null, null)] + [InlineData(null, "Query")] + [InlineData("Query", null)] + [InlineData("Query", "Another search query")] + public async Task TextUpdatesCorrectly(string setValue, string unsetValue) + { + var searchBar = new SearchBarStub(); + + await ValidatePropertyUpdatesValue( + searchBar, + nameof(ISearchBar.Text), + h => + { + var n = GetNativeText(h); + if (string.IsNullOrEmpty(n)) + n = null; // native platforms may not support null text + return n; + }, + setValue, + unsetValue); + } + } +} diff --git a/src/Core/tests/DeviceTests/Handlers/SearchBar/SearchBarHandlerTests.iOS.cs b/src/Core/tests/DeviceTests/Handlers/SearchBar/SearchBarHandlerTests.iOS.cs new file mode 100644 index 000000000000..17fa1fe8944e --- /dev/null +++ b/src/Core/tests/DeviceTests/Handlers/SearchBar/SearchBarHandlerTests.iOS.cs @@ -0,0 +1,14 @@ +using Microsoft.Maui.Handlers; +using UIKit; + +namespace Microsoft.Maui.DeviceTests +{ + public partial class SearchBarHandlerTests + { + UISearchBar GetNativeEntry(SearchBarHandler searchBarHandler) => + (UISearchBar)searchBarHandler.View; + + string GetNativeText(SearchBarHandler searchBarHandler) => + GetNativeEntry(searchBarHandler).Text; + } +} \ No newline at end of file diff --git a/src/Core/tests/DeviceTests/Stubs/SearchBarStub.cs b/src/Core/tests/DeviceTests/Stubs/SearchBarStub.cs new file mode 100644 index 000000000000..7e96be38c2f9 --- /dev/null +++ b/src/Core/tests/DeviceTests/Stubs/SearchBarStub.cs @@ -0,0 +1,9 @@ +namespace Microsoft.Maui.DeviceTests.Stubs +{ + public partial class SearchBarStub : StubBase, ISearchBar + { + private string _text; + + public string Text { get => _text; set => SetProperty(ref _text, value); } + } +} \ No newline at end of file diff --git a/src/Core/tests/DeviceTests/TestCategory.cs b/src/Core/tests/DeviceTests/TestCategory.cs index 0eccd1a3cc3b..e6b89c964433 100644 --- a/src/Core/tests/DeviceTests/TestCategory.cs +++ b/src/Core/tests/DeviceTests/TestCategory.cs @@ -7,6 +7,7 @@ public static class TestCategory public const string Entry = "Entry"; public const string Label = "Label"; public const string Layout = "Layout"; + public const string SearchBar = "SearchBar"; public const string Slider = "Slider"; public const string Switch = "Switch"; }