diff --git a/gehGassiApp/gehGassiApp/ViewModels/ProfileViewModel.cs b/gehGassiApp/gehGassiApp/ViewModels/ProfileViewModel.cs
index b2cb984..97c36f0 100644
--- a/gehGassiApp/gehGassiApp/ViewModels/ProfileViewModel.cs
+++ b/gehGassiApp/gehGassiApp/ViewModels/ProfileViewModel.cs
@@ -159,6 +159,39 @@ namespace gehGassiApp.ViewModels
[ObservableProperty]
private Country _selectedMainResidence;
+ ///
+ /// Gibt an ob sich Daten geändert haben
+ ///
+ [ObservableProperty]
+ private bool _hasChanges;
+
+ ///
+ /// Original AppUser für Change Detection
+ ///
+ private AppUser _originalAppUser;
+
+ ///
+ /// State Class für Change Detection
+ ///
+ private class OriginalProfileState
+ {
+ public string FirstName { get; set; } = "";
+ public string LastName { get; set; } = "";
+ public string Photo { get; set; } = "";
+ public DateTime? BirthDate { get; set; }
+ public string AddressLine1 { get; set; } = "";
+ public string AddressLine2 { get; set; } = "";
+ public string Zip { get; set; } = "";
+ public string City { get; set; } = "";
+ public string Mobile { get; set; } = "";
+ public string Phone { get; set; } = "";
+ public string CountryIso2 { get; set; } = "";
+ public string StateCode { get; set; } = "";
+ public Sex Sex { get; set; }
+ public string NationalityIso2 { get; set; } = "";
+ public string MainResidenceIso2 { get; set; } = "";
+ } private OriginalProfileState _originalState;
+
#region Extended
partial void OnSelectedCountryChanged(Country value)
@@ -173,12 +206,16 @@ namespace gehGassiApp.ViewModels
var states = _countryService.GetStatesAsync(value.Iso2).Result;
States = states.ToObservableCollection();
}
+
+ CheckForChanges();
}
partial void OnSelectedStateChanged(State value)
{
if (value != null)
AddressSelectionValid = true;
+
+ CheckForChanges();
}
partial void OnBirthDateChanged(DateTime? value)
@@ -187,6 +224,58 @@ namespace gehGassiApp.ViewModels
return;
if (value.HasValue)
BirthDay = value.Value.ToString("d", CultureInfo.CurrentCulture);
+
+ CheckForChanges();
+ }
+
+ partial void OnSelectedSexChanged(SexItem value)
+ {
+ CheckForChanges();
+ }
+
+ partial void OnSelectedNationalityChanged(Country value)
+ {
+ CheckForChanges();
+ }
+
+ partial void OnSelectedMainResidenceChanged(Country value)
+ {
+ CheckForChanges();
+ }
+
+ partial void OnAppUserChanged(AppUser value)
+ {
+ // Entferne alte Event-Handler falls vorhanden
+ if (_appUser != null)
+ {
+ _appUser.PropertyChanged -= OnAppUserPropertyChanged;
+ if (_appUser.Address != null)
+ _appUser.Address.PropertyChanged -= OnAppUserPropertyChanged;
+ if (_appUser.Contact != null)
+ _appUser.Contact.PropertyChanged -= OnAppUserPropertyChanged;
+ }
+
+ // Registriere neue Event-Handler
+ if (value != null)
+ {
+ value.PropertyChanged += OnAppUserPropertyChanged;
+ if (value.Address != null)
+ value.Address.PropertyChanged += OnAppUserPropertyChanged;
+ if (value.Contact != null)
+ value.Contact.PropertyChanged += OnAppUserPropertyChanged;
+ }
+
+ CheckForChanges();
+ }
+
+ partial void OnIsNewPhotoChanged(bool value)
+ {
+ CheckForChanges();
+ }
+
+ partial void OnPhotoPathChanged(string value)
+ {
+ CheckForChanges();
}
#endregion
@@ -545,11 +634,118 @@ namespace gehGassiApp.ViewModels
_countryHandlerEnabled = true;
+ // Speichere ursprüngliche Werte für Change Detection
+ SaveOriginalValues();
+
IsLoading = false;
}
+ #region Event Handlers for Change Detection
+
+ ///
+ /// Wird aufgerufen wenn sich eine Property des AppUser oder seiner Unterobjekte ändert
+ ///
+ private void OnAppUserPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
+ {
+ CheckForChanges();
+ }
+
+ #endregion
+
#region Helper
+ ///
+ /// Prüft ob sich Daten geändert haben
+ ///
+ private void CheckForChanges()
+ {
+ if (IsLoading || _originalState == null || AppUser == null)
+ return;
+
+ try
+ {
+ // Prüfe AppUser Properties
+ var hasChanges =
+ AppUser.FirstName != _originalState.FirstName ||
+ AppUser.LastName != _originalState.LastName ||
+ AppUser.Photo != _originalState.Photo ||
+ BirthDate != _originalState.BirthDate;
+
+ // Prüfe Address Properties
+ if (AppUser.Address != null)
+ {
+ hasChanges = hasChanges ||
+ (AppUser.Address.AddressLine1 ?? "") != _originalState.AddressLine1 ||
+ (AppUser.Address.AddressLine2 ?? "") != _originalState.AddressLine2 ||
+ (AppUser.Address.Zip ?? "") != _originalState.Zip ||
+ (AppUser.Address.City ?? "") != _originalState.City;
+ }
+
+ // Prüfe Contact Properties
+ if (AppUser.Contact != null)
+ {
+ hasChanges = hasChanges ||
+ (AppUser.Contact.Mobile ?? "") != _originalState.Mobile ||
+ (AppUser.Contact.Phone ?? "") != _originalState.Phone;
+ }
+
+ // Prüfe Selections
+ if (SelectedCountry?.Iso2 != _originalState.CountryIso2)
+ hasChanges = true;
+ if (SelectedState?.Code != _originalState.StateCode)
+ hasChanges = true;
+ if (SelectedSex?.Value != _originalState.Sex)
+ hasChanges = true;
+ if (SelectedNationality?.Iso2 != _originalState.NationalityIso2)
+ hasChanges = true;
+ if (SelectedMainResidence?.Iso2 != _originalState.MainResidenceIso2)
+ hasChanges = true;
+
+ // Prüfe ob neues Foto vorhanden
+ if (IsNewPhoto && !string.IsNullOrWhiteSpace(PhotoPath))
+ hasChanges = true;
+
+ HasChanges = hasChanges;
+ }
+ catch (Exception)
+ {
+ // Fallback: Bei Fehlern Changes auf true setzen
+ HasChanges = true;
+ }
+ }
+
+ ///
+ /// Speichert die ursprünglichen Werte für Change Detection
+ ///
+ private void SaveOriginalValues()
+ {
+ try
+ {
+ _originalState = new OriginalProfileState
+ {
+ FirstName = AppUser?.FirstName ?? "",
+ LastName = AppUser?.LastName ?? "",
+ Photo = AppUser?.Photo ?? "",
+ BirthDate = BirthDate,
+ AddressLine1 = AppUser?.Address?.AddressLine1 ?? "",
+ AddressLine2 = AppUser?.Address?.AddressLine2 ?? "",
+ Zip = AppUser?.Address?.Zip ?? "",
+ City = AppUser?.Address?.City ?? "",
+ Mobile = AppUser?.Contact?.Mobile ?? "",
+ Phone = AppUser?.Contact?.Phone ?? "",
+ CountryIso2 = SelectedCountry?.Iso2 ?? "",
+ StateCode = SelectedState?.Code ?? "",
+ Sex = SelectedSex?.Value ?? Sex.Undefined,
+ NationalityIso2 = SelectedNationality?.Iso2 ?? "",
+ MainResidenceIso2 = SelectedMainResidence?.Iso2 ?? ""
+ };
+ }
+ catch (Exception)
+ {
+ _originalState = new OriginalProfileState();
+ }
+ }
+
///
/// Laden eines Fotos
///
@@ -638,6 +834,11 @@ namespace gehGassiApp.ViewModels
IsNewPhoto = false;
await Task.Delay(Core.Common.Constants.AnimationDelayDetails);
await LoadAsync();
+
+ // Speichere Original-Werte für Change Detection
+ SaveOriginalValues();
+ HasChanges = false;
+
IsBusy = false;
}
diff --git a/gehGassiApp/gehGassiApp/ViewModels/ProfileWalkerViewModel.cs b/gehGassiApp/gehGassiApp/ViewModels/ProfileWalkerViewModel.cs
index 0f97463..2cb36d9 100644
--- a/gehGassiApp/gehGassiApp/ViewModels/ProfileWalkerViewModel.cs
+++ b/gehGassiApp/gehGassiApp/ViewModels/ProfileWalkerViewModel.cs
@@ -172,6 +172,60 @@ namespace gehGassiApp.ViewModels
[ObservableProperty]
private Country _selectedMainResidence;
+ ///
+ /// Gibt an ob sich Daten geändert haben
+ ///
+ [ObservableProperty]
+ private bool _hasChanges;
+
+ ///
+ /// Original AppUser für Change Detection
+ ///
+ private AppUser _originalAppUser;
+
+ ///
+ /// Original WalkerProfile für Change Detection
+ ///
+ private DogWalkerProfile _originalWalkerProfile;
+
+ ///
+ /// Original State für Change Detection
+ ///
+ private class OriginalWalkerProfileState
+ {
+ public string FirstName { get; set; } = "";
+ public string LastName { get; set; } = "";
+ public string Photo { get; set; } = "";
+ public DateTime? BirthDate { get; set; }
+ public string AddressLine1 { get; set; } = "";
+ public string AddressLine2 { get; set; } = "";
+ public string Zip { get; set; } = "";
+ public string City { get; set; } = "";
+ public string Mobile { get; set; } = "";
+ public string Phone { get; set; } = "";
+ public string CountryIso2 { get; set; } = "";
+ public string StateCode { get; set; } = "";
+ public Sex Sex { get; set; }
+ public string NationalityIso2 { get; set; } = "";
+ public string MainResidenceIso2 { get; set; } = "";
+
+ // Walker Profile Properties
+ public string About { get; set; } = "";
+ public double Radius { get; set; }
+ public DogWalkRequestType AllowedRequests { get; set; }
+ public bool PuppyAllowed { get; set; }
+ public bool DifficultAllowed { get; set; }
+ public DogAggressionLevel AggressionLevel { get; set; }
+ public DogSize AcceptedSize { get; set; }
+ public decimal PriceWalk { get; set; }
+ public decimal PriceDay { get; set; }
+ public decimal PriceSitting { get; set; }
+ public bool NotAvailable { get; set; }
+ public string NotAvailableInfo { get; set; } = "";
+ }
+
+ private OriginalWalkerProfileState _originalState;
+
///
/// Soll der Bottomsheet angezeigt werden?
///
@@ -210,12 +264,16 @@ namespace gehGassiApp.ViewModels
var states = _countryService.GetStatesAsync(value.Iso2).Result;
States = states.ToObservableCollection();
}
+
+ CheckForChanges();
}
partial void OnSelectedStateChanged(State value)
{
if (value != null)
AddressSelectionValid = true;
+
+ CheckForChanges();
}
partial void OnBirthDateChanged(DateTime? value)
@@ -224,6 +282,75 @@ namespace gehGassiApp.ViewModels
return;
if (value.HasValue)
BirthDay = value.Value.ToString("d", CultureInfo.CurrentCulture);
+
+ CheckForChanges();
+ }
+
+ partial void OnSelectedSexChanged(SexItem value)
+ {
+ CheckForChanges();
+ }
+
+ partial void OnSelectedNationalityChanged(Country value)
+ {
+ CheckForChanges();
+ }
+
+ partial void OnSelectedMainResidenceChanged(Country value)
+ {
+ CheckForChanges();
+ }
+
+ partial void OnAppUserChanged(AppUser value)
+ {
+ // Entferne alte Event-Handler falls vorhanden
+ if (_appUser != null)
+ {
+ _appUser.PropertyChanged -= OnAppUserPropertyChanged;
+ if (_appUser.Address != null)
+ _appUser.Address.PropertyChanged -= OnAppUserPropertyChanged;
+ if (_appUser.Contact != null)
+ _appUser.Contact.PropertyChanged -= OnAppUserPropertyChanged;
+ }
+
+ // Registriere neue Event-Handler
+ if (value != null)
+ {
+ value.PropertyChanged += OnAppUserPropertyChanged;
+ if (value.Address != null)
+ value.Address.PropertyChanged += OnAppUserPropertyChanged;
+ if (value.Contact != null)
+ value.Contact.PropertyChanged += OnAppUserPropertyChanged;
+ }
+
+ CheckForChanges();
+ }
+
+ partial void OnWalkerProfileChanged(DogWalkerProfile value)
+ {
+ // Entferne alte Event-Handler falls vorhanden
+ if (_walkerProfile != null)
+ {
+ _walkerProfile.PropertyChanged -= OnWalkerProfilePropertyChanged;
+ }
+
+ // Registriere neue Event-Handler
+ if (value != null)
+ {
+ value.PropertyChanged += OnWalkerProfilePropertyChanged;
+ }
+
+ CheckForChanges();
+ }
+
+ partial void OnIsNewPhotoChanged(bool value)
+ {
+ CheckForChanges();
+ }
+
+ partial void OnPhotoPathChanged(string value)
+ {
+ CheckForChanges();
}
#endregion
@@ -656,11 +783,158 @@ namespace gehGassiApp.ViewModels
var walkerProfile = await _walkerProfileService.GetAsync(App.CurrentUser.AccessToken, cts.Token, false);
WalkerProfile = walkerProfile;
+ // Speichere ursprüngliche Werte für Change Detection
+ SaveOriginalValues();
+
IsLoading = false;
}
+ #region Event Handlers for Change Detection
+
+ ///
+ /// Wird aufgerufen wenn sich eine Property des AppUser oder seiner Unterobjekte ändert
+ ///
+ private void OnAppUserPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
+ {
+ CheckForChanges();
+ }
+
+ ///
+ /// Wird aufgerufen wenn sich eine Property des WalkerProfile ändert
+ ///
+ private void OnWalkerProfilePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
+ {
+ CheckForChanges();
+ }
+
+ #endregion
+
#region Helper
+ ///
+ /// Prüft ob sich Daten geändert haben
+ ///
+ private void CheckForChanges()
+ {
+ if (IsLoading || _originalState == null || AppUser == null)
+ return;
+
+ try
+ {
+ // Prüfe AppUser Properties
+ var hasChanges =
+ AppUser.FirstName != _originalState.FirstName ||
+ AppUser.LastName != _originalState.LastName ||
+ AppUser.Photo != _originalState.Photo ||
+ BirthDate != _originalState.BirthDate;
+
+ // Prüfe Address Properties
+ if (AppUser.Address != null)
+ {
+ hasChanges = hasChanges ||
+ (AppUser.Address.AddressLine1 ?? "") != _originalState.AddressLine1 ||
+ (AppUser.Address.AddressLine2 ?? "") != _originalState.AddressLine2 ||
+ (AppUser.Address.Zip ?? "") != _originalState.Zip ||
+ (AppUser.Address.City ?? "") != _originalState.City;
+ }
+
+ // Prüfe Contact Properties
+ if (AppUser.Contact != null)
+ {
+ hasChanges = hasChanges ||
+ (AppUser.Contact.Mobile ?? "") != _originalState.Mobile ||
+ (AppUser.Contact.Phone ?? "") != _originalState.Phone;
+ }
+
+ // Prüfe Walker Profile Properties
+ if (WalkerProfile != null)
+ {
+ hasChanges = hasChanges ||
+ (WalkerProfile.About ?? "") != _originalState.About ||
+ WalkerProfile.Radius != _originalState.Radius ||
+ WalkerProfile.AllowedRequests != _originalState.AllowedRequests ||
+ WalkerProfile.PuppyAllowed != _originalState.PuppyAllowed ||
+ WalkerProfile.DifficultAllowed != _originalState.DifficultAllowed ||
+ WalkerProfile.AggressionLevel != _originalState.AggressionLevel ||
+ WalkerProfile.AcceptedSize != _originalState.AcceptedSize ||
+ WalkerProfile.PriceWalk != _originalState.PriceWalk ||
+ WalkerProfile.PriceDay != _originalState.PriceDay ||
+ WalkerProfile.PriceSitting != _originalState.PriceSitting ||
+ WalkerProfile.NotAvailable != _originalState.NotAvailable ||
+ (WalkerProfile.NotAvailableInfo ?? "") != _originalState.NotAvailableInfo;
+ }
+
+ // Prüfe Selections
+ if (SelectedCountry?.Iso2 != _originalState.CountryIso2)
+ hasChanges = true;
+ if (SelectedState?.Code != _originalState.StateCode)
+ hasChanges = true;
+ if (SelectedSex?.Value != _originalState.Sex)
+ hasChanges = true;
+ if (SelectedNationality?.Iso2 != _originalState.NationalityIso2)
+ hasChanges = true;
+ if (SelectedMainResidence?.Iso2 != _originalState.MainResidenceIso2)
+ hasChanges = true;
+
+ // Prüfe ob neues Foto vorhanden
+ if (IsNewPhoto && !string.IsNullOrWhiteSpace(PhotoPath))
+ hasChanges = true;
+
+ HasChanges = hasChanges;
+ }
+ catch (Exception)
+ {
+ // Fallback: Bei Fehlern Changes auf true setzen
+ HasChanges = true;
+ }
+ }
+
+ ///
+ /// Speichert die ursprünglichen Werte für Change Detection
+ ///
+ private void SaveOriginalValues()
+ {
+ try
+ {
+ _originalState = new OriginalWalkerProfileState
+ {
+ FirstName = AppUser?.FirstName ?? "",
+ LastName = AppUser?.LastName ?? "",
+ Photo = AppUser?.Photo ?? "",
+ BirthDate = BirthDate,
+ AddressLine1 = AppUser?.Address?.AddressLine1 ?? "",
+ AddressLine2 = AppUser?.Address?.AddressLine2 ?? "",
+ Zip = AppUser?.Address?.Zip ?? "",
+ City = AppUser?.Address?.City ?? "",
+ Mobile = AppUser?.Contact?.Mobile ?? "",
+ Phone = AppUser?.Contact?.Phone ?? "",
+ CountryIso2 = SelectedCountry?.Iso2 ?? "",
+ StateCode = SelectedState?.Code ?? "",
+ Sex = SelectedSex?.Value ?? Sex.Undefined,
+ NationalityIso2 = SelectedNationality?.Iso2 ?? "",
+ MainResidenceIso2 = SelectedMainResidence?.Iso2 ?? "",
+
+ // Walker Profile Properties
+ About = WalkerProfile?.About ?? "",
+ Radius = WalkerProfile?.Radius ?? 0,
+ AllowedRequests = WalkerProfile?.AllowedRequests ?? DogWalkRequestType.Walking,
+ PuppyAllowed = WalkerProfile?.PuppyAllowed ?? false,
+ DifficultAllowed = WalkerProfile?.DifficultAllowed ?? false,
+ AggressionLevel = WalkerProfile?.AggressionLevel ?? DogAggressionLevel.Low,
+ AcceptedSize = WalkerProfile?.AcceptedSize ?? DogSize.Small,
+ PriceWalk = WalkerProfile?.PriceWalk ?? 0,
+ PriceDay = WalkerProfile?.PriceDay ?? 0,
+ PriceSitting = WalkerProfile?.PriceSitting ?? 0,
+ NotAvailable = WalkerProfile?.NotAvailable ?? false,
+ NotAvailableInfo = WalkerProfile?.NotAvailableInfo ?? ""
+ };
+ }
+ catch (Exception)
+ {
+ _originalState = new OriginalWalkerProfileState();
+ }
+ }
+
///
/// Laden eines Fotos
///
@@ -752,6 +1026,11 @@ namespace gehGassiApp.ViewModels
IsNewPhoto = false;
await Task.Delay(Core.Common.Constants.AnimationDelayDetails);
await LoadAsync();
+
+ // Speichere Original-Werte für Change Detection
+ SaveOriginalValues();
+ HasChanges = false;
+
IsBusy = false;
_refresh = false;
}
diff --git a/gehGassiApp/gehGassiApp/Views/ProfileView.xaml b/gehGassiApp/gehGassiApp/Views/ProfileView.xaml
index ee6a40e..2d6bdc5 100644
--- a/gehGassiApp/gehGassiApp/Views/ProfileView.xaml
+++ b/gehGassiApp/gehGassiApp/Views/ProfileView.xaml
@@ -19,10 +19,13 @@
-
+
+
-
-
-
+
+
+
-
+
+
+
+
+
\ No newline at end of file
diff --git a/gehGassiApp/gehGassiApp/Views/ProfileWalkerView.xaml b/gehGassiApp/gehGassiApp/Views/ProfileWalkerView.xaml
index 4961678..1628aba 100644
--- a/gehGassiApp/gehGassiApp/Views/ProfileWalkerView.xaml
+++ b/gehGassiApp/gehGassiApp/Views/ProfileWalkerView.xaml
@@ -20,10 +20,13 @@
-
+
+
@@ -992,33 +995,15 @@
Scale="1"
VerticalOptions="Center" />
-
-
-
+
+
+
-
+
+
+
+
+