diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e2d4835..8ff47a8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,6 @@ name: CI -on: [push] +on: [push, pull_request] jobs: build: diff --git a/AndHUD.sln b/AndHUD.sln index 70b16e3..a4bbdba 100644 --- a/AndHUD.sln +++ b/AndHUD.sln @@ -16,6 +16,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt Directory.build.targets = Directory.build.targets global.json = global.json README.md = README.md + stylecop.json = stylecop.json + analyzers.ruleset = analyzers.ruleset EndProjectSection EndProject Global diff --git a/AndHUD/AndHUD.cs b/AndHUD/AndHUD.cs index 4c00e1c..06eb297 100644 --- a/AndHUD/AndHUD.cs +++ b/AndHUD/AndHUD.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Android.App; @@ -9,404 +9,545 @@ using Android.Util; using Android.Views; using Android.Widget; +using AndroidHUD.Extensions; namespace AndroidHUD { - public class AndHUD - { - static AndHUD shared; - - public static AndHUD Shared - { - get - { - if (shared == null) - shared = new AndHUD (); - - return shared; - } - } - - public AndHUD() - { - } - - ManualResetEvent waitDismiss = new ManualResetEvent(false); - public Dialog CurrentDialog { get; private set; } - - ProgressWheel progressWheel = null; - TextView statusText = null; - ImageView imageView = null; - - object statusObj = null; - - readonly object dialogLock = new object(); - - - public void Show (Context context, string status = null, int progress = -1, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, bool centered = true, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) - { - if (progress >= 0) - showProgress (context, progress, status, maskType, timeout, clickCallback, cancelCallback, prepareDialogCallback, dialogShownCallback); - else - showStatus (context, true, status, maskType, timeout, clickCallback, centered, cancelCallback, prepareDialogCallback, dialogShownCallback); - } - - public void ShowSuccess(Context context, string status = null, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) - { - showImage (context, GetDrawable(context, Resource.Drawable.ic_successstatus), status, maskType, timeout, clickCallback, cancelCallback, prepareDialogCallback, dialogShownCallback); - } - - public void ShowError(Context context, string status = null, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) - { - showImage (context, GetDrawable(context, Resource.Drawable.ic_errorstatus), status, maskType, timeout, clickCallback, cancelCallback, prepareDialogCallback, dialogShownCallback); - } - - public void ShowSuccessWithStatus(Context context, string status, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) - { - showImage (context, GetDrawable(context, Resource.Drawable.ic_successstatus), status, maskType, timeout, clickCallback, cancelCallback, prepareDialogCallback, dialogShownCallback); - } - - public void ShowErrorWithStatus(Context context, string status, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) - { - showImage (context, GetDrawable(context, Resource.Drawable.ic_errorstatus), status, maskType, timeout, clickCallback, cancelCallback, prepareDialogCallback, dialogShownCallback); - } - - public void ShowImage(Context context, int drawableResourceId, string status = null, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) - { - showImage (context, GetDrawable(context, drawableResourceId), status, maskType, timeout, clickCallback, cancelCallback, prepareDialogCallback, dialogShownCallback); - } - - public void ShowImage(Context context, Drawable drawable, string status = null, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) - { - showImage (context, drawable, status, maskType, timeout, clickCallback, cancelCallback, prepareDialogCallback, dialogShownCallback); - } - - public void ShowToast(Context context, string status, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, bool centered = true, Action clickCallback = null, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) - { - showStatus (context, false, status, maskType, timeout, clickCallback, centered, cancelCallback, prepareDialogCallback, dialogShownCallback); - } - - public void Dismiss(Context context = null) - { - DismissCurrent (context); - } - - Drawable GetDrawable(Context context, int drawableResourceId) + /// + /// Android HUD. + /// + public class AndHUD : IDisposable + { + private static AndHUD _shared; + private readonly object _dialogLock = new object(); + private readonly ManualResetEvent _waitDismiss = new ManualResetEvent(false); + + private ProgressWheel _progressWheel; + private TextView _statusText; + private ImageView _imageView; + + private object _statusObj; + + private AndHUD() { - if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop) + } + + /// + /// Gets the static instance of AndHUD. + /// + public static AndHUD Shared + { + get { - return context.Resources.GetDrawable(drawableResourceId, context.Theme); + if (_shared == null) + { + _shared = new AndHUD(); + } + + return _shared; + } + } + + /// + /// Gets the currently shown dialog. + /// + public Dialog CurrentDialog { get; private set; } + + /// + /// Show a dialog with a progress indicator. + /// If is provided it will be shown determinate, otherwise indeterminate. + /// + /// Android needed to show the dialog. + /// Status text to show under progress or loading indicator. + /// Progress, if over 0, then you should call this method again to update the progress. + /// indicating, whether background should be masked. + /// Timeout to automatically dismiss the dialog. + /// Callback for when dialog is clicked. + /// Center dialog if true, otherwise align towards bottom. + /// Callback for when dialog is dismissed by clicking outside of it. + /// Callback for preparing the dialog. + /// Callback for when dialog is shown on the screen. + public void Show(Context context, string status = null, int progress = -1, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, bool centered = true, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) + { + if (progress >= 0) + { + ShowProgress(context, progress, status, maskType, timeout, clickCallback, cancelCallback, prepareDialogCallback, dialogShownCallback); } else { + ShowStatus(context, true, status, maskType, timeout, clickCallback, centered, cancelCallback, prepareDialogCallback, dialogShownCallback); + } + } + + /// + /// Show a dialog with an success image. + /// + /// Android needed to show the dialog. + /// Status text to show under the success image. + /// indicating, whether background should be masked. + /// Timeout to automatically dismiss the dialog. + /// Callback for when dialog is clicked. + /// Callback for when dialog is dismissed by clicking outside of it. + /// Callback for preparing the dialog. + /// Callback for when dialog is shown on the screen. + public void ShowSuccess(Context context, string status = null, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) + { + ShowImage(context, Resource.Drawable.ic_successstatus, status, maskType, timeout, clickCallback, cancelCallback, prepareDialogCallback, dialogShownCallback); + } + + /// + /// Show a dialog with an error image. + /// + /// Android needed to show the dialog. + /// Status text to show under the error image. + /// indicating, whether background should be masked. + /// Timeout to automatically dismiss the dialog. + /// Callback for when dialog is clicked. + /// Callback for when dialog is dismissed by clicking outside of it. + /// Callback for preparing the dialog. + /// Callback for when dialog is shown on the screen. + public void ShowError(Context context, string status = null, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) + { + ShowImage(context, Resource.Drawable.ic_errorstatus, status, maskType, timeout, clickCallback, cancelCallback, prepareDialogCallback, dialogShownCallback); + } + + /// + /// Show a dialog with an image. + /// + /// Android needed to show the dialog. + /// Android drawable resource id. + /// Status text to show under the image. + /// indicating, whether background should be masked. + /// Timeout to automatically dismiss the dialog. + /// Callback for when dialog is clicked. + /// Callback for when dialog is dismissed by clicking outside of it. + /// Callback for preparing the dialog. + /// Callback for when dialog is shown on the screen. + public void ShowImage(Context context, int drawableResourceId, string status = null, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) + { + ShowImage(context, GetDrawable(context, drawableResourceId), status, maskType, timeout, clickCallback, cancelCallback, prepareDialogCallback, dialogShownCallback); + } + + /// + /// Show a dialog with an image. + /// + /// Android needed to show the dialog. + /// Android drawable resource. + /// Status text to show under the image. + /// indicating, whether background should be masked. + /// Timeout to automatically dismiss the dialog. + /// Callback for when dialog is clicked. + /// Callback for when dialog is dismissed by clicking outside of it. + /// Callback for preparing the dialog. + /// Callback for when dialog is shown on the screen. + public void ShowImage(Context context, Drawable drawable, string status = null, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) + { + ShowWithImage(context, drawable, status, maskType, timeout, clickCallback, cancelCallback, prepareDialogCallback, dialogShownCallback); + } + + /// + /// Show a toast dialog. + /// + /// Android needed to show the dialog. + /// Status text to show. + /// indicating, whether background should be masked. + /// Timeout to automatically dismiss the dialog. + /// Center dialog if true, otherwise align towards bottom. + /// Callback for when dialog is clicked. + /// Callback for when dialog is dismissed by clicking outside of it. + /// Callback for preparing the dialog. + /// Callback for when dialog is shown on the screen. + public void ShowToast(Context context, string status, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, bool centered = true, Action clickCallback = null, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) + { + ShowStatus(context, false, status, maskType, timeout, clickCallback, centered, cancelCallback, prepareDialogCallback, dialogShownCallback); + } + + /// + /// Dismiss currently shown dialog. + /// + /// Android needed to dismiss the dialog. + public void Dismiss(Context context = null) + { + DismissCurrent(context); + } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Dispose managed resources. + /// + /// Is disposing from call. + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _progressWheel.Dispose(); + _statusText.Dispose(); + _imageView.Dispose(); + _waitDismiss.Dispose(); + } + } + + private static Drawable GetDrawable(Context context, int drawableResourceId) + { + if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop) + { + return context.Resources.GetDrawable(drawableResourceId, context.Theme); + } + #pragma warning disable CS0618 // Type or member is obsolete - return context.Resources.GetDrawable(drawableResourceId); + return context.Resources.GetDrawable(drawableResourceId); #pragma warning restore CS0618 // Type or member is obsolete - } } - void showStatus (Context context, bool spinner, string status = null, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, bool centered = true, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) - { - if (timeout == null) - timeout = TimeSpan.Zero; + private static int DpToPx(Context context, int dp) + { + var displayMetrics = context.Resources.DisplayMetrics; + return (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, dp, displayMetrics); + } + + private void ShowStatus(Context context, bool spinner, string status = null, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, bool centered = true, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } - if (CurrentDialog != null && statusObj == null) - DismissCurrent (context); + if (timeout == null) + { + timeout = TimeSpan.Zero; + } - lock (dialogLock) - { - if (CurrentDialog == null) - { - SetupDialog (context, maskType, cancelCallback, (a, d, m) => { - View view = LayoutInflater.From (context).Inflate (Resource.Layout.loading, null); + if (CurrentDialog != null && _statusObj == null) + { + DismissCurrent(context); + } - if (clickCallback != null) - view.Click += (sender, e) => clickCallback(); + lock (_dialogLock) + { + if (CurrentDialog == null) + { + SetupDialog( + context, + maskType, + cancelCallback, + (_, d, __) => + { + View view = LayoutInflater.From(context).Inflate(Resource.Layout.loading, null); - statusObj = new object(); + if (clickCallback != null) + { + view.Click += (sender, e) => clickCallback(); + } - statusText = view.FindViewById(Resource.Id.textViewStatus); + _statusObj = new object(); - if (!spinner) - view.FindViewById(Resource.Id.loadingProgressBar).Visibility = ViewStates.Gone; + _statusText = view.FindViewById(Resource.Id.textViewStatus); - if (maskType != MaskType.Black) - view.SetBackgroundResource(Resource.Drawable.roundedbgdark); + if (!spinner) + { + view.FindViewById(Resource.Id.loadingProgressBar).Visibility = ViewStates.Gone; + } - if (statusText != null) - { - statusText.Text = status ?? ""; - statusText.Visibility = string.IsNullOrEmpty(status) ? ViewStates.Gone : ViewStates.Visible; - } + if (maskType != MaskType.Black) + { + view.SetBackgroundResource(Resource.Drawable.roundedbgdark); + } - if (!centered) - { - d.Window.SetGravity (GravityFlags.Bottom); - var p = d.Window.Attributes; + if (_statusText != null) + { + _statusText.Text = status ?? string.Empty; + _statusText.Visibility = string.IsNullOrEmpty(status) ? ViewStates.Gone : ViewStates.Visible; + } - p.Y = DpToPx (context, 22); + if (!centered) + { + d.Window.SetGravity(GravityFlags.Bottom); + var p = d.Window.Attributes; - d.Window.Attributes = p; - } - - return view; - }, prepareDialogCallback, dialogShownCallback); + p.Y = DpToPx(context, 22); + + d.Window.Attributes = p; + } + + return view; + }, + prepareDialogCallback, + dialogShownCallback); RunTimeout(context, timeout); } - else - { - - Application.SynchronizationContext.Send(state => { - if (statusText != null) - statusText.Text = status ?? ""; - }, null); - } - } - } - - int DpToPx(Context context, int dp) - { - var displayMetrics = context.Resources.DisplayMetrics; - return (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, dp, displayMetrics); - } + else + { + Application.SynchronizationContext.Send( + _ => + { + if (_statusText != null) + { + _statusText.Text = status ?? string.Empty; + } + }, null); + } + } + } - void showProgress(Context context, int progress, string status = null, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) - { - if (!timeout.HasValue || timeout == null) - timeout = TimeSpan.Zero; + private void ShowProgress(Context context, int progress, string status = null, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) + { + if (!timeout.HasValue || timeout == null) + { + timeout = TimeSpan.Zero; + } - if (CurrentDialog != null && progressWheel == null) - DismissCurrent (context); + if (CurrentDialog != null && _progressWheel == null) + { + DismissCurrent(context); + } - lock (dialogLock) - { - if (CurrentDialog == null) - { - SetupDialog (context, maskType, cancelCallback, (a, d, m) => { - var inflater = LayoutInflater.FromContext(context); - var view = inflater.Inflate(Resource.Layout.loadingprogress, null); + lock (_dialogLock) + { + if (CurrentDialog == null) + { + SetupDialog( + context, + maskType, + cancelCallback, + (a, d, m) => + { + var inflater = LayoutInflater.FromContext(context); + var view = inflater.Inflate(Resource.Layout.loadingprogress, null); - if (clickCallback != null) - view.Click += (sender, e) => clickCallback(); + if (clickCallback != null) + { + view.Click += (sender, e) => clickCallback(); + } - progressWheel = view.FindViewById(Resource.Id.loadingProgressWheel); - statusText = view.FindViewById(Resource.Id.textViewStatus); + _progressWheel = view.FindViewById(Resource.Id.loadingProgressWheel); + _statusText = view.FindViewById(Resource.Id.textViewStatus); - if (maskType != MaskType.Black) - view.SetBackgroundResource(Resource.Drawable.roundedbgdark); + if (maskType != MaskType.Black) + { + view.SetBackgroundResource(Resource.Drawable.roundedbgdark); + } - progressWheel.SetProgress(0); + _progressWheel.SetProgress(0); - if (statusText != null) - { - statusText.Text = status ?? ""; - statusText.Visibility = string.IsNullOrEmpty(status) ? ViewStates.Gone : ViewStates.Visible; - } + if (_statusText != null) + { + _statusText.Text = status ?? string.Empty; + _statusText.Visibility = string.IsNullOrEmpty(status) ? ViewStates.Gone : ViewStates.Visible; + } - return view; - }, prepareDialogCallback, dialogShownCallback); + return view; + }, + prepareDialogCallback, + dialogShownCallback); RunTimeout(context, timeout); } - else - { - Application.SynchronizationContext.Send(state => { - progressWheel?.SetProgress (progress); - statusText.Text = status ?? ""; - }, null); - } - } - } - - void showImage(Context context, Drawable image, string status = null, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) - { - if (timeout == null) - timeout = TimeSpan.Zero; - - if (CurrentDialog != null && imageView == null) - DismissCurrent (context); - - lock (dialogLock) - { - if (CurrentDialog == null) - { - SetupDialog (context, maskType, cancelCallback, (a, d, m) => { - var inflater = LayoutInflater.FromContext(context); - var view = inflater.Inflate(Resource.Layout.loadingimage, null); - - if (clickCallback != null) - view.Click += (sender, e) => clickCallback(); - - imageView = view.FindViewById(Resource.Id.loadingImage); - statusText = view.FindViewById(Resource.Id.textViewStatus); - - if (maskType != MaskType.Black) - view.SetBackgroundResource(Resource.Drawable.roundedbgdark); - - imageView?.SetImageDrawable(image); - - if (statusText != null) - { - statusText.Text = status ?? ""; - statusText.Visibility = string.IsNullOrEmpty(status) ? ViewStates.Gone : ViewStates.Visible; - } - - return view; - }, prepareDialogCallback, dialogShownCallback); + else + { + Application.SynchronizationContext.Send( + _ => + { + _progressWheel?.SetProgress(progress); + _statusText.Text = status ?? string.Empty; + }, null); + } + } + } - RunTimeout(context, timeout); - } - else - { - Application.SynchronizationContext.Send(state => { - imageView?.SetImageDrawable(image); - statusText.Text = status ?? ""; - }, null); - } - } - } - - void RunTimeout(Context context, TimeSpan? timeout) + private void ShowWithImage(Context context, Drawable image, string status = null, MaskType maskType = MaskType.Black, TimeSpan? timeout = null, Action clickCallback = null, Action cancelCallback = null, Action prepareDialogCallback = null, Action dialogShownCallback = null) { - if (timeout > TimeSpan.Zero) + if (timeout == null) { - Task.Run(() => { - if (!waitDismiss.WaitOne(timeout.Value)) - DismissCurrent(context); + timeout = TimeSpan.Zero; + } - }).ContinueWith(ct => { - var ex = ct.Exception; + if (CurrentDialog != null && _imageView == null) + { + DismissCurrent(context); + } - if (ex != null) - Android.Util.Log.Error("AndHUD", ex.ToString()); - }, TaskContinuationOptions.OnlyOnFaulted); + lock (_dialogLock) + { + if (CurrentDialog == null) + { + SetupDialog( + context, + maskType, + cancelCallback, + (a, d, m) => + { + var inflater = LayoutInflater.FromContext(context); + var view = inflater.Inflate(Resource.Layout.loadingimage, null); + + if (clickCallback != null) + { + view.Click += (sender, e) => clickCallback(); + } + + _imageView = view.FindViewById(Resource.Id.loadingImage); + _statusText = view.FindViewById(Resource.Id.textViewStatus); + + if (maskType != MaskType.Black) + { + view.SetBackgroundResource(Resource.Drawable.roundedbgdark); + } + + _imageView?.SetImageDrawable(image); + + if (_statusText != null) + { + _statusText.Text = status ?? string.Empty; + _statusText.Visibility = string.IsNullOrEmpty(status) ? ViewStates.Gone : ViewStates.Visible; + } + + return view; + }, + prepareDialogCallback, + dialogShownCallback); + + RunTimeout(context, timeout); + } + else + { + Application.SynchronizationContext.Send( + state => + { + _imageView?.SetImageDrawable(image); + _statusText.Text = status ?? string.Empty; + }, null); + } } } - void SetupDialog(Context context, MaskType maskType, Action cancelCallback, Func customSetup, Action prepareDialogCallback = null, Action dialogShownCallback = null) - { - Application.SynchronizationContext.Send(state => { + private void RunTimeout(Context context, TimeSpan? timeout) + { + if (timeout > TimeSpan.Zero) + { + _ = Task.Run(() => + { + if (!_waitDismiss.WaitOne(timeout.Value)) + { + DismissCurrent(context); + } + }) + .ContinueWith( + ct => + { + var ex = ct.Exception; - var dialog = new Dialog(context); + if (ex != null) + { + Android.Util.Log.Error("AndHUD", ex.ToString()); + } + }, + TaskContinuationOptions.OnlyOnFaulted); + } + } - dialog.RequestWindowFeature((int)WindowFeatures.NoTitle); + private void SetupDialog(Context context, MaskType maskType, Action cancelCallback, Func customSetup, Action prepareDialogCallback = null, Action dialogShownCallback = null) + { + Application.SynchronizationContext.Send( + state => + { + var dialog = new Dialog(context); - if (maskType != MaskType.Black) - dialog.Window.ClearFlags(WindowManagerFlags.DimBehind); + dialog.RequestWindowFeature((int)WindowFeatures.NoTitle); - if (maskType == MaskType.None) - dialog.Window.SetFlags(WindowManagerFlags.NotTouchModal, WindowManagerFlags.NotTouchModal); + if (maskType != MaskType.Black) + { + dialog.Window.ClearFlags(WindowManagerFlags.DimBehind); + } - dialog.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent)); + if (maskType == MaskType.None) + { + dialog.Window.SetFlags(WindowManagerFlags.NotTouchModal, WindowManagerFlags.NotTouchModal); + } - var customView = customSetup(context, dialog, maskType); + dialog.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent)); - dialog.SetContentView (customView); + var customView = customSetup(context, dialog, maskType); - dialog.SetCancelable (cancelCallback != null); - if (cancelCallback != null) - dialog.CancelEvent += (sender, e) => cancelCallback(); + dialog.SetContentView(customView); - prepareDialogCallback?.Invoke(dialog); + dialog.SetCancelable(cancelCallback != null); + if (cancelCallback != null) + { + dialog.CancelEvent += (sender, e) => cancelCallback(); + } - CurrentDialog = dialog; + prepareDialogCallback?.Invoke(dialog); - CurrentDialog.Show (); + CurrentDialog = dialog; - dialogShownCallback?.Invoke(CurrentDialog); + CurrentDialog.Show(); - }, null); - } + dialogShownCallback?.Invoke(CurrentDialog); + }, null); + } - void DismissCurrent(Context context = null) - { - lock (dialogLock) - { - if (CurrentDialog != null) - { - waitDismiss.Set (); + private void DismissCurrent(Context context = null) + { + lock (_dialogLock) + { + if (CurrentDialog != null) + { + _waitDismiss.Set(); - Action actionDismiss = () => - { + Action actionDismiss = () => + { if (CurrentDialog != null) { CurrentDialog.Hide(); CurrentDialog.Dismiss(); } - statusText = null; - statusObj = null; - imageView = null; - progressWheel = null; - CurrentDialog = null; - - waitDismiss.Reset (); - }; - - // First try the SynchronizationContext - if (Application.SynchronizationContext != null) - { - Application.SynchronizationContext.Send (state => actionDismiss (), null); - return; - } + _statusText = null; + _statusObj = null; + _imageView = null; + _progressWheel = null; + CurrentDialog = null; + + _waitDismiss.Reset(); + }; + + // First try the SynchronizationContext + if (Application.SynchronizationContext != null) + { + Application.SynchronizationContext.Send(state => actionDismiss(), null); + return; + } // Otherwise try OwnerActivity on dialog var ownerActivity = CurrentDialog.OwnerActivity; - if (IsAlive(ownerActivity)) + if (ownerActivity.IsAlive()) { ownerActivity.RunOnUiThread(actionDismiss); return; } // Otherwise try get it from the Window Context - if (IsAlive(CurrentDialog?.Window?.Context)) - { - if (CurrentDialog.Window.Context is Activity windowActivity) - { - windowActivity.RunOnUiThread(actionDismiss); - return; - } + if (CurrentDialog.Window.Context is Activity windowActivity && windowActivity.IsAlive()) + { + windowActivity.RunOnUiThread(actionDismiss); + return; } // Finally if all else fails, let's see if someone passed in a context to dismiss and it // happens to also be an Activity - if (context != null && context is Activity activity) + if (context != null && context is Activity activity && activity.IsAlive()) { - activity?.RunOnUiThread(actionDismiss); + activity.RunOnUiThread(actionDismiss); return; } } - } - } - - bool IsAlive(Java.Lang.Object @object) - { - if (@object == null) - return false; - - if (@object.Handle == IntPtr.Zero) - return false; - - if (@object is Activity activity) - { - if (activity.IsFinishing) - return false; - - if (Build.VERSION.SdkInt >= BuildVersionCodes.JellyBeanMr1 && - activity.IsDestroyed) - return false; } - - return true; } } - - public enum MaskType - { - None = 1, - Clear = 2, - Black = 3 - } } - diff --git a/AndHUD/AndHUD.csproj b/AndHUD/AndHUD.csproj index 79837c8..ce613c5 100644 --- a/AndHUD/AndHUD.csproj +++ b/AndHUD/AndHUD.csproj @@ -5,13 +5,16 @@ AndroidHUD AndHUD AndHUD is a Progress / HUD library for Android which allows you to easily add amazing HUDs to your app! + + true + latest - - - - + + + + - + \ No newline at end of file diff --git a/AndHUD/Extensions/ObjectExtensions.cs b/AndHUD/Extensions/ObjectExtensions.cs new file mode 100644 index 0000000..849af4b --- /dev/null +++ b/AndHUD/Extensions/ObjectExtensions.cs @@ -0,0 +1,52 @@ +using System; +using Android.App; +using Android.OS; + +namespace AndroidHUD.Extensions +{ + /// + /// Extensions for Java.Lang.Object. + /// + internal static class ObjectExtensions + { + /// + /// Checks whether a Java.Lang.Object is null, handle is Zero or if the type + /// is an Android Activity, then check whether it is Finishing or Destroyed. + /// + /// A to check for liveliness. + /// + /// Returns false if is . + /// Returns false if is . + /// Returns false if is an and is true. + /// Returns false if is an and is true. + /// + internal static bool IsAlive(this Java.Lang.Object thing) + { + if (thing == null) + { + return false; + } + + if (thing.Handle == IntPtr.Zero) + { + return false; + } + + if (thing is Activity activity) + { + if (activity.IsFinishing) + { + return false; + } + + if (Build.VERSION.SdkInt >= BuildVersionCodes.JellyBeanMr1 + && activity.IsDestroyed) + { + return false; + } + } + + return true; + } + } +} diff --git a/AndHUD/MaskType.cs b/AndHUD/MaskType.cs new file mode 100644 index 0000000..0674578 --- /dev/null +++ b/AndHUD/MaskType.cs @@ -0,0 +1,23 @@ +namespace AndroidHUD +{ + /// + /// Mask type to determine how to dim the background. + /// + public enum MaskType + { + /// + /// No mask type + /// + None = 1, + + /// + /// Show on top of clear background + /// + Clear = 2, + + /// + /// Show on top of black dimmed background + /// + Black = 3 + } +} diff --git a/AndHUD/ProgressWheel.cs b/AndHUD/ProgressWheel.cs index 8c12474..dee0703 100644 --- a/AndHUD/ProgressWheel.cs +++ b/AndHUD/ProgressWheel.cs @@ -1,308 +1,362 @@ -using System; -using Android.Views; -using Android.Graphics; -using Android.Util; +using System; using Android.Content; +using Android.Graphics; using Android.Runtime; +using Android.Util; +using Android.Views; +using AndroidHUD.Extensions; namespace AndroidHUD { + /// + /// Progress Wheel View for showing circular progress. + /// [Register("androidhud.ProgressWheel")] - public class ProgressWheel : View - { - public ProgressWheel(Context context) - : this(context, null, 0) - { - } - - public ProgressWheel(Context context, IAttributeSet attrs) - : this(context, attrs, 0) - { - } - - public ProgressWheel (Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle) - { - CircleRadius = 80; - BarLength = 60; - BarWidth = 20; - RimWidth = 20; - TextSize = 20; - - //Padding (with defaults) - WheelPaddingTop = 5; - WheelPaddingBottom = 5; - WheelPaddingLeft = 5; - WheelPaddingRight = 5; - - //Colors (with defaults) - BarColor = Color.White; - CircleColor = Color.Transparent; - RimColor = Color.Gray; - TextColor = Color.White; - - //Animation - //The amount of pixels to move the bar by on each draw - SpinSpeed = 2; - //The number of milliseconds to wait inbetween each draw - DelayMillis = 0; - - spinHandler = new SpinHandler(msg => { - Invalidate (); - - if (isSpinning) - { - progress += SpinSpeed; - if (progress > 360) - progress = 0; - - spinHandler.SendEmptyMessageDelayed (0, DelayMillis); - } - }); - - - //ParseAttributes(context.ObtainStyledAttributes(attrs, null)); //TODO: swap null for R.styleable.ProgressWheel - } - -// public string Text -// { -// get { return text; } -// set { text = value; splitText = text.Split('\n'); } -// } - - //public string[] SplitText { get { return splitText; } } - - - public int CircleRadius { get;set; } - public int BarLength { get;set; } - public int BarWidth { get;set; } - public int TextSize { get;set; } - public int WheelPaddingTop { get;set; } - public int WheelPaddingBottom { get; set; } - public int WheelPaddingLeft { get;set; } - public int WheelPaddingRight { get;set; } - public Color BarColor { get;set; } - public Color CircleColor { get;set; } - public Color RimColor { get;set; } - public Shader RimShader { get { return rimPaint.Shader; } set { rimPaint.SetShader(value); } } - public Color TextColor { get;set; } - public int SpinSpeed { get;set; } - public int RimWidth { get;set; } - public int DelayMillis { get;set; } - - public bool IsSpinning { get { return isSpinning; } } - - //Sizes (with defaults) - int fullRadius = 100; - - //Paints - Paint barPaint = new Paint(); - Paint circlePaint = new Paint(); - Paint rimPaint = new Paint(); - Paint textPaint = new Paint(); - - //Rectangles - //RectF rectBounds = new RectF(); - RectF circleBounds = new RectF(); - - int progress = 0; - bool isSpinning = false; - SpinHandler spinHandler; - - Android.OS.BuildVersionCodes version = Android.OS.Build.VERSION.SdkInt; - - //Other - //string text = ""; - //string[] splitText = new string[]{}; - - protected override void OnAttachedToWindow () - { - base.OnAttachedToWindow (); - - SetupBounds (); - SetupPaints (); - - Invalidate (); - } - - void SetupPaints() - { - barPaint.Color = BarColor; - barPaint.AntiAlias = true; - barPaint.SetStyle (Paint.Style.Stroke); - barPaint.StrokeWidth = BarWidth; - - rimPaint.Color = RimColor; - rimPaint.AntiAlias = true; - rimPaint.SetStyle (Paint.Style.Stroke); - rimPaint.StrokeWidth = RimWidth; - - circlePaint.Color = CircleColor; - circlePaint.AntiAlias = true; - circlePaint.SetStyle(Paint.Style.Fill); - - textPaint.Color = TextColor; - textPaint.SetStyle(Paint.Style.Fill); - textPaint.AntiAlias = true; - textPaint.TextSize = TextSize; - } - - void SetupBounds() - { - WheelPaddingTop = this.WheelPaddingTop; - WheelPaddingBottom = this.WheelPaddingBottom; - WheelPaddingLeft = this.WheelPaddingLeft; - WheelPaddingRight = this.WheelPaddingRight; - -// rectBounds = new RectF(WheelPaddingLeft, -// WheelPaddingTop, -// this.LayoutParameters.Width - WheelPaddingRight, -// this.LayoutParameters.Height - WheelPaddingBottom); -// - circleBounds = new RectF(WheelPaddingLeft + BarWidth, - WheelPaddingTop + BarWidth, - this.LayoutParameters.Width - WheelPaddingRight - BarWidth, - this.LayoutParameters.Height - WheelPaddingBottom - BarWidth); - - fullRadius = (this.LayoutParameters.Width - WheelPaddingRight - BarWidth)/2; - CircleRadius = (fullRadius - BarWidth) + 1; - } - -// void ParseAttributes(Android.Content.Res.TypedArray a) -// { -// BarWidth = (int) a.GetDimension(R.styleable.ProgressWheel_barWidth, barWidth); -// RimWidth = (int) a.GetDimension(R.styleable.ProgressWheel_rimWidth, rimWidth); -// SpinSpeed = (int) a.GetDimension(R.styleable.ProgressWheel_spinSpeed, spinSpeed); -// DelayMillis = (int) a.GetInteger(R.styleable.ProgressWheel_delayMillis, delayMillis); -// -// if(DelayMillis < 0) -// DelayMillis = 0; -// -// BarColor = a.GetColor(R.styleable.ProgressWheel_barColor, barColor); -// BarLength = (int) a.GetDimension(R.styleable.ProgressWheel_barLength, barLength); -// TextSize = (int) a.GetDimension(R.styleable.ProgressWheel_textSize, textSize); -// TextColor = (int) a.GetColor(R.styleable.ProgressWheel_textColor, textColor); -// -// Text = a.GetString(R.styleable.ProgressWheel_text); -// -// RimColor = (int) a.GetColor(R.styleable.ProgressWheel_rimColor, rimColor); -// CircleColor = (int) a.GetColor(R.styleable.ProgressWheel_circleColor, circleColor); -// } - - - - //---------------------------------- - //Animation stuff - //---------------------------------- - protected override void OnDraw (Canvas canvas) - { - base.OnDraw (canvas); - - //Draw the rim - canvas.DrawArc(circleBounds, 360, 360, false, rimPaint); - - //Draw the bar - if(isSpinning) - canvas.DrawArc(circleBounds, progress - 90, BarLength, false, barPaint); - else - canvas.DrawArc(circleBounds, -90, progress, false, barPaint); - - //Draw the inner circle - canvas.DrawCircle((circleBounds.Width() / 2) + RimWidth + WheelPaddingLeft, - (circleBounds.Height() / 2) + RimWidth + WheelPaddingTop, - CircleRadius, - circlePaint); - - //Draw the text (attempts to center it horizontally and vertically) -// int offsetNum = 2; -// -// foreach (var s in splitText) -// { -// float offset = textPaint.MeasureText(s) / 2; -// -// canvas.DrawText(s, this.Width / 2 - offset, -// this.Height / 2 + (TextSize * (offsetNum)) -// - ((splitText.Length - 1) * (TextSize / 2)), textPaint); -// offsetNum++; -// } - } - - public void ResetCount() - { - progress = 0; - //Text = "0%"; - Invalidate(); - } - - public void StopSpinning() - { - isSpinning = false; - progress = 0; - spinHandler.RemoveMessages(0); - } - - - public void Spin() - { - isSpinning = true; - spinHandler.SendEmptyMessage(0); - } - - public void IncrementProgress() - { - - - isSpinning = false; - progress++; - //Text = Math.Round(((float)progress/(float)360)*(float)100) + "%"; - spinHandler.SendEmptyMessage(0); - } - - public void SetProgress(int i) { - isSpinning = false; - var newProgress = (int)((float)i / (float)100 * (float)360); - - if (version >= Android.OS.BuildVersionCodes.Honeycomb) - { - Android.Animation.ValueAnimator va = - (Android.Animation.ValueAnimator)Android.Animation.ValueAnimator.OfInt (progress, newProgress).SetDuration (250); - - va.Update += (sender, e) => { - var interimValue = (int)e.Animation.AnimatedValue; - - progress = interimValue; - - //Text = Math.Round(((float)interimValue/(float)360)*(float)100) + "%"; - - Invalidate (); - }; - - va.Start (); - } else { - progress = newProgress; - Invalidate (); - } - - spinHandler.SendEmptyMessage(0); - } - - - - class SpinHandler : Android.OS.Handler - { - public SpinHandler(Action msgAction) : base() - { - MessageAction = msgAction; - } - - public Action MessageAction { get; private set; } - - public override void HandleMessage (Android.OS.Message msg) - { - MessageAction (msg); - } - } - - - } + public class ProgressWheel : View + { + private readonly SpinHandler _spinHandler; + private readonly Android.OS.BuildVersionCodes _version = Android.OS.Build.VERSION.SdkInt; + + // Paints + private readonly Paint _barPaint = new Paint(); + private readonly Paint _circlePaint = new Paint(); + private readonly Paint _rimPaint = new Paint(); + private readonly Paint _textPaint = new Paint(); + + // Sizes (with defaults) + private int _fullRadius = 100; + + // Rectangles + private RectF _circleBounds = new RectF(); + + private int _progress; + + /// + /// Create an instance of ProgressWheel. + /// + /// Android to create view from. + public ProgressWheel(Context context) + : this(context, null, 0) + { + } + + /// + /// Create an instance of ProgressWheel, used by Android . + /// + /// Android to create view from. + /// Android XML attributes from the layout. + public ProgressWheel(Context context, IAttributeSet attrs) + : this(context, attrs, 0) + { + } + + /// + /// Create an instance of ProgressWheel, used by Android . + /// + /// Android to create view from. + /// Android XML attributes from the layout. + /// Android style to apply to view. + public ProgressWheel(Context context, IAttributeSet attrs, int defStyle) + : base(context, attrs, defStyle) + { + CircleRadius = 80; + BarLength = 60; + BarWidth = 20; + RimWidth = 20; + TextSize = 20; + + // Padding (with defaults) + WheelPaddingTop = 5; + WheelPaddingBottom = 5; + WheelPaddingLeft = 5; + WheelPaddingRight = 5; + + // Colors (with defaults) + BarColor = Color.White; + CircleColor = Color.Transparent; + RimColor = Color.Gray; + TextColor = Color.White; + + // Animation + // The amount of pixels to move the bar by on each draw + SpinSpeed = 2; + + // The number of milliseconds to wait inbetween each draw + DelayMillis = 0; + + _spinHandler = new SpinHandler(msg => + { + Invalidate(); + + if (IsSpinning) + { + _progress += SpinSpeed; + if (_progress > 360) + { + _progress = 0; + } + + _spinHandler.SendEmptyMessageDelayed(0, DelayMillis); + } + }); + } + + /// + /// Get or set the radius of the circle to draw. Defaults to half of the + /// width of the view. + /// + public int CircleRadius { get; set; } + + /// + /// Get or set the length of the bar. + /// + public int BarLength { get; set; } + + /// + /// Get or set the width of the bar. + /// + public int BarWidth { get; set; } + + /// + /// Get or set the size of the text in px. + /// + public int TextSize { get; set; } + + /// + /// Get or set the top padding of the progress wheel. + /// + public int WheelPaddingTop { get; set; } + + /// + /// Get or set the bottom padding of the progress wheel. + /// + public int WheelPaddingBottom { get; set; } + + /// + /// Get or set the left padding of the progress wheel. + /// + public int WheelPaddingLeft { get; set; } + + /// + /// Get or set the right padding of the progress wheel. + /// + public int WheelPaddingRight { get; set; } + + /// + /// Gets or sets the color of the bar. + /// + public Color BarColor { get; set; } + + /// + /// Gets or sets the color of the circle. + /// + public Color CircleColor { get; set; } + + /// + /// Gets or sets the color of the rim. + /// + public Color RimColor { get; set; } + + /// + /// Gets or sets the shader of the rim. + /// + public Shader RimShader + { + get => _rimPaint.Shader; + set => _rimPaint.SetShader(value); + } + + /// + /// Gets or sets the text color. + /// + public Color TextColor { get; set; } + + /// + /// Gets or sets the spinning speed for the animation. + /// + public int SpinSpeed { get; set; } + + /// + /// Gets or sets the rim width. + /// + public int RimWidth { get; set; } + + /// + /// Gets or sets the delay in ms, between progress increases. + /// + public int DelayMillis { get; set; } + + /// + /// Gets whether the spinning animation is running. + /// + public bool IsSpinning { get; private set; } + + /// + /// Reset progress to 0. + /// + public void ResetCount() + { + _progress = 0; + + // Text = "0%"; + Invalidate(); + } + + /// + /// Stop spinning animation. + /// + public void StopSpinning() + { + IsSpinning = false; + _progress = 0; + _spinHandler.RemoveMessages(0); + } + + /// + /// Start spinning animation. + /// + public void Spin() + { + IsSpinning = true; + _spinHandler.SendEmptyMessage(0); + } + + /// + /// Increment progress by 1. + /// + public void IncrementProgress() + { + IsSpinning = false; + _progress++; + _spinHandler.SendEmptyMessage(0); + } + + /// + /// Set progress. + /// + /// Amount to increase progress. + public void SetProgress(int amount) + { + IsSpinning = false; + var newProgress = (int)((float)amount / 100 * 360); + + if (_version >= Android.OS.BuildVersionCodes.Honeycomb) + { + var va = + (Android.Animation.ValueAnimator)Android.Animation.ValueAnimator.OfInt(_progress, newProgress).SetDuration(250); + + va.Update += (sender, e) => + { + _progress = (int)e.Animation.AnimatedValue; + + Invalidate(); + }; + + va.Start(); + } + else + { + _progress = newProgress; + Invalidate(); + } + + _spinHandler.SendEmptyMessage(0); + } + + /// + protected override void OnAttachedToWindow() + { + base.OnAttachedToWindow(); + + SetupBounds(); + SetupPaints(); + + Invalidate(); + } + + // ---------------------------------- + // Animation stuff + // ---------------------------------- + + /// + protected override void OnDraw(Canvas canvas) + { + base.OnDraw(canvas); + + if (!canvas.IsAlive()) + { + return; + } + + // Draw the rim + canvas.DrawArc(_circleBounds, 360, 360, false, _rimPaint); + + // Draw the bar + if (IsSpinning) + { + canvas.DrawArc(_circleBounds, _progress - 90, BarLength, false, _barPaint); + } + else + { + canvas.DrawArc(_circleBounds, -90, _progress, false, _barPaint); + } + + // Draw the inner circle + canvas.DrawCircle( + (_circleBounds.Width() / 2) + RimWidth + WheelPaddingLeft, + (_circleBounds.Height() / 2) + RimWidth + WheelPaddingTop, + CircleRadius, + _circlePaint); + } + + private void SetupPaints() + { + _barPaint.Color = BarColor; + _barPaint.AntiAlias = true; + _barPaint.SetStyle(Paint.Style.Stroke); + _barPaint.StrokeWidth = BarWidth; + + _rimPaint.Color = RimColor; + _rimPaint.AntiAlias = true; + _rimPaint.SetStyle(Paint.Style.Stroke); + _rimPaint.StrokeWidth = RimWidth; + + _circlePaint.Color = CircleColor; + _circlePaint.AntiAlias = true; + _circlePaint.SetStyle(Paint.Style.Fill); + + _textPaint.Color = TextColor; + _textPaint.SetStyle(Paint.Style.Fill); + _textPaint.AntiAlias = true; + _textPaint.TextSize = TextSize; + } + + private void SetupBounds() + { + _circleBounds = + new RectF( + WheelPaddingLeft + BarWidth, + WheelPaddingTop + BarWidth, + LayoutParameters.Width - WheelPaddingRight - BarWidth, + LayoutParameters.Height - WheelPaddingBottom - BarWidth); + + _fullRadius = (LayoutParameters.Width - WheelPaddingRight - BarWidth) / 2; + CircleRadius = (_fullRadius - BarWidth) + 1; + } + + private class SpinHandler : Android.OS.Handler + { + public SpinHandler(Action msgAction) + { + MessageAction = msgAction; + } + + public Action MessageAction { get; private set; } + + public override void HandleMessage(Android.OS.Message msg) + { + MessageAction(msg); + } + } + } } - diff --git a/AndHUD/XHUD.MaskType.cs b/AndHUD/XHUD.MaskType.cs new file mode 100644 index 0000000..ca8703b --- /dev/null +++ b/AndHUD/XHUD.MaskType.cs @@ -0,0 +1,18 @@ +namespace XHUD +{ + /// + /// MaskType which maps to . + /// + public enum MaskType + { + /// + /// Show on top of clear background + /// + Clear = 2, + + /// + /// Show on top of black dimmed background + /// + Black = 3, + } +} diff --git a/AndHUD/XHUD.cs b/AndHUD/XHUD.cs index 9588558..83eabab 100644 --- a/AndHUD/XHUD.cs +++ b/AndHUD/XHUD.cs @@ -1,41 +1,61 @@ using System; using Android.App; - using AndroidHUD; namespace XHUD { - public enum MaskType - { -// None = 1, - Clear = 2, - Black = 3, -// Gradient - } - - public static class HUD - { - public static Activity MyActivity; - - public static void Show(string message, int progress = -1, MaskType maskType = MaskType.Black) - { - AndHUD.Shared.Show(HUD.MyActivity, message, progress,(AndroidHUD.MaskType)maskType); - } - - public static void Dismiss() - { - AndHUD.Shared.Dismiss(HUD.MyActivity); - } - - public static void ShowToast(string message, bool showToastCentered = true, double timeoutMs = 1000) - { - AndHUD.Shared.ShowToast(HUD.MyActivity, message, (AndroidHUD.MaskType)MaskType.Black, TimeSpan.FromSeconds(timeoutMs/1000), showToastCentered); - } - - public static void ShowToast(string message, MaskType maskType, bool showToastCentered = true, double timeoutMs = 1000) - { - AndHUD.Shared.ShowToast(HUD.MyActivity, message, (AndroidHUD.MaskType)maskType, TimeSpan.FromSeconds(timeoutMs/1000), showToastCentered); - } - } + /// + /// HUD class to help interface between BTProgressHUD and AndHUD. + /// +#pragma warning disable SA1649 // File name should match first type name + public static class HUD +#pragma warning restore SA1649 // File name should match first type name + { + /// + /// Get or set Activity used as context to show dialog in. + /// + public static Activity MyActivity { get; set; } + + /// + /// Show a dialog. + /// + /// Message to show under loading indicator. + /// If set between 1 and 100, the progress will be determinate. + /// Mask type used to dim background of dialog. + public static void Show(string message, int progress = -1, MaskType maskType = MaskType.Black) + { + AndHUD.Shared.Show(MyActivity, message, progress, (AndroidHUD.MaskType)maskType); + } + + /// + /// Dismiss currently shown dialog. + /// + public static void Dismiss() + { + AndHUD.Shared.Dismiss(MyActivity); + } + + /// + /// Show toast message. + /// + /// Message to show in toast. + /// If true, toast will be centered on screen. Otherwise towards bottom of screen. + /// Timeout in ms. Determines when to dismiss the toast. + public static void ShowToast(string message, bool showToastCentered = true, double timeoutMs = 1000) + { + AndHUD.Shared.ShowToast(MyActivity, message, (AndroidHUD.MaskType)MaskType.Black, TimeSpan.FromMilliseconds(timeoutMs), showToastCentered); + } + + /// + /// Show toast message. + /// + /// Message to show in toast. + /// Mask type used to dim background of dialog. + /// If true, toast will be centered on screen. Otherwise towards bottom of screen. + /// Timeout in ms. Determines when to dismiss the toast. + public static void ShowToast(string message, MaskType maskType, bool showToastCentered = true, double timeoutMs = 1000) + { + AndHUD.Shared.ShowToast(MyActivity, message, (AndroidHUD.MaskType)maskType, TimeSpan.FromMilliseconds(timeoutMs), showToastCentered); + } + } } - diff --git a/Directory.build.props b/Directory.build.props index 97e0f66..72890d8 100644 --- a/Directory.build.props +++ b/Directory.build.props @@ -2,15 +2,15 @@ Copyright (c) Redth Apache-2.0 - https://github.com/Redth/AndHUD - https://raw.githubusercontent.com/Redth/AndHUD/develop/icon.png + https://github.com/redth-org/AndHUD + https://raw.githubusercontent.com/redth-orgAndHUD/develop/icon.png Redth Redth Xamarin, Android, Progress, AndHUD, AndroidHUD - https://github.com/Redth/AndHUD/releases + https://github.com/redth-org/AndHUD/releases false - https://github.com/Redth/AndHUD + https://github.com/redth-org/AndHUD git $(AssemblyName) ($(TargetFramework)) en @@ -19,6 +19,8 @@ 7.3 $(NoWarn);1591;1701;1702;1705;VSX1000;NU1603 + + $(MSBuildThisFileDirectory)analyzers.ruleset @@ -42,5 +44,16 @@ true $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/SampleApp/MainActivity.cs b/Samples/SampleApp/MainActivity.cs index 9a5d8e5..c2790c7 100644 --- a/Samples/SampleApp/MainActivity.cs +++ b/Samples/SampleApp/MainActivity.cs @@ -13,7 +13,8 @@ namespace SampleApp [Activity(Label = "@string/app_name", Theme = "@style/AppTheme.NoActionBar", MainLauncher = true)] public class MainActivity : AppCompatActivity { - string[] _demos = new string[] { + private string[] _demos = new string[] + { "Status Indicator Only", "Status Indicator and Text", "Non-Modal Indicator and Text", @@ -34,6 +35,7 @@ public class MainActivity : AppCompatActivity private ListView _listView; + /// protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); @@ -49,10 +51,13 @@ protected override void OnCreate(Bundle savedInstanceState) _listView.ItemClick += OnItemClick; } + /// protected override void OnDestroy() { if (_listView != null) + { _listView.ItemClick -= OnItemClick; + } base.OnDestroy(); } @@ -79,16 +84,16 @@ private void OnItemClick(object sender, AdapterView.ItemClickEventArgs e) ShowProgressDemo(progress => AndHUD.Shared.Show(this, "Loading... " + progress + "%", progress, MaskType.Clear)); break; case "Success Image Only": - AndHUD.Shared.ShowSuccessWithStatus(this, null, MaskType.Black, TimeSpan.FromSeconds(3)); + AndHUD.Shared.ShowSuccess(this, null, MaskType.Black, TimeSpan.FromSeconds(3)); break; case "Success Image and Text": - AndHUD.Shared.ShowSuccessWithStatus(this, "It Worked!", MaskType.Clear, TimeSpan.FromSeconds(3)); + AndHUD.Shared.ShowSuccess(this, "It Worked!", MaskType.Clear, TimeSpan.FromSeconds(3)); break; case "Error Image Only": - AndHUD.Shared.ShowErrorWithStatus(this, null, MaskType.Clear, TimeSpan.FromSeconds(3)); + AndHUD.Shared.ShowError(this, null, MaskType.Clear, TimeSpan.FromSeconds(3)); break; case "Error Image and Text": - AndHUD.Shared.ShowErrorWithStatus(this, "It no worked :(", MaskType.Black, TimeSpan.FromSeconds(3)); + AndHUD.Shared.ShowError(this, "It no worked :(", MaskType.Black, TimeSpan.FromSeconds(3)); break; case "Toast": AndHUD.Shared.ShowToast(this, "This is a toast... Cheers!", MaskType.Black, TimeSpan.FromSeconds(3), true); @@ -114,9 +119,10 @@ private void OnItemClick(object sender, AdapterView.ItemClickEventArgs e) } } - void ShowProgressDemo(Action action) + private void ShowProgressDemo(Action action) { - Task.Run(() => { + _ = Task.Run(() => + { int progress = 0; while (progress <= 100) @@ -131,10 +137,10 @@ void ShowProgressDemo(Action action) }); } - void ShowDemo(Action action) + private void ShowDemo(Action action) { - Task.Run(() => { - + _ = Task.Run(() => + { action(); new ManualResetEvent(false).WaitOne(3000); @@ -144,4 +150,3 @@ void ShowDemo(Action action) } } } - diff --git a/Samples/SampleApp/Properties/AssemblyInfo.cs b/Samples/SampleApp/Properties/AssemblyInfo.cs index 92d42db..15dac17 100644 --- a/Samples/SampleApp/Properties/AssemblyInfo.cs +++ b/Samples/SampleApp/Properties/AssemblyInfo.cs @@ -1,4 +1,5 @@ using System.Reflection; +// using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Android.App; diff --git a/Samples/SampleApp/SampleApp.csproj b/Samples/SampleApp/SampleApp.csproj index 518c0e3..90f1ac3 100644 --- a/Samples/SampleApp/SampleApp.csproj +++ b/Samples/SampleApp/SampleApp.csproj @@ -17,7 +17,6 @@ Resources\Resource.designer.cs Resource Off - false v9.0 Properties\AndroidManifest.xml Resources @@ -35,10 +34,6 @@ True None False - false - false - false - false true d8 true @@ -55,10 +50,6 @@ False SdkOnly True - false - false - false - false true d8 true diff --git a/analyzers.ruleset b/analyzers.ruleset new file mode 100644 index 0000000..7fb7c50 --- /dev/null +++ b/analyzers.ruleset @@ -0,0 +1,272 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/global.json b/global.json index e6e7cdb..80d84a2 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "msbuild-sdks": { - "MSBuild.Sdk.Extras": "2.0.43" + "MSBuild.Sdk.Extras": "2.0.54" } } \ No newline at end of file diff --git a/stylecop.json b/stylecop.json new file mode 100644 index 0000000..324f4a9 --- /dev/null +++ b/stylecop.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "indentation": { + "useTabs": false, + "indentationSize": 4 + }, + "documentationRules": { + "documentExposedElements": true, + "documentInternalElements": false, + "documentPrivateElements": false, + "documentInterfaces": true, + "documentPrivateFields": false, + "documentationCulture": "en-US", + "variables": { + "licenseName": "Apache 2.0", + "licenseFile": "LICENSE" + }, + "xmlHeader": false + }, + "layoutRules": { + "newlineAtEndOfFile": "allow", + "allowConsecutiveUsings": true + }, + "maintainabilityRules": { + "topLevelTypes": [ + "class", + "interface", + "struct", + "enum", + "delegate" + ] + }, + "orderingRules": { + "usingDirectivesPlacement": "outsideNamespace", + "systemUsingDirectivesFirst": true + } + } +}