Skip to content

Commit

Permalink
ActivityIndicator Handlers (#417)
Browse files Browse the repository at this point in the history
* ActivityIndicatorHandler

* Register IActivityIndicator

* Add comments to IActivityIndicator

* Fix build error
  • Loading branch information
jsuarezruiz authored and hartez committed Mar 17, 2021
1 parent e0a563d commit 205573e
Show file tree
Hide file tree
Showing 19 changed files with 296 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public ActivityIndicatorRenderer(Context context) : base(context)
AutoPackage = false;
}

[PortHandler]
protected override AProgressBar CreateNativeControl()
{
return new AProgressBar(Context) { Indeterminate = true };
Expand Down Expand Up @@ -42,6 +43,7 @@ protected override void OnElementPropertyChanged(object sender, PropertyChangedE
UpdateColor();
}

[PortHandler]
void UpdateColor()
{
if (Element == null || Control == null)
Expand All @@ -55,6 +57,7 @@ void UpdateColor()
Control.IndeterminateDrawable?.ClearColorFilter();
}

[PortHandler]
void UpdateVisibility()
{
if (Element == null || Control == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace Microsoft.Maui.Controls.Compatibility.Platform.iOS
{
[PortHandler]
public sealed class UIActivityIndicatorViewDelegate : UIActivityIndicatorView
{
ActivityIndicator _element;
Expand Down Expand Up @@ -40,6 +41,7 @@ public ActivityIndicatorRenderer()

}

[PortHandler]
protected override void OnElementChanged(ElementChangedEventArgs<ActivityIndicator> e)
{
if (e.NewElement != null)
Expand Down Expand Up @@ -69,11 +71,13 @@ protected override void OnElementPropertyChanged(object sender, PropertyChangedE
UpdateIsRunning();
}

[PortHandler]
void UpdateColor()
{
Control.Color = Element.Color == Color.Default ? null : Element.Color.ToUIColor();
}

[PortHandler]
void UpdateIsRunning()
{
if (Control?.Superview == null)
Expand Down
2 changes: 2 additions & 0 deletions src/Controls/samples/Controls.Sample/Pages/MainPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ void SetupMauiLayout()
var underlineLabel = new Label { Text = "underline", TextDecorations = TextDecorations.Underline };
verticalStack.Add(underlineLabel);

verticalStack.Add(new ActivityIndicator());
verticalStack.Add(new ActivityIndicator { Color = Color.Red, IsRunning = true });

var button = new Button() { Text = _viewModel.Text, WidthRequest = 200 };
var button2 = new Button()
Expand Down
2 changes: 1 addition & 1 deletion src/Controls/src/Core/ActivityIndicator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Microsoft.Maui.Controls
{
public class ActivityIndicator : View, IColorElement, IElementConfiguration<ActivityIndicator>
public partial class ActivityIndicator : View, IColorElement, IElementConfiguration<ActivityIndicator>
{
public static readonly BindableProperty IsRunningProperty = BindableProperty.Create("IsRunning", typeof(bool), typeof(ActivityIndicator), default(bool));

Expand Down
7 changes: 7 additions & 0 deletions src/Controls/src/Core/HandlerImpl/ActivityIndicator.Impl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Microsoft.Maui.Controls
{
public partial class ActivityIndicator : IActivityIndicator
{

}
}
20 changes: 20 additions & 0 deletions src/Core/src/Core/IActivityIndicator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Microsoft.Maui
{
/// <summary>
/// Represents a View that displays an animation to show that the application is engaged
/// in a lengthy activity.
/// </summary>
public interface IActivityIndicator : IView
{
/// <summary>
/// Gets a value that indicates whether the ActivityIndicator should be visible and animating,
/// or hidden.
/// </summary>
bool IsRunning { get; }

/// <summary>
/// Gets a Color value that defines the display color.
/// </summary>
Color Color { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Android.Widget;

namespace Microsoft.Maui.Handlers
{
public partial class ActivityIndicatorHandler : AbstractViewHandler<IActivityIndicator, ProgressBar>
{
protected override ProgressBar CreateNativeView() => new ProgressBar(Context) { Indeterminate = true };
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System;

namespace Microsoft.Maui.Handlers
{
public partial class ActivityIndicatorHandler : AbstractViewHandler<IActivityIndicator, object>
{
protected override object CreateNativeView() => throw new NotImplementedException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace Microsoft.Maui.Handlers
{
public partial class ActivityIndicatorHandler
{
public static PropertyMapper<IActivityIndicator, ActivityIndicatorHandler> ActivityIndicatorMapper = new PropertyMapper<IActivityIndicator, ActivityIndicatorHandler>(ViewHandler.ViewMapper)
{
[nameof(IActivityIndicator.IsRunning)] = MapIsRunning,
[nameof(IActivityIndicator.Color)] = MapColor
};

public static void MapIsRunning(ActivityIndicatorHandler handler, IActivityIndicator activityIndicator)
{
handler.TypedNativeView?.UpdateIsRunning(activityIndicator);
}

public static void MapColor(ActivityIndicatorHandler handler, IActivityIndicator activityIndicator)
{
handler.TypedNativeView?.UpdateColor(activityIndicator);
}

public ActivityIndicatorHandler() : base(ActivityIndicatorMapper)
{

}

public ActivityIndicatorHandler(PropertyMapper mapper) : base(mapper ?? ActivityIndicatorMapper)
{

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using CoreGraphics;
using UIKit;

namespace Microsoft.Maui.Handlers
{
public partial class ActivityIndicatorHandler : AbstractViewHandler<IActivityIndicator, NativeActivityIndicator>
{
protected override NativeActivityIndicator CreateNativeView() => new NativeActivityIndicator(CGRect.Empty, VirtualView)
{
ActivityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
};
}
}
1 change: 1 addition & 0 deletions src/Core/src/Hosting/AppHostBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public static IAppHostBuilder UseMauiHandlers(this IAppHostBuilder builder)
{
builder.RegisterHandlers(new Dictionary<Type, Type>
{
{ typeof(IActivityIndicator), typeof(ActivityIndicatorHandler) },
{ typeof(IButton), typeof(ButtonHandler) },
{ typeof(ICheckBox), typeof(CheckBoxHandler) },
{ typeof(IEditor), typeof(EditorHandler) },
Expand Down
21 changes: 21 additions & 0 deletions src/Core/src/Platform/Android/ActivityIndicatorExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Android.Views;
using Android.Widget;

namespace Microsoft.Maui
{
public static class ActivityIndicatorExtensions
{
public static void UpdateIsRunning(this ProgressBar progressBar, IActivityIndicator activityIndicator) =>
progressBar.Visibility = activityIndicator.IsRunning ? ViewStates.Visible : ViewStates.Invisible;

public static void UpdateColor(this ProgressBar progressBar, IActivityIndicator activityIndicator)
{
Color color = activityIndicator.Color;

if (!color.IsDefault)
progressBar.IndeterminateDrawable?.SetColorFilter(color.ToNative(), FilterMode.SrcIn);
else
progressBar.IndeterminateDrawable?.ClearColorFilter();
}
}
}
15 changes: 15 additions & 0 deletions src/Core/src/Platform/Standard/ActivityIndicatorExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Microsoft.Maui
{
public static class ActivityIndicatorExtensions
{
public static void UpdateIsRunning(this object nothing, IActivityIndicator activityIndicator)
{

}

public static void UpdateColor(this object nothing, IActivityIndicator activityIndicator)
{

}
}
}
18 changes: 18 additions & 0 deletions src/Core/src/Platform/iOS/ActivityIndicatorExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Microsoft.Maui
{
public static class ActivityIndicatorExtensions
{
public static void UpdateIsRunning(this NativeActivityIndicator activityIndicatorView, IActivityIndicator activityIndicator)
{
if (activityIndicator.IsRunning)
activityIndicatorView.StartAnimating();
else
activityIndicatorView.StopAnimating();
}

public static void UpdateColor(this NativeActivityIndicator activityIndicatorView, IActivityIndicator activityIndicator)
{
activityIndicatorView.Color = activityIndicator.Color == Color.Default ? null : activityIndicator.Color.ToNative();
}
}
}
35 changes: 35 additions & 0 deletions src/Core/src/Platform/iOS/NativeActivityIndicator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using CoreGraphics;
using UIKit;

namespace Microsoft.Maui
{
public class NativeActivityIndicator : UIActivityIndicatorView
{
IActivityIndicator? _virtualView;

public NativeActivityIndicator(CGRect rect, IActivityIndicator? virtualView) : base(rect)
=> _virtualView = virtualView;

public override void Draw(CGRect rect)
{
base.Draw(rect);

if (_virtualView?.IsRunning == true)
StartAnimating();
}

public override void LayoutSubviews()
{
base.LayoutSubviews();

if (_virtualView?.IsRunning == true)
StartAnimating();
}

protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_virtualView = null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using System.Threading.Tasks;
using Android.Views;
using Android.Widget;
using Microsoft.Maui.Handlers;

namespace Microsoft.Maui.DeviceTests
{
public partial class ActivityIndicatorHandlerTests
{
ProgressBar GetNativeActivityIndicator(ActivityIndicatorHandler activityIndicatorHandler) =>
(ProgressBar)activityIndicatorHandler.View;

bool GetNativeIsRunning(ActivityIndicatorHandler activityIndicatorHandler) =>
GetNativeActivityIndicator(activityIndicatorHandler).Visibility == ViewStates.Visible;

Task ValidateColor(IActivityIndicator activityIndicator, Color color, Action action = null) =>
ValidateHasColor(activityIndicator, color, action);

Task ValidateHasColor(IActivityIndicator activityIndicator, Color color, Action action = null)
{
return InvokeOnMainThreadAsync(() =>
{
var nativeActivityIndicator = GetNativeActivityIndicator(CreateHandler(activityIndicator));
action?.Invoke();
nativeActivityIndicator.AssertContainsColor(color);
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.Threading.Tasks;
using Microsoft.Maui.DeviceTests.Stubs;
using Microsoft.Maui.Handlers;
using Xunit;

namespace Microsoft.Maui.DeviceTests
{
[Category("ActivityIndicatorHandler")]
public partial class ActivityIndicatorHandlerTests : HandlerTestBase<ActivityIndicatorHandler, ActivityIndicatorStub>
{
public ActivityIndicatorHandlerTests(HandlerTestFixture fixture) : base(fixture)
{
}

[Theory(DisplayName = "IsRunning Initializes Correctly")]
[InlineData(true)]
[InlineData(false)]
public async Task IsRunningInitializesCorrectly(bool isRunning)
{
var activityIndicator = new ActivityIndicatorStub()
{
IsRunning = isRunning
};

await ValidatePropertyInitValue(activityIndicator, () => activityIndicator.IsRunning, GetNativeIsRunning, activityIndicator.IsRunning);
}

[Fact(DisplayName = "BackgroundColor Updates Correctly")]
public async Task BackgroundColorUpdatesCorrectly()
{
var activityIndicator = new ActivityIndicatorStub()
{
BackgroundColor = Color.Yellow,
IsRunning = true
};

await ValidateColor(activityIndicator, Color.Yellow, () => activityIndicator.BackgroundColor = Color.Yellow);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Threading.Tasks;
using Microsoft.Maui.Handlers;
using UIKit;
using Xunit;

namespace Microsoft.Maui.DeviceTests
{
public partial class ActivityIndicatorHandlerTests
{
UIActivityIndicatorView GetNativeActivityIndicator(ActivityIndicatorHandler activityIndicatorHandler) =>
(UIActivityIndicatorView)activityIndicatorHandler.View;

bool GetNativeIsRunning(ActivityIndicatorHandler activityIndicatorHandler) =>
GetNativeActivityIndicator(activityIndicatorHandler).IsAnimating;

async Task ValidateColor(IActivityIndicator activityIndicator, Color color, Action action = null)
{
var expected = await GetValueAsync(activityIndicator, handler =>
{
var native = GetNativeActivityIndicator(handler);
action?.Invoke();
return native.BackgroundColor.ToColor();
});
Assert.Equal(expected, color);
}
}
}
9 changes: 9 additions & 0 deletions src/Core/tests/DeviceTests/Stubs/ActivityIndicatorStub.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Microsoft.Maui.DeviceTests.Stubs
{
public class ActivityIndicatorStub : StubBase, IActivityIndicator
{
public bool IsRunning { get; set; }

public Color Color { get; set; }
}
}

0 comments on commit 205573e

Please sign in to comment.