diff --git a/sample/Maui.Android.InAppUpdates.SampleApp.csproj b/sample/Maui.Android.InAppUpdates.SampleApp.csproj index 10cfe02..8fd362e 100644 --- a/sample/Maui.Android.InAppUpdates.SampleApp.csproj +++ b/sample/Maui.Android.InAppUpdates.SampleApp.csproj @@ -64,7 +64,7 @@ - + diff --git a/src/libs/Maui.Android.InAppUpdates/Maui.Android.InAppUpdates.csproj b/src/libs/Maui.Android.InAppUpdates/Maui.Android.InAppUpdates.csproj index 24b0f24..77c58e0 100644 --- a/src/libs/Maui.Android.InAppUpdates/Maui.Android.InAppUpdates.csproj +++ b/src/libs/Maui.Android.InAppUpdates/Maui.Android.InAppUpdates.csproj @@ -19,7 +19,7 @@ 10.0.17763.0 6.5 - + Oscore.$(AssemblyName) NuGet package that implementing Android In-App Updates for MAUI with debugging capabilities. @@ -27,14 +27,14 @@ - + - - - - + + + + diff --git a/src/libs/Maui.Android.InAppUpdates/Platforms/Android/DefaultUserInterface.cs b/src/libs/Maui.Android.InAppUpdates/Platforms/Android/DefaultUserInterface.cs index 908fc34..d4ac321 100644 --- a/src/libs/Maui.Android.InAppUpdates/Platforms/Android/DefaultUserInterface.cs +++ b/src/libs/Maui.Android.InAppUpdates/Platforms/Android/DefaultUserInterface.cs @@ -10,17 +10,30 @@ public static class DefaultUserInterface /// Displays a short duration toast message at the center of the screen. /// /// The text to be displayed in the toast message. - public static void ShowShortToast( - string text) + public static void ShowShortToast(string text) { - Toast.MakeText( - context: Platform.AppContext, - text: text, - duration: ToastLength.Short)?.Show(); + try + { + if (Platform.AppContext is null) + { + Handler.Options.DebugAction($"Cannot show toast - Platform.AppContext is null: {text}"); + return; + } + + Toast.MakeText( + context: Platform.AppContext, + text: text, + duration: ToastLength.Short)?.Show(); + } + catch (Exception ex) + { + Handler.Options.DebugAction($"Failed to show toast '{text}': {ex}"); + } } /// /// Displays a snackbar with an action to complete the app update process. + /// If snackbar fails due to theme incompatibility, falls back to toast message. /// /// The text to display on the snackbar. /// The text for the action button. @@ -30,18 +43,86 @@ public static void ShowSnackbar( string actionText, Action clickHandler) { - if (Platform.CurrentActivity?.Window?.DecorView is not {} view || - Snackbar.Make( - text: text, - duration: BaseTransientBottomBar.LengthIndefinite, - view: view) is not {} snackbar) + var fallbackMessage = $"{text} - {actionText}"; + + try + { + var view = Platform.CurrentActivity?.Window?.DecorView; + if (view is null) + { + FallbackToToastWithAction("Cannot show snackbar - no active view", fallbackMessage, clickHandler, null); + return; + } + + var snackbar = Snackbar.Make(view, text, BaseTransientBottomBar.LengthIndefinite); + if (snackbar is null) + { + FallbackToToastWithAction("Cannot create snackbar", fallbackMessage, clickHandler, view); + return; + } + + snackbar.SetAction(text: actionText, clickHandler: clickHandler); + snackbar.Show(); + } + catch (Exception ex) when (IsThemeRelated(ex)) + { + HandleSnackbarFailure(ex, "theme related", fallbackMessage, clickHandler, Platform.CurrentActivity?.Window?.DecorView); + } + catch (Exception ex) { - return; + HandleSnackbarFailure(ex, "general exception", fallbackMessage, null, null); } - - snackbar.SetAction( - text: actionText, - clickHandler: clickHandler); - snackbar.Show(); } + + private static void FallbackToToastWithAction( + string debugMessage, + string fallbackMessage, + Action? clickHandler, + global::Android.Views.View? fallbackView) + { + Handler.Options.DebugAction($"{debugMessage}, falling back to toast and auto-triggering action"); + ShowShortToast(fallbackMessage); + + // Auto-trigger the action since user can't click the snackbar + if (clickHandler is not null && fallbackView is not null) + { + try + { + clickHandler(fallbackView); + } + catch (Exception actionEx) + { + Handler.Options.DebugAction($"Error auto-executing snackbar action: {actionEx}"); + } + } + } + + private static void HandleSnackbarFailure( + Exception ex, + string errorType, + string fallbackMessage, + Action? clickHandler, + global::Android.Views.View? view) + { + Handler.Options.DebugAction($"Snackbar {errorType}: {ex}"); + ShowShortToast(fallbackMessage); + + // Only auto-trigger for theme-related exceptions where user interaction was expected + if (clickHandler is not null && view is not null) + { + try + { + clickHandler(view); + } + catch (Exception actionEx) + { + Handler.Options.DebugAction($"Error executing snackbar action: {actionEx}"); + } + } + } + + private static bool IsThemeRelated(Exception ex) => + ex is global::Android.Views.InflateException || + (ex is Java.Lang.UnsupportedOperationException && + ex.Message?.Contains("Failed to resolve attribute", StringComparison.Ordinal) == true); } \ No newline at end of file