Max Mannstein 4478fa2457 Update visual assets and refactor codebase
This commit includes a complete replacement of the binary content of the image files, significantly updating the visual assets of the application to enhance user experience and align with new design standards.

Key changes include:
- Resetting session state for the subscription offer popup in `App.xaml.cs`.
- Replacing buttons with touch-friendly labels in `Step2ExternalControl.xaml` and `Step3Control.xaml`.
- Updating image sources and bindings in `WalkerListControl.xaml` to reflect premium subscription status.
- Adding a new converter class `PremiumToChatImageConverter` in `CommonConverters.cs`.
- Modifying various view models to manage premium user status and subscription offers.
- Enhancing UI layouts across multiple XAML files for improved visibility and functionality.
- Updating localized strings in `Text.Designer.cs` and incrementing the app version in `Info.plist`.

These changes aim to improve the overall functionality, maintainability, and user experience of the application.
2025-07-01 15:53:21 +02:00

477 lines
19 KiB
C#

using System.Text.Json;
using CommunityToolkit.Maui.Core;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using gehGassi.Dto;
using gehGassiApp.Constants;
using gehGassiApp.Core.Interfaces;
using gehGassiApp.Core.Messaging;
using gehGassiApp.Domain.Common;
using gehGassiApp.Domain.Users;
using gehGassiApp.Resources;
using gehGassiApp.Services;
using gehGassiApp.Views;
using gehGassiApp.Views.Account;
using gehGassiApp.Views.Dogs;
using gehGassiApp.Views.Messages;
using gehGassiApp.Views.More;
using gehGassiApp.Views.Payments;
using gehGassiApp.Views.Ratings;
namespace gehGassiApp.ViewModels.More
{
/// <summary>
/// Viewmodel für die More-Ansicht
/// </summary>
public partial class MoreViewModel : MenuViewModel
{
private readonly IAccountService _accountService;
private readonly IDialogService _dialogService;
private readonly ISystemMessageService _systemMessageService;
private readonly IDispatcher _dispatcher;
private readonly IPushnotificationService _pushnotificationService;
/// <summary>
/// Erstellt eine Instanz
/// </summary>
/// <param name="accountService">Instanz eines IAccountService</param>
/// <param name="dialogService">Instanz eines IDialogService</param>
/// <param name="systemMessageService">Instanz eines ISystemMessageService</param>
/// <param name="dispatcher">Instanz eines IDispatcher</param>
/// <param name="pushnotificationService">Instanz eines IPushnotificationService</param>
public MoreViewModel(IAccountService accountService, IDialogService dialogService, ISystemMessageService systemMessageService, IDispatcher dispatcher,
IPushnotificationService pushnotificationService)
{
_accountService = accountService;
_dialogService = dialogService;
_systemMessageService = systemMessageService;
_dispatcher = dispatcher;
_pushnotificationService = pushnotificationService;
Title = Text.View_Title_More;
SelectedMenu = MenuSelected.More;
}
/// <summary>
/// Gibt an ob Switch verfügbar ist
/// </summary>
[ObservableProperty]
private bool _canSwitch;
/// <summary>
/// Gibt an ob der Benutzer auch ein Walker werden kann.
/// </summary>
[ObservableProperty]
private bool _canBecomeWalker;
/// <summary>
/// Aktuelle Version der App
/// </summary>
[ObservableProperty]
private string _currentVersion;
[ObservableProperty]
private bool _hasUnreadSystemMessagesOwner;
[ObservableProperty]
private bool _hasUnreadSystemMessagesWalker;
[ObservableProperty]
private bool _showAppMode;
/// <summary>
/// Gibt an ob der App-User über Payment verfügt
/// </summary>
[ObservableProperty]
private bool _hasPayment;
/// <summary>
/// Benötigt der App-User eine Bankverbindung?
/// </summary>
[ObservableProperty]
private bool _needsBankAccount;
/// <summary>
/// Benötigt der App-User eine KYC-Prüfung?
/// </summary>
[ObservableProperty]
private bool _needsIdentityProof;
#region Commands
/// <summary>
/// Command für die Abmeldung eines Benutzers
/// </summary>
[RelayCommand]
public async Task Logout()
{
if (App.CurrentUser != null)
{
IsBusy = true;
using var cts = new CancellationTokenSource(Core.Common.Constants.ListTimeout);
var installationId = await SecureStorage.GetAsync(Storage.PushnotificationInstallationId);
if (!string.IsNullOrWhiteSpace(installationId))
await _pushnotificationService.UnregisterAsycn(installationId, App.CurrentUser.AccessToken, cts.Token);
var logoutResult = await _accountService.LogoutAsync(App.CurrentUser.AccessToken, cts.Token);
App.CurrentUser = null;
WeakReferenceMessenger.Default.Send(new UserLoginStatusChangedMessage());
IsBusy = false;
}
}
/// <summary>
/// Command für das Wechseln zwischen Owner und Walker
/// </summary>
[RelayCommand]
public async Task Switch()
{
App.AppMode = App.AppMode == AppMode.DogOwner ? AppMode.DogWalker : AppMode.DogOwner;
var jsonOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web);
var currentAppModeJson = JsonSerializer.Serialize(App.AppMode, jsonOptions);
Preferences.Set(Storage.LastAppMode, currentAppModeJson);
WeakReferenceMessenger.Default.Send(new RefreshViewModelMessage(Core.Messaging.Messages.Refresh_Home));
if (App.AppMode == AppMode.DogOwner)
{
var stackCount = Shell.Current.Navigation.NavigationStack.Count;
if (stackCount > 1)
{
await Shell.Current.Navigation.PopToRootAsync();
}
if (HasUnreadSystemMessagesOwner)
await Shell.Current.GoToAsync($"//{nameof(MoreView)}", Core.Common.Constants.AnimateNavigation);
else
await Shell.Current.GoToAsync($"//{nameof(HomeView)}", Core.Common.Constants.AnimateNavigation);
await _dialogService.ToastAsync(Resources.Text.AppMode_Note + " " + Resources.Text.Enum_AppMode_DogOwner, ToastDuration.Short, 14);
}
else
{
var stackCount = Shell.Current.Navigation.NavigationStack.Count;
if (stackCount > 1)
{
await Shell.Current.Navigation.PopToRootAsync();
}
if (HasUnreadSystemMessagesWalker)
await Shell.Current.GoToAsync($"//{nameof(MoreWalkerView)}", Core.Common.Constants.AnimateNavigation);
else
await Shell.Current.GoToAsync($"//{nameof(HomeWalkerView)}", Core.Common.Constants.AnimateNavigation);
await _dialogService.ToastAsync(Resources.Text.AppMode_Note + " " + Resources.Text.Enum_AppMode_DogWalker, ToastDuration.Short, 14);
}
}
/// <summary>
/// Command für das Hinzufügen der Walker-Funktion
/// </summary>
[RelayCommand]
public async Task BecomeWalker()
{
WeakReferenceMessenger.Default.Send(new RefreshViewModelMessage(Core.Messaging.Messages.Refresh_BecomeWalker));
await Shell.Current.GoToAsync($"{nameof(BecomeWalkerView)}", Core.Common.Constants.AnimateNavigation);
}
/// <summary>
/// Command für die Anzeige des Profils eines Benutzers
/// </summary>
[RelayCommand]
public async Task ShowProfile()
{
await Shell.Current.GoToAsync($"{nameof(ProfileView)}", Core.Common.Constants.AnimateNavigation);
}
/// <summary>
/// Command für die Anzeige des Passwortes eines Benutzers
/// </summary>
[RelayCommand]
public async Task ShowPassword()
{
await Shell.Current.GoToAsync($"{nameof(PasswordView)}", Core.Common.Constants.AnimateNavigation);
}
/// <summary>
/// Command für die Anzeige der Hunde eines Benutzers
/// </summary>
[RelayCommand]
public async Task MyDogs()
{
await Shell.Current.GoToAsync($"{nameof(DogsView)}", Core.Common.Constants.AnimateNavigation);
}
/// <summary>
/// Command für die Anzeige der Ratings eines Benutzers
/// </summary>
[RelayCommand]
public async Task MyRatings()
{
WeakReferenceMessenger.Default.Send(new RefreshViewModelMessage(Core.Messaging.Messages.Refresh_RatingsMy));
await Shell.Current.GoToAsync($"{nameof(RatingsMyView)}", Core.Common.Constants.AnimateNavigation);
}
/// <summary>
/// Command für die Anzeige des Wettbewerbs
/// </summary>
[RelayCommand]
public async Task Competition()
{
var menu = MenuSelected.More.ToString();
var title = Text.View_Title_Competition;
await Shell.Current.GoToAsync($"{nameof(ShowTextPageView)}?code={Core.Common.Constants.PageCompetitioOwnerYearly}&menu={menu}&title={title}", Core.Common.Constants.AnimateNavigation);
}
/// <summary>
/// Command für die Anzeige des Datenschutzes
/// </summary>
[RelayCommand]
public async Task Privacy()
{
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);
}
/// <summary>
/// Command für die Anzeige des Impressum
/// </summary>
[RelayCommand]
public async Task Imprint()
{
var menu = MenuSelected.More.ToString();
var title = Text.View_Title_Imprint;
await Shell.Current.GoToAsync($"{nameof(ShowTextPageView)}?code={Core.Common.Constants.PageImprint}&menu={menu}&title={title}", Core.Common.Constants.AnimateNavigation);
}
/// <summary>
/// Command für die Anzeige des FAQ
/// </summary>
[RelayCommand]
public async Task Faq()
{
var menu = MenuSelected.More.ToString();
var title = Text.View_Title_Faq;
await Shell.Current.GoToAsync($"{nameof(ShowTextPageView)}?code={Core.Common.Constants.PageFAQ}&menu={menu}&title={title}", Core.Common.Constants.AnimateNavigation);
}
/// <summary>
/// Command für die Anzeige von Feedback
/// </summary>
[RelayCommand]
public async Task Feedback()
{
await Shell.Current.GoToAsync($"{nameof(FeedbackView)}", Core.Common.Constants.AnimateNavigation);
}
/// <summary>
/// Command für die Anzeige von Systemnachrichten
/// </summary>
[RelayCommand]
public async Task SystemMessages()
{
await Shell.Current.GoToAsync($"{nameof(SystemMessagesView)}", Core.Common.Constants.AnimateNavigation);
}
/// <summary>
/// Command für die Anzeige der Wallets
/// </summary>
/// <returns></returns>
[RelayCommand]
public async Task Wallets()
{
if (string.IsNullOrWhiteSpace(App.CurrentAppUser.PaymentId))
{
//Zusätzliche Profil-Daten holen
//Der User hat noch keinen PaymentUser...
WeakReferenceMessenger.Default.Send(new RefreshViewModelMessage(Core.Messaging.Messages.Refresh_AddPaymentUser));
await Shell.Current.GoToAsync($"{nameof(AddPaymentUserView)}", Core.Common.Constants.AnimateNavigation);
}
else
{
await Shell.Current.GoToAsync($"{nameof(WalletsView)}", Core.Common.Constants.AnimateNavigation);
}
}
/// <summary>
/// Command für die Anzeige der Bankverbindung
/// </summary>
/// <returns></returns>
[RelayCommand]
public async Task BankAccount()
{
if (string.IsNullOrWhiteSpace(App.CurrentAppUser.PaymentId))
{
//Zusätzliche Profil-Daten holen
//Der User hat noch keinen PaymentUser...
WeakReferenceMessenger.Default.Send(new RefreshViewModelMessage(Core.Messaging.Messages.Refresh_AddPaymentUser));
await Shell.Current.GoToAsync($"{nameof(AddPaymentUserView)}", Core.Common.Constants.AnimateNavigation);
}
else
{
await Shell.Current.GoToAsync($"{nameof(BankAccountView)}", Core.Common.Constants.AnimateNavigation);
}
}
/// <summary>
/// Command für die Anzeige der KYC-Prüfung
/// </summary>
/// <returns>Task</returns>
[RelayCommand]
public async Task IdentityProof()
{
if (string.IsNullOrWhiteSpace(App.CurrentAppUser.PaymentId))
{
//Zusätzliche Profil-Daten holen
//Der User hat noch keinen PaymentUser...
WeakReferenceMessenger.Default.Send(new RefreshViewModelMessage(Core.Messaging.Messages.Refresh_AddPaymentUser));
WeakReferenceMessenger.Default.Send(new RefreshViewModelMessage(Core.Messaging.Messages.Refresh_Kyc));
await Shell.Current.GoToAsync($"{nameof(AddPaymentUserView)}", Core.Common.Constants.AnimateNavigation);
}
else
{
await Shell.Current.GoToAsync($"{nameof(IdentityProofView)}", Core.Common.Constants.AnimateNavigation);
}
}
/// <summary>
/// Command für die Anzeige der Auszahlungen
/// </summary>
/// <returns>Task</returns>
[RelayCommand]
public async Task Payouts()
{
if (string.IsNullOrWhiteSpace(App.CurrentAppUser.PaymentId))
{
//Zusätzliche Profil-Daten holen
//Der User hat noch keinen PaymentUser...
WeakReferenceMessenger.Default.Send(new RefreshViewModelMessage(Core.Messaging.Messages.Refresh_AddPaymentUser));
WeakReferenceMessenger.Default.Send(new RefreshViewModelMessage(Core.Messaging.Messages.Refresh_Payouts));
await Shell.Current.GoToAsync($"{nameof(AddPaymentUserView)}", Core.Common.Constants.AnimateNavigation);
}
else if (!App.CurrentAppUser.KycPassed)
{
//KYC- weiterleiten
WeakReferenceMessenger.Default.Send(new RefreshViewModelMessage(Core.Messaging.Messages.Refresh_Kyc));
await Shell.Current.GoToAsync($"{nameof(IdentityProofView)}", Core.Common.Constants.AnimateNavigation);
}
else if (string.IsNullOrWhiteSpace(App.CurrentAppUser.BankId))
{
//Konto- weiterleiten
await Shell.Current.GoToAsync($"{nameof(BankAccountView)}", Core.Common.Constants.AnimateNavigation);
}
else
{
WeakReferenceMessenger.Default.Send(new RefreshViewModelMessage(Core.Messaging.Messages.Refresh_Payouts));
await Shell.Current.GoToAsync($"{nameof(PayoutsView)}", Core.Common.Constants.AnimateNavigation);
}
}
/// <summary>
/// Command für die Anzeige des Löschen des Accounts
/// </summary>
[RelayCommand]
public async Task DelecteAccount()
{
await Shell.Current.GoToAsync($"{nameof(DeleteView)}", Core.Common.Constants.AnimateNavigation);
}
/// <summary>
/// Command für die Anzeige der gesperrten App-User
/// </summary>
[RelayCommand]
public async Task Blocked()
{
WeakReferenceMessenger.Default.Send(new RefreshViewModelMessage(Core.Messaging.Messages.Refresh_BlockedAppUsers));
await Shell.Current.GoToAsync($"{nameof(BlockedAppUsersView)}", Core.Common.Constants.AnimateNavigation);
}
#endregion
#region Initialisierung
/// <summary>
/// Initialisieren des Viewmodels.
/// Soll überschrieben werden um lazy loading in Viewmodels ermöglicht wird
/// </summary>
/// <returns>Task</returns>
public override async Task InitializeAsync(object sender)
{
await base.InitializeAsync(sender);
IsBusy = true;
HasError = false;
ErrorMessage = string.Empty;
await TrackPageViewAsync("MoreDogOwner");
//System.Diagnostics.Debug.WriteLine($"CurrentAppUser Photo at MORE: {App.CurrentAppUser.Photo}");
if (App.CurrentAppUser != null)
{
ShowAppMode = App.CurrentAppUser.Type == AppUserType.Both;
HasUnreadSystemMessagesOwner = await _systemMessageService.CountUnreadAsync(AppUserType.DogOwner).ConfigureAwait(false) > 0;
HasUnreadSystemMessagesWalker = await _systemMessageService.CountUnreadAsync(AppUserType.DogWalker).ConfigureAwait(false) > 0;
CurrentVersion = AppInfo.VersionString;
CanSwitch = App.CurrentAppUser.Type == AppUserType.Both;
CanBecomeWalker = App.CurrentAppUser.Type == AppUserType.DogOwner;
HasPayment = !string.IsNullOrWhiteSpace(App.CurrentAppUser.PaymentId);
NeedsBankAccount = App.CurrentAppUser.Type != AppUserType.DogOwner && string.IsNullOrWhiteSpace(App.CurrentAppUser.BankId);
NeedsIdentityProof = App.CurrentAppUser.Type != AppUserType.DogOwner && App.CurrentAppUser.KycPassed == false;
}
IsBusy = false;
}
/// <summary>
/// Entladen des Viewmodels.
/// Soll überschrieben werden
/// </summary>
/// <returns>Task</returns>
public override Task DisappearingAsync(object sender)
{
IsBusy = false;
HasError = false;
ErrorMessage = string.Empty;
return base.DisappearingAsync(sender);
}
#endregion
#region Resumed
/// <summary>
/// Eventhandler wenn die App aus dem Sleepmode kommt
/// </summary>
/// <returns></returns>
internal override async Task AppResumed()
{
await _dispatcher.DispatchAsync(async () =>
{
await Task.Delay(1);
ShowAppMode = App.CurrentAppUser.Type == AppUserType.Both;
HasUnreadSystemMessagesOwner = await _systemMessageService.CountUnreadAsync(AppUserType.DogOwner).ConfigureAwait(false) > 0;
HasUnreadSystemMessagesWalker = await _systemMessageService.CountUnreadAsync(AppUserType.DogWalker).ConfigureAwait(false) > 0;
CurrentVersion = AppInfo.VersionString;
CanSwitch = App.CurrentAppUser.Type == AppUserType.Both;
CanBecomeWalker = App.CurrentAppUser.Type == AppUserType.DogOwner;
HasPayment = !string.IsNullOrWhiteSpace(App.CurrentAppUser.PaymentId);
NeedsBankAccount = App.CurrentAppUser.Type != AppUserType.DogOwner && string.IsNullOrWhiteSpace(App.CurrentAppUser.BankId);
NeedsIdentityProof = App.CurrentAppUser.Type != AppUserType.DogOwner && App.CurrentAppUser.KycPassed == false;
});
}
#endregion
}
}