Implement change detection in ProfileViewModel and ProfileWalkerViewModel; add original state tracking and update UI to reflect changes with a floating save button in ProfileView and ProfileWalkerView.
This commit is contained in:
parent
5c85ce545f
commit
fb1756b82b
@ -159,6 +159,39 @@ namespace gehGassiApp.ViewModels
|
||||
[ObservableProperty]
|
||||
private Country _selectedMainResidence;
|
||||
|
||||
/// <summary>
|
||||
/// Gibt an ob sich Daten geändert haben
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private bool _hasChanges;
|
||||
|
||||
/// <summary>
|
||||
/// Original AppUser für Change Detection
|
||||
/// </summary>
|
||||
private AppUser _originalAppUser;
|
||||
|
||||
/// <summary>
|
||||
/// State Class für Change Detection
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// Wird aufgerufen wenn sich eine Property des AppUser oder seiner Unterobjekte ändert
|
||||
/// </summary>
|
||||
private void OnAppUserPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
CheckForChanges();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper
|
||||
|
||||
/// <summary>
|
||||
/// Prüft ob sich Daten geändert haben
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Speichert die ursprünglichen Werte für Change Detection
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Laden eines Fotos
|
||||
/// </summary>
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -172,6 +172,60 @@ namespace gehGassiApp.ViewModels
|
||||
[ObservableProperty]
|
||||
private Country _selectedMainResidence;
|
||||
|
||||
/// <summary>
|
||||
/// Gibt an ob sich Daten geändert haben
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private bool _hasChanges;
|
||||
|
||||
/// <summary>
|
||||
/// Original AppUser für Change Detection
|
||||
/// </summary>
|
||||
private AppUser _originalAppUser;
|
||||
|
||||
/// <summary>
|
||||
/// Original WalkerProfile für Change Detection
|
||||
/// </summary>
|
||||
private DogWalkerProfile _originalWalkerProfile;
|
||||
|
||||
/// <summary>
|
||||
/// Original State für Change Detection
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Soll der Bottomsheet angezeigt werden?
|
||||
/// </summary>
|
||||
@ -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
|
||||
|
||||
/// <summary>
|
||||
/// Wird aufgerufen wenn sich eine Property des AppUser oder seiner Unterobjekte ändert
|
||||
/// </summary>
|
||||
private void OnAppUserPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
CheckForChanges();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wird aufgerufen wenn sich eine Property des WalkerProfile ändert
|
||||
/// </summary>
|
||||
private void OnWalkerProfilePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
CheckForChanges();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper
|
||||
|
||||
/// <summary>
|
||||
/// Prüft ob sich Daten geändert haben
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Speichert die ursprünglichen Werte für Change Detection
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Laden eines Fotos
|
||||
/// </summary>
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -19,10 +19,13 @@
|
||||
</controls:BaseContentPage.TitleView>
|
||||
|
||||
<ContentPage.Content>
|
||||
<Grid>
|
||||
<AbsoluteLayout>
|
||||
<!-- Main scrollable content (full screen) -->
|
||||
<ScrollView
|
||||
x:Name="rootScrollView"
|
||||
Padding="20"
|
||||
AbsoluteLayout.LayoutBounds="0,0,1,1"
|
||||
AbsoluteLayout.LayoutFlags="All"
|
||||
Padding="20,20,20,100"
|
||||
HorizontalOptions="Fill"
|
||||
IsVisible="{Binding IsNotLoading}">
|
||||
<VerticalStackLayout
|
||||
@ -485,30 +488,15 @@
|
||||
Scale="1"
|
||||
VerticalOptions="Center" />
|
||||
|
||||
<Button
|
||||
x:Name="btnSave"
|
||||
Command="{Binding SaveCommand}"
|
||||
Text="{Static res:Text.Button_Done}">
|
||||
<Button.IsEnabled>
|
||||
<MultiBinding Converter="{StaticResource AllTrueMultiConverter}">
|
||||
<Binding Path="IsValid" Source="{x:Reference firstNameValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference lastNameValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference birthdayValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference addressLine1Validation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference addressLine2Validation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference zipValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference cityValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference mobileValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference phoneValidation}" />
|
||||
<Binding Path="AddressSelectionValid" />
|
||||
<Binding Path="IsNotBusy" />
|
||||
</MultiBinding>
|
||||
</Button.IsEnabled>
|
||||
</Button>
|
||||
|
||||
</VerticalStackLayout>
|
||||
</ScrollView>
|
||||
<VerticalStackLayout IsVisible="{Binding IsLoading}" VerticalOptions="Center">
|
||||
|
||||
<!-- Loading Indicator -->
|
||||
<VerticalStackLayout
|
||||
AbsoluteLayout.LayoutBounds="0,0,1,1"
|
||||
AbsoluteLayout.LayoutFlags="All"
|
||||
IsVisible="{Binding IsLoading}"
|
||||
VerticalOptions="Center">
|
||||
<ActivityIndicator
|
||||
HorizontalOptions="Center"
|
||||
IsRunning="{Binding IsLoading}"
|
||||
@ -516,6 +504,35 @@
|
||||
Scale="2"
|
||||
VerticalOptions="Center" />
|
||||
</VerticalStackLayout>
|
||||
</Grid>
|
||||
|
||||
<!-- Floating Save Button (over content) -->
|
||||
<Button
|
||||
x:Name="btnSave"
|
||||
Margin="0,0,0,20"
|
||||
AbsoluteLayout.LayoutBounds="0.5,1,300,60"
|
||||
AbsoluteLayout.LayoutFlags="PositionProportional"
|
||||
Command="{Binding SaveCommand}"
|
||||
HorizontalOptions="Center"
|
||||
IsVisible="{Binding HasChanges}"
|
||||
Text="{x:Static res:Text.Button_Done}"
|
||||
VerticalOptions="End">
|
||||
<Button.IsEnabled>
|
||||
<MultiBinding Converter="{StaticResource AllTrueMultiConverter}">
|
||||
<Binding Path="IsValid" Source="{x:Reference firstNameValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference lastNameValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference birthdayValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference addressLine1Validation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference addressLine2Validation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference zipValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference cityValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference mobileValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference phoneValidation}" />
|
||||
<Binding Path="AddressSelectionValid" />
|
||||
<Binding Path="IsNotBusy" />
|
||||
</MultiBinding>
|
||||
</Button.IsEnabled>
|
||||
</Button>
|
||||
|
||||
</AbsoluteLayout>
|
||||
</ContentPage.Content>
|
||||
</controls:BaseContentPage>
|
||||
@ -20,10 +20,13 @@
|
||||
</controls:BaseContentPage.TitleView>
|
||||
|
||||
<ContentPage.Content>
|
||||
<Grid>
|
||||
<AbsoluteLayout>
|
||||
<!-- Main scrollable content (full screen) -->
|
||||
<ScrollView
|
||||
x:Name="rootScrollView"
|
||||
Padding="20"
|
||||
AbsoluteLayout.LayoutBounds="0,0,1,1"
|
||||
AbsoluteLayout.LayoutFlags="All"
|
||||
Padding="20,20,20,100"
|
||||
HorizontalOptions="Fill"
|
||||
IsVisible="{Binding IsNotLoading}"
|
||||
VerticalOptions="FillAndExpand">
|
||||
@ -992,33 +995,15 @@
|
||||
Scale="1"
|
||||
VerticalOptions="Center" />
|
||||
|
||||
<Button
|
||||
x:Name="btnSave"
|
||||
Command="{Binding SaveCommand}"
|
||||
Text="{Static res:Text.Button_Done}">
|
||||
<Button.IsEnabled>
|
||||
<MultiBinding Converter="{StaticResource AllTrueMultiConverter}">
|
||||
<Binding Path="IsValid" Source="{x:Reference firstNameValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference lastNameValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference birthdayValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference addressLine1Validation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference addressLine2Validation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference zipValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference cityValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference mobileValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference phoneValidation}" />
|
||||
<Binding Path="AddressSelectionValid" />
|
||||
<!--<Binding Source="{x:Reference priceWalkValidation}" Path="IsValid"></Binding>
|
||||
<Binding Source="{x:Reference priceDayValidation}" Path="IsValid"></Binding>
|
||||
<Binding Source="{x:Reference priceSittingValidation}" Path="IsValid"></Binding>-->
|
||||
<Binding Path="IsNotBusy" />
|
||||
</MultiBinding>
|
||||
</Button.IsEnabled>
|
||||
</Button>
|
||||
|
||||
</VerticalStackLayout>
|
||||
</ScrollView>
|
||||
<VerticalStackLayout IsVisible="{Binding IsLoading}" VerticalOptions="CenterAndExpand">
|
||||
|
||||
<!-- Loading Indicator -->
|
||||
<VerticalStackLayout
|
||||
AbsoluteLayout.LayoutBounds="0,0,1,1"
|
||||
AbsoluteLayout.LayoutFlags="All"
|
||||
IsVisible="{Binding IsLoading}"
|
||||
VerticalOptions="CenterAndExpand">
|
||||
<ActivityIndicator
|
||||
HorizontalOptions="Center"
|
||||
IsRunning="{Binding IsLoading}"
|
||||
@ -1026,7 +1011,36 @@
|
||||
Scale="2"
|
||||
VerticalOptions="Center" />
|
||||
</VerticalStackLayout>
|
||||
</Grid>
|
||||
|
||||
<!-- Floating Save Button (over content) -->
|
||||
<Button
|
||||
x:Name="btnSave"
|
||||
Margin="0,0,0,20"
|
||||
AbsoluteLayout.LayoutBounds="0.5,1,300,60"
|
||||
AbsoluteLayout.LayoutFlags="PositionProportional"
|
||||
Command="{Binding SaveCommand}"
|
||||
HorizontalOptions="Center"
|
||||
IsVisible="{Binding HasChanges}"
|
||||
Text="{x:Static res:Text.Button_Done}"
|
||||
VerticalOptions="End">
|
||||
<Button.IsEnabled>
|
||||
<MultiBinding Converter="{StaticResource AllTrueMultiConverter}">
|
||||
<Binding Path="IsValid" Source="{x:Reference firstNameValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference lastNameValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference birthdayValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference addressLine1Validation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference addressLine2Validation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference zipValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference cityValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference mobileValidation}" />
|
||||
<Binding Path="IsValid" Source="{x:Reference phoneValidation}" />
|
||||
<Binding Path="AddressSelectionValid" />
|
||||
<Binding Path="IsNotBusy" />
|
||||
</MultiBinding>
|
||||
</Button.IsEnabled>
|
||||
</Button>
|
||||
|
||||
</AbsoluteLayout>
|
||||
</ContentPage.Content>
|
||||
|
||||
<controls:BaseContentPage.BottomSheet>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user