Skip to content

Commit f79124a

Browse files
committed
feat: add Start, Stop, Restart Button.
1 parent bc117dc commit f79124a

File tree

3 files changed

+234
-11
lines changed

3 files changed

+234
-11
lines changed
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
2+
<ControlTheme x:Key="ButtonToggleSwitch" TargetType="ToggleSwitch">
3+
<Setter Property="HorizontalAlignment" Value="Center" />
4+
<Setter Property="VerticalAlignment" Value="Center" />
5+
<Setter Property="HorizontalContentAlignment" Value="Center" />
6+
<Setter Property="VerticalContentAlignment" Value="Center" />
7+
<Setter Property="Padding" Value="{DynamicResource ButtonDefaultPadding}" />
8+
<Setter Property="Background" Value="Transparent" />
9+
<Setter Property="BackgroundSizing" Value="OuterBorderEdge" />
10+
<Setter Property="BorderBrush" Value="{DynamicResource ButtonDefaultBorderBrush}" />
11+
<Setter Property="BorderThickness" Value="{DynamicResource ButtonBorderThickness}" />
12+
<Setter Property="CornerRadius" Value="{DynamicResource ButtonCornerRadius}" />
13+
<Setter Property="Cursor" Value="Hand" />
14+
<Setter Property="OnContent" Value="{x:Null}" />
15+
<Setter Property="OffContent" Value="{x:Null}" />
16+
<Setter Property="Content" Value="{x:Null}" />
17+
<Setter Property="MinHeight" Value="{DynamicResource ButtonDefaultHeight}" />
18+
<Setter Property="FontSize" Value="{DynamicResource ButtonDefaultFontSize}" />
19+
<Setter Property="FontWeight" Value="{DynamicResource ButtonDefaultFontWeight}" />
20+
<Setter Property="Template">
21+
<ControlTemplate TargetType="ToggleSwitch">
22+
<Border
23+
Name="Background"
24+
Padding="{TemplateBinding Padding}"
25+
Background="{TemplateBinding Background}"
26+
BorderBrush="{TemplateBinding BorderBrush}"
27+
BorderThickness="{TemplateBinding BorderThickness}"
28+
CornerRadius="{TemplateBinding CornerRadius}">
29+
<Panel>
30+
<Panel Name="PART_SwitchKnob" />
31+
<Panel Name="PART_MovingKnobs" />
32+
<ContentPresenter
33+
Name="PART_OnContentPresenter"
34+
IsVisible="{TemplateBinding IsChecked}"
35+
Content="{TemplateBinding OnContent}"
36+
ContentTemplate="{TemplateBinding OnContentTemplate}" />
37+
<ContentPresenter
38+
Name="PART_OffContentPresenter"
39+
IsVisible="{TemplateBinding IsChecked, Converter={x:Static BoolConverters.Not}}"
40+
Content="{TemplateBinding OffContent}"
41+
ContentTemplate="{TemplateBinding OffContentTemplate}" />
42+
<ContentPresenter
43+
Name="PART_ContentPresenter"
44+
Content="{TemplateBinding Content}"
45+
ContentTemplate="{TemplateBinding ContentTemplate}">
46+
<ContentPresenter.IsVisible>
47+
<MultiBinding Converter="{x:Static BoolConverters.And}">
48+
<TemplateBinding Property="Content" Converter="{x:Static ObjectConverters.IsNotNull}" />
49+
<TemplateBinding Property="OnContent" Converter="{x:Static ObjectConverters.IsNull}" />
50+
<TemplateBinding Property="OffContent" Converter="{x:Static ObjectConverters.IsNull}" />
51+
</MultiBinding>
52+
</ContentPresenter.IsVisible>
53+
</ContentPresenter>
54+
</Panel>
55+
</Border>
56+
</ControlTemplate>
57+
</Setter>
58+
59+
<Style Selector="^:pressed">
60+
<Setter Property="RenderTransform" Value="scale(0.98)" />
61+
</Style>
62+
63+
<Style Selector="^ /template/ Border#Background">
64+
<Setter Property="BorderBrush" Value="{TemplateBinding BorderBrush}" />
65+
<Setter Property="Background" Value="{TemplateBinding Background}" />
66+
</Style>
67+
68+
<Style Selector="^:pointerover /template/ Border#Background">
69+
<Setter Property="BorderBrush" Value="{DynamicResource ButtonDefaultPointeroverBorderBrush}" />
70+
<Setter Property="Background" Value="{DynamicResource ButtonDefaultPointeroverBackground}" />
71+
</Style>
72+
73+
<Style Selector="^:pressed /template/ Border#Background">
74+
<Setter Property="BorderBrush" Value="{DynamicResource ButtonDefaultPressedBorderBrush}" />
75+
<Setter Property="Background" Value="{DynamicResource ButtonDefaultPressedBackground}" />
76+
</Style>
77+
78+
<Style Selector="^:disabled /template/ Border#Background">
79+
<Setter Property="BorderBrush" Value="{DynamicResource ButtonDefaultDisabledBorderBrush}" />
80+
</Style>
81+
82+
<Style Selector="^:disabled">
83+
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
84+
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultDisabledForeground}" />
85+
</Style>
86+
<Style Selector="^ /template/ ContentPresenter#PART_OnContentPresenter">
87+
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultDisabledForeground}" />
88+
</Style>
89+
<Style Selector="^ /template/ ContentPresenter#PART_OffContentPresenter">
90+
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultDisabledForeground}" />
91+
</Style>
92+
</Style>
93+
94+
<Style Selector="^.Large">
95+
<Setter Property="MinHeight" Value="{DynamicResource ButtonLargeHeight}" />
96+
<Setter Property="Padding" Value="{DynamicResource ButtonLargePadding}" />
97+
</Style>
98+
<Style Selector="^.Small">
99+
<Setter Property="MinHeight" Value="{DynamicResource ButtonSmallHeight}" />
100+
<Setter Property="Padding" Value="{DynamicResource ButtonSmallPadding}" />
101+
</Style>
102+
103+
<Style Selector="^ /template/ Border#Background">
104+
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderlessBorderBrush}" />
105+
<Setter Property="Background" Value="{DynamicResource ButtonBorderlessBackground}" />
106+
</Style>
107+
<Style Selector="^:disabled /template/ Border#Background">
108+
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderlessBorderBrush}" />
109+
<Setter Property="Background" Value="{DynamicResource ButtonBorderlessBackground}" />
110+
<!-- <Setter Property="Foreground" Value="{DynamicResource ButtonDefaultDisabledForeground}" /> -->
111+
</Style>
112+
</ControlTheme>
113+
</ResourceDictionary>

src/Client.Avalonia/ViewModels/MainWindowViewModel.cs

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@
22
using System.ComponentModel;
33
using Avalonia.Threading;
44
using CommunityToolkit.Mvvm.ComponentModel;
5+
using CommunityToolkit.Mvvm.Input;
56

67
namespace Client.Avalonia.ViewModels;
78

89
public partial class MainWindowViewModel : ViewModelBase
910
{
1011
[ObservableProperty] private DownloadStatistics _statistics;
11-
[ObservableProperty] private bool _isCompleted;
12+
13+
[ObservableProperty] [NotifyCanExecuteChangedFor(nameof(StartCommand))]
14+
private bool _isCompleted;
15+
16+
[ObservableProperty] [NotifyCanExecuteChangedFor(nameof(StartCommand), nameof(StopCommand))]
17+
private bool _isUpdating;
18+
1219
private readonly DispatcherTimer _timer;
1320
private readonly Random _random;
1421

@@ -29,11 +36,47 @@ public MainWindowViewModel()
2936
Interval = TimeSpan.FromMilliseconds(1000)
3037
};
3138
_timer.Tick += UpdateProgress;
32-
_timer.Start();
3339

3440
_random = new Random();
3541
}
3642

43+
private bool CanStart => !IsCompleted;
44+
45+
[RelayCommand(CanExecute = nameof(CanStart))]
46+
private void Start()
47+
{
48+
if (!_timer.IsEnabled)
49+
{
50+
_timer.Start();
51+
IsUpdating = true;
52+
}
53+
else
54+
{
55+
_timer.Stop();
56+
IsUpdating = false;
57+
}
58+
}
59+
60+
[RelayCommand(CanExecute = nameof(IsUpdating))]
61+
private void Stop()
62+
{
63+
_timer.Stop();
64+
Statistics.BytesReceived = 0;
65+
Statistics.ProgressPercentage = 0;
66+
Statistics.Speed = "0 MB/s";
67+
Statistics.Remaining = TimeSpan.Zero;
68+
IsCompleted = false;
69+
IsUpdating = false;
70+
OnPropertyChanged(nameof(Statistics));
71+
}
72+
73+
[RelayCommand]
74+
private void Restart()
75+
{
76+
Stop();
77+
Start();
78+
}
79+
3780
private void UpdateProgress(object? sender, EventArgs e)
3881
{
3982
var received = Statistics.BytesReceived;
@@ -62,6 +105,7 @@ private void UpdateProgress(object? sender, EventArgs e)
62105
if (received >= total)
63106
{
64107
_timer.Stop();
108+
IsUpdating = false;
65109
IsCompleted = true;
66110
}
67111
}

src/Client.Avalonia/Views/MainWindow.axaml

Lines changed: 75 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,21 @@
77
x:Class="Client.Avalonia.Views.MainWindow"
88
x:DataType="vm:MainWindowViewModel"
99
Icon="/Assets/avalonia-logo.ico"
10+
RequestedThemeVariant="Dark"
11+
Width="800" Height="450"
12+
Background="{DynamicResource SemiBackground3Color}"
1013
Title="Client.Avalonia">
14+
<Window.Resources>
15+
<ResourceDictionary>
16+
<ResourceDictionary.MergedDictionaries>
17+
<ResourceInclude Source="../Themes/ToggleSwitch.axaml" />
18+
</ResourceDictionary.MergedDictionaries>
19+
<StreamGeometry x:Key="IconPlay">M 5 2.90101 C 5 2.09583 5.90303 1.62081 6.56653 2.07697 L 19.8014 11.1759 C 20.3794 11.5733 20.3794 12.4267 19.8014 12.824 L 6.56653 21.923 C 5.90303 22.3792 5 21.9041 5 21.0989 V 2.90101 Z</StreamGeometry>
20+
<StreamGeometry x:Key="IconPause">M4.5 4.75C4.5 3.23122 5.73122 2 7.25 2C8.76878 2 10 3.23122 10 4.75V19.25C10 20.7688 8.76878 22 7.25 22C5.73122 22 4.5 20.7688 4.5 19.25V4.75ZM14 4.75C14 3.23122 15.2312 2 16.75 2C18.2688 2 19.5 3.23122 19.5 4.75V19.25C19.5 20.7688 18.2688 22 16.75 22C15.2312 22 14 20.7688 14 19.25V4.75Z</StreamGeometry>
21+
<StreamGeometry x:Key="IconStop">M3 6C3 4.34315 4.34315 3 6 3H18C19.6569 3 21 4.34315 21 6V18C21 19.6569 19.6569 21 18 21H6C4.34315 21 3 19.6569 3 18V6Z</StreamGeometry>
22+
<StreamGeometry x:Key="IconRestart">M4.5 2C3.67157 2 3 2.67157 3 3.5V20.5C3 21.3284 3.67157 22 4.5 22C5.32843 22 6 21.3284 6 20.5V3.5C6 2.67157 5.32843 2 4.5 2ZM8.00083 11.2137L19.3822 2.27115C20.0384 1.75562 21.0001 2.22303 21.0001 3.05746V20.9425C21.0001 21.777 20.0384 22.2444 19.3822 21.7289L8.00083 12.7863C7.49126 12.3859 7.49126 11.6141 8.00083 11.2137Z</StreamGeometry>
23+
</ResourceDictionary>
24+
</Window.Resources>
1125

1226
<Design.DataContext>
1327
<vm:MainWindowViewModel />
@@ -16,10 +30,13 @@
1630
<SelectableTextBlock
1731
HorizontalAlignment="Center"
1832
FontSize="20"
19-
FontWeight="Bold"
20-
Text="版本更新中..." />
33+
FontWeight="Bold">
34+
<Run Text="{Binding Statistics.Version}" />
35+
<Run Text="版本更新中..." />
36+
</SelectableTextBlock>
2137

2238
<ProgressBar
39+
Name="Bar"
2340
Width="400"
2441
ShowProgressText="True"
2542
Classes.Success="{Binding IsCompleted}"
@@ -35,14 +52,63 @@
3552
</Style>
3653
</ProgressBar.Styles>
3754
</ProgressBar>
38-
55+
<Border
56+
Padding="10"
57+
Background="{DynamicResource SemiBackground3Color}"
58+
Theme="{StaticResource CardBorder}">
59+
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Spacing="10">
60+
<Button
61+
Name="StopButton"
62+
Padding="8"
63+
Theme="{StaticResource BorderlessButton}"
64+
Classes="Tertiary"
65+
ToolTip.Tip="停止"
66+
Command="{Binding StopCommand}">
67+
<PathIcon
68+
Theme="{StaticResource InnerPathIcon}"
69+
Data="{StaticResource IconStop}" />
70+
</Button>
71+
<ToggleSwitch
72+
Name="StartButton"
73+
Padding="8"
74+
Theme="{StaticResource ButtonToggleSwitch}"
75+
Command="{Binding StartCommand}">
76+
<ToolTip.Tip>
77+
<Panel>
78+
<TextBlock Text="下载" IsVisible="{Binding !$parent[ToggleSwitch].IsChecked}" />
79+
<TextBlock Text="暂停" IsVisible="{Binding $parent[ToggleSwitch].IsChecked}" />
80+
</Panel>
81+
</ToolTip.Tip>
82+
<ToggleSwitch.OffContent>
83+
<PathIcon
84+
Theme="{StaticResource InnerPathIcon}"
85+
Data="{StaticResource IconPlay}" />
86+
</ToggleSwitch.OffContent>
87+
<ToggleSwitch.OnContent>
88+
<PathIcon
89+
Theme="{StaticResource InnerPathIcon}"
90+
Data="{StaticResource IconPause}" />
91+
</ToggleSwitch.OnContent>
92+
</ToggleSwitch>
93+
<Button
94+
Name="RestartButton"
95+
Padding="8"
96+
Theme="{StaticResource BorderlessButton}"
97+
Classes="Tertiary"
98+
ToolTip.Tip="重新开始"
99+
Command="{Binding RestartCommand}">
100+
<PathIcon
101+
Theme="{StaticResource InnerPathIcon}"
102+
Data="{StaticResource IconRestart}" />
103+
</Button>
104+
</StackPanel>
105+
</Border>
39106
<StackPanel Spacing="5">
40-
<SelectableTextBlock Text="{Binding Statistics.Version}" FontWeight="Bold" FontSize="16" />
41-
<SelectableTextBlock Text="{Binding Statistics.Speed, StringFormat='下载速度: {0}'}" />
42-
<SelectableTextBlock Text="{Binding Statistics.Remaining, StringFormat='剩余时间: {0:mm\\:ss}'}" />
43-
<SelectableTextBlock Text="{Binding Statistics.BytesReceived, StringFormat='已下载: {0:N0} bytes'}" />
44-
<SelectableTextBlock Text="{Binding Statistics.TotalBytesToReceive, StringFormat='总大小: {0:N0} bytes'}" />
45-
<SelectableTextBlock Text="{Binding Statistics.ProgressPercentage, StringFormat='下载进度: {0:F2}%'}" />
107+
<SelectableTextBlock Text="{Binding Statistics.Speed, StringFormat='下载速度:{0}'}" />
108+
<SelectableTextBlock Text="{Binding Statistics.Remaining, StringFormat='剩余时间:{0:mm\\:ss}'}" />
109+
<SelectableTextBlock Text="{Binding Statistics.BytesReceived, StringFormat='已下载:{0:N0} bytes'}" />
110+
<SelectableTextBlock Text="{Binding Statistics.TotalBytesToReceive, StringFormat='总大小:{0:N0} bytes'}" />
111+
<SelectableTextBlock Text="{Binding Statistics.ProgressPercentage, StringFormat='下载进度:{0:F2}%'}" />
46112
</StackPanel>
47113
</StackPanel>
48114
</Window>

0 commit comments

Comments
 (0)