mirror of
https://github.com/2dust/v2rayN.git
synced 2026-05-30 01:34:08 +00:00
Add 'New Update' notification flow
Some checks are pending
release Linux / build (push) Waiting to run
release Linux / release-zip (push) Blocked by required conditions
release Linux / build and release deb x64 & arm64 (push) Waiting to run
release Linux / build and release rpm x64 & arm64 (push) Waiting to run
release Linux / build and release rpm riscv64 (push) Waiting to run
release Linux / build and release deb riscv64 (push) Waiting to run
release Linux / build and release deb loong64 (push) Waiting to run
release macOS / build (push) Waiting to run
release macOS / release-zip (push) Blocked by required conditions
release macOS / package and release macOS dmg (push) Blocked by required conditions
release Windows desktop (Avalonia UI) / build (push) Waiting to run
release Windows desktop (Avalonia UI) / release-zip (push) Blocked by required conditions
release Windows / build (push) Waiting to run
release Windows / release-zip (push) Blocked by required conditions
Some checks are pending
release Linux / build (push) Waiting to run
release Linux / release-zip (push) Blocked by required conditions
release Linux / build and release deb x64 & arm64 (push) Waiting to run
release Linux / build and release rpm x64 & arm64 (push) Waiting to run
release Linux / build and release rpm riscv64 (push) Waiting to run
release Linux / build and release deb riscv64 (push) Waiting to run
release Linux / build and release deb loong64 (push) Waiting to run
release macOS / build (push) Waiting to run
release macOS / release-zip (push) Blocked by required conditions
release macOS / package and release macOS dmg (push) Blocked by required conditions
release Windows desktop (Avalonia UI) / build (push) Waiting to run
release Windows desktop (Avalonia UI) / release-zip (push) Blocked by required conditions
release Windows / build (push) Waiting to run
release Windows / release-zip (push) Blocked by required conditions
Introduce a small update-notification feature: add AppEvents.HasUpdateNotified event and have TaskManager publish it when update messages exist. Add localized resource key (menuNewUpdate) and expose it in the ResUI designer; update resource files for several languages. In the UI, add a New Update button in MainWindow.xaml, wire its click to the existing check-update handler, bind its visibility to a new BlNewUpdate property on MainWindowViewModel, and subscribe the viewmodel to the new event. Also reset the notification flag after showing the Check Update dialog.
This commit is contained in:
parent
c7519f8ea7
commit
14cc37d07a
15 changed files with 66 additions and 0 deletions
|
|
@ -7,6 +7,7 @@ public static class AppEvents
|
||||||
public static readonly EventChannel<Unit> AddServerViaScanRequested = new();
|
public static readonly EventChannel<Unit> AddServerViaScanRequested = new();
|
||||||
public static readonly EventChannel<Unit> AddServerViaClipboardRequested = new();
|
public static readonly EventChannel<Unit> AddServerViaClipboardRequested = new();
|
||||||
public static readonly EventChannel<bool> SubscriptionsUpdateRequested = new();
|
public static readonly EventChannel<bool> SubscriptionsUpdateRequested = new();
|
||||||
|
public static readonly EventChannel<bool> HasUpdateNotified = new();
|
||||||
|
|
||||||
public static readonly EventChannel<Unit> ProfilesRefreshRequested = new();
|
public static readonly EventChannel<Unit> ProfilesRefreshRequested = new();
|
||||||
public static readonly EventChannel<Unit> SubscriptionsRefreshRequested = new();
|
public static readonly EventChannel<Unit> SubscriptionsRefreshRequested = new();
|
||||||
|
|
|
||||||
|
|
@ -142,5 +142,10 @@ public class TaskManager
|
||||||
await _updateFunc?.Invoke(false, msg);
|
await _updateFunc?.Invoke(false, msg);
|
||||||
}
|
}
|
||||||
NoticeManager.Instance.Enqueue(string.Join("\n", msgs));
|
NoticeManager.Instance.Enqueue(string.Join("\n", msgs));
|
||||||
|
|
||||||
|
if (msgs.Count > 0)
|
||||||
|
{
|
||||||
|
AppEvents.HasUpdateNotified.Publish(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
9
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
9
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
|
|
@ -1320,6 +1320,15 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 New Update 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuNewUpdate {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuNewUpdate", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Open the storage location 的本地化字符串。
|
/// 查找类似 Open the storage location 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -1743,4 +1743,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
||||||
<data name="LvTestIpInfo" xml:space="preserve">
|
<data name="LvTestIpInfo" xml:space="preserve">
|
||||||
<value>IP Info</value>
|
<value>IP Info</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuNewUpdate" xml:space="preserve">
|
||||||
|
<value>New Update</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -1740,4 +1740,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
||||||
<data name="LvTestIpInfo" xml:space="preserve">
|
<data name="LvTestIpInfo" xml:space="preserve">
|
||||||
<value>IP Info</value>
|
<value>IP Info</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuNewUpdate" xml:space="preserve">
|
||||||
|
<value>New Update</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -1743,4 +1743,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
||||||
<data name="LvTestIpInfo" xml:space="preserve">
|
<data name="LvTestIpInfo" xml:space="preserve">
|
||||||
<value>IP Info</value>
|
<value>IP Info</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuNewUpdate" xml:space="preserve">
|
||||||
|
<value>New Update</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -1743,4 +1743,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
||||||
<data name="LvTestIpInfo" xml:space="preserve">
|
<data name="LvTestIpInfo" xml:space="preserve">
|
||||||
<value>IP Info</value>
|
<value>IP Info</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuNewUpdate" xml:space="preserve">
|
||||||
|
<value>New Update</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -1743,4 +1743,7 @@
|
||||||
<data name="LvTestIpInfo" xml:space="preserve">
|
<data name="LvTestIpInfo" xml:space="preserve">
|
||||||
<value>IP Info</value>
|
<value>IP Info</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuNewUpdate" xml:space="preserve">
|
||||||
|
<value>New Update</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -1740,4 +1740,7 @@
|
||||||
<data name="LvTestIpInfo" xml:space="preserve">
|
<data name="LvTestIpInfo" xml:space="preserve">
|
||||||
<value>IP 信息</value>
|
<value>IP 信息</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuNewUpdate" xml:space="preserve">
|
||||||
|
<value>有更新</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -1740,4 +1740,7 @@
|
||||||
<data name="LvTestIpInfo" xml:space="preserve">
|
<data name="LvTestIpInfo" xml:space="preserve">
|
||||||
<value>IP 資訊</value>
|
<value>IP 資訊</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="menuNewUpdate" xml:space="preserve">
|
||||||
|
<value>有更新</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -65,6 +65,8 @@ public class MainWindowViewModel : MyReactiveObject
|
||||||
|
|
||||||
[Reactive] public bool BlIsWindows { get; set; }
|
[Reactive] public bool BlIsWindows { get; set; }
|
||||||
|
|
||||||
|
[Reactive] public bool BlNewUpdate { get; set; }
|
||||||
|
|
||||||
#endregion Menu
|
#endregion Menu
|
||||||
|
|
||||||
#region Init
|
#region Init
|
||||||
|
|
@ -251,6 +253,11 @@ public class MainWindowViewModel : MyReactiveObject
|
||||||
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||||
.Subscribe(async blProxy => await UpdateSubscriptionProcess("", blProxy));
|
.Subscribe(async blProxy => await UpdateSubscriptionProcess("", blProxy));
|
||||||
|
|
||||||
|
AppEvents.HasUpdateNotified
|
||||||
|
.AsObservable()
|
||||||
|
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||||
|
.Subscribe(async bl => BlNewUpdate = bl);
|
||||||
|
|
||||||
#endregion AppEvents
|
#endregion AppEvents
|
||||||
|
|
||||||
_ = Init();
|
_ = Init();
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,13 @@
|
||||||
|
|
||||||
<MenuItem x:Name="menuClose" Header="{x:Static resx:ResUI.menuExit}" />
|
<MenuItem x:Name="menuClose" Header="{x:Static resx:ResUI.menuExit}" />
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
x:Name="btnNewUpdate"
|
||||||
|
Margin="{StaticResource MarginLr8}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Content="{x:Static resx:ResUI.menuNewUpdate}"
|
||||||
|
IsVisible="False" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
|
||||||
<view:StatusBarView DockPanel.Dock="Bottom" />
|
<view:StatusBarView DockPanel.Dock="Bottom" />
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||||
menuSettingsSetUWP.Click += MenuSettingsSetUWP_Click;
|
menuSettingsSetUWP.Click += MenuSettingsSetUWP_Click;
|
||||||
menuPromotion.Click += MenuPromotion_Click;
|
menuPromotion.Click += MenuPromotion_Click;
|
||||||
menuCheckUpdate.Click += MenuCheckUpdate_Click;
|
menuCheckUpdate.Click += MenuCheckUpdate_Click;
|
||||||
|
btnNewUpdate.Click += MenuCheckUpdate_Click;
|
||||||
menuBackupAndRestore.Click += MenuBackupAndRestore_Click;
|
menuBackupAndRestore.Click += MenuBackupAndRestore_Click;
|
||||||
menuClose.Click += MenuClose_Click;
|
menuClose.Click += MenuClose_Click;
|
||||||
|
|
||||||
|
|
@ -102,6 +103,7 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.ReloadCmd, v => v.menuReload).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.ReloadCmd, v => v.menuReload).DisposeWith(disposables);
|
||||||
this.OneWayBind(ViewModel, vm => vm.BlReloadEnabled, v => v.menuReload.IsEnabled).DisposeWith(disposables);
|
this.OneWayBind(ViewModel, vm => vm.BlReloadEnabled, v => v.menuReload.IsEnabled).DisposeWith(disposables);
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.BlNewUpdate, v => v.btnNewUpdate.IsVisible).DisposeWith(disposables);
|
||||||
|
|
||||||
switch (_config.UiItem.MainGirdOrientation)
|
switch (_config.UiItem.MainGirdOrientation)
|
||||||
{
|
{
|
||||||
|
|
@ -367,6 +369,8 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||||
{
|
{
|
||||||
_checkUpdateView ??= new CheckUpdateView();
|
_checkUpdateView ??= new CheckUpdateView();
|
||||||
DialogHost.Show(_checkUpdateView);
|
DialogHost.Show(_checkUpdateView);
|
||||||
|
|
||||||
|
AppEvents.HasUpdateNotified.Publish(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MenuBackupAndRestore_Click(object? sender, RoutedEventArgs e)
|
private void MenuBackupAndRestore_Click(object? sender, RoutedEventArgs e)
|
||||||
|
|
|
||||||
|
|
@ -313,6 +313,13 @@
|
||||||
Style="{StaticResource MaterialDesignToolForegroundPopupBox}">
|
Style="{StaticResource MaterialDesignToolForegroundPopupBox}">
|
||||||
<ContentControl x:Name="pbTheme" />
|
<ContentControl x:Name="pbTheme" />
|
||||||
</materialDesign:PopupBox>
|
</materialDesign:PopupBox>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
x:Name="btnNewUpdate"
|
||||||
|
Margin="{StaticResource MarginLeftRight8}"
|
||||||
|
Content="{x:Static resx:ResUI.menuNewUpdate}"
|
||||||
|
Style="{StaticResource DefButton}"
|
||||||
|
Visibility="Hidden" />
|
||||||
</ToolBar>
|
</ToolBar>
|
||||||
</ToolBarTray>
|
</ToolBarTray>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ public partial class MainWindow
|
||||||
menuPromotion.Click += MenuPromotion_Click;
|
menuPromotion.Click += MenuPromotion_Click;
|
||||||
menuClose.Click += MenuClose_Click;
|
menuClose.Click += MenuClose_Click;
|
||||||
menuCheckUpdate.Click += MenuCheckUpdate_Click;
|
menuCheckUpdate.Click += MenuCheckUpdate_Click;
|
||||||
|
btnNewUpdate.Click += MenuCheckUpdate_Click;
|
||||||
menuBackupAndRestore.Click += MenuBackupAndRestore_Click;
|
menuBackupAndRestore.Click += MenuBackupAndRestore_Click;
|
||||||
|
|
||||||
ViewModel = new MainWindowViewModel(UpdateViewHandler);
|
ViewModel = new MainWindowViewModel(UpdateViewHandler);
|
||||||
|
|
@ -102,6 +103,8 @@ public partial class MainWindow
|
||||||
this.BindCommand(ViewModel, vm => vm.ReloadCmd, v => v.menuReload).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.ReloadCmd, v => v.menuReload).DisposeWith(disposables);
|
||||||
this.OneWayBind(ViewModel, vm => vm.BlReloadEnabled, v => v.menuReload.IsEnabled).DisposeWith(disposables);
|
this.OneWayBind(ViewModel, vm => vm.BlReloadEnabled, v => v.menuReload.IsEnabled).DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.BlNewUpdate, v => v.btnNewUpdate.Visibility).DisposeWith(disposables);
|
||||||
|
|
||||||
switch (_config.UiItem.MainGirdOrientation)
|
switch (_config.UiItem.MainGirdOrientation)
|
||||||
{
|
{
|
||||||
case EGirdOrientation.Horizontal:
|
case EGirdOrientation.Horizontal:
|
||||||
|
|
@ -363,6 +366,8 @@ public partial class MainWindow
|
||||||
{
|
{
|
||||||
_checkUpdateView ??= new CheckUpdateView();
|
_checkUpdateView ??= new CheckUpdateView();
|
||||||
DialogHost.Show(_checkUpdateView, "RootDialog");
|
DialogHost.Show(_checkUpdateView, "RootDialog");
|
||||||
|
|
||||||
|
AppEvents.HasUpdateNotified.Publish(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MenuBackupAndRestore_Click(object sender, RoutedEventArgs e)
|
private void MenuBackupAndRestore_Click(object sender, RoutedEventArgs e)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue