From 220959591734cadfe8dcc12a59167ea52497ab0e Mon Sep 17 00:00:00 2001 From: Aigio Liu Date: Thu, 5 Aug 2021 08:16:36 +0800 Subject: [PATCH 01/10] fix Desktop Bridge System Boot Run --- .../Launcher/App.config | 10 ++++----- .../Launcher/Launcher.csproj | 11 +++++++++- .../Launcher/Program.cs | 19 +++++++++++++--- src/ST.Client.Desktop.Avalonia.App/Program.cs | 22 +++++++++---------- ...pPlatformService.SystemBootRunArguments.cs | 19 ++++++++++++++++ .../Services/IDesktopPlatformService.cs | 5 +---- 6 files changed, 62 insertions(+), 24 deletions(-) create mode 100644 src/ST.Client.Desktop/Services/IDesktopPlatformService.SystemBootRunArguments.cs diff --git a/src/ST.Client.Desktop.Avalonia.App.Bridge.Package.RefLauncher/Launcher/App.config b/src/ST.Client.Desktop.Avalonia.App.Bridge.Package.RefLauncher/Launcher/App.config index 731f6de6c..c116b6cf4 100644 --- a/src/ST.Client.Desktop.Avalonia.App.Bridge.Package.RefLauncher/Launcher/App.config +++ b/src/ST.Client.Desktop.Avalonia.App.Bridge.Package.RefLauncher/Launcher/App.config @@ -1,6 +1,6 @@ - + - - - - \ No newline at end of file + + + + diff --git a/src/ST.Client.Desktop.Avalonia.App.Bridge.Package.RefLauncher/Launcher/Launcher.csproj b/src/ST.Client.Desktop.Avalonia.App.Bridge.Package.RefLauncher/Launcher/Launcher.csproj index 1a009c040..ac834b312 100644 --- a/src/ST.Client.Desktop.Avalonia.App.Bridge.Package.RefLauncher/Launcher/Launcher.csproj +++ b/src/ST.Client.Desktop.Avalonia.App.Bridge.Package.RefLauncher/Launcher/Launcher.csproj @@ -3,7 +3,7 @@ WinExe AnyCPU - net461 + net472 ..\..\ST.Client.Desktop.Avalonia.App\Properties\app.manifest Steam++.Launcher System @@ -31,5 +31,14 @@ Properties\ThisAssembly.Version.cs + + Application\Services\IDesktopPlatformService.SystemBootRunArguments.cs + + + + + + + \ No newline at end of file diff --git a/src/ST.Client.Desktop.Avalonia.App.Bridge.Package.RefLauncher/Launcher/Program.cs b/src/ST.Client.Desktop.Avalonia.App.Bridge.Package.RefLauncher/Launcher/Program.cs index c5dcf6dd2..37ce51dd0 100644 --- a/src/ST.Client.Desktop.Avalonia.App.Bridge.Package.RefLauncher/Launcher/Program.cs +++ b/src/ST.Client.Desktop.Avalonia.App.Bridge.Package.RefLauncher/Launcher/Program.cs @@ -1,17 +1,30 @@ using System; using System.Diagnostics; using System.IO; +using Windows.ApplicationModel; +using Windows.ApplicationModel.Activation; +using static System.Application.Services.IDesktopPlatformService; +static string? OnActivated(IActivatedEventArgs args) +{ + if (args.Kind == ActivationKind.StartupTask) + { + // 静默启动(不弹窗口) + return SystemBootRunArguments; + } + return default; +} + +var activatedArgs = AppInstance.GetActivatedEventArgs(); try { Process.Start(new ProcessStartInfo() { FileName = Path.Combine(AppContext.BaseDirectory, "..", "Steam++.exe"), - Arguments = string.Join(" ", args), - UseShellExecute = false, + Arguments = (activatedArgs == default ? default : OnActivated(activatedArgs)) ?? string.Join(" ", args), + UseShellExecute = default, }); } catch (FileNotFoundException) { - } \ No newline at end of file diff --git a/src/ST.Client.Desktop.Avalonia.App/Program.cs b/src/ST.Client.Desktop.Avalonia.App/Program.cs index c82e92305..49fc00be9 100644 --- a/src/ST.Client.Desktop.Avalonia.App/Program.cs +++ b/src/ST.Client.Desktop.Avalonia.App/Program.cs @@ -12,15 +12,15 @@ namespace System.Application.UI static readonly object lock_global_ex_log = new(); #if WINDOWS_DESKTOP_BRIDGE - static string[] OnActivated(string[] main_args, global::Windows.ApplicationModel.Activation.IActivatedEventArgs args) - { - if (args.Kind == global::Windows.ApplicationModel.Activation.ActivationKind.StartupTask) - { - // 静默启动(不弹窗口) - return IDesktopPlatformService.SystemBootRunArguments.Split(' '); - } - return main_args; - } + //static string[] OnActivated(string[] main_args, global::Windows.ApplicationModel.Activation.IActivatedEventArgs args) + //{ + // if (args.Kind == global::Windows.ApplicationModel.Activation.ActivationKind.StartupTask) + // { + // // 静默启动(不弹窗口) + // return IDesktopPlatformService.SystemBootRunArguments.Split(' '); + // } + // return main_args; + //} #endif // Initialization code. Don't use any Avalonia, third-party APIs or any @@ -34,8 +34,8 @@ namespace System.Application.UI { #if WINDOWS_DESKTOP_BRIDGE if (!DesktopBridgeHelper.Init()) return 0; - var activatedArgs = global::Windows.ApplicationModel.AppInstance.GetActivatedEventArgs(); - if (activatedArgs != null) args = OnActivated(args, activatedArgs); + //var activatedArgs = global::Windows.ApplicationModel.AppInstance.GetActivatedEventArgs(); + //if (activatedArgs != null) args = OnActivated(args, activatedArgs); #elif !__MOBILE__ #if MAC AppDelegateHelper.Init(args); diff --git a/src/ST.Client.Desktop/Services/IDesktopPlatformService.SystemBootRunArguments.cs b/src/ST.Client.Desktop/Services/IDesktopPlatformService.SystemBootRunArguments.cs new file mode 100644 index 000000000..97d2b1316 --- /dev/null +++ b/src/ST.Client.Desktop/Services/IDesktopPlatformService.SystemBootRunArguments.cs @@ -0,0 +1,19 @@ +namespace System.Application.Services +{ +#if NETFRAMEWORK + static +#endif + partial +#if NETFRAMEWORK + class +#else + interface +#endif + IDesktopPlatformService + { +#if NETFRAMEWORK + public +#endif + const string SystemBootRunArguments = "-clt c -silence"; + } +} \ No newline at end of file diff --git a/src/ST.Client.Desktop/Services/IDesktopPlatformService.cs b/src/ST.Client.Desktop/Services/IDesktopPlatformService.cs index e13868a6b..dc628ae4a 100644 --- a/src/ST.Client.Desktop/Services/IDesktopPlatformService.cs +++ b/src/ST.Client.Desktop/Services/IDesktopPlatformService.cs @@ -8,7 +8,7 @@ using System.Windows; namespace System.Application.Services { - public interface IDesktopPlatformService : IPlatformService + public partial interface IDesktopPlatformService : IPlatformService { protected new const string TAG = "DesktopPlatformS"; @@ -126,8 +126,6 @@ namespace System.Application.Services /// string? GetFileName(TextReaderProvider provider); - const string SystemBootRunArguments = "-clt c -silence"; - /// /// 设置开机自启动 /// @@ -231,7 +229,6 @@ namespace System.Application.Services void FixFluentWindowStyleOnWin7(IntPtr hWnd) { - } } } \ No newline at end of file From 16997b6c6ac2af2f9ca71975aef19806faeef72f Mon Sep 17 00:00:00 2001 From: rmbgame Date: Wed, 4 Aug 2021 18:23:51 +0800 Subject: [PATCH 02/10] Misc --- .../App.axaml.cs | 3 +- .../Implementation/ShowWindowServiceImpl.cs | 5 +- .../UI/Views/Pages/GameListPage.axaml | 2 +- .../Windows/GameListPage/IdleAppWindow.axaml | 2 +- .../Views/Windows/MessageBoxWindow.axaml.cs | 7 +++ .../PlatformNotificationServiceImpl.cs | 40 ++++++++++++ .../Services/IShowWindowService.cs | 3 +- .../Services/Mvvm/SteamConnectService.cs | 63 +++++-------------- .../ViewModels/Pages/GameListPageViewModel.cs | 4 +- .../SteamShutdownWindowViewModel.cs | 17 +++++ 10 files changed, 90 insertions(+), 56 deletions(-) create mode 100644 src/ST.Client.Desktop.Windows/Services/Implementation/PlatformNotificationServiceImpl.cs diff --git a/src/ST.Client.Desktop.Avalonia.App/App.axaml.cs b/src/ST.Client.Desktop.Avalonia.App/App.axaml.cs index 21eee23fd..100ed5980 100644 --- a/src/ST.Client.Desktop.Avalonia.App/App.axaml.cs +++ b/src/ST.Client.Desktop.Avalonia.App/App.axaml.cs @@ -270,8 +270,6 @@ namespace System.Application.UI #if WINDOWS JumpLists.Init(); #endif - - IsNotOfficialChannelPackageDetectionHelper.Check(); } desktop.MainWindow = @@ -301,6 +299,7 @@ namespace System.Application.UI #if StartupTrace StartupTrace.Restart("Desktop_Startup.Start"); #endif + IsNotOfficialChannelPackageDetectionHelper.Check(); #if WINDOWS if (isOfficialChannelPackage) { diff --git a/src/ST.Client.Desktop.Avalonia/Application/Services/Implementation/ShowWindowServiceImpl.cs b/src/ST.Client.Desktop.Avalonia/Application/Services/Implementation/ShowWindowServiceImpl.cs index 958814ea8..5ce319f64 100644 --- a/src/ST.Client.Desktop.Avalonia/Application/Services/Implementation/ShowWindowServiceImpl.cs +++ b/src/ST.Client.Desktop.Avalonia/Application/Services/Implementation/ShowWindowServiceImpl.cs @@ -159,12 +159,13 @@ namespace System.Application.Services.Implementation TWindowViewModel? viewModel = null, string title = "", ResizeModeCompat resizeMode = ResizeModeCompat.NoResize, - bool isDialog = true) + bool isDialog = true, + bool isParent = true) where TWindowViewModel : WindowViewModel, new() { DialogWindowViewModel? dialogWindowViewModel = null; await Show(typeof(TWindowViewModel), isDialog, customWindow, - title, viewModel, resizeMode, true, dwvm => + title, viewModel, resizeMode, isParent, dwvm => { dialogWindowViewModel = dwvm; }); diff --git a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Pages/GameListPage.axaml b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Pages/GameListPage.axaml index 46c0095a2..564bdabca 100644 --- a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Pages/GameListPage.axaml +++ b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Pages/GameListPage.axaml @@ -239,7 +239,7 @@ - + diff --git a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/MessageBoxWindow.axaml.cs b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/MessageBoxWindow.axaml.cs index 091b10b53..8dbd941bf 100644 --- a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/MessageBoxWindow.axaml.cs +++ b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/MessageBoxWindow.axaml.cs @@ -31,6 +31,13 @@ namespace System.Application.UI.Views.Windows AvaloniaXamlLoader.Load(this); } + protected override void OnOpened(EventArgs e) + { + base.OnOpened(e); + this.Topmost = true; + this.Topmost = false; + } + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); diff --git a/src/ST.Client.Desktop.Windows/Services/Implementation/PlatformNotificationServiceImpl.cs b/src/ST.Client.Desktop.Windows/Services/Implementation/PlatformNotificationServiceImpl.cs new file mode 100644 index 000000000..26cc862f2 --- /dev/null +++ b/src/ST.Client.Desktop.Windows/Services/Implementation/PlatformNotificationServiceImpl.cs @@ -0,0 +1,40 @@ +using System.Properties; + +namespace System.Application.Services.Implementation +{ + /// + internal sealed class PlatformNotificationServiceImpl : INotificationService + { + readonly IDesktopPlatformService dps; + + public PlatformNotificationServiceImpl(IDesktopPlatformService dps) + { + this.dps = dps; + } + + public bool AreNotificationsEnabled() => true; + + public void Cancel(NotificationType notificationType) + { + } + + public void CancelAll() + { + } + + public void Notify(string text, NotificationType notificationType, bool autoCancel, string? title, Entrance entrance) + { + title ??= ThisAssembly.AssemblyTrademark; + // 调用托盘显示通知 + throw new NotImplementedException(title); + } + + public Progress NotifyDownload(string text, NotificationType notificationType, string? title) + { + // 桌面端不支持带进度的通知,下载新版本改用桌面端的窗口进度条控件,由更新服务桌面端版实现 + //title ??= ThisAssembly.AssemblyTrademark; + //throw new NotImplementedException(title); + throw new PlatformNotSupportedException(); + } + } +} \ No newline at end of file diff --git a/src/ST.Client.Desktop/Services/IShowWindowService.cs b/src/ST.Client.Desktop/Services/IShowWindowService.cs index 09fe64691..f79ec8e5d 100644 --- a/src/ST.Client.Desktop/Services/IShowWindowService.cs +++ b/src/ST.Client.Desktop/Services/IShowWindowService.cs @@ -57,7 +57,8 @@ namespace System.Application.Services TWindowViewModel? viewModel = null, string title = "", ResizeModeCompat resizeMode = ResizeModeCompat.NoResize, - bool isDialog = true) + bool isDialog = true, + bool isParent = true) where TWindowViewModel : WindowViewModel, new(); diff --git a/src/ST.Client.Desktop/Services/Mvvm/SteamConnectService.cs b/src/ST.Client.Desktop/Services/Mvvm/SteamConnectService.cs index 0de77d9af..002475bcb 100644 --- a/src/ST.Client.Desktop/Services/Mvvm/SteamConnectService.cs +++ b/src/ST.Client.Desktop/Services/Mvvm/SteamConnectService.cs @@ -105,10 +105,11 @@ namespace System.Application.Services } } } - #endregion - #region 是否已经释放SteamClient private bool _IsDisposedClient = true; + /// + /// 是否已经释放SteamClient + /// public bool IsDisposedClient { get => _IsDisposedClient; @@ -136,22 +137,13 @@ namespace System.Application.Services } } } - public bool IsAutoAFKApps - { - get => GameLibrarySettings.IsAutoAFKApps.Value; - set - { - GameLibrarySettings.IsAutoAFKApps.Value = value; - this.RaisePropertyChanged(nameof(IsAutoAFKApps)); - } - } + public void RunAFKApps() { if (GameLibrarySettings.AFKAppList.Value?.Count > 0) { foreach (var item in GameLibrarySettings.AFKAppList.Value) { - RuningSteamApps.TryGetValue(item.Key, out var runState); if (runState == null) RuningSteamApps.TryAdd(item.Key, new SteamApp @@ -177,7 +169,7 @@ namespace System.Application.Services if (!SteamTool.IsRunningSteamProcess && SteamSettings.IsAutoRunSteam.Value) SteamTool.StartSteam(SteamSettings.SteamStratParameter.Value); - var t = new Task(async () => + Task.Factory.StartNew(async () => { Thread.CurrentThread.IsBackground = true; try @@ -206,10 +198,10 @@ namespace System.Application.Services CurrentSteamUser.IPCountry = ApiService.GetIPCountry(); IsSteamChinaLauncher = ApiService.IsSteamChinaLauncher(); - if (IsAutoAFKApps) + #region 初始化需要steam启动才能使用的功能 + if (GameLibrarySettings.IsAutoAFKApps.Value) RunAFKApps(); - #region 初始化需要steam启动才能使用的功能 if (SteamApps.Items.Any()) { LoadGames(ApiService.OwnsApps(await ISteamService.Instance.GetAppInfos())); @@ -234,13 +226,10 @@ namespace System.Application.Services } catch (Exception ex) { - Log.Error(nameof(SteamConnectService), ex, "Task LongRunning"); + Log.Error(nameof(SteamConnectService), ex, "SteamConnect Task LongRunning"); ToastService.Current.Notify(ex.Message); } - }, TaskCreationOptions.LongRunning); - - //t.Forget(); - t.Start(); + }, TaskCreationOptions.LongRunning).ConfigureAwait(false); } public bool Initialize(int appid) @@ -256,7 +245,7 @@ namespace System.Application.Services { SteamApps.Clear(); if (apps.Any_Nullable()) - SteamApps.AddOrUpdate(apps); + SteamApps.AddOrUpdate(apps!); } public async void InitializeGameList() @@ -267,29 +256,10 @@ namespace System.Application.Services IsLoadingGameList = false; } - // public void UpdateGamesImage() - // { - //#if DEBUG - // if (BuildConfig.IsDebuggerAttached) - // { - // return; - // } - //#endif - // //if (SteamApps.Items.Any()) - // //{ - // // Parallel.ForEach(SteamApps.Items, new ParallelOptions - // // { - // // MaxDegreeOfParallelism = (Environment.ProcessorCount / 2) + 1 - // // }, async app => - // // { - // // await ISteamService.Instance.LoadAppImageAsync(app); - // // //app.LibraryLogoStream = await IHttpService.Instance.GetImageAsync(app.LibraryLogoUrl, ImageChannelType.SteamGames); - // // //app.LibraryHeaderStream = await IHttpService.Instance.GetImageAsync(app.LibraryHeaderUrl, ImageChannelType.SteamGames); - // // //app.LibraryNameStream = await IHttpService.Instance.GetImageAsync(app.LibraryNameUrl, ImageChannelType.SteamGames); - // // //app.HeaderLogoStream = await IHttpService.Instance.GetImageAsync(app.HeaderLogoUrl, ImageChannelType.SteamGames); - // // }); - // //} - // } + public async void InitializeDownloadGameList() + { + + } private bool _IsRefreshing; public /*async*/ void RefreshGamesList() @@ -299,7 +269,7 @@ namespace System.Application.Services _IsRefreshing = true; if (SteamTool.IsRunningSteamProcess) { - var t = new Task(() => + Task.Factory.StartNew(() => { Thread.CurrentThread.IsBackground = true; try @@ -331,8 +301,7 @@ namespace System.Application.Services Log.Error(nameof(SteamConnectService), ex, "Task RefreshGamesList"); ToastService.Current.Notify(ex.Message); } - }, TaskCreationOptions.LongRunning); - t.Start(); + }, TaskCreationOptions.DenyChildAttach | TaskCreationOptions.PreferFairness).Forget().ConfigureAwait(false); } else { diff --git a/src/ST.Client.Desktop/UI/ViewModels/Pages/GameListPageViewModel.cs b/src/ST.Client.Desktop/UI/ViewModels/Pages/GameListPageViewModel.cs index ddec9dd2e..75a50a881 100644 --- a/src/ST.Client.Desktop/UI/ViewModels/Pages/GameListPageViewModel.cs +++ b/src/ST.Client.Desktop/UI/ViewModels/Pages/GameListPageViewModel.cs @@ -119,7 +119,7 @@ namespace System.Application.UI.ViewModels EnableAFKAutoUpdateCommand = ReactiveCommand.Create(() => { - AFKAutoUpdate?.CheckmarkChange(SteamConnectService.Current.IsAutoAFKApps = !SteamConnectService.Current.IsAutoAFKApps); + AFKAutoUpdate?.CheckmarkChange(GameLibrarySettings.IsAutoAFKApps.Value = !GameLibrarySettings.IsAutoAFKApps.Value); }); MenuItems = new ObservableCollection() @@ -135,7 +135,7 @@ namespace System.Application.UI.ViewModels IconKey ="ClockArrowDownloadDrawing", Command = SteamShutdownCommand }, }; - AFKAutoUpdate?.CheckmarkChange(SteamConnectService.Current.IsAutoAFKApps); + AFKAutoUpdate?.CheckmarkChange(GameLibrarySettings.IsAutoAFKApps.Value); } public ReactiveCommand EnableAFKAutoUpdateCommand { get; } diff --git a/src/ST.Client.Desktop/UI/ViewModels/Windows/GameListPage/SteamShutdownWindowViewModel.cs b/src/ST.Client.Desktop/UI/ViewModels/Windows/GameListPage/SteamShutdownWindowViewModel.cs index e3094627f..73134856b 100644 --- a/src/ST.Client.Desktop/UI/ViewModels/Windows/GameListPage/SteamShutdownWindowViewModel.cs +++ b/src/ST.Client.Desktop/UI/ViewModels/Windows/GameListPage/SteamShutdownWindowViewModel.cs @@ -1,7 +1,11 @@ +using DynamicData; using Newtonsoft.Json.Linq; +using ReactiveUI; using System.Application.Models; using System.Application.UI.Resx; +using System.Collections.ObjectModel; using System.Properties; +using System.Reactive.Linq; namespace System.Application.UI.ViewModels { @@ -10,8 +14,21 @@ namespace System.Application.UI.ViewModels public SteamShutdownWindowViewModel() : base() { Title = ThisAssembly.AssemblyTrademark + " | " + AppResources.GameList_SteamShutdown; + + _DownloadingAppSourceList = new SourceList(); + + _DownloadingAppSourceList + .Connect() + .ObserveOn(RxApp.MainThreadScheduler) + //.Sort(SortExpressionComparer.Descending(x => x.)) + .Bind(out _DownloadingApps) + .Subscribe(); } + private readonly ReadOnlyObservableCollection? _DownloadingApps; + public ReadOnlyObservableCollection? DownloadingApps => _DownloadingApps; + + private readonly SourceList _DownloadingAppSourceList; } } \ No newline at end of file From de29d52ee351923fa1aca818da32bde166bed2dc Mon Sep 17 00:00:00 2001 From: rmbgame Date: Thu, 5 Aug 2021 09:59:58 +0800 Subject: [PATCH 03/10] NotifyIcon --- .../Internals/UnmanagedMethods.cs | 103 +++++++++++++++++- .../PlatformNotificationServiceImpl.cs | 1 - .../UI/NotifyIcon.cs | 60 ++++++++-- 3 files changed, 149 insertions(+), 15 deletions(-) diff --git a/src/ST.Client.Desktop.Windows/Internals/UnmanagedMethods.cs b/src/ST.Client.Desktop.Windows/Internals/UnmanagedMethods.cs index ee76b649b..14e02686a 100644 --- a/src/ST.Client.Desktop.Windows/Internals/UnmanagedMethods.cs +++ b/src/ST.Client.Desktop.Windows/Internals/UnmanagedMethods.cs @@ -1,4 +1,4 @@ -// Copyright (c) The Avalonia Project. All rights reserved. +// Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. // Slightly modified and extended version for the use in SQRLDotNetClientUI @@ -19,7 +19,7 @@ namespace System public static extern IntPtr LoadImage(IntPtr hinst, string lpszName, uint uType, int cxDesired, int cyDesired, uint fuLoad); [DllImport("shell32", CharSet = CharSet.Auto)] - public static extern int Shell_NotifyIcon(NIM dwMessage, NOTIFYICONDATA lpData); + public static extern int Shell_NotifyIcon(NIM dwMessage, [In] ref NOTIFYICONDATA lpData); [DllImport("user32.dll")] public static extern void PostQuitMessage(int nExitCode); @@ -132,6 +132,46 @@ namespace System [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string szInfoTitle; public NIIF dwInfoFlags; + /// + /// String with the text for a balloon ToolTip. It can have a maximum of 255 characters. + /// To remove the ToolTip, set the NIF_INFO flag in uFlags and set szInfo to an empty string. + /// + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string BalloonText; + /// + /// String containing a title for a balloon ToolTip. This title appears in boldface + /// above the text. It can have a maximum of 63 characters. + /// + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] + public string BalloonTitle; + /// + /// Mainly used to set the version when is invoked + /// with . However, for legacy operations, + /// the same member is also used to set timeouts for balloon ToolTips. + /// + public uint VersionOrTimeout; + /// + /// Adds an icon to a balloon ToolTip, which is placed to the left of the title. If the + /// member is zero-length, the icon is not shown. + /// + public BalloonFlags BalloonFlags; + + /// + /// Windows XP (Shell32.dll version 6.0) and later.
+ /// - Windows 7 and later: A registered GUID that identifies the icon. + /// This value overrides uID and is the recommended method of identifying the icon.
+ /// - Windows XP through Windows Vista: Reserved. + ///
+ public Guid TaskbarIconGuid; + + /// + /// Windows Vista (Shell32.dll version 6.0.6) and later. The handle of a customized + /// balloon icon provided by the application that should be used independently + /// of the tray icon. If this member is non-NULL and the + /// flag is set, this icon is used as the balloon icon.
+ /// If this member is NULL, the legacy behavior is carried out. + ///
+ public IntPtr CustomBalloonIconHandle; } public enum NIM : uint @@ -2103,6 +2143,65 @@ namespace System } } + /// + /// Flags that define the icon that is shown on a balloon + /// tooltip. + /// + public enum BalloonFlags + { + /// + /// No icon is displayed. + /// + None = 0x00, + + /// + /// An information icon is displayed. + /// + Info = 0x01, + + /// + /// A warning icon is displayed. + /// + Warning = 0x02, + + /// + /// An error icon is displayed. + /// + Error = 0x03, + + /// + /// Windows XP Service Pack 2 (SP2) and later. + /// Use a custom icon as the title icon. + /// + User = 0x04, + + /// + /// Windows XP (Shell32.dll version 6.0) and later. + /// Do not play the associated sound. Applies only to balloon ToolTips. + /// + NoSound = 0x10, + + /// + /// Windows Vista (Shell32.dll version 6.0.6) and later. The large version + /// of the icon should be used as the balloon icon. This corresponds to the + /// icon with dimensions SM_CXICON x SM_CYICON. If this flag is not set, + /// the icon with dimensions XM_CXSMICON x SM_CYSMICON is used.
+ /// - This flag can be used with all stock icons.
+ /// - Applications that use older customized icons (NIIF_USER with hIcon) must + /// provide a new SM_CXICON x SM_CYICON version in the tray icon (hIcon). These + /// icons are scaled down when they are displayed in the System Tray or + /// System Control Area (SCA).
+ /// - New customized icons (NIIF_USER with hBalloonIcon) must supply an + /// SM_CXICON x SM_CYICON version in the supplied icon (hBalloonIcon). + ///
+ LargeIcon = 0x20, + + /// + /// Windows 7 and later. + /// + RespectQuietTime = 0x80 + } + [Flags] internal enum DropEffect : int { diff --git a/src/ST.Client.Desktop.Windows/Services/Implementation/PlatformNotificationServiceImpl.cs b/src/ST.Client.Desktop.Windows/Services/Implementation/PlatformNotificationServiceImpl.cs index 26cc862f2..7aeeedc4e 100644 --- a/src/ST.Client.Desktop.Windows/Services/Implementation/PlatformNotificationServiceImpl.cs +++ b/src/ST.Client.Desktop.Windows/Services/Implementation/PlatformNotificationServiceImpl.cs @@ -26,7 +26,6 @@ namespace System.Application.Services.Implementation { title ??= ThisAssembly.AssemblyTrademark; // 调用托盘显示通知 - throw new NotImplementedException(title); } public Progress NotifyDownload(string text, NotificationType notificationType, string? title) diff --git a/src/ST.Client.Desktop.Windows/UI/NotifyIcon.cs b/src/ST.Client.Desktop.Windows/UI/NotifyIcon.cs index fcb8c9768..b7b2d2c2a 100644 --- a/src/ST.Client.Desktop.Windows/UI/NotifyIcon.cs +++ b/src/ST.Client.Desktop.Windows/UI/NotifyIcon.cs @@ -20,6 +20,11 @@ namespace System.Application.UI string _toolTipText = string.Empty; bool _visible = false; bool _doubleClick = false; + /// + /// Represents the current icon data. + /// + private UnmanagedMethods.NOTIFYICONDATA iconData; + public event EventHandler? Click; public event EventHandler? DoubleClick; @@ -131,6 +136,15 @@ namespace System.Application.UI ~NotifyIcon() { + iconData = new UnmanagedMethods.NOTIFYICONDATA() + { + hWnd = _window.Handle, + uID = _uID, + uFlags = UnmanagedMethods.NIF.TIP | UnmanagedMethods.NIF.MESSAGE, + uCallbackMessage = (int)UnmanagedMethods.CustomWindowsMessage.WM_TRAYMOUSE, + hIcon = IntPtr.Zero, + szTip = ToolTipText + }; UpdateIcon(remove: true); } @@ -141,15 +155,6 @@ namespace System.Application.UI void UpdateIcon(bool remove = false) { if (_window == null) throw new ArgumentNullException(nameof(_window)); - UnmanagedMethods.NOTIFYICONDATA iconData = new UnmanagedMethods.NOTIFYICONDATA() - { - hWnd = _window.Handle, - uID = _uID, - uFlags = UnmanagedMethods.NIF.TIP | UnmanagedMethods.NIF.MESSAGE, - uCallbackMessage = (int)UnmanagedMethods.CustomWindowsMessage.WM_TRAYMOUSE, - hIcon = IntPtr.Zero, - szTip = ToolTipText - }; if (!remove && _icon != null && Visible) { @@ -158,17 +163,17 @@ namespace System.Application.UI if (!_iconAdded) { - _ = UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.ADD, iconData); + _ = UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.ADD,ref iconData); _iconAdded = true; } else { - _ = UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.MODIFY, iconData); + _ = UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.MODIFY,ref iconData); } } else { - _ = UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.DELETE, iconData); + _ = UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.DELETE,ref iconData); _iconAdded = false; } } @@ -242,6 +247,37 @@ namespace System.Application.UI } } + public void ShowBalloonTip(string title, string message, BalloonFlags flags, IntPtr balloonIconHandle) + { + iconData = new UnmanagedMethods.NOTIFYICONDATA() + { + hWnd = _window.Handle, + uID = _uID, + uFlags = UnmanagedMethods.NIF.TIP | UnmanagedMethods.NIF.MESSAGE, + uCallbackMessage = (int)UnmanagedMethods.CustomWindowsMessage.WM_TRAYMOUSE, + hIcon = IntPtr.Zero, + szTip = ToolTipText + }; + + iconData.BalloonText = message ?? string.Empty; + iconData.BalloonTitle = title ?? string.Empty; + + iconData.BalloonFlags = flags; + iconData.CustomBalloonIconHandle = balloonIconHandle; + + UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.MODIFY,ref iconData); + } + + /// + /// Hides a balloon ToolTip, if any is displayed. + /// + public void HideBalloonTip() + { + // reset balloon by just setting the info to an empty string + iconData.BalloonText = iconData.BalloonTitle = string.Empty; + UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.MODIFY, ref iconData); + } + /// /// Handles the NotifyIcon-specific window messages sent by the notification icon. /// From 4a1ae528abdea7af7a9d83281b37799fe5a4ab5c Mon Sep 17 00:00:00 2001 From: rmbgame Date: Thu, 5 Aug 2021 15:52:55 +0800 Subject: [PATCH 04/10] =?UTF-8?q?windows=E6=89=98=E7=9B=98=E9=80=9A?= =?UTF-8?q?=E7=9F=A5=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../App.axaml.cs | 3 +- .../PlatformNotificationServiceImpl.cs | 7 +- .../Internals/UnmanagedMethods.cs | 148 +++++------------- .../PlatformNotificationServiceImpl.cs | 39 ----- .../UI/NotifyIcon.cs | 95 ++++++++--- src/ST.Client.Desktop/UI/INotifyIcon.cs | 15 ++ .../UI/ViewModels/Pages/DebugPageViewModel.cs | 4 +- 7 files changed, 129 insertions(+), 182 deletions(-) delete mode 100644 src/ST.Client.Desktop.Windows/Services/Implementation/PlatformNotificationServiceImpl.cs diff --git a/src/ST.Client.Desktop.Avalonia.App/App.axaml.cs b/src/ST.Client.Desktop.Avalonia.App/App.axaml.cs index 100ed5980..6d817f16c 100644 --- a/src/ST.Client.Desktop.Avalonia.App/App.axaml.cs +++ b/src/ST.Client.Desktop.Avalonia.App/App.axaml.cs @@ -211,6 +211,7 @@ namespace System.Application.UI #region NotifyIcon var notifyIcon = INotifyIcon.Instance; + notifyIcon.Visible = true; notifyIcon.ToolTipText = ThisAssembly.AssemblyTrademark; switch (DI.Platform) { @@ -255,8 +256,6 @@ namespace System.Application.UI .Select(x => new MenuItem { Header = x.Key, Command = x.Value }).ToList(); notifyIcon.ContextMenu = NotifyIconContextMenu; #endif - - notifyIcon.Visible = true; notifyIcon.Click += NotifyIcon_Click; notifyIcon.DoubleClick += NotifyIcon_Click; compositeDisposable.Add(() => diff --git a/src/ST.Client.Desktop.Avalonia/Application/Services/Implementation/PlatformNotificationServiceImpl.cs b/src/ST.Client.Desktop.Avalonia/Application/Services/Implementation/PlatformNotificationServiceImpl.cs index 26cc862f2..8cfa5e6a4 100644 --- a/src/ST.Client.Desktop.Avalonia/Application/Services/Implementation/PlatformNotificationServiceImpl.cs +++ b/src/ST.Client.Desktop.Avalonia/Application/Services/Implementation/PlatformNotificationServiceImpl.cs @@ -1,3 +1,4 @@ +using System.Application.UI; using System.Properties; namespace System.Application.Services.Implementation @@ -25,8 +26,12 @@ namespace System.Application.Services.Implementation public void Notify(string text, NotificationType notificationType, bool autoCancel, string? title, Entrance entrance) { title ??= ThisAssembly.AssemblyTrademark; + // 调用托盘显示通知 - throw new NotImplementedException(title); + if (DI.Platform == Platform.Windows) + { + INotifyIcon.Instance.ShowBalloonTip(title, text); + } } public Progress NotifyDownload(string text, NotificationType notificationType, string? title) diff --git a/src/ST.Client.Desktop.Windows/Internals/UnmanagedMethods.cs b/src/ST.Client.Desktop.Windows/Internals/UnmanagedMethods.cs index 14e02686a..adfb4ac88 100644 --- a/src/ST.Client.Desktop.Windows/Internals/UnmanagedMethods.cs +++ b/src/ST.Client.Desktop.Windows/Internals/UnmanagedMethods.cs @@ -18,8 +18,11 @@ namespace System [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern IntPtr LoadImage(IntPtr hinst, string lpszName, uint uType, int cxDesired, int cyDesired, uint fuLoad); - [DllImport("shell32", CharSet = CharSet.Auto)] - public static extern int Shell_NotifyIcon(NIM dwMessage, [In] ref NOTIFYICONDATA lpData); + /// + /// Creates, updates or deletes the taskbar icon. + /// + [DllImport("shell32", CharSet = CharSet.Unicode)] + public static extern bool Shell_NotifyIcon(NIM cmd, NOTIFYICONDATA data); [DllImport("user32.dll")] public static extern void PostQuitMessage(int nExitCode); @@ -113,7 +116,7 @@ namespace System public uint dwTime; } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public class NOTIFYICONDATA { public int cbSize = Marshal.SizeOf(); @@ -126,48 +129,26 @@ namespace System public string szTip; public int dwState = 0; public int dwStateMask = 0; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] - public string szInfo; - public int uTimeoutOrVersion; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] - public string szInfoTitle; - public NIIF dwInfoFlags; /// /// String with the text for a balloon ToolTip. It can have a maximum of 255 characters. /// To remove the ToolTip, set the NIF_INFO flag in uFlags and set szInfo to an empty string. /// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] - public string BalloonText; + public string szInfo; + public int uVersion; + public int uTimeoutOrVersion; /// /// String containing a title for a balloon ToolTip. This title appears in boldface /// above the text. It can have a maximum of 63 characters. /// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] - public string BalloonTitle; - /// - /// Mainly used to set the version when is invoked - /// with . However, for legacy operations, - /// the same member is also used to set timeouts for balloon ToolTips. - /// - public uint VersionOrTimeout; - /// - /// Adds an icon to a balloon ToolTip, which is placed to the left of the title. If the - /// member is zero-length, the icon is not shown. - /// - public BalloonFlags BalloonFlags; - - /// - /// Windows XP (Shell32.dll version 6.0) and later.
- /// - Windows 7 and later: A registered GUID that identifies the icon. - /// This value overrides uID and is the recommended method of identifying the icon.
- /// - Windows XP through Windows Vista: Reserved. - ///
- public Guid TaskbarIconGuid; + public string szInfoTitle; + public NIIF dwInfoFlags; /// /// Windows Vista (Shell32.dll version 6.0.6) and later. The handle of a customized /// balloon icon provided by the application that should be used independently - /// of the tray icon. If this member is non-NULL and the + /// of the tray icon. If this member is non-NULL and the /// flag is set, this icon is used as the balloon icon.
/// If this member is NULL, the legacy behavior is carried out. ///
@@ -183,33 +164,6 @@ namespace System SETVERSION = 0x00000004 } - [Flags] - public enum NIF : uint - { - MESSAGE = 0x00000001, - ICON = 0x00000002, - TIP = 0x00000004, - STATE = 0x00000008, - INFO = 0x00000010, - GUID = 0x00000020, - REALTIME = 0x00000040, - SHOWTIP = 0x00000080 - } - - [Flags] - public enum NIIF : uint - { - NONE = 0x00000000, - INFO = 0x00000001, - WARNING = 0x00000002, - ERROR = 0x00000003, - USER = 0x00000004, - ICON_MASK = 0x0000000F, - NOSOUND = 0x00000010, - LARGE_ICON = 0x00000020, - RESPECT_QUIET_TIME = 0x00000080 - } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public class MENUITEMINFO { @@ -2143,63 +2097,31 @@ namespace System } } - /// - /// Flags that define the icon that is shown on a balloon - /// tooltip. - /// - public enum BalloonFlags + [Flags] + public enum NIF : uint { - /// - /// No icon is displayed. - /// - None = 0x00, + MESSAGE = 0x00000001, + ICON = 0x00000002, + TIP = 0x00000004, + STATE = 0x00000008, + INFO = 0x00000010, + GUID = 0x00000020, + REALTIME = 0x00000040, + SHOWTIP = 0x00000080 + } - /// - /// An information icon is displayed. - /// - Info = 0x01, - - /// - /// A warning icon is displayed. - /// - Warning = 0x02, - - /// - /// An error icon is displayed. - /// - Error = 0x03, - - /// - /// Windows XP Service Pack 2 (SP2) and later. - /// Use a custom icon as the title icon. - /// - User = 0x04, - - /// - /// Windows XP (Shell32.dll version 6.0) and later. - /// Do not play the associated sound. Applies only to balloon ToolTips. - /// - NoSound = 0x10, - - /// - /// Windows Vista (Shell32.dll version 6.0.6) and later. The large version - /// of the icon should be used as the balloon icon. This corresponds to the - /// icon with dimensions SM_CXICON x SM_CYICON. If this flag is not set, - /// the icon with dimensions XM_CXSMICON x SM_CYSMICON is used.
- /// - This flag can be used with all stock icons.
- /// - Applications that use older customized icons (NIIF_USER with hIcon) must - /// provide a new SM_CXICON x SM_CYICON version in the tray icon (hIcon). These - /// icons are scaled down when they are displayed in the System Tray or - /// System Control Area (SCA).
- /// - New customized icons (NIIF_USER with hBalloonIcon) must supply an - /// SM_CXICON x SM_CYICON version in the supplied icon (hBalloonIcon). - ///
- LargeIcon = 0x20, - - /// - /// Windows 7 and later. - /// - RespectQuietTime = 0x80 + [Flags] + public enum NIIF : uint + { + NONE = 0x00000000, + INFO = 0x00000001, + WARNING = 0x00000002, + ERROR = 0x00000003, + USER = 0x00000004, + ICON_MASK = 0x0000000F, + NOSOUND = 0x00000010, + LARGE_ICON = 0x00000020, + RESPECT_QUIET_TIME = 0x00000080 } [Flags] diff --git a/src/ST.Client.Desktop.Windows/Services/Implementation/PlatformNotificationServiceImpl.cs b/src/ST.Client.Desktop.Windows/Services/Implementation/PlatformNotificationServiceImpl.cs deleted file mode 100644 index 7aeeedc4e..000000000 --- a/src/ST.Client.Desktop.Windows/Services/Implementation/PlatformNotificationServiceImpl.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Properties; - -namespace System.Application.Services.Implementation -{ - /// - internal sealed class PlatformNotificationServiceImpl : INotificationService - { - readonly IDesktopPlatformService dps; - - public PlatformNotificationServiceImpl(IDesktopPlatformService dps) - { - this.dps = dps; - } - - public bool AreNotificationsEnabled() => true; - - public void Cancel(NotificationType notificationType) - { - } - - public void CancelAll() - { - } - - public void Notify(string text, NotificationType notificationType, bool autoCancel, string? title, Entrance entrance) - { - title ??= ThisAssembly.AssemblyTrademark; - // 调用托盘显示通知 - } - - public Progress NotifyDownload(string text, NotificationType notificationType, string? title) - { - // 桌面端不支持带进度的通知,下载新版本改用桌面端的窗口进度条控件,由更新服务桌面端版实现 - //title ??= ThisAssembly.AssemblyTrademark; - //throw new NotImplementedException(title); - throw new PlatformNotSupportedException(); - } - } -} \ No newline at end of file diff --git a/src/ST.Client.Desktop.Windows/UI/NotifyIcon.cs b/src/ST.Client.Desktop.Windows/UI/NotifyIcon.cs index b7b2d2c2a..dbe44392b 100644 --- a/src/ST.Client.Desktop.Windows/UI/NotifyIcon.cs +++ b/src/ST.Client.Desktop.Windows/UI/NotifyIcon.cs @@ -132,19 +132,21 @@ namespace System.Application.UI { _window = new NotifyIconWindow(this); } - } - ~NotifyIcon() - { iconData = new UnmanagedMethods.NOTIFYICONDATA() { hWnd = _window.Handle, uID = _uID, - uFlags = UnmanagedMethods.NIF.TIP | UnmanagedMethods.NIF.MESSAGE, + uFlags = NIF.TIP | NIF.MESSAGE, uCallbackMessage = (int)UnmanagedMethods.CustomWindowsMessage.WM_TRAYMOUSE, hIcon = IntPtr.Zero, - szTip = ToolTipText + uVersion = 2000, + szTip = ToolTipText, }; + } + + ~NotifyIcon() + { UpdateIcon(remove: true); } @@ -158,22 +160,22 @@ namespace System.Application.UI if (!remove && _icon != null && Visible) { - iconData.uFlags |= UnmanagedMethods.NIF.ICON; + iconData.uFlags |= NIF.ICON; iconData.hIcon = _icon.Handle; if (!_iconAdded) { - _ = UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.ADD,ref iconData); + _ = UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.ADD, iconData); _iconAdded = true; } else { - _ = UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.MODIFY,ref iconData); + _ = UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.MODIFY, iconData); } } else { - _ = UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.DELETE,ref iconData); + _ = UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.DELETE, iconData); _iconAdded = false; } } @@ -247,25 +249,68 @@ namespace System.Application.UI } } - public void ShowBalloonTip(string title, string message, BalloonFlags flags, IntPtr balloonIconHandle) + /// + /// Displays a balloon tip with the specified title, + /// text, and icon in the taskbar for the specified time period. + /// + /// The title to display on the balloon tip. + /// The text to display on the balloon tip. + public void ShowBalloonTip(string title, string message, NIIF flags) { - iconData = new UnmanagedMethods.NOTIFYICONDATA() + ShowBalloonTip(title, message, flags, IntPtr.Zero); + } + + /// + /// Displays a balloon tip with the specified title, + /// text, and icon in the taskbar for the specified time period. + /// + /// The title to display on the balloon tip. + /// The text to display on the balloon tip. + public void ShowBalloonTip(string title, string message) + { + ShowBalloonTip(title, message, NIIF.NONE, IntPtr.Zero); + } + + /// + /// Displays a balloon tip with the specified title, + /// text, and a custom icon in the taskbar for the specified time period. + /// + /// The title to display on the balloon tip. + /// The text to display on the balloon tip. + /// A custom icon. + /// True to allow large icons (Windows Vista and later). + /// If + /// is a null reference. + public void ShowBalloonTip(string title, string message, Icon customIcon, bool largeIcon = false) + { + if (customIcon == null) throw new ArgumentNullException(nameof(customIcon)); + var flags = NIIF.USER; + if (largeIcon) { - hWnd = _window.Handle, - uID = _uID, - uFlags = UnmanagedMethods.NIF.TIP | UnmanagedMethods.NIF.MESSAGE, - uCallbackMessage = (int)UnmanagedMethods.CustomWindowsMessage.WM_TRAYMOUSE, - hIcon = IntPtr.Zero, - szTip = ToolTipText - }; + // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags + flags |= NIIF.LARGE_ICON; + } + ShowBalloonTip(title, message, flags, customIcon.Handle); + } - iconData.BalloonText = message ?? string.Empty; - iconData.BalloonTitle = title ?? string.Empty; - - iconData.BalloonFlags = flags; + /// + /// Invokes in order to display + /// a given balloon ToolTip. + /// + /// The title to display on the balloon tip. + /// The text to display on the balloon tip. + /// Indicates what icon to use. + /// A handle to a custom icon, if any, or + /// . + public void ShowBalloonTip(string title, string message, NIIF flags, IntPtr balloonIconHandle) + { + iconData.szInfo = message ?? string.Empty; + iconData.szInfoTitle = title ?? string.Empty; + iconData.uFlags = NIF.INFO | NIF.ICON; iconData.CustomBalloonIconHandle = balloonIconHandle; + iconData.dwInfoFlags = flags; - UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.MODIFY,ref iconData); + var result = UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.MODIFY, iconData); } /// @@ -274,8 +319,8 @@ namespace System.Application.UI public void HideBalloonTip() { // reset balloon by just setting the info to an empty string - iconData.BalloonText = iconData.BalloonTitle = string.Empty; - UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.MODIFY, ref iconData); + iconData.szInfo = iconData.szInfoTitle = string.Empty; + UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.MODIFY, iconData); } /// diff --git a/src/ST.Client.Desktop/UI/INotifyIcon.cs b/src/ST.Client.Desktop/UI/INotifyIcon.cs index c036124c9..1fe08ce0c 100644 --- a/src/ST.Client.Desktop/UI/INotifyIcon.cs +++ b/src/ST.Client.Desktop/UI/INotifyIcon.cs @@ -53,11 +53,26 @@ namespace System.Application.UI /// event EventHandler RightClick; + public interface IUIFrameworkHelper { Stream OpenAsset(Uri uri); void ForEachMenuItems(TContextMenu menu, Action<(object menuItem, string header, Action activated)> action); } + + /// + /// Displays a balloon tip with the specified title, + /// text, and icon in the taskbar for the specified time period. + /// + /// The title to display on the balloon tip. + /// The text to display on the balloon tip. + /// A symbol that indicates the severity. + void ShowBalloonTip(string title, string message); + + /// + /// Hides a balloon ToolTip, if any is displayed. + /// + void HideBalloonTip(); } } \ No newline at end of file diff --git a/src/ST.Client.Desktop/UI/ViewModels/Pages/DebugPageViewModel.cs b/src/ST.Client.Desktop/UI/ViewModels/Pages/DebugPageViewModel.cs index 3b19131f2..9cbd0b527 100644 --- a/src/ST.Client.Desktop/UI/ViewModels/Pages/DebugPageViewModel.cs +++ b/src/ST.Client.Desktop/UI/ViewModels/Pages/DebugPageViewModel.cs @@ -277,8 +277,8 @@ namespace System.Application.UI.ViewModels // FileShareTest(); // } //#endif - - ShowDialogButton_Click1(); + INotificationService.Instance.Notify("测试Test🎆🎇→→", NotificationType.Announcement); + //ShowDialogButton_Click1(); } #if DEBUG From 1ba0c1f785e523873808b027cb95c95b4113e53f Mon Sep 17 00:00:00 2001 From: rmbgame Date: Thu, 5 Aug 2021 16:15:00 +0800 Subject: [PATCH 05/10] Fix --- .../Implementation/PlatformNotificationServiceImpl.cs | 8 ++++++++ .../Internals/UnmanagedMethods.cs | 3 +-- src/ST.Client.Desktop.Windows/UI/NotifyIcon.cs | 5 +++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/ST.Client.Desktop.Avalonia/Application/Services/Implementation/PlatformNotificationServiceImpl.cs b/src/ST.Client.Desktop.Avalonia/Application/Services/Implementation/PlatformNotificationServiceImpl.cs index 8cfa5e6a4..808ea8672 100644 --- a/src/ST.Client.Desktop.Avalonia/Application/Services/Implementation/PlatformNotificationServiceImpl.cs +++ b/src/ST.Client.Desktop.Avalonia/Application/Services/Implementation/PlatformNotificationServiceImpl.cs @@ -17,10 +17,18 @@ namespace System.Application.Services.Implementation public void Cancel(NotificationType notificationType) { + if (DI.Platform == Platform.Windows) + { + INotifyIcon.Instance.HideBalloonTip(); + } } public void CancelAll() { + if (DI.Platform == Platform.Windows) + { + INotifyIcon.Instance.HideBalloonTip(); + } } public void Notify(string text, NotificationType notificationType, bool autoCancel, string? title, Entrance entrance) diff --git a/src/ST.Client.Desktop.Windows/Internals/UnmanagedMethods.cs b/src/ST.Client.Desktop.Windows/Internals/UnmanagedMethods.cs index adfb4ac88..52cdba278 100644 --- a/src/ST.Client.Desktop.Windows/Internals/UnmanagedMethods.cs +++ b/src/ST.Client.Desktop.Windows/Internals/UnmanagedMethods.cs @@ -135,7 +135,6 @@ namespace System /// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string szInfo; - public int uVersion; public int uTimeoutOrVersion; /// /// String containing a title for a balloon ToolTip. This title appears in boldface @@ -152,7 +151,7 @@ namespace System /// flag is set, this icon is used as the balloon icon.
/// If this member is NULL, the legacy behavior is carried out. ///
- public IntPtr CustomBalloonIconHandle; + //public IntPtr CustomBalloonIconHandle; } public enum NIM : uint diff --git a/src/ST.Client.Desktop.Windows/UI/NotifyIcon.cs b/src/ST.Client.Desktop.Windows/UI/NotifyIcon.cs index dbe44392b..165c79437 100644 --- a/src/ST.Client.Desktop.Windows/UI/NotifyIcon.cs +++ b/src/ST.Client.Desktop.Windows/UI/NotifyIcon.cs @@ -140,7 +140,7 @@ namespace System.Application.UI uFlags = NIF.TIP | NIF.MESSAGE, uCallbackMessage = (int)UnmanagedMethods.CustomWindowsMessage.WM_TRAYMOUSE, hIcon = IntPtr.Zero, - uVersion = 2000, + uTimeoutOrVersion = 0, szTip = ToolTipText, }; } @@ -162,6 +162,7 @@ namespace System.Application.UI { iconData.uFlags |= NIF.ICON; iconData.hIcon = _icon.Handle; + iconData.szTip = ToolTipText; if (!_iconAdded) { @@ -307,7 +308,7 @@ namespace System.Application.UI iconData.szInfo = message ?? string.Empty; iconData.szInfoTitle = title ?? string.Empty; iconData.uFlags = NIF.INFO | NIF.ICON; - iconData.CustomBalloonIconHandle = balloonIconHandle; + //iconData.CustomBalloonIconHandle = balloonIconHandle; iconData.dwInfoFlags = flags; var result = UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM.MODIFY, iconData); From dab60bcd251b8cc1a48fce3240cb30eb50163d9c Mon Sep 17 00:00:00 2001 From: rmbgame Date: Thu, 5 Aug 2021 16:31:05 +0800 Subject: [PATCH 06/10] =?UTF-8?q?=E6=96=B0=E5=A2=9Esteam=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=97=B6=E9=80=9A=E7=9F=A5=E6=88=91=E8=AE=BE=E7=BD=AE=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Views/Pages/Settings/Settings_Steam.axaml | 99 ++++++++++--------- .../Models/Settings2/SteamSettings.cs | 4 +- .../Services/Mvvm/SteamConnectService.cs | 13 ++- .../UI/Resx/AppResources.Designer.cs | 54 ++++++++++ .../UI/Resx/AppResources.resx | 18 ++++ .../UI/ViewModels/Pages/DebugPageViewModel.cs | 2 +- 6 files changed, 138 insertions(+), 52 deletions(-) diff --git a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Pages/Settings/Settings_Steam.axaml b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Pages/Settings/Settings_Steam.axaml index 901cd20a1..27455246d 100644 --- a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Pages/Settings/Settings_Steam.axaml +++ b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Pages/Settings/Settings_Steam.axaml @@ -7,57 +7,62 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="System.Application.UI.Views.Pages.Settings_Steam"> - - - - - - - + + + + + + + - - - - + + + + - - - - + + + + - - - - + + + + - + + + + - - - - + - - - + + + + + + + + diff --git a/src/ST.Client.Desktop/Models/Settings2/SteamSettings.cs b/src/ST.Client.Desktop/Models/Settings2/SteamSettings.cs index 3110cbdd8..48d4efea8 100644 --- a/src/ST.Client.Desktop/Models/Settings2/SteamSettings.cs +++ b/src/ST.Client.Desktop/Models/Settings2/SteamSettings.cs @@ -57,9 +57,9 @@ namespace System.Application.Models.Settings = GetProperty(defaultValue: false, autoSave: true); /// - /// 检测到Steam启动时弹出消息通知 + /// 检测到Steam登录时弹出消息通知 /// public static SerializableProperty IsEnableSteamLaunchNotification { get; } - = GetProperty(defaultValue: false, autoSave: true); + = GetProperty(defaultValue: true, autoSave: true); } } \ No newline at end of file diff --git a/src/ST.Client.Desktop/Services/Mvvm/SteamConnectService.cs b/src/ST.Client.Desktop/Services/Mvvm/SteamConnectService.cs index 002475bcb..853c89168 100644 --- a/src/ST.Client.Desktop/Services/Mvvm/SteamConnectService.cs +++ b/src/ST.Client.Desktop/Services/Mvvm/SteamConnectService.cs @@ -199,9 +199,18 @@ namespace System.Application.Services IsSteamChinaLauncher = ApiService.IsSteamChinaLauncher(); #region 初始化需要steam启动才能使用的功能 - if (GameLibrarySettings.IsAutoAFKApps.Value) - RunAFKApps(); + if (SteamSettings.IsEnableSteamLaunchNotification.Value) + { + INotificationService.Instance.Notify($"{AppResources.Steam_CheckStarted}({(IsSteamChinaLauncher ? AppResources.Steam_SteamChina : AppResources.Steam_SteamWorld)}){Environment.NewLine}{Environment.NewLine}{AppResources.Steam_CurrentUser}{CurrentSteamUser.SteamNickName}{Environment.NewLine}{AppResources.Steam_CurrentIPCountry}{CurrentSteamUser.IPCountry}", NotificationType.Announcement); + } + + if (GameLibrarySettings.IsAutoAFKApps.Value) + { + RunAFKApps(); + } + + //仅在有游戏数据情况下加载登录用户的游戏 if (SteamApps.Items.Any()) { LoadGames(ApiService.OwnsApps(await ISteamService.Instance.GetAppInfos())); diff --git a/src/ST.Client.Desktop/UI/Resx/AppResources.Designer.cs b/src/ST.Client.Desktop/UI/Resx/AppResources.Designer.cs index ff594a63d..35858fc88 100644 --- a/src/ST.Client.Desktop/UI/Resx/AppResources.Designer.cs +++ b/src/ST.Client.Desktop/UI/Resx/AppResources.Designer.cs @@ -3222,6 +3222,15 @@ namespace System.Application.UI.Resx { } } + /// + /// 查找类似 当Steam客户端登录时通知我 的本地化字符串。 + /// + public static string Settings_Steam_CheckSteamRuningNotification { + get { + return ResourceManager.GetString("Settings_Steam_CheckSteamRuningNotification", resourceCulture); + } + } + /// /// 查找类似 Steam启动时不检查更新 的本地化字符串。 /// @@ -3339,6 +3348,33 @@ namespace System.Application.UI.Resx { } } + /// + /// 查找类似 检测到启动: 的本地化字符串。 + /// + public static string Steam_CheckStarted { + get { + return ResourceManager.GetString("Steam_CheckStarted", resourceCulture); + } + } + + /// + /// 查找类似 Steam客户端登录区域: 的本地化字符串。 + /// + public static string Steam_CurrentIPCountry { + get { + return ResourceManager.GetString("Steam_CurrentIPCountry", resourceCulture); + } + } + + /// + /// 查找类似 Steam登录用户: 的本地化字符串。 + /// + public static string Steam_CurrentUser { + get { + return ResourceManager.GetString("Steam_CurrentUser", resourceCulture); + } + } + /// /// 查找类似 输入图中验证码 的本地化字符串。 /// @@ -3357,6 +3393,24 @@ namespace System.Application.UI.Resx { } } + /// + /// 查找类似 Steam国服 的本地化字符串。 + /// + public static string Steam_SteamChina { + get { + return ResourceManager.GetString("Steam_SteamChina", resourceCulture); + } + } + + /// + /// 查找类似 Steam国际服 的本地化字符串。 + /// + public static string Steam_SteamWorld { + get { + return ResourceManager.GetString("Steam_SteamWorld", resourceCulture); + } + } + /// /// 查找类似 Steam用户名 的本地化字符串。 /// diff --git a/src/ST.Client.Desktop/UI/Resx/AppResources.resx b/src/ST.Client.Desktop/UI/Resx/AppResources.resx index 4d954454f..f1d6fe52c 100644 --- a/src/ST.Client.Desktop/UI/Resx/AppResources.resx +++ b/src/ST.Client.Desktop/UI/Resx/AppResources.resx @@ -1519,4 +1519,22 @@ 启用开机自启动失败,原因: {0} + + 当Steam客户端登录时通知我 + + + 检测到启动: + + + Steam客户端登录区域: + + + Steam登录用户: + + + Steam国服 + + + Steam国际服 + \ No newline at end of file diff --git a/src/ST.Client.Desktop/UI/ViewModels/Pages/DebugPageViewModel.cs b/src/ST.Client.Desktop/UI/ViewModels/Pages/DebugPageViewModel.cs index 9cbd0b527..9c2638489 100644 --- a/src/ST.Client.Desktop/UI/ViewModels/Pages/DebugPageViewModel.cs +++ b/src/ST.Client.Desktop/UI/ViewModels/Pages/DebugPageViewModel.cs @@ -278,7 +278,7 @@ namespace System.Application.UI.ViewModels // } //#endif INotificationService.Instance.Notify("测试Test🎆🎇→→", NotificationType.Announcement); - //ShowDialogButton_Click1(); + ShowDialogButton_Click1(); } #if DEBUG From edb2f8affb26e6bd3097c8a3668c6a5e2b573867 Mon Sep 17 00:00:00 2001 From: rmbgame Date: Thu, 5 Aug 2021 16:53:34 +0800 Subject: [PATCH 07/10] Fix --- src/ST.Client.Desktop/Services/Mvvm/SteamConnectService.cs | 2 +- src/ST.Client.Desktop/UI/Resx/AppResources.Designer.cs | 2 +- src/ST.Client.Desktop/UI/Resx/AppResources.resx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ST.Client.Desktop/Services/Mvvm/SteamConnectService.cs b/src/ST.Client.Desktop/Services/Mvvm/SteamConnectService.cs index 853c89168..5c478d0f5 100644 --- a/src/ST.Client.Desktop/Services/Mvvm/SteamConnectService.cs +++ b/src/ST.Client.Desktop/Services/Mvvm/SteamConnectService.cs @@ -201,7 +201,7 @@ namespace System.Application.Services #region 初始化需要steam启动才能使用的功能 if (SteamSettings.IsEnableSteamLaunchNotification.Value) { - INotificationService.Instance.Notify($"{AppResources.Steam_CheckStarted}({(IsSteamChinaLauncher ? AppResources.Steam_SteamChina : AppResources.Steam_SteamWorld)}){Environment.NewLine}{Environment.NewLine}{AppResources.Steam_CurrentUser}{CurrentSteamUser.SteamNickName}{Environment.NewLine}{AppResources.Steam_CurrentIPCountry}{CurrentSteamUser.IPCountry}", NotificationType.Announcement); + INotificationService.Instance.Notify($"{AppResources.Steam_CheckStarted}{(IsSteamChinaLauncher ? AppResources.Steam_SteamChina : AppResources.Steam_SteamWorld)}{Environment.NewLine}{AppResources.Steam_CurrentUser}{CurrentSteamUser.SteamNickName}{Environment.NewLine}{AppResources.Steam_CurrentIPCountry}{CurrentSteamUser.IPCountry}", NotificationType.Announcement); } diff --git a/src/ST.Client.Desktop/UI/Resx/AppResources.Designer.cs b/src/ST.Client.Desktop/UI/Resx/AppResources.Designer.cs index 35858fc88..d6da94ecd 100644 --- a/src/ST.Client.Desktop/UI/Resx/AppResources.Designer.cs +++ b/src/ST.Client.Desktop/UI/Resx/AppResources.Designer.cs @@ -3223,7 +3223,7 @@ namespace System.Application.UI.Resx { } /// - /// 查找类似 当Steam客户端登录时通知我 的本地化字符串。 + /// 查找类似 当Steam客户端登录时弹出通知 的本地化字符串。 /// public static string Settings_Steam_CheckSteamRuningNotification { get { diff --git a/src/ST.Client.Desktop/UI/Resx/AppResources.resx b/src/ST.Client.Desktop/UI/Resx/AppResources.resx index f1d6fe52c..30b9d2d6f 100644 --- a/src/ST.Client.Desktop/UI/Resx/AppResources.resx +++ b/src/ST.Client.Desktop/UI/Resx/AppResources.resx @@ -1520,7 +1520,7 @@ 启用开机自启动失败,原因: {0} - 当Steam客户端登录时通知我 + 当Steam客户端登录时弹出通知 检测到启动: From 1a6438eff6be34c9fd666e698bc02cfd4eb7083d Mon Sep 17 00:00:00 2001 From: Aigio Liu Date: Thu, 5 Aug 2021 18:21:41 +0800 Subject: [PATCH 08/10] Android Notification --- .../PlatformNotificationServiceImpl`2.cs | 21 +++++++-------- .../Services/INotificationService.cs | 2 +- .../Windows/LocalAuthPage/AddAuthWindow.axaml | 7 ++--- .../MobileAppUpdateServiceImpl.cs | 26 ++++++++++++++++++- .../UI/MainApplication.cs | 6 +++++ ...NotificationType_Channel_EnumExtensions.cs | 2 +- src/ST.Client/ST.Client.csproj | 14 +++++----- .../Implementation/AppUpdateServiceImpl.cs | 2 +- src/ST/NotificationType.cs | 4 +-- 9 files changed, 57 insertions(+), 27 deletions(-) rename src/ST.Client/{ => Extensions}/NotificationType_Channel_EnumExtensions.cs (98%) diff --git a/src/Common.ClientLib.Droid/Application/Services/Implementation/PlatformNotificationServiceImpl`2.cs b/src/Common.ClientLib.Droid/Application/Services/Implementation/PlatformNotificationServiceImpl`2.cs index 1a0715772..3470ab6e6 100644 --- a/src/Common.ClientLib.Droid/Application/Services/Implementation/PlatformNotificationServiceImpl`2.cs +++ b/src/Common.ClientLib.Droid/Application/Services/Implementation/PlatformNotificationServiceImpl`2.cs @@ -199,11 +199,9 @@ namespace System.Application.Services.Implementation TNotificationType notificationType, bool autoCancel, string? title, - TEntrance entrance) + TEntrance? entrance) { - var notificationEntrance = entrance != null ? - GetActivityType(entrance).GetJClass() : - R.activities.entrance; + var notificationEntrance = (entrance != null ? GetActivityType(entrance)?.GetJClass() : null) ?? R.activities.entrance; var context = AndroidApplication.Context; var manager = NotificationManagerCompat.From(context); var builder = BuildNotify(context, manager, text, notificationType, @@ -213,24 +211,25 @@ namespace System.Application.Services.Implementation } public Progress NotifyDownload( - string text, + Func text, TNotificationType notificationType, string? title) { var context = AndroidApplication.Context; var manager = NotificationManagerCompat.From(context); var builder = BuildNotify(context, manager, - text: text.Format(0), + text: text(), notificationType, title: title); // 进度单位说明 // 通用层采用 float 浮点数作为进度值,范围从0~100,保留两位小数 // 平台层采用 int 整型作为进度值,范围从0~10000,转换需要 乘 100 const int unit_convert_multiple = 100; // 从float到int转换单位倍数 - const int PROGRESS_MAX = 100 * unit_convert_multiple; // 进度条满值 + const float PROGRESS_MAX = IAppUpdateService.MaxProgressValue * unit_convert_multiple; // 进度条满值 + int PROGRESS_MAX_INT32 = PROGRESS_MAX.ToInt32(); // 发出零进度的初始通知 // Issue the initial notification with zero progress - builder.SetProgress(PROGRESS_MAX, 0, false); + builder.SetProgress(PROGRESS_MAX_INT32, 0, false); var notifyId = GetNotifyId(notificationType); manager.Notify(notifyId, builder.Build()); // 在这里完成跟踪进度的工作。 @@ -248,7 +247,7 @@ namespace System.Application.Services.Implementation void Handler(float current) { var currentInt32 = (current * unit_convert_multiple).ToInt32(); - if (currentInt32 >= PROGRESS_MAX) + if (currentInt32 >= PROGRESS_MAX_INT32) { // 这将使100%时直接取消通知,并不会在UI上显示 // 报告进度值满的操作应当是幂等的 @@ -266,8 +265,8 @@ namespace System.Application.Services.Implementation // 在报告进度值满后不可再更改进度 if (builder == null) throw new ArgumentNullException(nameof(builder)); if (manager == null) throw new ArgumentNullException(nameof(manager)); - builder.SetProgress(PROGRESS_MAX, currentInt32, false); - builder.SetContentText(text.Format(currentInt32)); + builder.SetProgress(PROGRESS_MAX_INT32, currentInt32, false); + builder.SetContentText(text()); manager.Notify(notifyId, builder.Build()); } } diff --git a/src/Common.ClientLib/Application/Services/INotificationService.cs b/src/Common.ClientLib/Application/Services/INotificationService.cs index 82685e1c9..fd7bd569c 100644 --- a/src/Common.ClientLib/Application/Services/INotificationService.cs +++ b/src/Common.ClientLib/Application/Services/INotificationService.cs @@ -45,7 +45,7 @@ namespace System.Application.Services /// 下载进度通知 /// Progress NotifyDownload( - string text, + Func text, TNotificationType notificationType, string? title = default); } diff --git a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/LocalAuthPage/AddAuthWindow.axaml b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/LocalAuthPage/AddAuthWindow.axaml index 7c9b4889b..d22a128b8 100644 --- a/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/LocalAuthPage/AddAuthWindow.axaml +++ b/src/ST.Client.Desktop.Avalonia/Application/UI/Views/Windows/LocalAuthPage/AddAuthWindow.axaml @@ -2,7 +2,10 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" + mc:Ignorable="d" + d:DesignWidth="720" d:DesignHeight="400" + MinWidth="720" MinHeight="400" + Width="720" Height="400" x:Class="System.Application.UI.Views.Windows.AddAuthWindow" xmlns:resx="clr-namespace:System.Application.UI.Resx;assembly=System.Application.SteamTools.Client.Desktop" xmlns:vm="clr-namespace:System.Application.UI.ViewModels;assembly=System.Application.SteamTools.Client.Desktop" @@ -10,8 +13,6 @@ xmlns:controls="clr-namespace:System.Application.UI.Views.Controls" xmlns:ms="clr-namespace:System.Application.Models.Settings;assembly=System.Application.SteamTools.Client.Desktop" FontFamily="{Binding Source={x:Static ms:UISettings.FontName},Path=Value, Mode=OneWay,Converter={StaticResource NameToFontFamilyConverter}}" - MinWidth="600" - MinHeight="400" WindowStartupLocation="CenterOwner" ExtendClientAreaTitleBarHeightHint="30" Background="Transparent" diff --git a/src/ST.Client.Mobile.Droid/Services/Implementation/MobileAppUpdateServiceImpl.cs b/src/ST.Client.Mobile.Droid/Services/Implementation/MobileAppUpdateServiceImpl.cs index 13a6d1a96..c2c35d600 100644 --- a/src/ST.Client.Mobile.Droid/Services/Implementation/MobileAppUpdateServiceImpl.cs +++ b/src/ST.Client.Mobile.Droid/Services/Implementation/MobileAppUpdateServiceImpl.cs @@ -6,13 +6,16 @@ using System.Application.Models; using System.Windows; using XEPlatform = Xamarin.Essentials.Platform; using static System.Application.UI.Resx.AppResources; +using static System.Application.Services.IAppUpdateService; namespace System.Application.Services.Implementation { internal sealed partial class MobileAppUpdateServiceImpl : AppUpdateServiceImpl { - public MobileAppUpdateServiceImpl(IToast toast, ICloudServiceClient client, IOptions options) : base(toast, client, options) + readonly INotificationService notification; + public MobileAppUpdateServiceImpl(INotificationService notification, IToast toast, ICloudServiceClient client, IOptions options) : base(toast, client, options) { + this.notification = notification; } protected override Version OSVersion => @@ -46,5 +49,26 @@ namespace System.Application.Services.Implementation throw new NotImplementedException(); #endif } + + IProgress? progress; + protected override void OnReport(float value, string str) + { + base.OnReport(value, str); + if (value == 0) + { + progress?.Report(MaxProgressValue); + progress = notification.NotifyDownload(() => ProgressString, + NotificationType.NewVersionDownloadProgress); + } + else if (value == MaxProgressValue) + { + progress?.Report(MaxProgressValue); + progress = null; + } + else + { + progress?.Report(value); + } + } } } \ No newline at end of file diff --git a/src/ST.Client.Mobile.Droid/UI/MainApplication.cs b/src/ST.Client.Mobile.Droid/UI/MainApplication.cs index 94002927d..dee91908a 100644 --- a/src/ST.Client.Mobile.Droid/UI/MainApplication.cs +++ b/src/ST.Client.Mobile.Droid/UI/MainApplication.cs @@ -13,6 +13,8 @@ using XEPlatform = Xamarin.Essentials.Platform; using XEVersionTracking = Xamarin.Essentials.VersionTracking; using System.Application.Models.Settings; using AndroidX.AppCompat.App; +using System.Application.Services; +using System.Application.Services.Implementation; #if DEBUG using Square.LeakCanary; #endif @@ -79,6 +81,10 @@ namespace System.Application.UI Startup.Init(level); if (IsMainProcess) { + if (INotificationService.Instance is PlatformNotificationServiceImpl notification) + { + notification.InitNotificationChannels(this); + } XEVersionTracking.Track(); ImageLoader.Init(this); UISettings.Theme.Subscribe(x => diff --git a/src/ST.Client/NotificationType_Channel_EnumExtensions.cs b/src/ST.Client/Extensions/NotificationType_Channel_EnumExtensions.cs similarity index 98% rename from src/ST.Client/NotificationType_Channel_EnumExtensions.cs rename to src/ST.Client/Extensions/NotificationType_Channel_EnumExtensions.cs index 183a37041..cf3fa2e5a 100644 --- a/src/ST.Client/NotificationType_Channel_EnumExtensions.cs +++ b/src/ST.Client/Extensions/NotificationType_Channel_EnumExtensions.cs @@ -1,4 +1,4 @@ -using System.Application.Properties; +using System.Application.Properties; using System.Application.Services; namespace System.Application diff --git a/src/ST.Client/ST.Client.csproj b/src/ST.Client/ST.Client.csproj index bb5015afd..aadc6b3c0 100644 --- a/src/ST.Client/ST.Client.csproj +++ b/src/ST.Client/ST.Client.csproj @@ -23,16 +23,16 @@ - + - - - - - - + + + + + + diff --git a/src/ST.Client/Services/Implementation/AppUpdateServiceImpl.cs b/src/ST.Client/Services/Implementation/AppUpdateServiceImpl.cs index 90cc4d734..8c54a0862 100644 --- a/src/ST.Client/Services/Implementation/AppUpdateServiceImpl.cs +++ b/src/ST.Client/Services/Implementation/AppUpdateServiceImpl.cs @@ -211,7 +211,7 @@ namespace System.Application.Services.Implementation protected void OnReportCalcHashing(float value) => OnReport(value, SR.CalcHashing_.Format(MathF.Round(value, 2))); protected void OnReportDecompressing(float value) => OnReport(value, SR.Decompressing_.Format(MathF.Round(value, 2))); protected void OnReport(float value = 0f) => OnReport(value, string.Empty); - protected void OnReport(float value, string str) + protected virtual void OnReport(float value, string str) { ProgressValue = value; ProgressString = str; diff --git a/src/ST/NotificationType.cs b/src/ST/NotificationType.cs index c14e2f7b5..f21995962 100644 --- a/src/ST/NotificationType.cs +++ b/src/ST/NotificationType.cs @@ -1,4 +1,4 @@ -namespace System.Application +namespace System.Application { /// /// 通知类型 @@ -17,7 +17,7 @@ /// /// /// 添加新的枚举常量注意事项: - /// (客户端)如果要显示在设备的通知栏上,则需要在中添加对应渠道 + /// (客户端)如果要显示在设备的通知栏上,则需要在 src\ST.Client\Extensions\NotificationType_Channel_EnumExtensions.cs 中添加或指定已有渠道 /// public enum NotificationType { From 0546522eb58e5f491389b40770356a802958c474 Mon Sep 17 00:00:00 2001 From: Aigio Liu Date: Thu, 5 Aug 2021 18:35:13 +0800 Subject: [PATCH 09/10] ClearAllPackCacheDir --- src/Common.CoreLib/FileEx.cs | 2 + .../UI/MainApplication.cs | 5 ++ src/ST.Client/Services/IAppUpdateService.cs | 68 +++++++++++++++++++ .../Implementation/AppUpdateServiceImpl.cs | 41 +---------- .../ScriptManagerServiceImpl.cs | 4 +- 5 files changed, 79 insertions(+), 41 deletions(-) diff --git a/src/Common.CoreLib/FileEx.cs b/src/Common.CoreLib/FileEx.cs index 10b8006a1..94af590e3 100644 --- a/src/Common.CoreLib/FileEx.cs +++ b/src/Common.CoreLib/FileEx.cs @@ -75,6 +75,8 @@ namespace System public const string MPO = ".mpo"; + public const string DownloadCache = ".download_cache"; + public static string Clean(string extension, bool trimLeadingPeriod = false) { if (string.IsNullOrWhiteSpace(extension)) diff --git a/src/ST.Client.Mobile.Droid/UI/MainApplication.cs b/src/ST.Client.Mobile.Droid/UI/MainApplication.cs index dee91908a..2139c4e6e 100644 --- a/src/ST.Client.Mobile.Droid/UI/MainApplication.cs +++ b/src/ST.Client.Mobile.Droid/UI/MainApplication.cs @@ -86,6 +86,11 @@ namespace System.Application.UI notification.InitNotificationChannels(this); } XEVersionTracking.Track(); + if (XEVersionTracking.IsFirstLaunchForCurrentVersion) + { + // 当前版本第一次启动时,清除存放升级包缓存文件夹的目录 + IAppUpdateService.ClearAllPackCacheDir(); + } ImageLoader.Init(this); UISettings.Theme.Subscribe(x => { diff --git a/src/ST.Client/Services/IAppUpdateService.cs b/src/ST.Client/Services/IAppUpdateService.cs index c8cc153b3..6ade60ff7 100644 --- a/src/ST.Client/Services/IAppUpdateService.cs +++ b/src/ST.Client/Services/IAppUpdateService.cs @@ -1,4 +1,6 @@ using System.Application.Models; +using System.IO; +using System.Security.Cryptography; using System.Threading.Tasks; using System.Windows.Input; @@ -13,6 +15,11 @@ namespace System.Application.Services const float MaxProgressValue = 100f; + /// + /// 升级包存放文件夹名称 + /// + const string PackDirName = "UpgradePackages"; + /// /// 进度值 /// @@ -57,6 +64,67 @@ namespace System.Application.Services Task CheckUpdateAsync(bool force = false, bool showIsExistUpdateFalse = true); ICommand StartUpdateCommand { get; } + + /// + /// 根据新版本信息获取升级包路径名 + /// + /// + /// + protected static string GetPackName(AppVersionDTO m, bool isDirOrFile) => $"{m.Version}@{Hashs.String.Crc32(m.Id.ToByteArray())}{(isDirOrFile ? "" : $"{FileEx.TAR_GZ}")}"; + + /// + /// 获取存放升级包缓存文件夹的目录 + /// + /// 当目录不存在时是否创建目录 + /// 目录是否存在 + /// + protected static string GetPackCacheDirPath(bool onNotExistsCreateDirectory, out bool exists) + { + var dirPath = Path.Combine(IOPath.CacheDirectory, PackDirName); + exists = Directory.Exists(dirPath); + if (!exists && onNotExistsCreateDirectory) + { + Directory.CreateDirectory(dirPath); + + } + return dirPath; + } + + /// + /// 获取存放升级包缓存文件夹的目录 + /// + /// 是否需要清理之前的缓存 + /// + protected static string GetPackCacheDirPath(bool clear) + { + var dirPath = GetPackCacheDirPath(true, out var exists); + if (exists && clear) + { + var files = Directory.GetFiles(dirPath, "*" + FileEx.DownloadCache); + foreach (var item in files) + { + IOPath.FileTryDelete(item); + } + } + return dirPath; + } + + /// + /// 清理存放升级包缓存文件夹的目录 + /// + /// + static void ClearAllPackCacheDir() + { + var dirPath = GetPackCacheDirPath(true, out var exists); + if (exists) + { + var files = Directory.GetFiles(dirPath); + foreach (var item in files) + { + IOPath.FileTryDelete(item); + } + } + } } #if DEBUG diff --git a/src/ST.Client/Services/Implementation/AppUpdateServiceImpl.cs b/src/ST.Client/Services/Implementation/AppUpdateServiceImpl.cs index 8c54a0862..d1d407683 100644 --- a/src/ST.Client/Services/Implementation/AppUpdateServiceImpl.cs +++ b/src/ST.Client/Services/Implementation/AppUpdateServiceImpl.cs @@ -147,43 +147,6 @@ namespace System.Application.Services.Implementation isCheckUpdateing = false; } - /// - /// 升级包存放文件夹名称 - /// - const string PackDirName = "UpgradePackages"; - - public const string FileExDownloadCache = ".download_cache"; - - /// - /// 根据新版本信息获取升级包路径名 - /// - /// - /// - static string GetPackName(AppVersionDTO m, bool isDirOrFile) => $"{m.Version}@{Hashs.String.Crc32(m.Id.ToByteArray())}{(isDirOrFile ? "" : $"{FileEx.TAR_GZ}")}"; - - /// - /// 获取存放升级包缓存文件夹的目录 - /// - /// 是否需要清理之前的缓存 - /// - static string GetPackCacheDirPath(bool clear) - { - var dirPath = Path.Combine(IOPath.CacheDirectory, PackDirName); - if (!Directory.Exists(dirPath)) - { - Directory.CreateDirectory(dirPath); - } - else if (clear) - { - var files = Directory.GetFiles(dirPath, "*" + FileExDownloadCache); - foreach (var item in files) - { - IOPath.FileTryDelete(item); - } - } - return dirPath; - } - static bool isDownloading; /// @@ -362,7 +325,7 @@ namespace System.Application.Services.Implementation #endregion #region 下载文件,并加入 hashFiles 中 - var cacheFileDownloadPath = downloadPath + FileExDownloadCache; + var cacheFileDownloadPath = downloadPath + FileEx.DownloadCache; var requestUri = GetSingleFileUrl(item.FileId!); var rsp = await client.Download( @@ -505,7 +468,7 @@ namespace System.Application.Services.Implementation requestUri = GetSingleFileUrl(download.FileIdOrUrl!); } - var cacheFilePath = packFilePath + FileExDownloadCache; + var cacheFilePath = packFilePath + FileEx.DownloadCache; OnReportDownloading(0f); var rsp = await client.Download( isAnonymous: true, diff --git a/src/ST.Client/Services/Implementation/ScriptManagerServiceImpl.cs b/src/ST.Client/Services/Implementation/ScriptManagerServiceImpl.cs index 6bdd13aa7..73ac5c99a 100644 --- a/src/ST.Client/Services/Implementation/ScriptManagerServiceImpl.cs +++ b/src/ST.Client/Services/Implementation/ScriptManagerServiceImpl.cs @@ -362,7 +362,7 @@ namespace System.Application.Services.Implementation var jspath = await DI.Get().DownloadScript(basicsInfo.Content.UpdateLink); if (jspath.state) { - var build = await DI.Get().AddScriptAsync(jspath.path,item, build: false, order: 1, deleteFile: true, pid: basicsInfo.Content.Id, ignoreCache: true); + var build = await DI.Get().AddScriptAsync(jspath.path, item, build: false, order: 1, deleteFile: true, pid: basicsInfo.Content.Id, ignoreCache: true); if (build.state && build.model?.Content != null) item.Content = build.model!.Content; } @@ -394,7 +394,7 @@ namespace System.Application.Services.Implementation try { var md5 = Hashs.String.MD5(scriptInfo); - var cachePath = Path.Combine(IOPath.CacheDirectory, TAG, $"{md5}{AppUpdateServiceImpl.FileExDownloadCache}"); + var cachePath = Path.Combine(IOPath.CacheDirectory, TAG, md5 + FileEx.DownloadCache); var fileInfo = new FileInfo(cachePath); if (!fileInfo.Directory.Exists) { From ca90312476fc29b5a0d16ce2ef27a42757249e2b Mon Sep 17 00:00:00 2001 From: Aigio Liu Date: Thu, 5 Aug 2021 18:45:22 +0800 Subject: [PATCH 10/10] fix --- .../Services/Implementation/PlatformNotificationServiceImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ST.Client.Desktop.Avalonia/Application/Services/Implementation/PlatformNotificationServiceImpl.cs b/src/ST.Client.Desktop.Avalonia/Application/Services/Implementation/PlatformNotificationServiceImpl.cs index 808ea8672..5e3019f96 100644 --- a/src/ST.Client.Desktop.Avalonia/Application/Services/Implementation/PlatformNotificationServiceImpl.cs +++ b/src/ST.Client.Desktop.Avalonia/Application/Services/Implementation/PlatformNotificationServiceImpl.cs @@ -42,7 +42,7 @@ namespace System.Application.Services.Implementation } } - public Progress NotifyDownload(string text, NotificationType notificationType, string? title) + public Progress NotifyDownload(Func text, NotificationType notificationType, string? title) { // 桌面端不支持带进度的通知,下载新版本改用桌面端的窗口进度条控件,由更新服务桌面端版实现 //title ??= ThisAssembly.AssemblyTrademark;