From 806edf76763b99c56c5cd34c4e1c3aa96e383bfd Mon Sep 17 00:00:00 2001 From: Max Mannstein Date: Thu, 14 Aug 2025 10:34:58 +0200 Subject: [PATCH] net-9 upgrade v1 --- .DS_Store | Bin 6148 -> 6148 bytes gehGassiApp/.DS_Store | Bin 6148 -> 8196 bytes .../gehGassi.LocalNotifications/.DS_Store | Bin 6148 -> 6148 bytes gehGassiApp/gehGassiApp.Core/.DS_Store | Bin 6148 -> 6148 bytes gehGassiApp/gehGassiApp.Data/.DS_Store | Bin 6148 -> 6148 bytes gehGassiApp/gehGassiApp.Domain/.DS_Store | Bin 0 -> 6148 bytes gehGassiApp/gehGassiApp/.DS_Store | Bin 6148 -> 6148 bytes gehGassiApp/gehGassiApp/MauiProgram.cs | 5 + .../Models/PopupResults/AGBUpdateResult.cs | 17 ++ .../PopupResults/SubscriptionOfferResult.cs | 17 ++ .../PopupResults/SubscriptionSuccessResult.cs | 17 ++ .../Platforms/Android/MainActivity.cs | 3 +- .../gehGassiApp/ViewModels/HomeViewModel.cs | 28 ++- .../ViewModels/HomeWalkerViewModel.cs | 14 +- .../Onboarding/OnboardingViewModel.cs | 29 --- .../Popups/AGBUpdatePopupViewModel.cs | 170 ++++++++++-------- .../Popups/PaymentInfoPopupViewModel.cs | 57 ------ .../Popups/SubscriptionOfferPopupViewModel.cs | 103 ++++++----- .../SubscriptionSuccessPopupViewModel.cs | 99 ++++++---- .../Subscriptions/SubscriptionsViewModel.cs | 28 ++- .../Views/Popups/AGBUpdatePopup.xaml | 5 +- .../Views/Popups/AGBUpdatePopup.xaml.cs | 4 +- .../Views/Popups/PaymentInfoPopup.xaml | 98 ---------- .../Views/Popups/PaymentInfoPopup.xaml.cs | 13 -- .../Views/Popups/SubscriptionOfferPopup.xaml | 5 +- .../Popups/SubscriptionOfferPopup.xaml.cs | 4 +- .../Popups/SubscriptionSuccessPopup.xaml | 5 +- .../Popups/SubscriptionSuccessPopup.xaml.cs | 4 +- gehGassiApp/gehGassiApp/gehGassiApp.csproj | 22 ++- 29 files changed, 347 insertions(+), 400 deletions(-) create mode 100644 gehGassiApp/gehGassiApp.Domain/.DS_Store create mode 100644 gehGassiApp/gehGassiApp/Models/PopupResults/AGBUpdateResult.cs create mode 100644 gehGassiApp/gehGassiApp/Models/PopupResults/SubscriptionOfferResult.cs create mode 100644 gehGassiApp/gehGassiApp/Models/PopupResults/SubscriptionSuccessResult.cs delete mode 100644 gehGassiApp/gehGassiApp/ViewModels/Popups/PaymentInfoPopupViewModel.cs delete mode 100644 gehGassiApp/gehGassiApp/Views/Popups/PaymentInfoPopup.xaml delete mode 100644 gehGassiApp/gehGassiApp/Views/Popups/PaymentInfoPopup.xaml.cs diff --git a/.DS_Store b/.DS_Store index 28f106b5a7aed2ab49ef35f44f7a16379bf29e1e..b250e352695b16db8308416e9689518c8275e4e8 100644 GIT binary patch delta 158 zcmZoMXfc=|#>B`mu~2NHo+2ab!~pAw2O5BMj}jxp#2zVuoOHwBYOn+}1c1-!WBSbs}n>c?#2Eq(SmIWI(YO-x+=iui6+PiV%cjn3b XBDy>v^BIA-0f;yIi0ojV*uVk+osca4 delta 82 zcmZoMXfc=|#>CJzu~2NHo+2aT!~knX#>x7OQk*Hp$vH{+`8kZ6A2O=3ZT`S$#JHKA jgP#Ma7%1|cc{0CxM>yL diff --git a/gehGassiApp/.DS_Store b/gehGassiApp/.DS_Store index 536eebef8364ac47ae4b651bb28633c8a5b0bed8..4196e61be3df38e42a414ec874eb8a55416d5f0d 100644 GIT binary patch literal 8196 zcmeI1K}#D!6vyAJ76L+%wuclE7V4p=Vv6)8th&;IMGE!<)Fc|En@liDbKI}dTR%mq zhn}Ukl3oJ+0G6Km5&XZINiw=gx=|6)H(};&X5W8y-*0zk_w5pqT0N?kh>Ap1KxI2S zgJwwK^;|P0a6NOd3VNb#YT>s}FX(N?TRMb*5D)@FKnMtd+du&KY%YZn_kFuoS|K0= z?j-@9A3{{Nk+Z3_X6is=QUKU#ben=@n zE-Lr%vZe;Ls;x>=);i%qFF8a~D{WPDy~#tUZ)<-pKT=)CaXHatj8LdO+<5xq*~!XP zMyp=qXwAJrltJ+)b_ z^Zn@5@*6R3T@U#D-`kJ>W%~?a|*$*@Lbo?OC2K<1Z&-YK5 z?18zkV}9t9=zIvl@5S+P#pXKO&IiFcpM%hu#ml`hl%2+h@OL2xguZTY{3p@*5T=&? zF@z_>Pi~wEF_q2P&@fX^&4=-5j7U=*^!BMSvA`#&etmt6z00*BpW^5CyN#~Bc5-S5 zBq!DSG=o=W5@n)Ngg`C=Q`W1<`Tsg*3waNa3!69zfjdP&O~+gDDnfF(btX8@wL{bo zs9e}Dwbn?`m~dDA^G$o=0O5ozuN FfiwG2cPIb= delta 151 zcmZp1XfcprU|?W$DortDU=RQ@Ie-{MGjUEV6q~50$jH7iU^gQp`(%FstH~>b;jo{TANEA~xFfP`3Le>l41}pn!ViGjkio`+zig8YL|8U+ ibMSC5wr@=Q&ODi4L{X3ls7L{b6Mz^DHam(OW(ENIBrTW# delta 71 zcmZoMXfc=|&Zs)EP;8=}A_oHyFfuR*Y-VI+W1lR*xN0*yhX4noDv;n0>S2z#P@+!0we1&?e&29l}sE&#P5gN+4$*(Mu^ux#e$ h;Nf6w-#}2OXmnz|8Rz)T>=O#>?T9BWC(eekh616$r2<3Sj-~(K!oQjSFG;Zr1ww&; zr2voWWxc>Fd2j8#ob=iRzk`1oYPB4Twql^RVr--pPdar;o{`Uvt)bEpS2{3$1Vopx JP~a~V_yB{#DVYEO literal 0 HcmV?d00001 diff --git a/gehGassiApp/gehGassiApp/.DS_Store b/gehGassiApp/gehGassiApp/.DS_Store index ee640fe8e711e362f7d53b420688ddb466fe4ccd..6b2e450323a963c10bd46feb16630523de1ae0a8 100644 GIT binary patch delta 312 zcmZoMXfc=|#>B`mF;R?_gMono$Pf`{0y01VB*4hPAi!W4oSdIqFfnm$JxGX|A&DWA zAulH#A`DUq1yGsXd>5Cboctu9D97HsZkglC#~p!exNHg@*@6r#rse}}%mUe$0CES& zGMSY-kAsZ_OCeim+oiHvP8Dh)R2E?&rYy3Bvg!!bD-Rp@{Hi50O300QNdWuK)l5 delta 109 zcmZoMXfc=|#>AjHF;Uo(); builder.Services.AddTransient(); + + // Popup ViewModels - NEW PATTERN + builder.Services.AddTransientPopup(); + builder.Services.AddTransientPopup(); + builder.Services.AddTransientPopup(); #endregion #region Views diff --git a/gehGassiApp/gehGassiApp/Models/PopupResults/AGBUpdateResult.cs b/gehGassiApp/gehGassiApp/Models/PopupResults/AGBUpdateResult.cs new file mode 100644 index 0000000..4b18a96 --- /dev/null +++ b/gehGassiApp/gehGassiApp/Models/PopupResults/AGBUpdateResult.cs @@ -0,0 +1,17 @@ +namespace gehGassiApp.Models.PopupResults; + +public class AGBUpdateResult +{ + public bool IsAccepted { get; set; } + + // Factory Methods für bessere Usability + public static AGBUpdateResult Accepted() => new() + { + IsAccepted = true + }; + + public static AGBUpdateResult Declined() => new() + { + IsAccepted = false + }; +} diff --git a/gehGassiApp/gehGassiApp/Models/PopupResults/SubscriptionOfferResult.cs b/gehGassiApp/gehGassiApp/Models/PopupResults/SubscriptionOfferResult.cs new file mode 100644 index 0000000..6a8b893 --- /dev/null +++ b/gehGassiApp/gehGassiApp/Models/PopupResults/SubscriptionOfferResult.cs @@ -0,0 +1,17 @@ +namespace gehGassiApp.Models.PopupResults; + +public class SubscriptionOfferResult +{ + public bool IsAccepted { get; set; } + + // Factory Methods für bessere Usability + public static SubscriptionOfferResult Accepted() => new() + { + IsAccepted = true + }; + + public static SubscriptionOfferResult Declined() => new() + { + IsAccepted = false + }; +} diff --git a/gehGassiApp/gehGassiApp/Models/PopupResults/SubscriptionSuccessResult.cs b/gehGassiApp/gehGassiApp/Models/PopupResults/SubscriptionSuccessResult.cs new file mode 100644 index 0000000..1981793 --- /dev/null +++ b/gehGassiApp/gehGassiApp/Models/PopupResults/SubscriptionSuccessResult.cs @@ -0,0 +1,17 @@ +namespace gehGassiApp.Models.PopupResults; + +public class SubscriptionSuccessResult +{ + public bool HasOpenedStrayz { get; set; } + + // Factory Methods für bessere Usability + public static SubscriptionSuccessResult StrayzOpened() => new() + { + HasOpenedStrayz = true + }; + + public static SubscriptionSuccessResult Closed() => new() + { + HasOpenedStrayz = false + }; +} diff --git a/gehGassiApp/gehGassiApp/Platforms/Android/MainActivity.cs b/gehGassiApp/gehGassiApp/Platforms/Android/MainActivity.cs index 1124d50..6ac4ea4 100644 --- a/gehGassiApp/gehGassiApp/Platforms/Android/MainActivity.cs +++ b/gehGassiApp/gehGassiApp/Platforms/Android/MainActivity.cs @@ -2,6 +2,7 @@ using Android.App; using Android.Content; using Android.Content.PM; +using Android.Gms.Tasks; using Android.OS; using Android.Views; using CommunityToolkit.Mvvm.Messaging; @@ -24,7 +25,7 @@ namespace gehGassiApp; Android.Content.Intent.CategoryDefault, Android.Content.Intent.CategoryBrowsable })] -public class MainActivity : MauiAppCompatActivity, Android.Gms.Tasks.IOnSuccessListener +public class MainActivity : MauiAppCompatActivity, IOnSuccessListener { //Service der die Installation des Gerätes am PNS ermöglicht IDeviceInstallationService _deviceInstallationService; diff --git a/gehGassiApp/gehGassiApp/ViewModels/HomeViewModel.cs b/gehGassiApp/gehGassiApp/ViewModels/HomeViewModel.cs index 294fc4c..bad785c 100644 --- a/gehGassiApp/gehGassiApp/ViewModels/HomeViewModel.cs +++ b/gehGassiApp/gehGassiApp/ViewModels/HomeViewModel.cs @@ -1,4 +1,5 @@ -using CommunityToolkit.Maui.Core; +using CommunityToolkit.Maui; +using CommunityToolkit.Maui.Core; using CommunityToolkit.Maui.Core.Extensions; using CommunityToolkit.Maui.Views; using CommunityToolkit.Mvvm.ComponentModel; @@ -14,6 +15,7 @@ using gehGassiApp.Domain.Common; using gehGassiApp.Domain.Lookup; using gehGassiApp.Domain.Walks; using gehGassiApp.Helper; +using gehGassiApp.Models.PopupResults; using gehGassiApp.Resources; using gehGassiApp.Services; using gehGassiApp.Views; @@ -40,6 +42,7 @@ namespace gehGassiApp.ViewModels private readonly IUserService _userService; private readonly IFavouriteService _favouriteService; private readonly IConversationService _conversationService; + private readonly IPopupService _popupService; /// /// Hilfsvariable: max. Anzahl verfügbare Walker /// @@ -64,7 +67,7 @@ namespace gehGassiApp.ViewModels /// Instanz eines IDispatcher /// Instanz eines IUserService /// Instanz eines IFavouriteService - public HomeViewModel(IWalkService walkService, IBannerService bannerService, IDialogService dialogService, IDogWalkerService dogWalkerService, IDispatcher dispatcher, IUserService userService, IFavouriteService favouriteService, IConversationService conversationService) + public HomeViewModel(IWalkService walkService, IBannerService bannerService, IDialogService dialogService, IDogWalkerService dogWalkerService, IDispatcher dispatcher, IUserService userService, IFavouriteService favouriteService, IConversationService conversationService, IPopupService popupService) { _walkService = walkService; _bannerService = bannerService; @@ -74,6 +77,7 @@ namespace gehGassiApp.ViewModels _userService = userService; _favouriteService = favouriteService; _conversationService = conversationService; + _popupService = popupService; Title = Text.View_Title_Home; SelectedMenu = MenuSelected.Home; @@ -797,11 +801,13 @@ namespace gehGassiApp.ViewModels && registrationDate != null && registrationDate.Value.Date < cutoffDate) { - var popup = new AGBUpdatePopup(); - var result = await Shell.Current.CurrentPage.ShowPopupAsync(popup); + var popupResult = await _popupService.ShowPopupAsync( + Shell.Current + ); // Nach dem Schließen des Popups prüfen wir erneut - if (result is bool accepted && accepted) + var result = popupResult.Result; + if (result != null && result.IsAccepted) { UserPreferencesService.HasAcceptedAGB = true; } @@ -816,14 +822,22 @@ namespace gehGassiApp.ViewModels // UND der Count <= 5 ist und noch nicht in dieser Session gezeigt wurde if (!IsPremiumUser && UserPreferencesService.ShowSubscriptionOffer) { - var popup = new SubscriptionOfferPopup(); - var result = await Shell.Current.CurrentPage.ShowPopupAsync(popup); + var popupResult = await _popupService.ShowPopupAsync( + Shell.Current + ); // Markiere als in dieser Session gezeigt UserPreferencesService.MarkSubscriptionOfferShownThisSession(); // Erhöhe den Counter, unabhängig davon ob das Popup angenommen oder abgelehnt wurde UserPreferencesService.IncreaseSubscriptionOfferPopupCount(); + + // Falls der User das Abo akzeptiert hat, ist Navigation bereits im ViewModel behandelt + var result = popupResult.Result; + if (result != null && result.IsAccepted) + { + // Navigation erfolgt bereits im SubscriptionOfferPopupViewModel + } } } diff --git a/gehGassiApp/gehGassiApp/ViewModels/HomeWalkerViewModel.cs b/gehGassiApp/gehGassiApp/ViewModels/HomeWalkerViewModel.cs index 8bc52c8..7b08141 100644 --- a/gehGassiApp/gehGassiApp/ViewModels/HomeWalkerViewModel.cs +++ b/gehGassiApp/gehGassiApp/ViewModels/HomeWalkerViewModel.cs @@ -1,4 +1,5 @@ using System.Collections.ObjectModel; +using CommunityToolkit.Maui; using CommunityToolkit.Maui.Core; using CommunityToolkit.Maui.Core.Extensions; using CommunityToolkit.Maui.Views; @@ -10,6 +11,7 @@ using gehGassiApp.Core.Messaging; using gehGassiApp.Domain.Banners; using gehGassiApp.Domain.Common; using gehGassiApp.Domain.Walks; +using gehGassiApp.Models.PopupResults; using gehGassiApp.Resources; using gehGassiApp.Services; using gehGassiApp.Views.Popups; @@ -28,6 +30,7 @@ namespace gehGassiApp.ViewModels private readonly IDispatcher _dispatcher; private readonly IUserService _userService; private readonly IFavouriteService _favouriteService; + private readonly IPopupService _popupService; /// /// Hilfsvariable: max. Anzahl verfügbare öffentlichen Anfragen @@ -55,7 +58,7 @@ namespace gehGassiApp.ViewModels /// Instanz eines IUserService /// Instanz eines IFavouriteService public HomeWalkerViewModel(IWalkService walkService, IBannerService bannerService, - IPublicWalkRequestService publicWalkRequestService, IPublicWalkResponseService publicWalkResponseService, IDialogService dialogService, IDispatcher dispatcher, IUserService userService, IFavouriteService favouriteService) + IPublicWalkRequestService publicWalkRequestService, IPublicWalkResponseService publicWalkResponseService, IDialogService dialogService, IDispatcher dispatcher, IUserService userService, IFavouriteService favouriteService, IPopupService popupService) { _walkService = walkService; _bannerService = bannerService; @@ -65,6 +68,7 @@ namespace gehGassiApp.ViewModels _dispatcher = dispatcher; _userService = userService; _favouriteService = favouriteService; + _popupService = popupService; Title = Text.View_Title_Home; SelectedMenu = MenuSelected.HomeWalker; BannerMargin = new Thickness(0, 0, 0, 0); @@ -364,11 +368,13 @@ namespace gehGassiApp.ViewModels && registrationDate != null && registrationDate.Value.Date < cutoffDate) { - var popup = new AGBUpdatePopup(); - var result = await Shell.Current.CurrentPage.ShowPopupAsync(popup); + var popupResult = await _popupService.ShowPopupAsync( + Shell.Current + ); // Nach dem Schließen des Popups prüfen wir erneut - if (result is bool accepted && accepted) + var result = popupResult.Result; + if (result != null && result.IsAccepted) { UserPreferencesService.HasAcceptedAGB = true; } diff --git a/gehGassiApp/gehGassiApp/ViewModels/Onboarding/OnboardingViewModel.cs b/gehGassiApp/gehGassiApp/ViewModels/Onboarding/OnboardingViewModel.cs index 22c841d..68a9ed6 100644 --- a/gehGassiApp/gehGassiApp/ViewModels/Onboarding/OnboardingViewModel.cs +++ b/gehGassiApp/gehGassiApp/ViewModels/Onboarding/OnboardingViewModel.cs @@ -153,35 +153,6 @@ namespace gehGassiApp.ViewModels.Onboarding //await ShowSubscriptionSuccessPopup(); //await CheckAGBStatus(); } - [RelayCommand] - private async Task CheckAGBStatus() - { - // Prüfe, ob AGB-Popup angezeigt werden muss - if (!AGBUpdatePopupViewModel.HasUserAcceptedCurrentAGB()) - { - // Popup und ViewModel erstellen - var popup = new AGBUpdatePopup(); - var viewModel = new AGBUpdatePopupViewModel(popup); - popup.BindingContext = viewModel; - - // Popup anzeigen und auf Ergebnis warten - var result = await Shell.Current.CurrentPage.ShowPopupAsync(popup); - - // result ist true wenn akzeptiert, false wenn abgelehnt - if (result is bool accepted) - { - if (accepted) - { - await Shell.Current.DisplayAlert("Info", "Danke für die Zustimmung!", "OK"); - } - else - { - // User hat abgelehnt - weitere Aktionen - await Shell.Current.DisplayAlert("Info", "AGB wurden abgelehnt", "OK"); - } - } - } - } } public class OnboardingItemViewModel diff --git a/gehGassiApp/gehGassiApp/ViewModels/Popups/AGBUpdatePopupViewModel.cs b/gehGassiApp/gehGassiApp/ViewModels/Popups/AGBUpdatePopupViewModel.cs index 9e2babf..5c8e21e 100644 --- a/gehGassiApp/gehGassiApp/ViewModels/Popups/AGBUpdatePopupViewModel.cs +++ b/gehGassiApp/gehGassiApp/ViewModels/Popups/AGBUpdatePopupViewModel.cs @@ -1,97 +1,109 @@ -using CommunityToolkit.Maui.Core; +using CommunityToolkit.Maui; +using CommunityToolkit.Maui.Core; using CommunityToolkit.Maui.Views; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using gehGassiApp.Models.PopupResults; using gehGassiApp.Resources; using gehGassiApp.Services; using gehGassiApp.Views; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace gehGassiApp.ViewModels.Popups -{ public partial class AGBUpdatePopupViewModel : ObservableObject +namespace gehGassiApp.ViewModels.Popups; + +public partial class AGBUpdatePopupViewModel : ObservableObject, IQueryAttributable +{ + #region Properties + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(AcceptButtonColor))] + private bool _hasAccepted = false; + + // Computed Property für Button-Farbe + readonly IPopupService _popupService; + public Color AcceptButtonColor => HasAccepted ? Color.FromArgb("#2E7D32") : Color.FromArgb("#BDBDBD"); + #endregion + + #region Constructor + public AGBUpdatePopupViewModel(IPopupService popupService) { - private readonly Popup _popup; - private const string AGB_URL = "https://gehgassi.app/agb"; // Ersetze mit eurer tatsächlichen AGB-URL + _popupService = popupService; + // Initialisiere die AGB-Status + HasAccepted = HasUserAcceptedCurrentAGB(); + } + #endregion - [ObservableProperty] - [NotifyPropertyChangedFor(nameof(AcceptButtonColor))] - private bool _hasAccepted = false; + #region IQueryAttributable Implementation + public void ApplyQueryAttributes(IDictionary query) + { + // Falls Parameter benötigt werden, hier implementieren + } + #endregion - // Computed Property für Button-Farbe - public Color AcceptButtonColor => HasAccepted ? Color.FromArgb("#2E7D32") : Color.FromArgb("#BDBDBD"); + #region Static Methods + /// + /// Prüft, ob der User bereits den aktuellen AGB zugestimmt hat + /// + public static bool HasUserAcceptedCurrentAGB() + { + return UserPreferencesService.HasAcceptedAGB; + } - public AGBUpdatePopupViewModel(Popup popup) + /// + /// Markiert die aktuellen AGB als vom User akzeptiert + /// + private static void MarkAGBAsAccepted() + { + UserPreferencesService.HasAcceptedAGB = true; + } + #endregion + + #region Commands + /// + /// Öffnet die vollständigen AGB im Browser + /// + [RelayCommand] + private async Task OpenAGB() + { + try { - _popup = popup; + var menu = MenuSelected.More.ToString(); + var title = Text.View_Title_Privacy; + await Shell.Current.GoToAsync($"{nameof(ShowTextPageView)}?code={Core.Common.Constants.PagePrivacy}&menu={menu}&title={title}", Core.Common.Constants.AnimateNavigation); } - - /// - /// Prüft, ob der User bereits den aktuellen AGB zugestimmt hat - /// - public static bool HasUserAcceptedCurrentAGB() + catch (Exception ex) { - return UserPreferencesService.HasAcceptedAGB; - } + // Fallback: Zeige Error-Dialog + await Shell.Current.DisplayAlert( + "Fehler", + "Die Nutzungsbedingungen konnten nicht geöffnet werden. Bitte versuchen Sie es später erneut.", + "OK"); - /// - /// Markiert die aktuellen AGB als vom User akzeptiert - /// - private static void MarkAGBAsAccepted() - { - UserPreferencesService.HasAcceptedAGB = true; - } - - /// - /// Öffnet die vollständigen AGB im Browser - /// - [RelayCommand] - private async Task OpenAGB() - { - try - { - - var menu = MenuSelected.More.ToString(); - var title = Text.View_Title_Privacy; - await Shell.Current.GoToAsync($"{nameof(ShowTextPageView)}?code={Core.Common.Constants.PagePrivacy}&menu={menu}&title={title}", Core.Common.Constants.AnimateNavigation); - - } - catch (Exception ex) - { - // Fallback: Zeige Error-Dialog - await Shell.Current.DisplayAlert( - "Fehler", - "Die Nutzungsbedingungen konnten nicht geöffnet werden. Bitte versuchen Sie es später erneut.", - "OK"); - - // Optional: Logging - System.Diagnostics.Debug.WriteLine($"Error opening AGB URL: {ex.Message}"); - } - } - - /// - /// User hat die AGB akzeptiert - /// - [RelayCommand] - private async Task Accept() - { - if (!HasAccepted) - { - await Shell.Current.DisplayAlert( - "Hinweis", - "Bitte bestätige zuerst, dass du die Nutzungsbedingungen gelesen hast und ihnen zustimmst.", - "OK"); - return; - } - - // AGB als akzeptiert markieren - MarkAGBAsAccepted(); - - // Popup schließen - await _popup.CloseAsync(true); + // Optional: Logging + System.Diagnostics.Debug.WriteLine($"Error opening AGB URL: {ex.Message}"); } } + + /// + /// User hat die AGB akzeptiert + /// + [RelayCommand] + private async Task Accept() + { + if (!HasAccepted) + { + await Shell.Current.DisplayAlert( + "Hinweis", + "Bitte bestätige zuerst, dass du die Nutzungsbedingungen gelesen hast und ihnen zustimmst.", + "OK"); + return; + } + + // AGB als akzeptiert markieren + MarkAGBAsAccepted(); + + var result = AGBUpdateResult.Accepted(); + + // ✅ Toolkit übernimmt das Popup-Closing + await _popupService.ClosePopupAsync(Shell.Current, result); + } + #endregion } diff --git a/gehGassiApp/gehGassiApp/ViewModels/Popups/PaymentInfoPopupViewModel.cs b/gehGassiApp/gehGassiApp/ViewModels/Popups/PaymentInfoPopupViewModel.cs deleted file mode 100644 index 1efd047..0000000 --- a/gehGassiApp/gehGassiApp/ViewModels/Popups/PaymentInfoPopupViewModel.cs +++ /dev/null @@ -1,57 +0,0 @@ -using CommunityToolkit.Maui.Views; -using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; - -namespace gehGassiApp.ViewModels.Popups -{ - /// - /// ViewModel für das Zahlungshinweis-Popup - /// - /// Verwendung: - /// // Prüfen ob bereits angezeigt - /// if (!PaymentInfoPopupViewModel.HasInfoBeenShown()) - /// { - /// var popup = new PaymentInfoPopup(); - /// await Shell.Current.CurrentPage.ShowPopupAsync(popup); - /// } - /// - public partial class PaymentInfoPopupViewModel : ObservableObject - { - private readonly Popup _popup; - private const string PAYMENT_INFO_SHOWN_KEY = "payment_info_july_shown_2025"; - - public PaymentInfoPopupViewModel(Popup popup) - { - _popup = popup; - } - - /// - /// Prüft, ob der Zahlungshinweis bereits angezeigt wurde - /// - public static bool HasInfoBeenShown() - { - return Preferences.Get(PAYMENT_INFO_SHOWN_KEY, false); - } - - /// - /// Markiert den Hinweis als angezeigt - /// - private static void MarkInfoAsShown() - { - Preferences.Set(PAYMENT_INFO_SHOWN_KEY, true); - } - - /// - /// User hat den Hinweis zur Kenntnis genommen - /// - [RelayCommand] - private async Task Acknowledge() - { - // Hinweis als angezeigt markieren - MarkInfoAsShown(); - - // Popup schließen - await _popup.CloseAsync(true); - } - } -} diff --git a/gehGassiApp/gehGassiApp/ViewModels/Popups/SubscriptionOfferPopupViewModel.cs b/gehGassiApp/gehGassiApp/ViewModels/Popups/SubscriptionOfferPopupViewModel.cs index ef53d11..9dead5a 100644 --- a/gehGassiApp/gehGassiApp/ViewModels/Popups/SubscriptionOfferPopupViewModel.cs +++ b/gehGassiApp/gehGassiApp/ViewModels/Popups/SubscriptionOfferPopupViewModel.cs @@ -1,61 +1,58 @@ -using CommunityToolkit.Maui.Views; +using CommunityToolkit.Maui; +using CommunityToolkit.Maui.Views; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using gehGassiApp.Models.PopupResults; using gehGassiApp.Views.Subscriptions; -namespace gehGassiApp.ViewModels.Popups +namespace gehGassiApp.ViewModels.Popups; + +public partial class SubscriptionOfferPopupViewModel : ObservableObject, IQueryAttributable { - public partial class SubscriptionOfferPopupViewModel : ObservableObject + #region Dependencies + private readonly IPopupService _popupService; + #endregion + + #region Constructor + public SubscriptionOfferPopupViewModel(IPopupService popupService) { - private readonly Popup _popup; - private const string SUBSCRIPTION_OFFER_SHOWN_KEY = "subscription_offer_shown_v2025"; - - public SubscriptionOfferPopupViewModel(Popup popup) - { - _popup = popup; - } - - /// - /// Prüft, ob das Abo-Angebot bereits angezeigt wurde - /// - public static bool HasOfferBeenShown() - { - return Preferences.Get(SUBSCRIPTION_OFFER_SHOWN_KEY, false); - } - - /// - /// Markiert das Angebot als angezeigt - /// - private static void MarkOfferAsShown() - { - //Preferences.Set(SUBSCRIPTION_OFFER_SHOWN_KEY, true); - } - - /// - /// User möchte Abo abschließen - /// - [RelayCommand] - private async Task Accept() - { - // Angebot als angezeigt markieren - MarkOfferAsShown(); - - // Popup schließen mit true (User will Abo) - await _popup.CloseAsync(true); - await Shell.Current.GoToAsync($"{nameof(SubscriptionsView)}", Core.Common.Constants.AnimateNavigation); - } - - /// - /// User möchte später entscheiden - /// - [RelayCommand] - private async Task Decline() - { - // Angebot als angezeigt markieren - MarkOfferAsShown(); - - // Popup schließen mit false (User will kein Abo) - await _popup.CloseAsync(false); - } + _popupService = popupService; } + #endregion + + #region IQueryAttributable Implementation + public void ApplyQueryAttributes(IDictionary query) + { + // Falls Parameter benötigt werden, hier implementieren + } + #endregion + + #region Commands + /// + /// User möchte Abo abschließen + /// + [RelayCommand] + private async Task Accept() + { + var result = SubscriptionOfferResult.Accepted(); + + // Popup schließen mit Result + await _popupService.ClosePopupAsync(Shell.Current, result); + + // Navigation zu Subscriptions + await Shell.Current.GoToAsync($"{nameof(SubscriptionsView)}", Core.Common.Constants.AnimateNavigation); + } + + /// + /// User möchte später entscheiden + /// + [RelayCommand] + private async Task Decline() + { + var result = SubscriptionOfferResult.Declined(); + + // Popup schließen mit Result + await _popupService.ClosePopupAsync(Shell.Current, result); + } + #endregion } diff --git a/gehGassiApp/gehGassiApp/ViewModels/Popups/SubscriptionSuccessPopupViewModel.cs b/gehGassiApp/gehGassiApp/ViewModels/Popups/SubscriptionSuccessPopupViewModel.cs index e7fda44..5a2f525 100644 --- a/gehGassiApp/gehGassiApp/ViewModels/Popups/SubscriptionSuccessPopupViewModel.cs +++ b/gehGassiApp/gehGassiApp/ViewModels/Popups/SubscriptionSuccessPopupViewModel.cs @@ -1,53 +1,74 @@ -using CommunityToolkit.Maui.Views; +using CommunityToolkit.Maui; +using CommunityToolkit.Maui.Views; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using gehGassiApp.Models.PopupResults; -namespace gehGassiApp.ViewModels.Popups +namespace gehGassiApp.ViewModels.Popups; + +public partial class SubscriptionSuccessPopupViewModel : ObservableObject, IQueryAttributable { - public partial class SubscriptionSuccessPopupViewModel : ObservableObject + #region Constants + private const string STRAYZ_URL = "https://www.strayz.de/pages/fuer-hunde"; + #endregion + + #region Dependencies + private readonly IPopupService _popupService; + #endregion + + #region Constructor + public SubscriptionSuccessPopupViewModel(IPopupService popupService) { - private readonly Popup _popup; - private const string STRAYZ_URL = "https://www.strayz.de/pages/fuer-hunde"; // Ersetze mit der tatsächlichen STRAYZ-URL + _popupService = popupService; + } + #endregion + #region IQueryAttributable Implementation + public void ApplyQueryAttributes(IDictionary query) + { + // Falls Parameter benötigt werden, hier implementieren + } + #endregion - public SubscriptionSuccessPopupViewModel(Popup popup) + #region Commands + /// + /// Öffnet die STRAYZ-Partnerseite + /// + [RelayCommand] + private async Task OpenStrayz() + { + try { - _popup = popup; + // Öffne STRAYZ-Seite im Browser + await Browser.OpenAsync(STRAYZ_URL, BrowserLaunchMode.External); + + var result = SubscriptionSuccessResult.StrayzOpened(); + + // Popup schließen mit Result + await _popupService.ClosePopupAsync(Shell.Current, result); } - - /// - /// Öffnet die STRAYZ-Partnerseite - /// - [RelayCommand] - private async Task OpenStrayz() + catch (Exception ex) { - try - { - // Öffne STRAYZ-Seite im Browser - await Browser.OpenAsync(STRAYZ_URL, BrowserLaunchMode.External); + // Fehlerbehandlung + await Shell.Current.DisplayAlert( + "Fehler", + "Die STRAYZ-Seite konnte nicht geöffnet werden. Bitte versuche es später erneut oder besuche strayz.de direkt.", + "OK"); - // Popup schließen - await _popup.CloseAsync(true); - } - catch (Exception ex) - { - // Fehlerbehandlung - await Shell.Current.DisplayAlert( - "Fehler", - "Die STRAYZ-Seite konnte nicht geöffnet werden. Bitte versuche es später erneut oder besuche strayz.de direkt.", - "OK"); - - System.Diagnostics.Debug.WriteLine($"Error opening STRAYZ URL: {ex.Message}"); - } - } - - /// - /// Popup schließen ohne STRAYZ zu öffnen - /// - [RelayCommand] - private async Task Close() - { - await _popup.CloseAsync(false); + System.Diagnostics.Debug.WriteLine($"Error opening STRAYZ URL: {ex.Message}"); } } + + /// + /// Popup schließen ohne STRAYZ zu öffnen + /// + [RelayCommand] + private async Task Close() + { + var result = SubscriptionSuccessResult.Closed(); + + // Popup schließen mit Result + await _popupService.ClosePopupAsync(Shell.Current, result); + } + #endregion } diff --git a/gehGassiApp/gehGassiApp/ViewModels/Subscriptions/SubscriptionsViewModel.cs b/gehGassiApp/gehGassiApp/ViewModels/Subscriptions/SubscriptionsViewModel.cs index 4cdcf44..60e77f6 100644 --- a/gehGassiApp/gehGassiApp/ViewModels/Subscriptions/SubscriptionsViewModel.cs +++ b/gehGassiApp/gehGassiApp/ViewModels/Subscriptions/SubscriptionsViewModel.cs @@ -1,3 +1,4 @@ +using CommunityToolkit.Maui; using CommunityToolkit.Maui.Core.Extensions; using CommunityToolkit.Maui.Views; using CommunityToolkit.Mvvm.ComponentModel; @@ -8,6 +9,7 @@ using gehGassiApp.Core.Messaging; using gehGassiApp.Domain.Common; using gehGassiApp.Domain.Subscriptions; using gehGassiApp.Models; +using gehGassiApp.Models.PopupResults; using gehGassiApp.Resources; using gehGassiApp.Services; using gehGassiApp.Views; @@ -30,6 +32,7 @@ namespace gehGassiApp.ViewModels.Subscriptions private readonly ISubscriptionValidationService _subscriptionValidationService; private readonly IDispatcher _dispatcher; private readonly IDialogService _dialogService; + private readonly IPopupService _popupService; /// /// ERstellt eine Instanz @@ -38,12 +41,13 @@ namespace gehGassiApp.ViewModels.Subscriptions /// Instanz eines ISubscriptionValidationService /// Instanz eines IDispatcher /// Instanz eines IDialogService - public SubscriptionsViewModel(ISubscriptionService subscriptionService, ISubscriptionValidationService subscriptionValidationService, IDispatcher dispatcher, IDialogService dialogService) + public SubscriptionsViewModel(ISubscriptionService subscriptionService, ISubscriptionValidationService subscriptionValidationService, IDispatcher dispatcher, IDialogService dialogService, IPopupService popupService) { _subscriptionService = subscriptionService; _subscriptionValidationService = subscriptionValidationService; _dispatcher = dispatcher; _dialogService = dialogService; + _popupService = popupService; Title = Text.View_Title_Subscriptions; SelectedMenu = MenuSelected.More; @@ -205,8 +209,15 @@ namespace gehGassiApp.ViewModels.Subscriptions await LoadAsync(); if (MySubscriptions != null && MySubscriptions.Any()) { - var popup = new SubscriptionSuccessPopup(); - await Shell.Current.CurrentPage.ShowPopupAsync(popup); + var popupResult = await _popupService.ShowPopupAsync( + Shell.Current + ); + + var result = popupResult.Result; + if (result != null && result.HasOpenedStrayz) + { + // User hat STRAYZ geöffnet + } } } else @@ -425,8 +436,15 @@ namespace gehGassiApp.ViewModels.Subscriptions IsBusy = false; if (MySubscriptions != null && MySubscriptions.Any()) { - var popup = new SubscriptionSuccessPopup(); - await Shell.Current.CurrentPage.ShowPopupAsync(popup); + var popupResult = await _popupService.ShowPopupAsync( + Shell.Current + ); + + var result = popupResult.Result; + if (result != null && result.HasOpenedStrayz) + { + // User hat STRAYZ geöffnet + } } } diff --git a/gehGassiApp/gehGassiApp/Views/Popups/AGBUpdatePopup.xaml b/gehGassiApp/gehGassiApp/Views/Popups/AGBUpdatePopup.xaml index 0acce5b..fd47309 100644 --- a/gehGassiApp/gehGassiApp/Views/Popups/AGBUpdatePopup.xaml +++ b/gehGassiApp/gehGassiApp/Views/Popups/AGBUpdatePopup.xaml @@ -5,8 +5,9 @@ xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:res="clr-namespace:gehGassiApp.Resources" xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" - CanBeDismissedByTappingOutsideOfPopup="False" - Color="Transparent"> + xmlns:viewModels="clr-namespace:gehGassiApp.ViewModels.Popups" + x:DataType="viewModels:AGBUpdatePopupViewModel" + CanBeDismissedByTappingOutsideOfPopup="False"> - - - - - - - - - - - - - - - - - - - - - - - -