diff --git a/eng/pipelines/ci-device-tests.yml b/eng/pipelines/ci-device-tests.yml index 1547831fb642..d33cf5b4e7e4 100644 --- a/eng/pipelines/ci-device-tests.yml +++ b/eng/pipelines/ci-device-tests.yml @@ -5,6 +5,7 @@ trigger: - release/* - net*.0 - inflight/* + - darc-* tags: include: - '*' diff --git a/eng/pipelines/ci-uitests.yml b/eng/pipelines/ci-uitests.yml index c3b6ace38f43..7e16e1733d75 100644 --- a/eng/pipelines/ci-uitests.yml +++ b/eng/pipelines/ci-uitests.yml @@ -5,6 +5,7 @@ trigger: - release/* - net*.0 - inflight/* + - darc-* tags: include: - '*' diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SliderShouldChangeThumbImageAndResetIt.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SliderShouldChangeThumbImageAndResetIt.png index 9c7bdee2fb6d..d0fc26d2309c 100644 Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SliderShouldChangeThumbImageAndResetIt.png and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SliderShouldChangeThumbImageAndResetIt.png differ diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SliderThumbImageShouldBeScaled.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SliderThumbImageShouldBeScaled.png new file mode 100644 index 000000000000..00ddb986bfde Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/SliderThumbImageShouldBeScaled.png differ diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue13258.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue13258.cs new file mode 100644 index 000000000000..ade96442da2e --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue13258.cs @@ -0,0 +1,51 @@ +namespace Maui.Controls.Sample.Issues; + +[Issue(IssueTracker.Github, 13258, "MAUI Slider thumb image is big on android", PlatformAffected.Android)] +public class Issue13258 : TestContentPage +{ + protected override void Init() + { + StackLayout rootLayout = new StackLayout() { Spacing = 10, Padding = 10 }; + + Label slider1DescriptionLabel = CreateLabel("Slider with Thumb Image"); + Slider slider1 = CreateSlider("avatar.png"); + + Label slider2DescriptionLabel = CreateLabel("Thumb Image will be set to coffee.png at run time"); + Slider slider2 = CreateSlider(); + + Label slider3DescriptionLabel = CreateLabel("Thumb Image will be set to null at run time"); + Slider slider3 = CreateSlider("shopping_cart.png"); + + Button button = new Button() { Text = "Change Thumb Image", AutomationId = "ToggleImageBtn" }; + button.Clicked += (s, e) => ToggleThumbImages(slider2, slider3); + + rootLayout.Children.Add(slider1DescriptionLabel); + rootLayout.Children.Add(slider1); + + rootLayout.Children.Add(slider2DescriptionLabel); + rootLayout.Children.Add(slider2); + + rootLayout.Children.Add(slider3DescriptionLabel); + rootLayout.Children.Add(slider3); + + rootLayout.Children.Add(button); + + Content = rootLayout; + } + + Label CreateLabel(string text) + { + return new Label { Text = text }; + } + + Slider CreateSlider(string thumbImageSource = null) + { + return new Slider { ThumbImageSource = thumbImageSource }; + } + + private void ToggleThumbImages(Slider slider2, Slider slider3) + { + slider2.ThumbImageSource = "coffee.png"; + slider3.ThumbImageSource = null; + } +} diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue13258.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue13258.cs new file mode 100644 index 000000000000..97252542761d --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue13258.cs @@ -0,0 +1,25 @@ +#if TEST_FAILS_ON_WINDOWS && TEST_FAILS_ON_IOS && TEST_FAILS_ON_CATALYST //Window issue link - https://github.com/dotnet/maui/issues/29125 && iOS and Mac PR - https://github.com/dotnet/maui/pull/34184 +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; + +public class Issue13258 : _IssuesUITest +{ + public Issue13258(TestDevice testDevice) : base(testDevice) + { + } + + public override string Issue => "MAUI Slider thumb image is big on android"; + + [Test] + [Category(UITestCategories.Slider)] + public void SliderThumbImageShouldBeScaled() + { + App.WaitForElement("ToggleImageBtn"); + App.Tap("ToggleImageBtn"); + VerifyScreenshot(); + } +} +#endif diff --git a/src/Core/src/Platform/Android/SliderExtensions.cs b/src/Core/src/Platform/Android/SliderExtensions.cs index 720d3eb0e3b5..09932dcd7b78 100644 --- a/src/Core/src/Platform/Android/SliderExtensions.cs +++ b/src/Core/src/Platform/Android/SliderExtensions.cs @@ -1,6 +1,8 @@ using System.Threading.Tasks; +using Android.Content; using Android.Content.Res; using Android.Graphics; +using Android.Graphics.Drawables; using Android.Util; using Android.Widget; @@ -10,6 +12,11 @@ public static class SliderExtensions { public const double PlatformMaxValue = int.MaxValue; + //Material 2 design spec - https://m2.material.io/components/sliders/android#discrete-slider + //Additional info - https://github.com/material-components/material-components-android/blob/60b0325b39741784fca4d7aba079b65453bc7c66/lib/java/com/google/android/material/slider/res/values/dimens.xml#L27 + // Thumb diameter per Material Design spec: https://m2.material.io/components/sliders + const int ThumbDiameterDp = 20; + public static void UpdateMinimum(this SeekBar seekBar, ISlider slider) => UpdateValue(seekBar, slider); public static void UpdateMaximum(this SeekBar seekBar, ISlider slider) => UpdateValue(seekBar, slider); @@ -25,7 +32,7 @@ public static void UpdateValue(this SeekBar seekBar, ISlider slider) public static void UpdateMinimumTrackColor(this SeekBar seekBar, ISlider slider) { - if (slider.MinimumTrackColor != null) + if (slider.MinimumTrackColor is not null) { seekBar.ProgressTintList = ColorStateList.ValueOf(slider.MinimumTrackColor.ToPlatform()); seekBar.ProgressTintMode = PorterDuff.Mode.SrcIn; @@ -34,7 +41,7 @@ public static void UpdateMinimumTrackColor(this SeekBar seekBar, ISlider slider) public static void UpdateMaximumTrackColor(this SeekBar seekBar, ISlider slider) { - if (slider.MaximumTrackColor != null) + if (slider.MaximumTrackColor is not null) { seekBar.ProgressBackgroundTintList = ColorStateList.ValueOf(slider.MaximumTrackColor.ToPlatform()); seekBar.ProgressBackgroundTintMode = PorterDuff.Mode.SrcIn; @@ -47,37 +54,74 @@ public static void UpdateThumbColor(this SeekBar seekBar, ISlider slider) => public static async Task UpdateThumbImageSourceAsync(this SeekBar seekBar, ISlider slider, IImageSourceServiceProvider provider) { var context = seekBar.Context; - - if (context == null) + if (context is null) + { return; + } var thumbImageSource = slider.ThumbImageSource; - - if (thumbImageSource != null) + if (thumbImageSource is not null) { var service = provider.GetRequiredImageSourceService(thumbImageSource); var result = await service.GetDrawableAsync(thumbImageSource, context); - var thumbDrawable = result?.Value; - if (seekBar.IsAlive() && thumbDrawable != null) - seekBar.SetThumb(thumbDrawable); + if (seekBar.IsAlive()) + { + if (thumbDrawable is not null) + { + SetThumbDrawable(seekBar, context, thumbDrawable); + } + else + { + SetDefaultThumb(seekBar, slider, context); + } + } } else { - seekBar.SetThumb(context.GetDrawable(Resource.Drawable.abc_seekbar_thumb_material)); - if (slider.ThumbColor is null && context.Theme is not null) + SetDefaultThumb(seekBar, slider, context); + } + } + + static void SetThumbDrawable(SeekBar seekBar, Context context, Drawable thumbDrawable) + { + int thumbSize = (int)context.ToPixels(ThumbDiameterDp); + + if (thumbSize <= 0) + { + return; + } + + using (Bitmap bitmap = Bitmap.CreateBitmap(thumbSize, thumbSize, Bitmap.Config.Argb8888!)) + using (Canvas canvas = new Canvas(bitmap)) + { + thumbDrawable.SetBounds(0, 0, thumbSize, thumbSize); + thumbDrawable.Draw(canvas); + + using (BitmapDrawable finalDrawable = new BitmapDrawable(context.Resources, bitmap)) { - using var value = new TypedValue(); - context.Theme.ResolveAttribute(global::Android.Resource.Attribute.ColorAccent, value, true); - var color = new Color(value.Data); - seekBar.Thumb?.SetColorFilter(color, FilterMode.SrcIn); + seekBar.SetThumb(finalDrawable); } - else + } + } + + static void SetDefaultThumb(SeekBar seekBar, ISlider slider, Context context) + { + seekBar.SetThumb(context.GetDrawable(Resource.Drawable.abc_seekbar_thumb_material)); + + if (slider.ThumbColor is null && context.Theme is not null) + { + using var value = new TypedValue(); + if (context.Theme.ResolveAttribute(global::Android.Resource.Attribute.ColorAccent, value, true)) { - seekBar.UpdateThumbColor(slider); + seekBar.Thumb?.SetColorFilter(new Color(value.Data), FilterMode.SrcIn); } } + else + { + seekBar.UpdateThumbColor(slider); + } } } -} \ No newline at end of file +}