浏览代码

avalonia: Added progress indicator

Kenric Nugteren 4 月之前
父节点
当前提交
4777ca77c7

+ 1 - 0
PRS.Avalonia/Directory.Packages.props

@@ -17,6 +17,7 @@
     <PackageVersion Include="Avalonia.Diagnostics" Version="11.2.3" />
     <PackageVersion Include="AvaloniaDialogs" Version="3.6.1" />
     <PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
+    <PackageVersion Include="Deadpikle.AvaloniaProgressRing" Version="0.10.10" />
     <PackageVersion Include="DialogHost.Avalonia" Version="0.9.2" />
     <PackageVersion Include="Mapsui.Avalonia" Version="4.1.8" />
     <PackageVersion Include="Material.Avalonia" Version="3.9.2" />

+ 3 - 0
PRS.Avalonia/PRS.Avalonia/App.axaml

@@ -23,6 +23,9 @@
 		
         <StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml" />
 
+		<StyleInclude Source="avares://AvaloniaProgressRing/Styles/ProgressRing.xaml"/>
+		<StyleInclude Source="avares://PRS.Avalonia/Theme/ProgressRing.axaml"/>
+
 		<dialogHostAvalonia:DialogHostStyles/>
 
     </Application.Styles>

+ 9 - 0
PRS.Avalonia/PRS.Avalonia/MainView.axaml

@@ -6,6 +6,7 @@
 			 xmlns:dialogHostAvalonia="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia"
 			 xmlns:positioners="clr-namespace:DialogHostAvalonia.Positioners;assembly=DialogHost.Avalonia"
              xmlns:components="clr-namespace:InABox.Avalonia.Components;assembly=InABox.Avalonia"
+			 xmlns:progRing="clr-namespace:AvaloniaProgressRing;assembly=AvaloniaProgressRing"
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
              x:Class="PRS.Avalonia.Modules.MainView"
              x:DataType="avalonia:MainViewModel">
@@ -95,6 +96,14 @@
 				</TransitioningContentControl.PageTransition>
 			</TransitioningContentControl>
 
+			<progRing:ProgressRing Grid.Row="1" Grid.Column="0"
+								   Width="80" Height="80"
+								   IsActive="{Binding ProgressVisible}"
+								   Background="{StaticResource PrsMenuBackground}"
+								   CornerRadius="{StaticResource PrsCornerRadius}"
+								   Foreground="White"
+								   Padding="10"/>
+
 		</Grid>
 	</dialogHostAvalonia:DialogHost>
 

+ 5 - 0
PRS.Avalonia/PRS.Avalonia/MainView.axaml.cs

@@ -7,6 +7,8 @@ namespace PRS.Avalonia.Modules;
 
 public partial class MainView : UserControl
 {
+    private bool _isTransitioning;
+
     public MainView()
     {
         InitializeComponent();
@@ -15,6 +17,9 @@ public partial class MainView : UserControl
     private void TransitioningContentControl_OnTransitionCompleted(object? sender, TransitionCompletedEventArgs e)
     {
         if (DataContext is MainViewModel mvm)
+        {
             mvm.ReverseTransition = false;
+            mvm.IsTransitioning = false;
+        }
     }
 }

+ 30 - 0
PRS.Avalonia/PRS.Avalonia/MainViewModel.cs

@@ -12,6 +12,10 @@ public partial class MainViewModel : ViewModelBase
     [ObservableProperty] private IViewModelBase? _content;
 
     [ObservableProperty] private string? _title;
+
+    [ObservableProperty] private bool _modelProgressVisible;
+
+    [ObservableProperty] private bool _isTransitioning;
     
     public MainViewModel()
     {
@@ -24,6 +28,7 @@ public partial class MainViewModel : ViewModelBase
         {
             if (Content != null)
                 Content.Deactivate();
+            IsTransitioning = true;
             Content = viewModel;
             Title = viewModel is ModuleViewModel module
                 ? module.Title
@@ -31,10 +36,35 @@ public partial class MainViewModel : ViewModelBase
             PrimaryMenu = viewModel.PrimaryMenu;
             SecondaryMenu = viewModel.SecondaryMenu;
             BackButtonVisible = viewModel.BackButtonVisible;
+            ModelProgressVisible = viewModel.ProgressVisible;
+            if(viewModel is ObservableObject observable)
+            {
+                observable.PropertyChanged += (o, e) =>
+                {
+                    if(e.PropertyName == nameof(IViewModelBase.ProgressVisible))
+                    {
+                        ModelProgressVisible = viewModel.ProgressVisible;
+                    }
+                };
+            }
             _ = viewModel.Activate();
         };
 
+        PropertyChanged += MainViewModel_PropertyChanged;
+
         // change to HomeView 
         Navigation.Reset<LoginViewModel>();
     }
+
+    private void MainViewModel_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
+    {
+        if(e.PropertyName == nameof(ModelProgressVisible) && !IsTransitioning)
+        {
+            ProgressVisible = ModelProgressVisible;
+        }
+        else if(e.PropertyName == nameof(IsTransitioning) && !IsTransitioning)
+        {
+            ProgressVisible = ModelProgressVisible;
+        }
+    }
 }

+ 6 - 0
PRS.Avalonia/PRS.Avalonia/Modules/EquipmentModule/EquipmentMaps/EquipmentMapsViewModel.cs

@@ -64,6 +64,8 @@ public partial class EquipmentMapsViewModel : ModuleViewModel
             () => DefaultCacheFileName<EquipmentShell>());
 
         PrimaryMenu.Add(new AvaloniaMenuItem(Images.menu, SelectFilter));
+
+        ProgressVisible = true;
     }
 
     protected override async Task<TimeSpan> OnRefresh()
@@ -72,8 +74,12 @@ public partial class EquipmentMapsViewModel : ModuleViewModel
             Jobs.RefreshAsync(false),
             Equipment.RefreshAsync(false));
 
+        await Task.Delay(10000);
+
         Refresh();
 
+        ProgressVisible = false;
+
         return TimeSpan.Zero;
     }
 

+ 2 - 0
PRS.Avalonia/PRS.Avalonia/PRS.Avalonia.csproj

@@ -309,6 +309,8 @@
 		<PackageReference Condition="'$(Configuration)' == 'DebugDev'" Include="Avalonia.Diagnostics" />
 
         <PackageReference Include="CommunityToolkit.Mvvm" />
+
+        <PackageReference Include="Deadpikle.AvaloniaProgressRing" />
         <PackageReference Include="DialogHost.Avalonia" />
         <PackageReference Include="Mapsui.Avalonia" />
         <PackageReference Include="Material.Avalonia" />

+ 79 - 0
PRS.Avalonia/PRS.Avalonia/Theme/ProgressRing.axaml

@@ -0,0 +1,79 @@
+<Styles xmlns="https://github.com/avaloniaui"
+                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+					xmlns:prog="clr-namespace:AvaloniaProgressRing;assembly=AvaloniaProgressRing">
+	<Style Selector="prog|ProgressRing"
+		   x:DataType="prog:ProgressRing">
+		<Setter Property="Template">
+			<Setter.Value>
+				<ControlTemplate>
+					<Border x:Name="Ring"
+							Background="{TemplateBinding Background}"
+							BorderThickness="{TemplateBinding BorderThickness}"
+							BorderBrush="{TemplateBinding BorderBrush}"
+							CornerRadius="{TemplateBinding CornerRadius}"
+							Padding="{TemplateBinding Padding}"
+							MaxWidth="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=MaxSideLength}"
+							MaxHeight="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=MaxSideLength}"
+							IsVisible="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsActive}">
+						<Border.RenderTransform>
+							<TransformGroup>
+									<RotateTransform/>
+									<TranslateTransform/>
+							</TransformGroup>
+						</Border.RenderTransform>
+						<Grid>
+							<Canvas Name="E1R">
+								<Ellipse x:Name="E1"
+										 Classes="ProgressRingEllipseStyle"
+										 Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseDiameter}"
+										 Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseDiameter}"
+										 Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseOffset}"
+										 Fill="{TemplateBinding Foreground}"/>
+							</Canvas>
+							<Canvas Name="E2R">
+								<Ellipse x:Name="E2"
+										 Classes="ProgressRingEllipseStyle"
+										 Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseDiameter}"
+										 Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseDiameter}"
+										 Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseOffset}"
+										 Fill="{TemplateBinding Foreground}"/>
+							</Canvas>
+							<Canvas Name="E3R">
+								<Ellipse x:Name="E3"
+										 Classes="ProgressRingEllipseStyle"
+										 Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseDiameter}"
+										 Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseDiameter}"
+										 Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseOffset}"
+										 Fill="{TemplateBinding Foreground}"/>
+							</Canvas>
+							<Canvas Name="E4R">
+								<Ellipse x:Name="E4"
+										 Classes="ProgressRingEllipseStyle"
+										 Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseDiameter}"
+										 Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseDiameter}"
+										 Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseOffset}"
+										 Fill="{TemplateBinding Foreground}"/>
+							</Canvas>
+							<Canvas Name="E5R">
+								<Ellipse x:Name="E5"
+										 Classes="ProgressRingEllipseStyle"
+										 Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseDiameter}"
+										 Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseDiameter}"
+										 Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseOffset}"
+										 Fill="{TemplateBinding Foreground}"/>
+							</Canvas>
+							<Canvas x:Name="E6R">
+								<Ellipse x:Name="E6"
+										 Classes="ProgressRingEllipseStyle"
+										 Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseDiameter}"
+										 Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseDiameter}"
+										 Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EllipseOffset}"
+										 Fill="{TemplateBinding Foreground}"/>
+							</Canvas>
+						</Grid>
+					</Border>
+				</ControlTemplate>
+			</Setter.Value>
+		</Setter>
+	</Style>
+</Styles>

+ 3 - 0
PRS.Avalonia/PRS.Avalonia/ViewModelBase.cs

@@ -40,6 +40,9 @@ public abstract partial class ViewModelBase : ObservableObject, IViewModelBase
 
     [ObservableProperty] private AvaloniaMenuItemCollection _secondaryMenu = new();
 
+    [ObservableProperty]
+    private bool _progressVisible = false;
+
     public static DataAccessLayer DataAccess
     {
         get