diff --git a/src/Controls/src/Core/SearchBar/SearchBar.cs b/src/Controls/src/Core/SearchBar/SearchBar.cs index 18837b845b89..fbb593264ab2 100644 --- a/src/Controls/src/Core/SearchBar/SearchBar.cs +++ b/src/Controls/src/Core/SearchBar/SearchBar.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.Diagnostics; using System.Windows.Input; +using Microsoft.Maui.ApplicationModel; using Microsoft.Maui.Controls.Internals; using Microsoft.Maui.Graphics; @@ -115,6 +116,26 @@ public SearchBar() _platformConfigurationRegistry = new Lazy>(() => new PlatformConfigurationRegistry(this)); } + private protected override void OnHandlerChangingCore(HandlerChangingEventArgs args) + { + base.OnHandlerChangingCore(args); + + if (Application.Current == null) + return; + + if (args.NewHandler == null || args.OldHandler is not null) + Application.Current.RequestedThemeChanged -= OnRequestedThemeChanged; + if (args.NewHandler != null && args.OldHandler == null) + Application.Current.RequestedThemeChanged += OnRequestedThemeChanged; + } + + private void OnRequestedThemeChanged(object sender, AppThemeChangedEventArgs e) + { + OnPropertyChanged(nameof(PlaceholderColor)); + OnPropertyChanged(nameof(TextColor)); + OnPropertyChanged(nameof(CancelButtonColor)); + } + ICommand ICommandElement.Command => SearchCommand; object ICommandElement.CommandParameter => SearchCommandParameter; diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/PlaceholderColorShouldChange.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/PlaceholderColorShouldChange.png index 6efff9dea96e..f7c68bafbea9 100644 Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/PlaceholderColorShouldChange.png and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/PlaceholderColorShouldChange.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetFontAttributesAndPlaceholderText_VerifyVisualState.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetFontAttributesAndPlaceholderText_VerifyVisualState.png index 4997ea3e7160..61e933602632 100644 Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetFontAttributesAndPlaceholderText_VerifyVisualState.png and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetFontAttributesAndPlaceholderText_VerifyVisualState.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetFontFamilyAndPlaceholder_VerifyVisualState.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetFontFamilyAndPlaceholder_VerifyVisualState.png index 874fa16a1a8d..58c2155919d1 100644 Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetFontFamilyAndPlaceholder_VerifyVisualState.png and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetFontFamilyAndPlaceholder_VerifyVisualState.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetFontSizeAndPlaceholder_VerifyVisualState.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetFontSizeAndPlaceholder_VerifyVisualState.png index bf51cf3e96d2..a817e82c79b1 100644 Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetFontSizeAndPlaceholder_VerifyVisualState.png and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetFontSizeAndPlaceholder_VerifyVisualState.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetHorizontalTextAlignmentAndPlaceholder_VerifyVisualState.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetHorizontalTextAlignmentAndPlaceholder_VerifyVisualState.png index 82f04ae4b997..5c23cc616256 100644 Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetHorizontalTextAlignmentAndPlaceholder_VerifyVisualState.png and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetHorizontalTextAlignmentAndPlaceholder_VerifyVisualState.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetPlaceholderAndCharacterSpacing_VerifyVisualState.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetPlaceholderAndCharacterSpacing_VerifyVisualState.png index e41d95f505fb..d770b041b51f 100644 Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetPlaceholderAndCharacterSpacing_VerifyVisualState.png and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetPlaceholderAndCharacterSpacing_VerifyVisualState.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetPlaceholderAndVerticalTextAlignment_VerifyVisualState.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetPlaceholderAndVerticalTextAlignment_VerifyVisualState.png index e2432edde8ca..cdbcd1d46f09 100644 Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetPlaceholderAndVerticalTextAlignment_VerifyVisualState.png and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchBar_SetPlaceholderAndVerticalTextAlignment_VerifyVisualState.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchbarColorsShouldUpdate.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchbarColorsShouldUpdate.png new file mode 100644 index 000000000000..fff5a5e12649 Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SearchbarColorsShouldUpdate.png differ diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue30601.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue30601.cs new file mode 100644 index 000000000000..acd9c5bf0503 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue30601.cs @@ -0,0 +1,41 @@ +namespace Maui.Controls.Sample.Issues; + +[Issue(IssueTracker.Github, 30601, "[Android] SearchBar does not update colors on theme change", PlatformAffected.Android)] +public class Issue30601 : ContentPage +{ + public Issue30601() + { + var searchBar3 = new SearchBar + { + Placeholder = "Placeholder with AppThemeBinding - red/green" + }; + searchBar3.SetAppThemeColor(SearchBar.PlaceholderColorProperty, Colors.Red, Colors.Green); + this.SetAppThemeColor(BackgroundProperty, Colors.White, Colors.Black); + + Content = new StackLayout + { + Children = + { + new SearchBar + { + Placeholder = "Placeholder - system's default" + }, + new SearchBar + { + PlaceholderColor = Colors.Red, + Placeholder = "Placeholder - red" + }, + searchBar3, + new Button + { + Text = "Change Theme", + AutomationId = "changeThemeButton", + Command= new Command(() => + { + Application.Current!.UserAppTheme = Application.Current!.UserAppTheme != AppTheme.Dark ? AppTheme.Dark : AppTheme.Light; + }) + } + } + }; + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/SearchbarColorsShouldUpdate.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/SearchbarColorsShouldUpdate.png new file mode 100644 index 000000000000..f4ef9c4f7943 Binary files /dev/null and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/SearchbarColorsShouldUpdate.png differ diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30601.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30601.cs new file mode 100644 index 000000000000..1b892162da00 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30601.cs @@ -0,0 +1,21 @@ +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; + +public class Issue30601 : _IssuesUITest +{ + public Issue30601(TestDevice testDevice) : base(testDevice) { } + + public override string Issue => "[Android] SearchBar does not update colors on theme change"; + + [Test] + [Category(UITestCategories.SearchBar)] + public void SearchbarColorsShouldUpdate() + { + App.WaitForElement("changeThemeButton"); + App.Tap("changeThemeButton"); + VerifyScreenshot(); + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/SearchbarColorsShouldUpdate.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/SearchbarColorsShouldUpdate.png new file mode 100644 index 000000000000..df6bf62b627f Binary files /dev/null and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/SearchbarColorsShouldUpdate.png differ diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/SearchbarColorsShouldUpdate.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/SearchbarColorsShouldUpdate.png new file mode 100644 index 000000000000..4300b3756f63 Binary files /dev/null and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/SearchbarColorsShouldUpdate.png differ diff --git a/src/Core/src/Handlers/SearchBar/SearchBarHandler.Android.cs b/src/Core/src/Handlers/SearchBar/SearchBarHandler.Android.cs index e04b145e7c84..aef4b346caf2 100644 --- a/src/Core/src/Handlers/SearchBar/SearchBarHandler.Android.cs +++ b/src/Core/src/Handlers/SearchBar/SearchBarHandler.Android.cs @@ -112,6 +112,7 @@ public static void MapCharacterSpacing(ISearchBarHandler handler, ISearchBar sea public static void MapTextColor(ISearchBarHandler handler, ISearchBar searchBar) { handler.QueryEditor?.UpdateTextColor(searchBar); + handler.PlatformView?.UpdateTextColor(searchBar); } public static void MapIsTextPredictionEnabled(ISearchBarHandler handler, ISearchBar searchBar) diff --git a/src/Core/src/Platform/Android/SearchViewExtensions.cs b/src/Core/src/Platform/Android/SearchViewExtensions.cs index cdfe739f80bc..5308599fab4c 100644 --- a/src/Core/src/Platform/Android/SearchViewExtensions.cs +++ b/src/Core/src/Platform/Android/SearchViewExtensions.cs @@ -1,6 +1,11 @@ -using Android.Content.Res; +using System; +using Android.Content.Res; +using Android.Graphics; +using Android.Graphics.Drawables; using Android.Text; +using Android.Util; using Android.Widget; +using static Android.Content.Res.Resources; using SearchView = AndroidX.AppCompat.Widget.SearchView; namespace Microsoft.Maui.Platform @@ -21,22 +26,36 @@ public static void UpdatePlaceholderColor(this SearchView searchView, ISearchBar { editText ??= searchView.GetFirstChildOfType(); - if (editText == null) + if (editText is null) return; - var placeholderTextColor = searchBar.PlaceholderColor; - - if (placeholderTextColor == null) - { - editText.SetHintTextColor(defaultPlaceholderColor); - } - else + if (searchBar?.PlaceholderColor is Graphics.Color placeholderTextColor) { if (PlatformInterop.CreateEditTextColorStateList(editText.HintTextColors, placeholderTextColor.ToPlatform()) is ColorStateList c) { editText.SetHintTextColor(c); } } + else if (TryGetDefaultStateColor(searchView, Android.Resource.Attribute.TextColorHint, out var color)) + { + editText.SetHintTextColor(color); + + var searchMagIconImage = searchView.FindViewById(Resource.Id.search_mag_icon); + searchMagIconImage?.Drawable?.SetTint(color); + } + } + + internal static void UpdateTextColor(this SearchView searchView, ITextStyle entry) + { + if (TryGetDefaultStateColor(searchView, Android.Resource.Attribute.TextColorPrimary, out var color) && + searchView.GetFirstChildOfType() is EditText editText) + { + if (entry.TextColor is null) + editText.SetTextColor(color); + + var searchMagIconImage = searchView.FindViewById(Resource.Id.search_mag_icon); + searchMagIconImage?.Drawable?.SetTint(color); + } } public static void UpdateFont(this SearchView searchView, ISearchBar searchBar, IFontManager fontManager, EditText? editText = null) @@ -108,12 +127,12 @@ public static void UpdateCancelButtonColor(this SearchView searchView, ISearchBa { var image = searchView.FindViewById(searchCloseButtonIdentifier); - if (image != null && image.Drawable != null) + if (image is not null && image.Drawable is Drawable drawable) { - if (searchBar.CancelButtonColor != null) - image.Drawable.SetColorFilter(searchBar.CancelButtonColor, FilterMode.SrcIn); - else - image.Drawable.ClearColorFilter(); + if (searchBar.CancelButtonColor is not null) + drawable.SetColorFilter(searchBar.CancelButtonColor, FilterMode.SrcIn); + else if (TryGetDefaultStateColor(searchView, Android.Resource.Attribute.TextColorPrimary, out var color)) + drawable.SetColorFilter(color, FilterMode.SrcIn); } } } @@ -171,5 +190,28 @@ internal static void SetInputType(this SearchView searchView, ISearchBar searchB editText.SetInputType(searchBar); } + + static bool TryGetDefaultStateColor(SearchView searchView, int attribute, out Color color) + { + color = default; + + if (!OperatingSystem.IsAndroidVersionAtLeast(23)) + return false; + + if (searchView.Context?.Theme is not Theme theme) + return false; + + int[] s_disabledState = [-Android.Resource.Attribute.StateEnabled]; + int[] s_enabledState = [Android.Resource.Attribute.StateEnabled]; + + using var ta = theme.ObtainStyledAttributes([attribute]); + var cs = ta.GetColorStateList(0); + if (cs is null) + return false; + + var state = searchView.Enabled ? s_enabledState : s_disabledState; + color = new Color(cs.GetColorForState(state, Color.Black)); + return true; + } } } \ No newline at end of file