Merge branch 'improvements/homescreen' into net9-upgradeyxc

.
klsdfhgölsdfhg <yxc<yxc<yxc

dfasdfasdf

:wq

:::::WQ

W
Q:WQ
W
Q:WQ:Wdfasdfasdf

:wq

:::::WQ

W
Q:WQ
W
Q:WQ:Wdfasdfasdf

:wq

:::::WQ

W
Q:WQ
W
Q:WQ:Wdfasdfasdf

:wq

:::::WQ

W
Q:WQ
W
Q:WQ:Wdfasdfasdf

:wq

:::::WQ

W
Q:WQ
W
Q:WQ:Wdfasdfasdf

:wq

:::::WQ

W
Q:WQ
W
Q:WQ:W:
This commit is contained in:
Max Mannstein 2025-08-09 16:22:56 +02:00
commit c49c043801
3 changed files with 223 additions and 245 deletions

View File

@ -112,6 +112,12 @@ namespace gehGassiApp.ViewModels
[ObservableProperty] [ObservableProperty]
private ObservableCollection<DogWalkerLookup> _walkers; private ObservableCollection<DogWalkerLookup> _walkers;
/// <summary>
/// First 10 walkers for the home screen display
/// </summary>
[ObservableProperty]
private ObservableCollection<DogWalkerLookup> _first10Walkers;
[ObservableProperty] [ObservableProperty]
private DogWalkerLookup _selectedWalker; private DogWalkerLookup _selectedWalker;
@ -541,6 +547,9 @@ namespace gehGassiApp.ViewModels
Walkers = requests.Value.ToObservableCollection(); Walkers = requests.Value.ToObservableCollection();
// Set First10Walkers for the home screen display
First10Walkers = requests.Value.Take(10).ToObservableCollection();
_total = requests.Total; _total = requests.Total;
_skip = requests.Skip + requests.Take; _skip = requests.Skip + requests.Take;
} }
@ -549,6 +558,7 @@ namespace gehGassiApp.ViewModels
_total = 0; _total = 0;
_skip = 0; _skip = 0;
Walkers = null; Walkers = null;
First10Walkers = null;
} }
} }
catch (Exception ex) catch (Exception ex)
@ -557,6 +567,7 @@ namespace gehGassiApp.ViewModels
_total = 0; _total = 0;
_skip = 0; _skip = 0;
Walkers = null; Walkers = null;
First10Walkers = null;
} }
} }

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<controls:BaseContentPage <controls:BaseContentPage
x:Class="gehGassiApp.Views.HomeView" x:Class="gehGassiApp.Views.HomeView"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
@ -23,189 +23,147 @@
</controls:BaseContentPage.TitleView> </controls:BaseContentPage.TitleView>
<ContentPage.Content> <ContentPage.Content>
<Grid <AbsoluteLayout>
x:Name="rootHomeGrid" <!-- Main scrollable content (full screen) -->
Padding="20,20,20,0"
HorizontalOptions="FillAndExpand"
RowDefinitions="Auto,*"
VerticalOptions="FillAndExpand">
<VerticalStackLayout
x:Name="rootVerticalStackLayout"
Grid.Row="0"
HorizontalOptions="Fill"
SizeChanged="rootVerticalStackLayout_SizeChanged"
Spacing="0"
VerticalOptions="FillAndExpand">
<Border x:Name="permissionStatusBorder" Style="{StaticResource PermissionStatusBorder}">
<Label Style="{StaticResource PermissionStatusLabel}" Text="{x:Static res:Text.Permission_Location_Error}" />
<Border.IsVisible>
<MultiBinding Converter="{StaticResource AllTrueMultiConverter}">
<Binding Converter="{StaticResource PermissionsStatusToBoolConverter}" Path="LocationPermissionStatus" />
<Binding Path="ShowPermissionStatus" />
</MultiBinding>
</Border.IsVisible>
<Border.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ShowPermissionsCommand}" />
</Border.GestureRecognizers>
</Border>
<controls:ProfileNotFinishedControl
Margin="{StaticResource MarginMid}"
HorizontalOptions="Fill"
IsVisible="{Binding ProfileNotFinished}"
VerticalOptions="StartAndExpand"
ViewModel="{Binding .}" />
<ownerDashboardControls:NextWalkControlSmall
HorizontalOptions="FillAndExpand"
IsVisible="{Binding HasNextWalk}"
NextWalk="{Binding NextWalk}"
ShowCommand="{Binding WalkSelectedCommand}"
VerticalOptions="StartAndExpand" />
<Grid
HeightRequest="130"
HorizontalOptions="Fill"
VerticalOptions="StartAndExpand">
<CollectionView ItemsSource="{Binding NextWalks}" VerticalOptions="StartAndExpand">
<CollectionView.ItemsLayout>
<GridItemsLayout
HorizontalItemSpacing="10"
Orientation="Horizontal"
SnapPointsAlignment="Center"
SnapPointsType="MandatorySingle" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<ownerDashboardControls:NextWalkListControl
NextWalk="{Binding .}"
NextWalkWidth="{Binding Source={RelativeSource AncestorType={x:Type viewmodels:HomeViewModel}}, Path=NextWalkWidth}"
ShowCommand="{Binding Source={RelativeSource AncestorType={x:Type viewmodels:HomeViewModel}}, Path=NextWalkSelectedCommand}" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Grid.IsVisible>
<MultiBinding Converter="{StaticResource AllTrueMultiConverter}">
<Binding Converter="{StaticResource InvertedBoolConverter}" Path="HasNextWalk" />
<Binding Converter="{StaticResource IsListNotNullOrEmptyConverter}" Path="NextWalks" />
<Binding Converter="{StaticResource ListContainsMoreThanOneItemConverter}" Path="NextWalks" />
</MultiBinding>
</Grid.IsVisible>
</Grid>
<Image
Margin="{Binding BannerMargin}"
HeightRequest="{Binding Banner.Height}"
IsVisible="{Binding HasBanner}"
WidthRequest="{Binding Banner.Width}">
<Image.Source>
<UriImageSource CachingEnabled="True" Uri="{Binding Banner.Image}" />
</Image.Source>
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ShowBannerCommand}" />
</Image.GestureRecognizers>
</Image>
<Label
Grid.Row="1"
Margin="{Binding ListMargin}"
Style="{StaticResource H6_Blue}"
Text="{x:Static res:Text.Common_DogWalkers_NearYou}" />
</VerticalStackLayout>
<controls:EmptyListViewControl
Grid.Row="1"
ImageHeight="150"
IsBusy="{Binding IsBusy}"
IsNotBusy="{Binding IsNotBusy}"
IsVisible="{Binding Walkers, Converter={StaticResource IsListNullOrEmptyConverter}}"
ListSource="{Binding Walkers}"
NotFoundImage="walking_dogs"
NotFoundText="{x:Static res:Text.Walker_NotFound}"
RefreshCommand="{Binding RefreshWalkersCommand}"
SearchImage="walking_dogs"
SearchText="{x:Static res:Text.Walker_Searching}" />
<RefreshView <RefreshView
x:Name="homeRefreshView" x:Name="homeRefreshView"
Grid.Row="1" AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
BackgroundColor="#ffffff" BackgroundColor="#ffffff"
Command="{Binding RefreshWalkersCommand}" Command="{Binding RefreshWalkersCommand}"
HorizontalOptions="FillAndExpand" IsRefreshing="{Binding WalkersRefreshing}">
IsRefreshing="{Binding WalkersRefreshing}" <ScrollView>
IsVisible="{Binding Walkers, Converter={StaticResource IsListNotNullOrEmptyConverter}}" <Grid
Refreshing="RefreshView_Refreshing" x:Name="rootHomeGrid"
VerticalOptions="FillAndExpand"> Padding="20,20,20,90"
<Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<CollectionView
x:Name="homeCollectionView"
Background="#ffffff"
HorizontalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"
ItemsSource="{Binding Walkers}" RowDefinitions="Auto,Auto"
RemainingItemsThreshold="5" VerticalOptions="FillAndExpand">
RemainingItemsThresholdReachedCommand="{Binding LoadMoreCommand}"
Scrolled="homeCollectionView_Scrolled" <VerticalStackLayout
SelectedItem="{Binding SelectedWalker}" x:Name="rootVerticalStackLayout"
SelectionMode="Single" Grid.Row="0"
VerticalOptions="Fill" HorizontalOptions="Fill"
VerticalScrollBarVisibility="Never"> Spacing="0"
<CollectionView.ItemsLayout> VerticalOptions="Start">
<GridItemsLayout Orientation="Vertical" VerticalItemSpacing="12" /> <Border x:Name="permissionStatusBorder" Style="{StaticResource PermissionStatusBorder}">
</CollectionView.ItemsLayout> <Label Style="{StaticResource PermissionStatusLabel}" Text="{x:Static res:Text.Permission_Location_Error}" />
<CollectionView.ItemTemplate> <Border.IsVisible>
<DataTemplate> <MultiBinding Converter="{StaticResource AllTrueMultiConverter}">
<!--<SwipeView BackgroundColor="{StaticResource Primary_White}" Margin="0,0,0,12"> <Binding Converter="{StaticResource PermissionsStatusToBoolConverter}" Path="LocationPermissionStatus" />
<SwipeView.LeftItems> <Binding Path="ShowPermissionStatus" />
<SwipeItems> </MultiBinding>
<SwipeItemView Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodels:HomeViewModel}}, Path=BlockCommand}" CommandParameter="{Binding .}"> </Border.IsVisible>
<StackLayout HorizontalOptions="Center" VerticalOptions="Center"> <Border.GestureRecognizers>
<Image Source="block_user" WidthRequest="24" HeightRequest="24" HorizontalOptions="Center" VerticalOptions="Center"/> <TapGestureRecognizer Command="{Binding ShowPermissionsCommand}" />
<Label Text="{x:Static res:Text.Common_Block}" HorizontalOptions="Center" Style="{StaticResource BodyS_GreyDark}"></Label> </Border.GestureRecognizers>
</StackLayout> </Border>
</SwipeItemView> <controls:ProfileNotFinishedControl
</SwipeItems> Margin="{StaticResource MarginMid}"
</SwipeView.LeftItems> HorizontalOptions="Fill"
<SwipeView.RightItems> IsVisible="{Binding ProfileNotFinished}"
<SwipeItems> VerticalOptions="StartAndExpand"
<SwipeItemView Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodels:HomeViewModel}}, Path=ReportCommand}" CommandParameter="{Binding .}"> ViewModel="{Binding .}" />
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<Image Source="report_user" WidthRequest="24" HeightRequest="24" HorizontalOptions="Center" VerticalOptions="Center"/> <ownerDashboardControls:NextWalkControlSmall
<Label Text="{x:Static res:Text.Common_Report}" HorizontalOptions="Center" Style="{StaticResource BodyS_GreyDark}"></Label> HorizontalOptions="FillAndExpand"
</StackLayout> IsVisible="{Binding HasNextWalk}"
</SwipeItemView> NextWalk="{Binding NextWalk}"
</SwipeItems> ShowCommand="{Binding WalkSelectedCommand}"
</SwipeView.RightItems>--> VerticalOptions="StartAndExpand" />
<controls:WalkerListControl DogOwnerHasPremium="{Binding IsPremiumUser}" Walker="{Binding .}">
<controls:WalkerListControl.GestureRecognizers> <Grid
<TapGestureRecognizer Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodels:HomeViewModel}}, Path=WalkerSelectedCommand}" CommandParameter="{Binding .}" /> HeightRequest="130"
</controls:WalkerListControl.GestureRecognizers> HorizontalOptions="Fill"
</controls:WalkerListControl> VerticalOptions="StartAndExpand">
<!--<VisualStateManager.VisualStateGroups> <CollectionView ItemsSource="{Binding NextWalks}" VerticalOptions="StartAndExpand">
<VisualStateGroup Name="CommonStates"> <CollectionView.ItemsLayout>
<VisualState Name="Selected"> <GridItemsLayout
<VisualState.Setters> HorizontalItemSpacing="10"
<Setter Property="BackgroundColor" Value="{StaticResource Primary_White}" /> Orientation="Horizontal"
</VisualState.Setters> SnapPointsAlignment="Center"
</VisualState> SnapPointsType="MandatorySingle" />
</VisualStateGroup> </CollectionView.ItemsLayout>
</VisualStateManager.VisualStateGroups>--> <CollectionView.ItemTemplate>
<!--</SwipeView>--> <DataTemplate>
</DataTemplate> <ownerDashboardControls:NextWalkListControl
</CollectionView.ItemTemplate> NextWalk="{Binding .}"
</CollectionView> NextWalkWidth="{Binding Source={RelativeSource AncestorType={x:Type viewmodels:HomeViewModel}}, Path=NextWalkWidth}"
</Grid> ShowCommand="{Binding Source={RelativeSource AncestorType={x:Type viewmodels:HomeViewModel}}, Path=NextWalkSelectedCommand}" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Grid.IsVisible>
<MultiBinding Converter="{StaticResource AllTrueMultiConverter}">
<Binding Converter="{StaticResource InvertedBoolConverter}" Path="HasNextWalk" />
<Binding Converter="{StaticResource IsListNotNullOrEmptyConverter}" Path="NextWalks" />
<Binding Converter="{StaticResource ListContainsMoreThanOneItemConverter}" Path="NextWalks" />
</MultiBinding>
</Grid.IsVisible>
</Grid>
<Image
Margin="{Binding BannerMargin}"
HeightRequest="{Binding Banner.Height}"
IsVisible="{Binding HasBanner}"
WidthRequest="{Binding Banner.Width}">
<Image.Source>
<UriImageSource CachingEnabled="True" Uri="{Binding Banner.Image}" />
</Image.Source>
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ShowBannerCommand}" />
</Image.GestureRecognizers>
</Image>
<Label
Grid.Row="1"
Margin="{Binding ListMargin}"
Style="{StaticResource H6_Blue}"
Text="{x:Static res:Text.Common_DogWalkers_NearYou}" />
<!-- Walker StackLayout (first 10) -->
<StackLayout
x:Name="walkersStackLayout"
BindableLayout.ItemsSource="{Binding First10Walkers}"
Spacing="12">
<BindableLayout.ItemTemplate>
<DataTemplate>
<controls:WalkerListControl DogOwnerHasPremium="{Binding Source={RelativeSource AncestorType={x:Type viewmodels:HomeViewModel}}, Path=IsPremiumUser}" Walker="{Binding .}">
<controls:WalkerListControl.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodels:HomeViewModel}}, Path=WalkerSelectedCommand}" CommandParameter="{Binding .}" />
</controls:WalkerListControl.GestureRecognizers>
</controls:WalkerListControl>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
<!-- "Alle anzeigen" Link Label -->
<Label
Margin="0,16,0,0"
Style="{StaticResource LinkLabelStyle}"
HorizontalOptions="Center"
Text="Alle anzeigen">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding NavigateCommand}" CommandParameter="{x:Static viewmodels:MenuSelected.Walkers}" />
</Label.GestureRecognizers>
</Label>
</VerticalStackLayout>
</Grid>
</ScrollView>
</RefreshView> </RefreshView>
<!-- Floating Public Request Button (over content) -->
<Button <Button
Grid.Row="0" Margin="0,0,0,20"
Grid.RowSpan="2" AbsoluteLayout.LayoutBounds="0.5,1,300,90"
Margin="0,0,0,10" AbsoluteLayout.LayoutFlags="PositionProportional"
BackgroundColor="{StaticResource Primary}"
Command="{Binding CreatePublicWalkRequestCommand}" Command="{Binding CreatePublicWalkRequestCommand}"
ContentLayout="Left, 5" ContentLayout="Left, 5"
HorizontalOptions="CenterAndExpand" CornerRadius="15"
HorizontalOptions="Center"
LineBreakMode="TailTruncation" LineBreakMode="TailTruncation"
Text="{x:Static res:Text.PublicWalkRequest_Title}" Text="{x:Static res:Text.PublicWalkRequest_Title}"
VerticalOptions="End"> VerticalOptions="End">
@ -217,7 +175,7 @@
</Button.ImageSource> </Button.ImageSource>
</Button> </Button>
</Grid> </AbsoluteLayout>
</ContentPage.Content> </ContentPage.Content>

View File

@ -10,9 +10,11 @@ public partial class HomeView : BaseContentPage
IDeviceInstallationService _deviceInstallationService; IDeviceInstallationService _deviceInstallationService;
IDeviceInstallationService DeviceInstallationService => _deviceInstallationService ??= ServiceHelper.GetService<IDeviceInstallationService>(); IDeviceInstallationService DeviceInstallationService => _deviceInstallationService ??= ServiceHelper.GetService<IDeviceInstallationService>();
private HomeViewModel ViewModel => BindingContext as HomeViewModel; private HomeViewModel ViewModel => BindingContext as HomeViewModel;
private bool _isRowHidden = false;
private double _initialRowHeight; // COMMENTED OUT: Animation variables for collapsing header
private bool _animationRunning = false; //private bool _isRowHidden = false;
//private double _initialRowHeight;
//private bool _animationRunning = false;
/// <summary> /// <summary>
/// Erstellt eine Instanz /// Erstellt eine Instanz
@ -31,10 +33,13 @@ public partial class HomeView : BaseContentPage
await ViewModel.InitializeAsync(this); await ViewModel.InitializeAsync(this);
var width = DeviceDisplay.Current.MainDisplayInfo.Width / DeviceDisplay.Current.MainDisplayInfo.Density; var width = DeviceDisplay.Current.MainDisplayInfo.Width / DeviceDisplay.Current.MainDisplayInfo.Density;
ViewModel.NextWalkWidth = width * 0.8; ViewModel.NextWalkWidth = width * 0.8;
_isRowHidden = false;
_initialRowHeight = 0; // COMMENTED OUT: Animation initialization
_animationRunning = false; //_isRowHidden = false;
rootVerticalStackLayout.HeightRequest = -1; //_initialRowHeight = 0;
//_animationRunning = false;
//rootVerticalStackLayout.HeightRequest = -1;
#if IOS #if IOS
if (DeviceInstallationService.NotificationsSupported) if (DeviceInstallationService.NotificationsSupported)
{ {
@ -50,74 +55,78 @@ public partial class HomeView : BaseContentPage
await ViewModel.DisappearingAsync(this); await ViewModel.DisappearingAsync(this);
} }
//Workaround für den IOS-Bug der Höhenberechnung! Siehe https://github.com/dotnet/maui/issues/8820 // COMMENTED OUT: Workaround für den IOS-Bug der Höhenberechnung! Siehe https://github.com/dotnet/maui/issues/8820
private void rootVerticalStackLayout_SizeChanged(object sender, EventArgs e) //private void rootVerticalStackLayout_SizeChanged(object sender, EventArgs e)
{ //{
if(!_isRowHidden && rootVerticalStackLayout.Height > _initialRowHeight) // if(!_isRowHidden && rootVerticalStackLayout.Height > _initialRowHeight)
_initialRowHeight = rootVerticalStackLayout.Height; // _initialRowHeight = rootVerticalStackLayout.Height;
} //}
private async void homeCollectionView_Scrolled(object sender, ItemsViewScrolledEventArgs e) // COMMENTED OUT: Scroll handler for collapsing animation
{ //private async void homeCollectionView_Scrolled(object sender, ItemsViewScrolledEventArgs e)
if(_animationRunning) //{
return; // if(_animationRunning)
// return;
//
// if (e.VerticalDelta > 0 && e.VerticalOffset >= 50 && !_isRowHidden)
// {
// await HideHeader();
// }
// else if (e.VerticalDelta < 0 && e.VerticalOffset <= 50 && _isRowHidden)
// {
// await ShowHeader();
// }
//}
if (e.VerticalDelta > 0 && e.VerticalOffset >= 50 && !_isRowHidden) // COMMENTED OUT: Show header animation
{ //private async Task ShowHeader()
await HideHeader(); //{
} // homeRefreshView.IsEnabled = false;
else if (e.VerticalDelta < 0 && e.VerticalOffset <= 50 && _isRowHidden) // homeCollectionView.IsEnabled = false;
{ // _isRowHidden = false;
await ShowHeader(); // _animationRunning = true;
} // var animation = new Animation(v => rootVerticalStackLayout.HeightRequest = v, 0, _initialRowHeight);
}
private async Task ShowHeader() // MainThread.BeginInvokeOnMainThread(() =>
{ // {
homeRefreshView.IsEnabled = false; // animation.Commit(this, "HideRowAnimation", length: 500, easing: Easing.SinIn);
homeCollectionView.IsEnabled = false; //
_isRowHidden = false; // });
_animationRunning = true;
var animation = new Animation(v => rootVerticalStackLayout.HeightRequest = v, 0, _initialRowHeight);
MainThread.BeginInvokeOnMainThread(() => // await Task.Delay(500);
{ // _animationRunning = false;
animation.Commit(this, "HideRowAnimation", length: 500, easing: Easing.SinIn); // homeCollectionView.IsEnabled = true;
// homeRefreshView.IsEnabled = true;
//}
}); // COMMENTED OUT: Hide header animation
//private async Task HideHeader()
//{
// homeRefreshView.IsEnabled = false;
// homeCollectionView.IsEnabled = false;
// _isRowHidden = true;
// _animationRunning = true;
// var animation = new Animation(v => rootVerticalStackLayout.HeightRequest = v, _initialRowHeight, 0);
//
// MainThread.BeginInvokeOnMainThread(() =>
// {
// animation.Commit(this, "HideRowAnimation", length: 500, easing: Easing.SinOut);
//
// });
//
// await Task.Delay(500);
// _animationRunning = false;
// homeCollectionView.IsEnabled = true;
// homeRefreshView.IsEnabled = true;
//}
await Task.Delay(500); // COMMENTED OUT: RefreshView refreshing handler
_animationRunning = false; //private async void RefreshView_Refreshing(object sender, EventArgs e)
homeCollectionView.IsEnabled = true; //{
homeRefreshView.IsEnabled = true; // if (_isRowHidden)
} // {
// await ShowHeader();
private async Task HideHeader() // }
{ //}
homeRefreshView.IsEnabled = false;
homeCollectionView.IsEnabled = false;
_isRowHidden = true;
_animationRunning = true;
var animation = new Animation(v => rootVerticalStackLayout.HeightRequest = v, _initialRowHeight, 0);
MainThread.BeginInvokeOnMainThread(() =>
{
animation.Commit(this, "HideRowAnimation", length: 500, easing: Easing.SinOut);
});
await Task.Delay(500);
_animationRunning = false;
homeCollectionView.IsEnabled = true;
homeRefreshView.IsEnabled = true;
}
private async void RefreshView_Refreshing(object sender, EventArgs e)
{
if (_isRowHidden)
{
await ShowHeader();
}
}
} }