Skip to content

Commit 09744ad

Browse files
committed
Updated AggregatedDataWidget design
1 parent bc045cf commit 09744ad

9 files changed

Lines changed: 253 additions & 125 deletions

File tree

src/Platforms/SecureFolderFS.Maui/UserControls/Widgets/AggregatedDataWidget.xaml

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,73 @@
99
<Grid
1010
x:DataType="local:AggregatedDataWidget"
1111
BindingContext="{x:Reference RootControl}"
12-
ColumnSpacing="16">
12+
ColumnSpacing="12">
1313
<Grid.ColumnDefinitions>
1414
<ColumnDefinition />
1515
<ColumnDefinition />
1616
</Grid.ColumnDefinitions>
1717

18-
<VerticalStackLayout Grid.Column="0">
19-
<Label Opacity="0.6" Text="{l:ResourceString Rid=TotalRead}" />
20-
<Label
21-
FontAttributes="Bold"
22-
FontSize="22"
23-
Text="{Binding TotalRead, Mode=OneWay}" />
24-
</VerticalStackLayout>
25-
<VerticalStackLayout Grid.Column="1">
26-
<Label Opacity="0.6" Text="{l:ResourceString Rid=TotalWrite}" />
27-
<Label
28-
FontAttributes="Bold"
29-
FontSize="22"
30-
Text="{Binding TotalWrite, Mode=OneWay}" />
31-
</VerticalStackLayout>
18+
<!-- Total Read -->
19+
<Border
20+
Grid.Column="0"
21+
Background="{StaticResource ThemeElevatedFillPrimaryColorBrush}"
22+
Stroke="{StaticResource ThemeElevatedFillSecondaryColorBrush}"
23+
StrokeThickness="1">
24+
<Border.StrokeShape>
25+
<RoundRectangle CornerRadius="12" />
26+
</Border.StrokeShape>
27+
<Grid RowSpacing="0">
28+
<Grid.RowDefinitions>
29+
<RowDefinition Height="4" />
30+
<RowDefinition />
31+
</Grid.RowDefinitions>
32+
33+
<VerticalStackLayout
34+
Grid.Row="1"
35+
Padding="12,10,12,12"
36+
Spacing="2">
37+
<Label
38+
FontSize="12"
39+
Opacity="0.6"
40+
Text="{l:ResourceString Rid=TotalRead}" />
41+
<Label
42+
FontAttributes="Bold"
43+
FontSize="22"
44+
Text="{Binding TotalRead, Mode=OneWay}" />
45+
</VerticalStackLayout>
46+
</Grid>
47+
</Border>
48+
49+
<!-- Total Write -->
50+
<Border
51+
Grid.Column="1"
52+
Background="{StaticResource ThemeElevatedFillPrimaryColorBrush}"
53+
Stroke="{StaticResource ThemeElevatedFillSecondaryColorBrush}"
54+
StrokeThickness="1">
55+
<Border.StrokeShape>
56+
<RoundRectangle CornerRadius="12" />
57+
</Border.StrokeShape>
58+
<Grid RowSpacing="0">
59+
<Grid.RowDefinitions>
60+
<RowDefinition Height="4" />
61+
<RowDefinition />
62+
</Grid.RowDefinitions>
63+
64+
<VerticalStackLayout
65+
Grid.Row="1"
66+
Padding="12,10,12,12"
67+
Spacing="2">
68+
<Label
69+
FontSize="12"
70+
Opacity="0.6"
71+
Text="{l:ResourceString Rid=TotalWrite}" />
72+
<Label
73+
FontAttributes="Bold"
74+
FontSize="22"
75+
Text="{Binding TotalWrite, Mode=OneWay}" />
76+
</VerticalStackLayout>
77+
</Grid>
78+
</Border>
79+
3280
</Grid>
3381
</ContentView>

src/Platforms/SecureFolderFS.Maui/UserControls/Widgets/HealthWidget.xaml

Lines changed: 86 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,53 +8,96 @@
88
xmlns:mi_material="clr-namespace:MauiIcons.Material;assembly=MauiIcons.Material"
99
x:Name="RootControl">
1010

11-
<Grid
11+
<Border
12+
x:Name="CardBorder"
1213
x:DataType="local:HealthWidget"
1314
BindingContext="{x:Reference RootControl}"
14-
ColumnSpacing="10">
15-
<Grid.ColumnDefinitions>
16-
<ColumnDefinition Width="Auto" />
17-
<ColumnDefinition />
18-
<ColumnDefinition Width="Auto" />
19-
</Grid.ColumnDefinitions>
15+
StrokeThickness="0">
16+
<Border.StrokeShape>
17+
<RoundRectangle CornerRadius="12" />
18+
</Border.StrokeShape>
2019

21-
<Image
22-
Grid.Column="0"
23-
Margin="-4,0,0,0"
24-
HeightRequest="48"
25-
Source="{Binding Severity, Mode=OneWay, Converter={StaticResource SeverityHealthIconConverter}}"
26-
VerticalOptions="Center" />
20+
<Grid>
21+
<!-- Gradient background (set from code-behind) -->
22+
<BoxView x:Name="GradientBackground" />
2723

28-
<Label
29-
Grid.Column="1"
30-
FontAttributes="Bold"
31-
FontSize="18"
32-
Text="{Binding StatusTitle, Mode=OneWay}"
33-
VerticalOptions="Center" />
24+
<!-- Shimmer sweep overlay -->
25+
<BoxView
26+
x:Name="ShimmerOverlay"
27+
IsVisible="False"
28+
Opacity="0.18">
29+
<BoxView.Background>
30+
<LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
31+
<GradientStop Offset="0.0" Color="Transparent" />
32+
<GradientStop Offset="0.4" Color="White" />
33+
<GradientStop Offset="0.6" Color="White" />
34+
<GradientStop Offset="1.0" Color="Transparent" />
35+
</LinearGradientBrush>
36+
</BoxView.Background>
37+
</BoxView>
3438

35-
<OnPlatform x:TypeArguments="Button">
36-
<On Platform="Android">
37-
<Button
38-
Grid.Column="2"
39-
Padding="8"
40-
mi:MauiIcon.Value="{mi_material:Material ChevronRight}"
41-
Command="{Binding OpenVaultHealthCommand, Mode=OneWay}"
42-
HeightRequest="48"
43-
Style="{StaticResource TransparentButtonStyle}"
44-
VerticalOptions="Center"
45-
WidthRequest="48" />
46-
</On>
47-
<On Platform="iOS">
48-
<Button
49-
Grid.Column="2"
50-
Padding="8"
51-
mi:MauiIcon.Value="{mi_cupertino:Cupertino ChevronRight}"
52-
Command="{Binding OpenVaultHealthCommand, Mode=OneWay}"
53-
HeightRequest="48"
54-
Style="{StaticResource TransparentButtonStyle}"
39+
<!-- Content row -->
40+
<Grid Padding="16,14" ColumnSpacing="12">
41+
<Grid.ColumnDefinitions>
42+
<ColumnDefinition Width="Auto" />
43+
<ColumnDefinition />
44+
<ColumnDefinition Width="Auto" />
45+
</Grid.ColumnDefinitions>
46+
47+
<!-- Severity icon -->
48+
<Image
49+
Grid.Column="0"
50+
HeightRequest="36"
51+
Source="{Binding Severity, Mode=OneWay, Converter={StaticResource SeverityHealthIconConverter}}"
5552
VerticalOptions="Center"
56-
WidthRequest="48" />
57-
</On>
58-
</OnPlatform>
59-
</Grid>
53+
WidthRequest="36" />
54+
55+
<!-- Title + last checked -->
56+
<VerticalStackLayout
57+
Grid.Column="1"
58+
Spacing="2"
59+
VerticalOptions="Center">
60+
<Label
61+
FontAttributes="Bold"
62+
FontSize="16"
63+
Text="{Binding StatusTitle, Mode=OneWay}"
64+
TextColor="White" />
65+
<Label
66+
FontSize="12"
67+
IsVisible="{Binding LastCheckedText, Mode=OneWay, Converter={StaticResource NullToBoolConverter}}"
68+
Opacity="0.7"
69+
Text="{Binding LastCheckedText, Mode=OneWay}"
70+
TextColor="White" />
71+
</VerticalStackLayout>
72+
73+
<!-- Chevron button -->
74+
<OnPlatform x:TypeArguments="Button">
75+
<On Platform="Android">
76+
<Button
77+
Grid.Column="2"
78+
Padding="8"
79+
mi:MauiIcon.Value="{mi_material:Material ChevronRight,
80+
IconColor=White}"
81+
Command="{Binding OpenVaultHealthCommand, Mode=OneWay}"
82+
HeightRequest="44"
83+
Style="{StaticResource TransparentButtonStyle}"
84+
VerticalOptions="Center"
85+
WidthRequest="44" />
86+
</On>
87+
<On Platform="iOS">
88+
<Button
89+
Grid.Column="2"
90+
Padding="8"
91+
mi:MauiIcon.Value="{mi_cupertino:Cupertino ChevronRight,
92+
IconColor=White}"
93+
Command="{Binding OpenVaultHealthCommand, Mode=OneWay}"
94+
HeightRequest="44"
95+
Style="{StaticResource TransparentButtonStyle}"
96+
VerticalOptions="Center"
97+
WidthRequest="44" />
98+
</On>
99+
</OnPlatform>
100+
</Grid>
101+
</Grid>
102+
</Border>
60103
</ContentView>
Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,48 @@
11
using System.Windows.Input;
2+
using SecureFolderFS.Maui.Views.Vault;
23
using SecureFolderFS.Sdk.Enums;
34

45
namespace SecureFolderFS.Maui.UserControls.Widgets
56
{
6-
public partial class HealthWidget : ContentView
7+
public partial class HealthWidget : ContentView, IDisposable
78
{
9+
private CancellationTokenSource? _shimmerCts;
10+
811
public HealthWidget()
912
{
1013
InitializeComponent();
14+
GradientBackground.Background = HealthPage.GetGradientBrush(Severity);
15+
}
16+
17+
private void StartShimmer()
18+
{
19+
_shimmerCts?.Cancel();
20+
_shimmerCts = new CancellationTokenSource();
21+
var token = _shimmerCts.Token;
22+
23+
ShimmerOverlay.IsVisible = true;
24+
25+
_ = Task.Run(async () =>
26+
{
27+
while (!token.IsCancellationRequested)
28+
{
29+
await MainThread.InvokeOnMainThreadAsync(async () =>
30+
{
31+
var cardWidth = CardBorder.Width;
32+
ShimmerOverlay.TranslationX = -cardWidth;
33+
await ShimmerOverlay.TranslateToAsync(cardWidth, 0, 900, Easing.SinInOut);
34+
});
35+
await Task.Delay(400, token).ContinueWith(_ => { }, CancellationToken.None);
36+
}
37+
}, token);
38+
}
39+
40+
private void StopShimmer()
41+
{
42+
_shimmerCts?.Cancel();
43+
_shimmerCts = null;
44+
ShimmerOverlay.IsVisible = false;
45+
ShimmerOverlay.CancelAnimations();
1146
}
1247

1348
public Severity Severity
@@ -16,31 +51,60 @@ public Severity Severity
1651
set => SetValue(SeverityProperty, value);
1752
}
1853
public static readonly BindableProperty SeverityProperty =
19-
BindableProperty.Create(nameof(Severity), typeof(Severity), typeof(HealthWidget), Severity.Default);
54+
BindableProperty.Create(nameof(Severity), typeof(Severity), typeof(HealthWidget), Severity.Default,
55+
propertyChanged: static (bindable, _, newValue) =>
56+
{
57+
if (bindable is HealthWidget widget && newValue is Severity severity)
58+
widget.GradientBackground.Background = HealthPage.GetGradientBrush(severity);
59+
});
2060

2161
public string? StatusTitle
2262
{
2363
get => (string?)GetValue(StatusTitleProperty);
2464
set => SetValue(StatusTitleProperty, value);
2565
}
2666
public static readonly BindableProperty StatusTitleProperty =
27-
BindableProperty.Create(nameof(StatusTitle), typeof(string), typeof(HealthWidget), null);
67+
BindableProperty.Create(nameof(StatusTitle), typeof(string), typeof(HealthWidget));
2868

2969
public string? LastCheckedText
3070
{
3171
get => (string?)GetValue(LastCheckedTextProperty);
3272
set => SetValue(LastCheckedTextProperty, value);
3373
}
3474
public static readonly BindableProperty LastCheckedTextProperty =
35-
BindableProperty.Create(nameof(LastCheckedText), typeof(string), typeof(HealthWidget), null);
75+
BindableProperty.Create(nameof(LastCheckedText), typeof(string), typeof(HealthWidget));
3676

3777
public ICommand? OpenVaultHealthCommand
3878
{
3979
get => (ICommand?)GetValue(OpenVaultHealthCommandProperty);
4080
set => SetValue(OpenVaultHealthCommandProperty, value);
4181
}
4282
public static readonly BindableProperty OpenVaultHealthCommandProperty =
43-
BindableProperty.Create(nameof(OpenVaultHealthCommand), typeof(ICommand), typeof(HealthWidget), null);
83+
BindableProperty.Create(nameof(OpenVaultHealthCommand), typeof(ICommand), typeof(HealthWidget));
84+
85+
public bool IsProgressing
86+
{
87+
get => (bool)GetValue(IsProgressingProperty);
88+
set => SetValue(IsProgressingProperty, value);
89+
}
90+
public static readonly BindableProperty IsProgressingProperty =
91+
BindableProperty.Create(nameof(IsProgressing), typeof(bool), typeof(HealthWidget), false,
92+
propertyChanged: static (bindable, _, newValue) =>
93+
{
94+
if (bindable is not HealthWidget widget)
95+
return;
96+
97+
if (newValue is true)
98+
widget.StartShimmer();
99+
else
100+
widget.StopShimmer();
101+
});
102+
103+
/// <inheritdoc/>
104+
public void Dispose()
105+
{
106+
StopShimmer();
107+
}
44108
}
45109
}
46110

src/Platforms/SecureFolderFS.Maui/ValueConverters/VisibilityToColumnSpanConverter.cs

Lines changed: 0 additions & 32 deletions
This file was deleted.

src/Platforms/SecureFolderFS.Maui/Views/Modals/BaseModalPage.xaml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,12 @@
44
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
55
xmlns:local="clr-namespace:SecureFolderFS.Maui.Views.Modals"
66
xmlns:uc="clr-namespace:SecureFolderFS.Maui.UserControls"
7-
xmlns:vc="clr-namespace:SecureFolderFS.Maui.ValueConverters"
87
x:Name="Root"
98
x:DataType="local:BaseModalPage"
109
Background="{OnPlatform Android={AppThemeBinding Light={StaticResource LightTransparentColor},
1110
Dark={StaticResource DarkTransparentColor}},
1211
iOS={StaticResource ThemeBackgroundFillSecondaryColorBrush}}">
1312

14-
<ContentPage.Resources>
15-
<vc:VisibilityToColumnSpanConverter x:Key="VisibilityToColumnSpanConverter" />
16-
</ContentPage.Resources>
17-
1813
<NavigationPage.HasNavigationBar>
1914
<OnPlatform x:TypeArguments="x:Boolean">
2015
<On Platform="Android" Value="False" />

0 commit comments

Comments
 (0)