├── i18n ├── Languages.zh-TW.Designer.cs └── languages_list.json ├── docs ├── ok.png ├── dark.jpg └── IDE.svg ├── Melon-Studio.cer ├── Resources ├── ok.png ├── Image1.png ├── logo-new.ico ├── we(dark).png ├── MouseDark.png ├── MouseLight.png ├── we(light).png ├── Fonts │ └── icons.ttf ├── office(dark).png ├── office(light).png └── we(light).svg ├── ViewModels ├── SettingsViewModel.cs ├── MainWindowViewModel.cs ├── DownloadWindowViewModel.cs ├── SetDIYViewModel.cs ├── SetMoreViewModel.cs ├── SetAboutViewModel.cs ├── SetWallpaperViewModel.cs ├── DeveloperModeViewModel.cs ├── SetSettingViewModel.cs ├── SetTimesViewModel.cs └── ColorsViewModel.cs ├── Models ├── AppConfig.cs ├── StartUrl.cs ├── icon.cs ├── DarkModeException.cs ├── VersionControl.cs ├── Colors │ └── Pa__one.cs ├── ReplaceWallpaper.cs ├── ToastHelper.cs ├── LanguageSettings.cs ├── MessageBox.cs ├── DetermineSystemColorMode.cs ├── AutoStartManager.cs ├── RedRawWindow.cs ├── WallpaperChanger.cs ├── JsonSerialization.cs ├── Interface │ └── IUpdate.cs ├── WindowsVersionHelper.cs ├── LanguageHandler.cs ├── SystemHotKey.cs ├── DownloadManager.cs ├── LocationService.cs ├── RegistryInit.cs ├── Update.cs └── NewVersion.cs ├── Services ├── Contracts │ └── ITestWindowService.cs ├── MessageQueue │ └── QueueService.cs ├── PageService.cs ├── TestWindowService.cs └── ApplicationHostService.cs ├── .github └── dependabot.yml ├── App.xaml ├── Views ├── Pages │ ├── Colors.xaml.cs │ ├── SetMore.xaml.cs │ ├── SetAbout.xaml.cs │ ├── SetDIY.xaml.cs │ ├── SetMore.xaml │ ├── Colors.xaml │ ├── SetDIY.xaml │ ├── SetWallpaper.xaml.cs │ └── SetSetting.xaml ├── Diagnostics │ ├── DebuggingLayerView.xaml │ └── DebuggingLayerView.xaml.cs ├── MainWindow.xaml ├── DownloadWindow.xaml ├── DeveloperModeWindow.xaml.cs ├── DeveloperModeWindow.xaml ├── DownloadWindow.xaml.cs ├── SettingsWindow.xaml.cs └── SettingsWindow.xaml ├── .circleci └── config.yml ├── Properties ├── AssemblyInfo.cs └── app.manifest ├── .gitattributes ├── PRIVACY ├── App.config ├── DarkMode_2.sln ├── App.xaml.cs ├── README.md ├── .gitignore └── README_EN.md /i18n/Languages.zh-TW.Designer.cs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunova-Studio/DarkMode2/HEAD/docs/ok.png -------------------------------------------------------------------------------- /docs/dark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunova-Studio/DarkMode2/HEAD/docs/dark.jpg -------------------------------------------------------------------------------- /Melon-Studio.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunova-Studio/DarkMode2/HEAD/Melon-Studio.cer -------------------------------------------------------------------------------- /Resources/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunova-Studio/DarkMode2/HEAD/Resources/ok.png -------------------------------------------------------------------------------- /Resources/Image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunova-Studio/DarkMode2/HEAD/Resources/Image1.png -------------------------------------------------------------------------------- /Resources/logo-new.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunova-Studio/DarkMode2/HEAD/Resources/logo-new.ico -------------------------------------------------------------------------------- /Resources/we(dark).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunova-Studio/DarkMode2/HEAD/Resources/we(dark).png -------------------------------------------------------------------------------- /Resources/MouseDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunova-Studio/DarkMode2/HEAD/Resources/MouseDark.png -------------------------------------------------------------------------------- /Resources/MouseLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunova-Studio/DarkMode2/HEAD/Resources/MouseLight.png -------------------------------------------------------------------------------- /Resources/we(light).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunova-Studio/DarkMode2/HEAD/Resources/we(light).png -------------------------------------------------------------------------------- /Resources/Fonts/icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunova-Studio/DarkMode2/HEAD/Resources/Fonts/icons.ttf -------------------------------------------------------------------------------- /Resources/office(dark).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunova-Studio/DarkMode2/HEAD/Resources/office(dark).png -------------------------------------------------------------------------------- /Resources/office(light).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lunova-Studio/DarkMode2/HEAD/Resources/office(light).png -------------------------------------------------------------------------------- /ViewModels/SettingsViewModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Toolkit.Mvvm.ComponentModel; 2 | 3 | namespace DarkMode_2.ViewModels; 4 | 5 | public class SettingsViewModel : ObservableObject 6 | { 7 | } -------------------------------------------------------------------------------- /ViewModels/MainWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Toolkit.Mvvm.ComponentModel; 2 | 3 | namespace DarkMode_2.ViewModels; 4 | 5 | public class MainWindowViewModel : ObservableObject 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /Models/AppConfig.cs: -------------------------------------------------------------------------------- 1 | namespace DarkMode_2.Models; 2 | 3 | public class AppConfig 4 | { 5 | public string ConfigurationsFolder { get; set; } 6 | 7 | public string AppPropertiesFileName { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Models/StartUrl.cs: -------------------------------------------------------------------------------- 1 | namespace DarkMode_2.Models; 2 | 3 | public class StartUrl 4 | { 5 | public static void StartUrlLink(string url) 6 | { 7 | System.Diagnostics.Process.Start(url); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ViewModels/DownloadWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Toolkit.Mvvm.ComponentModel; 2 | 3 | namespace DarkMode_2.ViewModels 4 | { 5 | public class DownloadWindowViewModel : ObservableObject 6 | { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Models/icon.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DarkMode_2.Models 8 | { 9 | internal class icon 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ViewModels/SetDIYViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DarkMode_2.ViewModels; 8 | 9 | internal class SetDIYViewModel 10 | { 11 | } 12 | -------------------------------------------------------------------------------- /ViewModels/SetMoreViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DarkMode_2.ViewModels; 8 | 9 | internal class SetMoreViewModel 10 | { 11 | } 12 | -------------------------------------------------------------------------------- /ViewModels/SetAboutViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DarkMode_2.ViewModels; 8 | 9 | internal class SetAboutViewModel 10 | { 11 | } 12 | -------------------------------------------------------------------------------- /ViewModels/SetWallpaperViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DarkMode_2.ViewModels; 8 | 9 | internal class SetWallpaperViewModel 10 | { 11 | } 12 | -------------------------------------------------------------------------------- /Models/DarkModeException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DarkMode_2.Models; 4 | 5 | public static class DarkModeException 6 | { 7 | public class PositionTimeoutException : Exception 8 | { 9 | public PositionTimeoutException(string message) : base(message) { } 10 | } 11 | 12 | } 13 | 14 | -------------------------------------------------------------------------------- /ViewModels/DeveloperModeViewModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Toolkit.Mvvm.ComponentModel; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DarkMode_2.ViewModels; 9 | 10 | public class DeveloperModeViewModel : ObservableObject 11 | { 12 | } 13 | -------------------------------------------------------------------------------- /Models/VersionControl.cs: -------------------------------------------------------------------------------- 1 | namespace DarkMode_2.Models; 2 | 3 | public class VersionControl 4 | { 5 | public static string Channel() 6 | { 7 | string channel = "Release"; 8 | return channel; 9 | } 10 | public static string Version() 11 | { 12 | string version = "2.1.4"; 13 | return version; 14 | } 15 | public static string InternalVersion() 16 | { 17 | string internalVersion = "20240918"; 18 | return internalVersion; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Services/Contracts/ITestWindowService.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | using System; 7 | 8 | namespace DarkMOde_2.Services.Contracts; 9 | 10 | public interface ITestWindowService 11 | { 12 | public void Show(Type windowType); 13 | 14 | public T Show() where T : class; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "nuget" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /Models/Colors/Pa__one.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | using System.Windows.Media; 7 | 8 | namespace DarkMode_2.Models.Colors; 9 | 10 | public struct Pa__one 11 | { 12 | public string Title { get; set; } 13 | public string Subtitle { get; set; } 14 | public Brush Brush { get; set; } 15 | public string BrushKey { get; set; } 16 | } 17 | -------------------------------------------------------------------------------- /App.xaml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Models/ReplaceWallpaper.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace DarkMode_2.Models; 5 | 6 | public class ReplaceWallpaper 7 | { 8 | [DllImport("user32.dll", EntryPoint = "SystemParametersInfo")] 9 | public static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni); 10 | public static bool ChangeNativeWallpaper(string FilePath) 11 | { 12 | bool result = false; 13 | if(File.Exists(FilePath)) 14 | { 15 | string filePath = Path.GetFullPath(FilePath); 16 | SystemParametersInfo(20, 1, FilePath, 0x1 | 0x2); 17 | result = true; 18 | } 19 | 20 | return result; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Views/Pages/Colors.xaml.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | using Wpf.Ui.Common.Interfaces; 7 | using DarkMode_2.ViewModels; 8 | 9 | namespace DarkMode_2.Views.Pages; 10 | 11 | /// 12 | /// Interaction logic for Colors.xaml 13 | /// 14 | public partial class Colors : INavigableView 15 | { 16 | public ColorsViewModel ViewModel 17 | { 18 | get; 19 | } 20 | 21 | public Colors(ColorsViewModel viewModel) 22 | { 23 | ViewModel = viewModel; 24 | 25 | InitializeComponent(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Models/ToastHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Toolkit.Uwp.Notifications; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DarkMode_2.Models; 9 | 10 | public class ToastHelper 11 | { 12 | public static void ShowToast(string title, string message) 13 | { 14 | try 15 | { 16 | new ToastContentBuilder() 17 | .AddArgument("conversationId", 98135474) 18 | .AddText(LanguageHandler.GetLocalizedString(title)) 19 | .AddText(LanguageHandler.GetLocalizedString(message)) 20 | .Show(toast => 21 | { 22 | toast.ExpirationTime = DateTime.Now.AddDays(1); 23 | }); 24 | }catch (Exception ex) 25 | { 26 | MessageBox.OpenMessageBox(LanguageHandler.GetLocalizedString("ToastHelper_Error_title"), ex.ToString()); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ViewModels/SetSettingViewModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Toolkit.Mvvm.ComponentModel; 2 | using System.Collections.Generic; 3 | 4 | namespace DarkMode_2.ViewModels; 5 | 6 | public class SetSettingViewModel : ObservableObject 7 | { 8 | private bool _dataInitialized = false; 9 | 10 | private IEnumerable _comboCollection = new string[] { }; 11 | 12 | public IEnumerable ComboCollection 13 | { 14 | get => _comboCollection; 15 | set => SetProperty(ref _comboCollection, value); 16 | } 17 | 18 | public void OnNavigatedTo() 19 | { 20 | if (!_dataInitialized) 21 | InitializeData(); 22 | } 23 | private void InitializeData() 24 | { 25 | ComboCollection = new[] 26 | { 27 | "简体中文(zh-CN)", 28 | "繁体中文(zh-TW)", 29 | "日本語(ja-JP)", 30 | "Русский(ru-RU)", 31 | "English(en-EN)" 32 | }; 33 | _dataInitialized = true; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Use the latest 2.1 version of CircleCI pipeline process engine. 2 | # See: https://circleci.com/docs/configuration-reference 3 | version: 2.1 4 | 5 | # Define a job to be invoked later in a workflow. 6 | # See: https://circleci.com/docs/configuration-reference/#jobs 7 | jobs: 8 | say-hello: 9 | # Specify the execution environment. You can specify an image from Docker Hub or use one of our convenience images from CircleCI's Developer Hub. 10 | # See: https://circleci.com/docs/configuration-reference/#executor-job 11 | docker: 12 | - image: cimg/base:stable 13 | # Add steps to the job 14 | # See: https://circleci.com/docs/configuration-reference/#steps 15 | steps: 16 | - checkout 17 | - run: 18 | name: "Say hello" 19 | command: "echo Hello, World!" 20 | 21 | # Orchestrate jobs using workflows 22 | # See: https://circleci.com/docs/configuration-reference/#workflows 23 | workflows: 24 | say-hello-workflow: 25 | jobs: 26 | - say-hello 27 | -------------------------------------------------------------------------------- /Models/LanguageSettings.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DarkMode_2.Models 4 | { 5 | public class LanguageSettings 6 | { 7 | public List Languages { get; set; } 8 | 9 | public string GetLanguageCodeByName(string name) 10 | { 11 | foreach (var language in Languages) 12 | { 13 | if (language.Name == name) 14 | { 15 | return language.Code; 16 | } 17 | } 18 | return null; 19 | } 20 | 21 | public string GetLanguageNameByCode(string code) 22 | { 23 | foreach (var language in Languages) 24 | { 25 | if (language.Code == code) 26 | { 27 | return language.Name; 28 | } 29 | } 30 | return null; 31 | } 32 | } 33 | 34 | public class LanguageInfo 35 | { 36 | public string Name { get; set; } 37 | public string Code { get; set; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Models/MessageBox.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace DarkMode_2.Models; 4 | 5 | public class MessageBox 6 | { 7 | 8 | private static string Content; 9 | public static void OpenMessageBox(string title, string content) 10 | { 11 | Content = content; 12 | var messageBox = new Wpf.Ui.Controls.MessageBox 13 | { 14 | ButtonRightName = "关闭", 15 | 16 | ButtonLeftName = "确定" 17 | }; 18 | 19 | messageBox.ButtonRightClick += MessageBox_RightButtonClick; 20 | 21 | messageBox.ButtonLeftClick += MessageBox_LeftButtonClick; 22 | 23 | messageBox.ButtonLeftName = "复制"; 24 | messageBox.ButtonRightName = "关闭"; 25 | 26 | messageBox.Show(title, content); 27 | } 28 | 29 | private static void MessageBox_RightButtonClick(object sender, System.Windows.RoutedEventArgs e) 30 | { 31 | (sender as Wpf.Ui.Controls.MessageBox)?.Close(); 32 | Clipboard.SetText(Content); 33 | } 34 | private static void MessageBox_LeftButtonClick(object sender, System.Windows.RoutedEventArgs e) 35 | { 36 | (sender as Wpf.Ui.Controls.MessageBox)?.Close(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Models/DetermineSystemColorMode.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | 3 | namespace DarkMode_2.Models; 4 | 5 | public class DetermineSystemColorMode 6 | { 7 | //获取系统用户APP主题色 8 | public static string GetState() 9 | { 10 | string state = null; 11 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", false); 12 | if (key.GetValue("AppsUseLightTheme").ToString() == "1") 13 | { 14 | state = "light"; 15 | } 16 | else 17 | { 18 | state = "dark"; 19 | } 20 | key.Close(); 21 | return state; 22 | } 23 | 24 | //获取系统用户主题色 25 | public static string GetSysState() 26 | { 27 | string state = null; 28 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", false); 29 | if (key.GetValue("SystemUsesLightTheme").ToString() == "1") 30 | { 31 | state = "light"; 32 | } 33 | else 34 | { 35 | state = "dark"; 36 | } 37 | key.Close(); 38 | return state; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Services/MessageQueue/QueueService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Threading; 3 | using System; 4 | using System.Threading.Tasks; 5 | using System.Windows; 6 | 7 | namespace DarkMode_2.Services.MessageQueue; 8 | 9 | public class QueueService 10 | { 11 | private static BlockingCollection messageQueue = new BlockingCollection(); 12 | private static ManualResetEventSlim signal = new ManualResetEventSlim(false); 13 | public QueueService() 14 | { 15 | InitQueueService(); 16 | } 17 | public void InitQueueService() 18 | { 19 | Task.Run(() => PreProcessMessage()); 20 | } 21 | 22 | public void AddMessage(Action action) 23 | { 24 | messageQueue.Add(action); 25 | } 26 | 27 | void PreProcessMessage() 28 | { 29 | foreach (var action in messageQueue.GetConsumingEnumerable()) 30 | { 31 | Application.Current.Dispatcher.Invoke((Action)delegate { 32 | action(); 33 | }); 34 | 35 | if (messageQueue.Count == 0) 36 | { 37 | signal.Reset(); 38 | signal.Wait(); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Models/AutoStartManager.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | 3 | namespace DarkMode_2.Models 4 | { 5 | public class AutoStartManager 6 | { 7 | private const string RunRegistryPath = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Run"; 8 | private const string RunRegistryKeyName = "DarkMode 2"; 9 | 10 | public static bool IsAutoStartEnabled() 11 | { 12 | using (var key = Registry.LocalMachine.OpenSubKey(RunRegistryPath, false)) 13 | { 14 | return (key.GetValue(RunRegistryKeyName) != null); 15 | } 16 | } 17 | 18 | public static void EnableAutoStart() 19 | { 20 | using (var key = Registry.LocalMachine.OpenSubKey(RunRegistryPath, true)) 21 | { 22 | key.SetValue(RunRegistryKeyName, "\"" + System.Reflection.Assembly.GetEntryAssembly().Location + "\""); 23 | } 24 | } 25 | 26 | public static void DisableAutoStart() 27 | { 28 | using (var key = Registry.LocalMachine.OpenSubKey(RunRegistryPath, true)) 29 | { 30 | key.DeleteValue(RunRegistryKeyName, false); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Models/RedRawWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace DarkMode_2.Models; 5 | 6 | public class RedRawWindow 7 | { 8 | [DllImport("user32.dll")] 9 | private static extern bool SendNotifyMessage(uint hWnd, uint Msg, IntPtr wPARAM, IntPtr lPARAM); 10 | 11 | [DllImport("user32.dll", CharSet = CharSet.Auto)] 12 | private static extern bool SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni); 13 | public static bool ChangeColorMode() 14 | { 15 | const uint HWND_BROADCAST = 0xffff; 16 | const uint WM_SETTINGCHANGE = 0x001A; 17 | 18 | bool res = SendNotifyMessage(HWND_BROADCAST, WM_SETTINGCHANGE, new IntPtr(0), Marshal.StringToHGlobalAnsi("ImmersiveColorSet")); 19 | if (res) 20 | { 21 | return true; 22 | } 23 | return false; 24 | } 25 | 26 | public static bool RefreshSystemScheme() 27 | { 28 | const int SPI_SETCURSOR = 0x0057; 29 | const int SPIF_UPDATEINIFILE = 0x01; 30 | const int SPIF_SENDCHANGE = 0x02; 31 | 32 | bool res = SystemParametersInfo(SPI_SETCURSOR, 0, null, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); 33 | if (res) 34 | { 35 | return true; 36 | } 37 | return false; 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /Services/PageService.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | using System; 4 | using System.Windows; 5 | using Wpf.Ui.Mvvm.Contracts; 6 | 7 | namespace DarkMode_2.Services; 8 | 9 | /// 10 | /// Service that provides pages for navigation. 11 | /// 12 | public class PageService : IPageService 13 | { 14 | /// 15 | /// 页面实例化 16 | /// 17 | private readonly IServiceProvider _serviceProvider; 18 | 19 | /// 20 | /// Creates new instance and attaches the . 21 | /// 22 | public PageService(IServiceProvider serviceProvider) 23 | { 24 | _serviceProvider = serviceProvider; 25 | } 26 | 27 | /// 28 | public T? GetPage() where T : class 29 | { 30 | if (!typeof(FrameworkElement).IsAssignableFrom(typeof(T))) 31 | throw new InvalidOperationException("The page should be a WPF control."); 32 | 33 | return (T?)_serviceProvider.GetService(typeof(T)); 34 | } 35 | 36 | /// 37 | public FrameworkElement? GetPage(Type pageType) 38 | { 39 | if (!typeof(FrameworkElement).IsAssignableFrom(pageType)) 40 | throw new InvalidOperationException("The page should be a WPF control."); 41 | 42 | return _serviceProvider.GetService(pageType) as FrameworkElement; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Models/WallpaperChanger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace DarkMode_2.Models 5 | { 6 | public class WallpaperChanger 7 | { 8 | public static string GetWallpaperPath(string appPath) 9 | { 10 | string command = $"\"{appPath}\" -control getWallpaper"; 11 | return ExecuteCommand(command); 12 | } 13 | 14 | public static void SetWallpaper(string appPath, string wallpaperPath) 15 | { 16 | string command = $"\"{appPath}\" -control openWallpaper -file \"{wallpaperPath}\""; 17 | ExecuteCommand(command); 18 | } 19 | 20 | private static string ExecuteCommand(string command) 21 | { 22 | ProcessStartInfo processInfo = new ProcessStartInfo 23 | { 24 | FileName = "cmd.exe", 25 | Arguments = $"/C \"{command}\"", 26 | RedirectStandardOutput = true, 27 | UseShellExecute = false, 28 | CreateNoWindow = true 29 | }; 30 | 31 | Process process = new Process(); 32 | Console.WriteLine(command); 33 | process.StartInfo = processInfo; 34 | process.Start(); 35 | 36 | string output = process.StandardOutput.ReadToEnd(); 37 | process.WaitForExit(); 38 | 39 | return output; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Models/JsonSerialization.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace DarkMode_2.Models; 5 | 6 | public class JsonSerialization 7 | { 8 | public string ParseJson(string json) //返回版本名称 9 | { 10 | JObject keyValuePairs = JObject.Parse(json); 11 | string tag_name = Regex.Match(keyValuePairs["tag_name"]?.ToString(), @"(.*?)(?=-)").Groups[1].Value; 12 | 13 | return tag_name; 14 | } 15 | public string ParseTagName(string json) 16 | { 17 | JObject keyValuePairs = JObject.Parse(json); 18 | string tag_name = keyValuePairs["tag_name"]?.ToString(); 19 | 20 | return tag_name; 21 | } 22 | public string FileDownloadUrl(string json) //返回版本下载地址 23 | { 24 | JObject keyValuePairs = JObject.Parse(json); 25 | string url = keyValuePairs["assets"]["browser_download_url"].ToString(); 26 | return url; 27 | } 28 | public string FileUpdateTime(string json) //返回版本创建时间 29 | { 30 | JObject keyValuePairs = JObject.Parse(json); 31 | string time; 32 | try 33 | { 34 | time = Regex.Replace(keyValuePairs["assets"]["created_at"].ToString(), @"(.+(?= T))", ""); 35 | } 36 | finally 37 | { 38 | time = Regex.Replace(keyValuePairs["created_at"].ToString(), @"(.+(?= T))", ""); 39 | } 40 | return time; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /i18n/languages_list.json: -------------------------------------------------------------------------------- 1 | /* 2 | 多语言国际化说明: 3 | 感谢各位支持软件国际化,本项目语言国际化采用资源字典的方式进行处理。 4 | 首先请先拷贝一份本JSON文件文件夹中你熟悉的语言,将它重命名为你想 5 | 国际化语言的国家代码+统一格式。Languages.{国家代码}.resx 6 | 例如:Languages.zh-CN.resx, Languages.en-US.resx 7 | 然后打开代码编辑器(Visual Studio Code),将键值内的文字翻译为 8 | 你想国际化的语言,翻译完成之后就到GitHub创建一个拉取请求,将你的 9 | 国际化文件pull到Forked仓库,等待审阅完毕后你将进入贡献列表。 10 | 11 | Multi-Language Internationalization Instructions: 12 | Thank you for supporting software internationalization. 13 | This project's language internationalization is managed 14 | using a resource dictionary approach. 15 | First, please make a copy of this JSON file in the folder 16 | for the language you are familiar with. Rename it to the 17 | desired internationalized language's country code + 18 | standardized format. 19 | For example: languages.{country code}.resx,such as Languag- 20 | es.zh-CN.resx, Languages.en-US.resx. 21 | Then, open a code editor (Visual Studio Code) and translate 22 | the text within the key values to the language you want to 23 | internationalize. 24 | After completing the translation, proceed to create a pull 25 | request on GitHub. Pull your internationalization file into 26 | the Forked repository and wait for the review. Upon comple- 27 | tion of the review, you will be added to the contribute list. 28 | */ 29 | { 30 | "Languages": [ 31 | { 32 | "name": "简体中文", 33 | "code": "zh-CN" 34 | }, 35 | { 36 | "name": "繁體中文", 37 | "code": "zh-TW" 38 | }, 39 | { 40 | "name": "English", 41 | "code": "en-US" 42 | } 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /Services/TestWindowService.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | using System; 7 | using System.Windows; 8 | using DarkMOde_2.Services.Contracts; 9 | 10 | namespace DarkMOde_2.Services; 11 | 12 | public class TestWindowService : ITestWindowService 13 | { 14 | private readonly IServiceProvider _serviceProvider; 15 | 16 | public TestWindowService(IServiceProvider serviceProvider) 17 | { 18 | _serviceProvider = serviceProvider; 19 | } 20 | 21 | public void Show(Type windowType) 22 | { 23 | if (!typeof(Window).IsAssignableFrom(windowType)) 24 | throw new InvalidOperationException($"The window class should be derived from {typeof(Window)}."); 25 | 26 | var windowInstance = _serviceProvider.GetService(windowType) as Window; 27 | 28 | windowInstance?.Show(); 29 | } 30 | 31 | public T Show() where T : class 32 | { 33 | if (!typeof(Window).IsAssignableFrom(typeof(T))) 34 | throw new InvalidOperationException($"The window class should be derived from {typeof(Window)}."); 35 | 36 | var windowInstance = _serviceProvider.GetService(typeof(T)) as Window; 37 | 38 | if (windowInstance == null) 39 | throw new InvalidOperationException("Window is not registered as service."); 40 | 41 | windowInstance.Show(); 42 | 43 | return (T)Convert.ChangeType(windowInstance, typeof(T)); 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Models/Interface/IUpdate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DarkMode_2.Models.Interface 8 | { 9 | public interface IUpdate 10 | { 11 | public static class Consts 12 | { 13 | internal const string githubUrl = "https://api.github.com/repos/Melon-Studio/DarkMode2/releases/latest"; 14 | internal const string giteeUrl = "https://gitee.com/api/v5/repos/melon-studio/DarkMode2/releases/latest"; 15 | internal const string username = "6get-xiaofan"; 16 | internal const string token = "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"; //此 Token 仅限访问公开库的基本信息 17 | internal const string giteeToken = "e995460832ca545707451332283aadc1"; //此 Token 仅限访问公开库的基本信息 18 | internal const string githubIP = "192.30.255.113"; 19 | internal const string giteeIP = "212.64.63.215"; 20 | } 21 | 22 | public enum Channel 23 | { 24 | Github, 25 | Gitee, 26 | TimeOut 27 | } 28 | 29 | public enum type 30 | { 31 | TagName, 32 | Content, 33 | DownloadUrl, 34 | Date 35 | } 36 | 37 | // 获取更新渠道 38 | public Channel UpdateChannel(); 39 | 40 | // Ping IP 地址 41 | public Channel PingIp(); 42 | 43 | // 版本对比: New V:TRUE | Old V:FALSE 44 | public string UpdateVersionCompared(Version OldV, Version NewV); 45 | 46 | // 更新相关JSON解析 47 | public Task UpdateJsonInterpreter(string res, type type, Channel? channel); 48 | 49 | // 获取对应渠道JSON 50 | public Task GetJson(Channel channel); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Views/Pages/SetMore.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using MessageBox = DarkMode_2.Models.MessageBox; 3 | using System; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using log4net; 7 | using DarkMode_2.Models; 8 | 9 | namespace DarkMode_2.Views.Pages; 10 | 11 | /// 12 | /// SetMore.xaml 的交互逻辑 13 | /// 14 | public partial class SetMore 15 | { 16 | private static readonly ILog log = LogManager.GetLogger(typeof(SetMore)); 17 | public SetMore() 18 | { 19 | InitializeComponent(); 20 | } 21 | 22 | public bool StartProcess(string filename, string args) 23 | { 24 | try 25 | { 26 | Process myprocess = new Process(); 27 | ProcessStartInfo startInfo = new ProcessStartInfo(filename, args.Trim()); 28 | myprocess.StartInfo = startInfo; 29 | myprocess.Start(); 30 | return true; 31 | } 32 | catch (Exception ex) 33 | { 34 | MessageBox.OpenMessageBox(LanguageHandler.GetLocalizedString("SetSettingPage_Tip8"), ex.ToString()); 35 | log.Error(ex.ToString()); 36 | } 37 | return false; 38 | } 39 | 40 | private void KillProcess(string name) 41 | { 42 | try 43 | { 44 | System.Diagnostics.Process[] myProcesses = System.Diagnostics.Process.GetProcesses(); 45 | foreach (System.Diagnostics.Process myProcess in myProcesses) 46 | { 47 | if (name == myProcess.ProcessName) 48 | myProcess.Kill(); 49 | } 50 | } 51 | catch (Exception ex) 52 | { 53 | MessageBox.OpenMessageBox(LanguageHandler.GetLocalizedString("SetSettingPage_Tip8"), ex.ToString()); 54 | log.Error(ex); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // 有关程序集的一般信息由以下 8 | // 控制。更改这些特性值可修改 9 | // 与程序集关联的信息。 10 | [assembly: AssemblyTitle("DarkMode2")] 11 | [assembly: AssemblyDescription("Windows 10/11 颜色模式自动切换工具")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("Melon Studio")] 14 | [assembly: AssemblyProduct("DarkMode2")] 15 | [assembly: AssemblyCopyright("Copyright © Melon-Studio 2023")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // 将 ComVisible 设置为 false 会使此程序集中的类型 20 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 21 | //请将此类型的 ComVisible 特性设置为 true。 22 | [assembly: ComVisible(false)] 23 | 24 | //若要开始生成可本地化的应用程序,请设置 25 | //.csproj 文件中的 CultureYouAreCodingWith 26 | //例如,如果您在源文件中使用的是美国英语, 27 | //使用的是美国英语,请将 设置为 en-US。 然后取消 28 | //对以下 NeutralResourceLanguage 特性的注释。 更新 29 | //以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //主题特定资源词典所处位置 36 | //(未在页面中找到资源时使用, 37 | //或应用程序资源字典中找到时使用) 38 | ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 39 | //(未在页面中找到资源时使用, 40 | //应用程序或任何主题专用资源字典中找到时使用) 41 | )] 42 | 43 | 44 | // 程序集的版本信息由下列四个值组成: 45 | // 46 | // 主版本 47 | // 次版本 48 | // 生成号 49 | // 修订号 50 | // 51 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 52 | //通过使用 "*",如下所示: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("2.1.3.1")] 55 | [assembly: AssemblyFileVersion("2.1.3.1")] 56 | [assembly: NeutralResourcesLanguage("zh-CN")] 57 | -------------------------------------------------------------------------------- /Views/Diagnostics/DebuggingLayerView.xaml: -------------------------------------------------------------------------------- 1 | 12 | 13 | 19 | 20 | 21 | 22 | 28 | 35 | 36 | 37 | 38 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Models/WindowsVersionHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Management; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DarkMode_2.Models 9 | { 10 | public class WindowsVersionHelper 11 | { 12 | public static string GetWindowsEdition() 13 | { 14 | string edition = "Unknown"; 15 | ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem"); 16 | foreach (ManagementObject os in searcher.Get()) 17 | { 18 | if (os["Caption"] != null) 19 | { 20 | string caption = os["Caption"].ToString(); 21 | if (caption.Contains("Windows 10")) 22 | { 23 | edition = "Windows 10"; 24 | } 25 | else if (caption.Contains("Windows 8")) 26 | { 27 | edition = "Windows 8"; 28 | } 29 | else if (caption.Contains("Windows 7")) 30 | { 31 | edition = "Windows 7"; 32 | } 33 | else if (caption.Contains("Windows Vista")) 34 | { 35 | edition = "Windows Vista"; 36 | } 37 | else if (caption.Contains("Windows XP")) 38 | { 39 | edition = "Windows XP"; 40 | } 41 | else if (caption.Contains("Windows 11")) 42 | { 43 | edition = "Windows 11"; 44 | } 45 | } 46 | } 47 | return edition; 48 | } 49 | 50 | public static Version GetWindowsVersion() 51 | { 52 | return Environment.OSVersion.Version; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Models/LanguageHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System; 3 | using System.Globalization; 4 | using WPFLocalizeExtension.Extensions; 5 | 6 | namespace DarkMode_2.Models; 7 | 8 | public class LanguageHandler 9 | { 10 | private string _i18nFolderPath; 11 | private string _currentLanguageCode; 12 | 13 | public LanguageHandler(string i18nFolderPath) 14 | { 15 | _i18nFolderPath = i18nFolderPath; 16 | _currentLanguageCode = RegistryInit.GetSavedLanguageCode(); 17 | InitializeLanguage(); 18 | MonitorLanguageChanges(); 19 | } 20 | 21 | private void InitializeLanguage() 22 | { 23 | ChangeLanguage(_currentLanguageCode); 24 | } 25 | 26 | private void MonitorLanguageChanges() 27 | { 28 | SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged; 29 | } 30 | 31 | private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) 32 | { 33 | if (e.Category == UserPreferenceCategory.Locale) 34 | { 35 | string newLanguageCode = RegistryInit.GetSavedLanguageCode(); 36 | if (newLanguageCode != _currentLanguageCode) 37 | { 38 | _currentLanguageCode = newLanguageCode; 39 | ChangeLanguage(newLanguageCode); 40 | } 41 | } 42 | } 43 | 44 | public void ChangeLanguage(string languageCode) 45 | { 46 | WPFLocalizeExtension.Engine.LocalizeDictionary.Instance.Culture = new CultureInfo(languageCode); 47 | } 48 | 49 | public static string GetLocalizedString(string key, string resourceFileName = "Languages", bool addSpaceAfter = false) 50 | { 51 | var localizedString = String.Empty; 52 | 53 | // Build up the fully-qualified name of the key 54 | var assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name; 55 | var fullKey = assemblyName + ":" + resourceFileName + ":" + key; 56 | var locExtension = new LocExtension(fullKey); 57 | locExtension.ResolveLocalizedValue(out localizedString); 58 | 59 | // Add a space to the end, if requested 60 | if (addSpaceAfter) 61 | { 62 | localizedString += " "; 63 | } 64 | 65 | return localizedString; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Views/Pages/SetAbout.xaml.cs: -------------------------------------------------------------------------------- 1 | using DarkMode_2.Models; 2 | using System; 3 | using System.Runtime.InteropServices; 4 | using System.Text.RegularExpressions; 5 | using System.Threading.Tasks; 6 | using Wpf.Ui.Common; 7 | using Wpf.Ui.Mvvm.Contracts; 8 | 9 | namespace DarkMode_2.Views.Pages; 10 | 11 | /// 12 | /// SetAbout.xaml 的交互逻辑 13 | /// 14 | public partial class SetAbout 15 | { 16 | 17 | [DllImport("winmm.dll")] 18 | public static extern bool PlaySound(String Filename, int Mod, int Flags); 19 | private readonly ISnackbarService _snackbarService; 20 | public SetAbout(ISnackbarService snackbarService) 21 | { 22 | InitializeComponent(); 23 | _snackbarService = snackbarService; 24 | Channel.Text = VersionControl.Channel(); 25 | Version.Text = VersionControl.Version() + "(" + VersionControl.InternalVersion() + ")"; 26 | } 27 | 28 | //帮助中心 29 | private void OpenDiscussions_Click(object sender, System.Windows.RoutedEventArgs e) 30 | { 31 | System.Diagnostics.Process.Start("https://github.com/Melon-Studio/DarkMode2/discussions"); 32 | } 33 | //检查更新 34 | private async void CheckUpdate_onClick(object sender, System.Windows.RoutedEventArgs e) 35 | { 36 | NewVersion update = new NewVersion(); 37 | ProgressRing.Visibility = System.Windows.Visibility.Visible; 38 | checkUpdateBtn.IsEnabled= false; 39 | 40 | 41 | string res = await update.CheckUpdate(); 42 | Match match = Regex.Match(res, @"\d+\.\d+\.\d+\.\d+"); 43 | if (match.Success) 44 | { 45 | DownloadWindow window = new DownloadWindow(match.Groups[1].Value); 46 | ProgressRing.Visibility = System.Windows.Visibility.Hidden; 47 | checkUpdateBtn.IsEnabled = true; 48 | window.ShowDialog(); 49 | } 50 | else 51 | { 52 | OpenSnackbar(res); 53 | ProgressRing.Visibility = System.Windows.Visibility.Hidden; 54 | checkUpdateBtn.IsEnabled = true; 55 | } 56 | 57 | } 58 | 59 | private void VersionChannel_Click(object sender, System.Windows.RoutedEventArgs e) 60 | { 61 | OpenSnackbar(LanguageHandler.GetLocalizedString("SetAboutPage_Tip1")); 62 | } 63 | 64 | private void OpenSnackbar(string connect) 65 | { 66 | PlaySound(@"C:\Windows\Media\Windows Notify System Generic.wav", 0, 1); 67 | _snackbarService.Show(LanguageHandler.GetLocalizedString("SetAboutPage_Tip2"), connect, SymbolRegular.Alert24); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Models/SystemHotKey.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Windows.Forms; 4 | 5 | namespace DarkMode_2.Models 6 | { 7 | public class SystemHotKey 8 | { 9 | /// 10 | /// 如果函数执行成功,返回值不为0。 11 | /// 如果函数执行失败,返回值为0。要得到扩展错误信息,调用GetLastError。 12 | /// 13 | /// 要定义热键的窗口的句柄 14 | /// 定义热键ID(不能与其它ID重复) 15 | /// 标识热键是否在按Alt、Ctrl、Shift、Windows等键时才会生效 16 | /// 定义热键的内容 17 | /// 18 | [DllImport("user32.dll", SetLastError = true)] 19 | public static extern bool RegisterHotKey(IntPtr hWnd, int id, KeyModifiers fsModifiers, Keys vk); 20 | 21 | /// 22 | /// 注销热键 23 | /// 24 | /// 要取消热键的窗口的句柄 25 | /// 要取消热键的ID 26 | /// 27 | [DllImport("user32.dll", SetLastError = true)] 28 | public static extern bool UnregisterHotKey(IntPtr hWnd, int id); 29 | 30 | /// 31 | /// 辅助键名称。 32 | /// Alt, Ctrl, Shift, WindowsKey 33 | /// 34 | [Flags()] 35 | public enum KeyModifiers { None = 0, Ctrl = 1 , Alt = 2} 36 | 37 | /// 38 | /// 注册热键 39 | /// 40 | /// 窗口句柄 41 | /// 热键ID 42 | /// 组合键 43 | /// 热键 44 | public static int RegHotKey(IntPtr hwnd, int hotKeyId, KeyModifiers keyModifiers, Keys key) 45 | { 46 | if (!RegisterHotKey(hwnd, hotKeyId, keyModifiers, key)) 47 | { 48 | int errorCode = Marshal.GetLastWin32Error(); 49 | if (errorCode == 1409) 50 | { 51 | return -1; 52 | } 53 | else 54 | { 55 | return -2; 56 | } 57 | } 58 | return 0; 59 | } 60 | 61 | /// 62 | /// 注销热键 63 | /// 64 | /// 窗口句柄 65 | /// 热键ID 66 | public static void UnRegHotKey(IntPtr hwnd, int hotKeyId) 67 | { 68 | //注销指定的热键 69 | UnregisterHotKey(hwnd, hotKeyId); 70 | } 71 | 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Resources/we(light).svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /PRIVACY: -------------------------------------------------------------------------------- 1 | Thank you for using DarkMode. We take your privacy and data security seriously. 2 | 3 | To better protect your personal information, we have written the following Privacy Policy: 4 | 1. This software is committed to strictly complying with laws, regulations, and privacy protection principles and will not disclose user privacy data over the network. 5 | 2. This software has administrator privileges but will not abuse this privilege to maliciously damage user data. 6 | 3. Features like sunrise and sunset mode require internet access for location. Please make sure you have agreed and authorized this software to access your location information before using these features. 7 | 4. This software also uses the internet to report version numbers and other information for data statistics (such as user numbers and channel distribution). We promise not to disclose users' personal information in any form. 8 | 5. This software collects necessary user information, such as device information, network information, error logs, etc., to improve software performance and user experience. We promise not to use this information for illegal purposes or disclose it to third parties. 9 | 6. Under specific circumstances, in order to protect users' rights and comply with laws and regulations, this software may disclose user information. For example, when requested by government agencies or judicial authorities, or to protect the interests of this software, other users, or public interests. 10 | 7. Users have the right to contact the developer to delete their personal information at any time. If you have any questions, complaints, or concerns about the Privacy Policy, you can contact the developer through the contact information provided by us. We will do our best to solve problems and protect the security of your personal information. 11 | 12 | Please read and understand the above Privacy Policy carefully and follow our commitment to user privacy. If you do not agree with any content of this Privacy Policy, you can choose to stop using this software. If you continue to use this software, it means you have understood and agreed to the above terms. 13 | 14 | 15 | 非常感谢您使用DarkMode。我们非常重视用户隐私和信息安全问题。 16 | 17 | 为了更好地保护您的个人信息,我们编写了下面的隐私政策: 18 | 1. 本软件承诺严格遵守法律法规和用户隐私保护原则,不会通过网络泄露用户隐私数据。 19 | 2. 本软件拥有管理员权限,但不会滥用此权限恶意破坏用户数据。 20 | 3. 本软件的日出日落模式等相关功能需要联网进行定位。使用这些功能前请确保您已同意并授权本软件获得您的定位信息。 21 | 4. 本软件联网还用来向开发者汇报版本号等信息用于数据统计(如用户数量、各渠道占比等)。我们承诺不会以任何形式泄露用户的个人信息。 22 | 5. 本软件会收集必要的用户信息,例如设备信息、网络信息、错误日志等,以便改善软件性能和用户体验。我们承诺不会将这些信息用于非法用途或泄露给第三方。 23 | 6. 在特定情况下,为了保护用户权益和遵守法律法规,本软件有可能会披露用户的信息。例如,当政府机关或司法机构正式要求时,或者为了保护本软件、其他用户或社会公共利益时。 24 | 7. 用户有权随时联系开发者删除其个人信息。如果您对隐私政策有任何疑问、申诉或投诉,可以通过我们提供的联系方式与开发者取得联系。我们将竭尽所能为您解决问题,保护您的个人信息安全 25 | 26 | 请您仔细阅读并理解上述隐私政策,遵循我们对用户隐私的承诺。如果您不同意本隐私政策的任何内容,您可以选择停止使用本软件。如果您继续使用本软件,则视为您已经理解并同意上述条款。 27 | -------------------------------------------------------------------------------- /ViewModels/SetTimesViewModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Toolkit.Mvvm.ComponentModel; 2 | using System.Collections.Generic; 3 | 4 | namespace DarkMode_2.ViewModels; 5 | 6 | public class SetTimesViewModel : ObservableObject 7 | { 8 | 9 | private IEnumerable _oneComboCollection = new string[] 10 | { 11 | "00", 12 | "01", 13 | "02", 14 | "03", 15 | "04", 16 | "05", 17 | "06", 18 | "07", 19 | "08", 20 | "09", 21 | "10", 22 | "11", 23 | "12", 24 | "13", 25 | "14", 26 | "15", 27 | "16", 28 | "17", 29 | "18", 30 | "19", 31 | "20", 32 | "21", 33 | "22", 34 | "23" 35 | }; 36 | 37 | private IEnumerable _twoComboCollection = new string[] 38 | { 39 | "00", 40 | "01", 41 | "02", 42 | "03", 43 | "04", 44 | "05", 45 | "06", 46 | "07", 47 | "08", 48 | "09", 49 | "10", 50 | "11", 51 | "12", 52 | "13", 53 | "14", 54 | "15", 55 | "16", 56 | "17", 57 | "18", 58 | "19", 59 | "20", 60 | "21", 61 | "22", 62 | "23", 63 | "24", 64 | "25", 65 | "26", 66 | "27", 67 | "28", 68 | "29", 69 | "30", 70 | "31", 71 | "32", 72 | "33", 73 | "34", 74 | "35", 75 | "36", 76 | "37", 77 | "38", 78 | "39", 79 | "40", 80 | "41", 81 | "42", 82 | "43", 83 | "44", 84 | "45", 85 | "46", 86 | "47", 87 | "48", 88 | "49", 89 | "50", 90 | "51", 91 | "52", 92 | "53", 93 | "54", 94 | "55", 95 | "56", 96 | "57", 97 | "58", 98 | "59" 99 | }; 100 | 101 | public IEnumerable OneComboCollection 102 | { 103 | get => _oneComboCollection; 104 | set => SetProperty(ref _oneComboCollection, value); 105 | } 106 | 107 | public IEnumerable TwoComboCollection 108 | { 109 | get => _twoComboCollection; 110 | set => SetProperty(ref _twoComboCollection, value); 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Views/MainWindow.xaml: -------------------------------------------------------------------------------- 1 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 36 | 39 | 40 | 45 | 46 | 47 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /Services/ApplicationHostService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using System.Windows; 6 | using Microsoft.Extensions.Hosting; 7 | using DarkMode_2.Views; 8 | using Wpf.Ui.Mvvm.Contracts; 9 | 10 | namespace DarkMode_2.Services; 11 | 12 | /// 13 | /// Managed host of the application. 14 | /// 15 | public class ApplicationHostService : IHostedService 16 | { 17 | private readonly IServiceProvider _serviceProvider; 18 | private readonly INavigationService _navigationService; 19 | private readonly IPageService _pageService; 20 | private readonly IThemeService _themeService; 21 | private readonly ITaskBarService _taskBarService; 22 | 23 | private INavigationWindow _navigationWindow; 24 | 25 | public ApplicationHostService(IServiceProvider serviceProvider, INavigationService navigationService, 26 | IPageService pageService, IThemeService themeService, 27 | ITaskBarService taskBarService) 28 | { 29 | // If you want, you can do something with these services at the beginning of loading the application. 30 | _serviceProvider = serviceProvider; 31 | _navigationService = navigationService; 32 | _pageService = pageService; 33 | _themeService = themeService; 34 | _taskBarService = taskBarService; 35 | } 36 | 37 | /// 38 | /// Triggered when the application host is ready to start the service. 39 | /// 40 | /// Indicates that the start process has been aborted. 41 | public async Task StartAsync(CancellationToken cancellationToken) 42 | { 43 | PrepareNavigation(); 44 | 45 | await HandleActivationAsync(); 46 | } 47 | 48 | /// 49 | /// Triggered when the application host is performing a graceful shutdown. 50 | /// 51 | /// Indicates that the shutdown process should no longer be graceful. 52 | public async Task StopAsync(CancellationToken cancellationToken) 53 | { 54 | await Task.CompletedTask; 55 | } 56 | 57 | /// 58 | /// Creates main window during activation. 59 | /// 60 | private async Task HandleActivationAsync() 61 | { 62 | await Task.CompletedTask; 63 | 64 | if (!Application.Current.Windows.OfType().Any()) 65 | { 66 | _navigationWindow = _serviceProvider.GetService(typeof(INavigationWindow)) as INavigationWindow; 67 | _navigationWindow!.ShowWindow(); 68 | 69 | // NOTICE: You can set this service directly in the window 70 | // _navigationWindow.SetPageService(_pageService); 71 | 72 | // NOTICE: In the case of this window, we navigate to the Dashboard after loading with Container.InitializeUi() 73 | // _navigationWindow.Navigate(typeof(Views.Pages.Dashboard)); 74 | } 75 | 76 | 77 | 78 | await Task.CompletedTask; 79 | } 80 | 81 | private void PrepareNavigation() 82 | { 83 | _navigationService.SetPageService(_pageService); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Properties/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 50 | 58 | 59 | 73 | -------------------------------------------------------------------------------- /Views/Pages/SetDIY.xaml.cs: -------------------------------------------------------------------------------- 1 | using DarkMode_2.Models; 2 | using Microsoft.Win32; 3 | 4 | namespace DarkMode_2.Views.Pages; 5 | 6 | /// 7 | /// SetDIY.xaml 的交互逻辑 8 | /// 9 | public partial class SetDIY 10 | { 11 | public SetDIY() 12 | { 13 | InitializeComponent(); 14 | //设置初始化 15 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 16 | if (key.GetValue("LightMouse").ToString() == "Light") 17 | { 18 | LightMouse_white.IsChecked = true; 19 | LightMouse_black.IsChecked = false; 20 | } 21 | else if(key.GetValue("LightMouse").ToString() == "Dark") 22 | { 23 | LightMouse_black.IsChecked = true; 24 | LightMouse_white.IsChecked = false; 25 | } 26 | if(key.GetValue("DarkMouse").ToString() == "Light") 27 | { 28 | DarkMouse_white.IsChecked = true; 29 | DarkMouse_black.IsChecked = false; 30 | } 31 | else if(key.GetValue("DarkMouse").ToString() == "Dark") 32 | { 33 | DarkMouse_black.IsChecked = true; 34 | DarkMouse_white.IsChecked = false; 35 | } 36 | if(key.GetValue("SwitchMouse").ToString() == "true") 37 | { 38 | MouseSwitch.IsChecked = true; 39 | } 40 | key.Close(); 41 | 42 | 43 | } 44 | 45 | private void LightMouse_white_Click(object sender, System.Windows.RoutedEventArgs e) 46 | { 47 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 48 | key.SetValue("LightMouse", "Light"); 49 | key.Close(); 50 | LightMouse_white.IsChecked = true; 51 | LightMouse_black.IsChecked = false; 52 | } 53 | 54 | private void LightMouse_black_Click(object sender, System.Windows.RoutedEventArgs e) 55 | { 56 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 57 | key.SetValue("LightMouse", "Dark"); 58 | key.Close(); 59 | LightMouse_black.IsChecked = true; 60 | LightMouse_white.IsChecked = false; 61 | } 62 | 63 | private void DarkMouse_white_Click(object sender, System.Windows.RoutedEventArgs e) 64 | { 65 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 66 | key.SetValue("DarkMouse", "Light"); 67 | key.Close(); 68 | DarkMouse_white.IsChecked = true; 69 | DarkMouse_black.IsChecked = false; 70 | } 71 | 72 | private void DarkMouse_black_Click(object sender, System.Windows.RoutedEventArgs e) 73 | { 74 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 75 | key.SetValue("DarkMouse", "Dark"); 76 | key.Close(); 77 | DarkMouse_black.IsChecked = true; 78 | DarkMouse_white.IsChecked = false; 79 | } 80 | 81 | 82 | private void MouseSwitch_Click(object sender, System.Windows.RoutedEventArgs e) 83 | { 84 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 85 | if (key.GetValue("SwitchMouse").ToString() == "true") 86 | { 87 | MouseSwitch.IsChecked = false; 88 | key.SetValue("SwitchMouse", "false"); 89 | } 90 | else 91 | { 92 | MouseSwitch.IsChecked = true; 93 | key.SetValue("SwitchMouse", "true"); 94 | } 95 | key.Close(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Models/DownloadManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net.Http; 4 | using System.Threading.Tasks; 5 | using System.Windows; 6 | using System.Windows.Threading; 7 | using Microsoft.WindowsAPICodePack.Shell; 8 | 9 | namespace DarkMode_2.Models 10 | { 11 | public class DownloadManager 12 | { 13 | private const string DownloadFolderName = "DarkModeDownloads"; 14 | 15 | public event Action ProgressChanged; 16 | public event Action SpeedChanged; 17 | public event Action DownloadCompleted; 18 | 19 | private HttpClient httpClient; 20 | private Dispatcher dispatcher; 21 | private DateTime startTime; 22 | private long totalBytesDownloaded; 23 | private double totalFileSize; 24 | 25 | public DownloadManager() 26 | { 27 | httpClient = new HttpClient(); 28 | dispatcher = Application.Current.Dispatcher; 29 | } 30 | 31 | public async Task DownloadFileAsync(string url) 32 | { 33 | try 34 | { 35 | string downloadFolderPath = Path.Combine(KnownFolders.Downloads.Path, DownloadFolderName); 36 | if (!Directory.Exists(downloadFolderPath)) 37 | { 38 | Directory.CreateDirectory(downloadFolderPath); 39 | } 40 | 41 | string fileName = Path.GetFileName(url); 42 | string filePath = Path.Combine(downloadFolderPath, fileName); 43 | 44 | using (var response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead)) 45 | using (var stream = await response.Content.ReadAsStreamAsync()) 46 | using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 8192, useAsync: true)) 47 | { 48 | byte[] buffer = new byte[8192]; 49 | long totalRead = 0; 50 | int bytesRead; 51 | totalFileSize = response.Content.Headers.ContentLength ?? -1; 52 | 53 | startTime = DateTime.Now; 54 | totalBytesDownloaded = 0; 55 | 56 | while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0) 57 | { 58 | await fileStream.WriteAsync(buffer, 0, bytesRead); 59 | totalRead += bytesRead; 60 | totalBytesDownloaded += bytesRead; 61 | 62 | if (totalFileSize > 0) 63 | { 64 | double progress = (double)totalRead / totalFileSize; 65 | ProgressChanged?.Invoke(progress); 66 | 67 | double elapsedTimeInSeconds = (DateTime.Now - startTime).TotalSeconds; 68 | double downloadSpeedMBps = totalBytesDownloaded / (elapsedTimeInSeconds * 1024 * 1024); 69 | SpeedChanged?.Invoke(downloadSpeedMBps); 70 | } 71 | } 72 | } 73 | 74 | DownloadCompleted?.Invoke(filePath); 75 | } 76 | catch { } 77 | } 78 | 79 | public static string GetDownloadPath() 80 | { 81 | string downloadFolderPath = Path.Combine(KnownFolders.Downloads.Path, DownloadFolderName); 82 | return downloadFolderPath; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Models/LocationService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Device.Location; 3 | using System.Net.Http; 4 | using System.Threading.Tasks; 5 | using System.Text.Json; 6 | using System.Text.Json.Serialization; 7 | using System.Globalization; 8 | 9 | namespace DarkMode_2.Models 10 | { 11 | public class LocationService 12 | { 13 | private const string BingMapsKey = "9POfGrKXu2XVUBErnEDA~3azXh-0YKYqoT4IjnFnMog~Ajfj1WaDN-iosAXUuTjX02P8d5tXv8c6rfKg31cm50Qw6Ug8q5Ns2CVdGY-jebpE"; 14 | 15 | private readonly HttpClient _httpClient; 16 | 17 | public LocationService() 18 | { 19 | _httpClient = new HttpClient(); 20 | } 21 | 22 | public async Task GetLocationName(double latitude, double longitude) 23 | { 24 | var coordinate = new GeoCoordinate(latitude, longitude); 25 | 26 | // Build the Bing Maps API request URL with the Chinese language and district-level location information 27 | var url = string.Format("https://dev.virtualearth.net/REST/v1/Locations/{0},{1}?o=json&key={2}&c=zh-Hans&inclnb=1&incl=ciso2&ul=39.9,-105.3&lvl=19", 28 | coordinate.Latitude, coordinate.Longitude, BingMapsKey); 29 | 30 | var response = await _httpClient.GetAsync(url); 31 | response.EnsureSuccessStatusCode(); 32 | var json = await response.Content.ReadAsStringAsync(); 33 | 34 | var options = new JsonSerializerOptions 35 | { 36 | PropertyNamingPolicy = JsonNamingPolicy.CamelCase, 37 | Converters = 38 | { 39 | new JsonStringEnumConverter() 40 | } 41 | }; 42 | var locationData = JsonSerializer.Deserialize(json, options); 43 | 44 | var address = locationData?.ResourceSets?[0]?.Resources?[0]?.Address; 45 | if (address == null) 46 | { 47 | return null; 48 | } 49 | 50 | // Use the CISO2 country code to format the address with the correct name for the country. 51 | // (e.g. "China" instead of "People's Republic of China") 52 | var countryCode = locationData.ResourceSets[0].Resources[0].Address.CountryRegionIso2; 53 | var countryName = new RegionInfo(countryCode)?.NativeName ?? address.CountryRegion; 54 | 55 | // Build the location name string with the desired order of address components. 56 | var locationName = $"{countryName}, {address.AdminDistrict}, {address.Locality}"; 57 | 58 | // If the locality is blank, use the admin district 2 as the locality. 59 | if (string.IsNullOrEmpty(address.Locality)) 60 | { 61 | locationName = $"{countryName}, {address.AdminDistrict}, {address.AdminDistrict2}"; 62 | } 63 | 64 | return locationName; 65 | } 66 | } 67 | 68 | public class LocationData 69 | { 70 | public ResourceSet[] ResourceSets { get; set; } 71 | } 72 | 73 | public class ResourceSet 74 | { 75 | public Resource[] Resources { get; set; } 76 | } 77 | 78 | public class Resource 79 | { 80 | public Address Address { get; set; } 81 | } 82 | 83 | public class Address 84 | { 85 | public string FormattedAddress { get; set; } 86 | public string Locality { get; set; } 87 | public string AdminDistrict { get; set; } 88 | public string AdminDistrict2 { get; set; } 89 | public string CountryRegion { get; set; } 90 | public string CountryRegionIso2 { get; set; } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /DarkMode_2.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.2.32630.192 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DarkMode_2", "DarkMode_2.csproj", "{4632FA56-60E4-4F55-958F-8283C97D2042}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | All|Any CPU = All|Any CPU 11 | All|ARM64 = All|ARM64 12 | All|x64 = All|x64 13 | All|x86 = All|x86 14 | arm|Any CPU = arm|Any CPU 15 | arm|ARM64 = arm|ARM64 16 | arm|x64 = arm|x64 17 | arm|x86 = arm|x86 18 | Debug|Any CPU = Debug|Any CPU 19 | Debug|ARM64 = Debug|ARM64 20 | Debug|x64 = Debug|x64 21 | Debug|x86 = Debug|x86 22 | Release|Any CPU = Release|Any CPU 23 | Release|ARM64 = Release|ARM64 24 | Release|x64 = Release|x64 25 | Release|x86 = Release|x86 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {4632FA56-60E4-4F55-958F-8283C97D2042}.All|Any CPU.ActiveCfg = All|x64 29 | {4632FA56-60E4-4F55-958F-8283C97D2042}.All|Any CPU.Build.0 = All|x64 30 | {4632FA56-60E4-4F55-958F-8283C97D2042}.All|ARM64.ActiveCfg = All|ARM64 31 | {4632FA56-60E4-4F55-958F-8283C97D2042}.All|ARM64.Build.0 = All|ARM64 32 | {4632FA56-60E4-4F55-958F-8283C97D2042}.All|x64.ActiveCfg = All|x64 33 | {4632FA56-60E4-4F55-958F-8283C97D2042}.All|x64.Build.0 = All|x64 34 | {4632FA56-60E4-4F55-958F-8283C97D2042}.All|x86.ActiveCfg = All|Any CPU 35 | {4632FA56-60E4-4F55-958F-8283C97D2042}.All|x86.Build.0 = All|Any CPU 36 | {4632FA56-60E4-4F55-958F-8283C97D2042}.arm|Any CPU.ActiveCfg = arm|ARM64 37 | {4632FA56-60E4-4F55-958F-8283C97D2042}.arm|Any CPU.Build.0 = arm|ARM64 38 | {4632FA56-60E4-4F55-958F-8283C97D2042}.arm|ARM64.ActiveCfg = arm|ARM64 39 | {4632FA56-60E4-4F55-958F-8283C97D2042}.arm|ARM64.Build.0 = arm|ARM64 40 | {4632FA56-60E4-4F55-958F-8283C97D2042}.arm|x64.ActiveCfg = arm|x64 41 | {4632FA56-60E4-4F55-958F-8283C97D2042}.arm|x64.Build.0 = arm|x64 42 | {4632FA56-60E4-4F55-958F-8283C97D2042}.arm|x86.ActiveCfg = arm|Any CPU 43 | {4632FA56-60E4-4F55-958F-8283C97D2042}.arm|x86.Build.0 = arm|Any CPU 44 | {4632FA56-60E4-4F55-958F-8283C97D2042}.Debug|Any CPU.ActiveCfg = Release|x64 45 | {4632FA56-60E4-4F55-958F-8283C97D2042}.Debug|Any CPU.Build.0 = Release|x64 46 | {4632FA56-60E4-4F55-958F-8283C97D2042}.Debug|ARM64.ActiveCfg = Debug|ARM64 47 | {4632FA56-60E4-4F55-958F-8283C97D2042}.Debug|ARM64.Build.0 = Debug|ARM64 48 | {4632FA56-60E4-4F55-958F-8283C97D2042}.Debug|x64.ActiveCfg = Debug|x64 49 | {4632FA56-60E4-4F55-958F-8283C97D2042}.Debug|x64.Build.0 = Debug|x64 50 | {4632FA56-60E4-4F55-958F-8283C97D2042}.Debug|x86.ActiveCfg = Debug|Any CPU 51 | {4632FA56-60E4-4F55-958F-8283C97D2042}.Debug|x86.Build.0 = Debug|Any CPU 52 | {4632FA56-60E4-4F55-958F-8283C97D2042}.Release|Any CPU.ActiveCfg = Release|x64 53 | {4632FA56-60E4-4F55-958F-8283C97D2042}.Release|Any CPU.Build.0 = Release|x64 54 | {4632FA56-60E4-4F55-958F-8283C97D2042}.Release|ARM64.ActiveCfg = Release|ARM64 55 | {4632FA56-60E4-4F55-958F-8283C97D2042}.Release|ARM64.Build.0 = Release|ARM64 56 | {4632FA56-60E4-4F55-958F-8283C97D2042}.Release|x64.ActiveCfg = Release|x64 57 | {4632FA56-60E4-4F55-958F-8283C97D2042}.Release|x64.Build.0 = Release|x64 58 | {4632FA56-60E4-4F55-958F-8283C97D2042}.Release|x86.ActiveCfg = Release|Any CPU 59 | {4632FA56-60E4-4F55-958F-8283C97D2042}.Release|x86.Build.0 = Release|Any CPU 60 | EndGlobalSection 61 | GlobalSection(SolutionProperties) = preSolution 62 | HideSolutionNode = FALSE 63 | EndGlobalSection 64 | GlobalSection(ExtensibilityGlobals) = postSolution 65 | SolutionGuid = {A79E25F7-72FA-46DA-92EA-1EED14406992} 66 | EndGlobalSection 67 | EndGlobal 68 | -------------------------------------------------------------------------------- /Views/Pages/SetMore.xaml: -------------------------------------------------------------------------------- 1 | 15 | 16 | 21 | 22 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 42 | 46 | 47 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 68 | 75 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /App.xaml.cs: -------------------------------------------------------------------------------- 1 | using DarkMode_2.Services; 2 | using DarkMode_2.ViewModels; 3 | using DarkMOde_2.Services; 4 | using DarkMOde_2.Services.Contracts; 5 | using log4net.Config; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.DependencyInjection; 8 | using Microsoft.Extensions.Hosting; 9 | using System; 10 | using System.IO; 11 | using System.Reflection; 12 | using System.Windows; 13 | using Wpf.Ui.Mvvm.Contracts; 14 | using Wpf.Ui.Mvvm.Services; 15 | using WPFLocalizeExtension.Engine; 16 | 17 | 18 | namespace DarkMode_2; 19 | 20 | /// 21 | /// App.xaml 的交互逻辑 22 | /// 23 | public partial class App 24 | { 25 | private static readonly IHost _host = Host 26 | .CreateDefaultBuilder() 27 | .ConfigureAppConfiguration(c => { c.SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location)); }) 28 | .ConfigureServices((context, services) => 29 | { 30 | // 注册程序实例 31 | services.AddHostedService(); 32 | 33 | // 注册主题实例 34 | services.AddSingleton(); 35 | 36 | // 注册任务栏操作实例 37 | services.AddSingleton(); 38 | 39 | // 注册弹窗实例 40 | services.AddSingleton(); 41 | 42 | // 注册命令行参数实例 43 | //services.AddSingleton(); 44 | 45 | // 注册对话服务实例 46 | services.AddSingleton(); 47 | 48 | // 窗口页面解析 49 | services.AddSingleton(); 50 | services.AddSingleton(); 51 | 52 | // 注册Navigation实例 53 | services.AddSingleton(); 54 | 55 | // 注册启动窗口实例 56 | services.AddScoped(); 57 | services.AddScoped(); 58 | 59 | // 注册Page页面实例 60 | services.AddScoped(); 61 | services.AddScoped(); 62 | services.AddScoped(); 63 | services.AddScoped(); 64 | services.AddScoped(); 65 | services.AddScoped(); 66 | 67 | services.AddScoped(); 68 | services.AddScoped(); 69 | services.AddScoped(); 70 | services.AddScoped(); 71 | services.AddScoped(); 72 | services.AddScoped(); 73 | 74 | // 注册窗口及模型实例 75 | services.AddTransient(); 76 | services.AddTransient(); 77 | 78 | services.AddTransient(); 79 | services.AddTransient(); 80 | 81 | services.AddTransient(); 82 | services.AddTransient(); 83 | }).Build(); 84 | 85 | 86 | private async void OnStartup(object sender, StartupEventArgs e) 87 | { 88 | XmlConfigurator.Configure(); 89 | string logDirectory = Path.Combine(Path.GetTempPath(), "DarkMode2", "logs"); 90 | 91 | if (!Directory.Exists(logDirectory)) 92 | { 93 | Directory.CreateDirectory(logDirectory); 94 | } 95 | //启动程序入口 96 | 97 | await _host.StartAsync(); 98 | 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Views/DownloadWindow.xaml: -------------------------------------------------------------------------------- 1 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 38 | 39 | 40 | 41 | 42 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /Views/Diagnostics/DebuggingLayerView.xaml.cs: -------------------------------------------------------------------------------- 1 | // This Source Code is partially based on the source code provided by the .NET Foundation. 2 | // This Source Code Form is subject to the terms of the MIT License. 3 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 4 | // Copyright (C) Leszek Pomianowski. 5 | // All Rights Reserved. 6 | 7 | #nullable enable 8 | 9 | using System.Windows; 10 | using System.Windows.Automation.Peers; 11 | using System.Windows.Controls; 12 | using System.Windows.Input; 13 | 14 | namespace DarkMode_2.Views.Diagnostics; 15 | 16 | public partial class DebuggingLayerView : UserControl 17 | { 18 | private bool _isFocusIndicatorEnabled; 19 | 20 | public DebuggingLayerView() 21 | { 22 | InitializeComponent(); 23 | Loaded += OnLoaded; 24 | } 25 | 26 | public Rect? FocusBounds 27 | { 28 | get => FocusIndicator.IsVisible 29 | ? new Rect(FocusIndicatorTranslateTransform.X, FocusIndicatorTranslateTransform.Y, FocusIndicator.ActualWidth, FocusIndicator.ActualHeight) 30 | : null; 31 | set 32 | { 33 | if (value is null) 34 | { 35 | FocusIndicator.Visibility = Visibility.Collapsed; 36 | } 37 | else 38 | { 39 | var bounds = value.Value; 40 | FocusIndicator.Visibility = Visibility.Visible; 41 | FocusIndicatorTranslateTransform.X = bounds.X; 42 | FocusIndicatorTranslateTransform.Y = bounds.Y; 43 | FocusIndicator.Width = bounds.Width; 44 | FocusIndicator.Height = bounds.Height; 45 | } 46 | } 47 | } 48 | 49 | public bool IsFocusIndicatorEnabled 50 | { 51 | get => _isFocusIndicatorEnabled; 52 | set 53 | { 54 | _isFocusIndicatorEnabled = value; 55 | if (value) 56 | { 57 | ShowFocusBounds(Keyboard.FocusedElement); 58 | } 59 | else 60 | { 61 | FocusBounds = null; 62 | } 63 | } 64 | } 65 | 66 | private void OnLoaded(object sender, RoutedEventArgs e) 67 | { 68 | var window = Window.GetWindow(this); 69 | if (window is not null) 70 | { 71 | window.GotKeyboardFocus += Window_GotKeyboardFocus; 72 | window.LostKeyboardFocus += Window_LostKeyboardFocus; 73 | } 74 | } 75 | 76 | private void Window_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) 77 | { 78 | FocusBounds = null; 79 | } 80 | 81 | private void Window_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) 82 | { 83 | if (IsFocusIndicatorEnabled 84 | && Keyboard.FocusedElement is UIElement element 85 | && Window.GetWindow(element) is { } window 86 | && window == sender) 87 | { 88 | ShowFocusBounds(element); 89 | } 90 | } 91 | 92 | private void ShowFocusBounds(IInputElement focusedElement) 93 | { 94 | if (Keyboard.FocusedElement is UIElement element) 95 | { 96 | var topLeft = element.TranslatePoint(default, this); 97 | var bottomRight = element.TranslatePoint(new(element.RenderSize.Width, element.RenderSize.Height), this); 98 | FocusBounds = new(topLeft, bottomRight); 99 | FocusIndicatorTextBlock.Text = (focusedElement as FrameworkElement)?.Name is { } name 100 | ? (string.IsNullOrEmpty(name) ? focusedElement.GetType().Name : name) 101 | : focusedElement.GetType().Name; 102 | } 103 | } 104 | 105 | protected override AutomationPeer? OnCreateAutomationPeer() 106 | { 107 | return null; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Views/Pages/Colors.xaml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 22 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /Views/DeveloperModeWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using DarkMode_2.Models; 2 | using DarkMode_2.ViewModels; 3 | using Microsoft.Win32; 4 | //using OpenHardwareMonitor.Hardware; 5 | using System; 6 | using System.Collections; 7 | using System.Configuration.Install; 8 | using System.Runtime.InteropServices; 9 | using System.ServiceProcess; 10 | using System.Threading.Tasks; 11 | using System.Timers; 12 | using System.Windows; 13 | using Windows.Devices.Sensors; 14 | using MessageBox = DarkMode_2.Models.MessageBox; 15 | 16 | namespace DarkMode_2.Views; 17 | 18 | /// 19 | /// DeveloperModeWindow.xaml 的交互逻辑 20 | /// 21 | public partial class DeveloperModeWindow 22 | { 23 | string serviceFilePath = "E:\\Project\\C#\\DarkModeService\\bin\\Debug\\DarkModeService.exe"; 24 | string serviceName = "DarkMode Service"; 25 | public DeveloperModeViewModel ViewModel 26 | { 27 | get; 28 | } 29 | public DeveloperModeWindow(DeveloperModeViewModel viewModel) 30 | { 31 | ViewModel = viewModel; 32 | InitializeComponent(); 33 | 34 | //GPUload.Text = GetGPULoad.GetUsage().ToString(); 35 | } 36 | 37 | private void UiWindow_Loaded(object sender, RoutedEventArgs e) 38 | { 39 | 40 | } 41 | private void Internal_OnClick(object sender, RoutedEventArgs e) 42 | { 43 | 44 | } 45 | private void Dialog_OnClick(object sender, RoutedEventArgs e) 46 | { 47 | 48 | } 49 | private void Message_OnClick(object sender, RoutedEventArgs e) 50 | { 51 | OpenMessageBox("错误发生", "你猜发生了什么错误?"); 52 | } 53 | 54 | private void OpenMessageBox(string title, string content) 55 | { 56 | var messageBox = new Wpf.Ui.Controls.MessageBox(); 57 | 58 | messageBox.ButtonLeftName = "复制内容"; 59 | messageBox.ButtonRightName = "关闭弹窗"; 60 | 61 | messageBox.ButtonLeftClick += MessageBox_LeftButtonClick; 62 | messageBox.ButtonRightClick += MessageBox_RightButtonClick; 63 | 64 | messageBox.Show(title, content); 65 | } 66 | 67 | private void MessageBox_LeftButtonClick(object sender, RoutedEventArgs e) 68 | { 69 | (sender as Wpf.Ui.Controls.MessageBox)?.Close(); 70 | } 71 | 72 | private void MessageBox_RightButtonClick(object sender, RoutedEventArgs e) 73 | { 74 | (sender as Wpf.Ui.Controls.MessageBox)?.Close(); 75 | } 76 | 77 | //发送消息 78 | //声明 API 函数 79 | [DllImport("User32.dll", EntryPoint = "SendMessage")] 80 | private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); 81 | 82 | [DllImport("User32.dll", EntryPoint = "FindWindow")] 83 | private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 84 | 85 | [DllImport("User32.dll", EntryPoint = "FindWindowEx")] 86 | private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); 87 | 88 | //定义消息常数 89 | public const int CUSTOM_MESSAGE = 0X000F;//自定义消息 90 | 91 | 92 | 93 | 94 | private void Button_Click(object sender, RoutedEventArgs e) 95 | { 96 | // TUDO:TEST 97 | DownloadWindow downloadWindow = new DownloadWindow("2.1.2.20230809-Release"); 98 | downloadWindow.ShowDialog(); 99 | 100 | } 101 | 102 | private void InstallService_Click(object sender, RoutedEventArgs e) 103 | { 104 | using (AssemblyInstaller installer = new AssemblyInstaller()) 105 | { 106 | installer.UseNewContext = true; 107 | installer.Path = serviceFilePath; 108 | IDictionary savedState = new Hashtable(); 109 | installer.Install(savedState); 110 | installer.Commit(savedState); 111 | MessageBox.OpenMessageBox("提示","服务安装成功。"); 112 | } 113 | } 114 | private void UnInstallService_Click(object sender, RoutedEventArgs e) 115 | { 116 | using (AssemblyInstaller installer = new AssemblyInstaller()) 117 | { 118 | installer.UseNewContext = true; 119 | installer.Path = serviceFilePath; 120 | installer.Uninstall(null); 121 | MessageBox.OpenMessageBox("提示", "服务卸载成功。"); 122 | } 123 | } 124 | private void StartService_Click(object sender, RoutedEventArgs e) 125 | { 126 | using (ServiceController control = new ServiceController(serviceName)) 127 | { 128 | if (control.Status == ServiceControllerStatus.Stopped) 129 | { 130 | control.Start(); 131 | MessageBox.OpenMessageBox("提示", "服务启动成功。"); 132 | } 133 | } 134 | } 135 | } 136 | 137 | -------------------------------------------------------------------------------- /Views/DeveloperModeWindow.xaml: -------------------------------------------------------------------------------- 1 | 16 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 39 | 40 | 44 | 48 | 49 | 50 | 51 | 57 | 58 | 62 | 66 | 67 | 68 | 69 | 75 | 76 | 80 | 84 | 85 | 86 | 87 | 95 | 105 | 112 | 118 | 124 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /Views/DownloadWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using DarkMode_2.Models; 2 | using DarkMode_2.Models.Interface; 3 | using Microsoft.Toolkit.Uwp.Notifications; 4 | using System; 5 | using System.Diagnostics; 6 | using System.IO; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using System.Windows.Controls; 10 | using Wpf.Ui.Controls.Interfaces; 11 | using MessageBox = DarkMode_2.Models.MessageBox; 12 | 13 | namespace DarkMode_2.Views 14 | { 15 | /// 16 | /// DownloadWindow.xaml 的交互逻辑 17 | /// 18 | public partial class DownloadWindow 19 | { 20 | public Frame RootFrame { get; private set; } 21 | public INavigation RootNavigation { get; private set; } 22 | 23 | private string _version; 24 | 25 | private string url; 26 | 27 | private string downloadPath; 28 | public DownloadWindow(string version) 29 | { 30 | _version = version; 31 | InitializeComponent(); 32 | this.downloadPath = DownloadManager.GetDownloadPath(); 33 | foreach (string d in Directory.GetFileSystemEntries(this.downloadPath)) 34 | { 35 | if (File.Exists(d)) 36 | { 37 | FileInfo fi = new FileInfo(d); 38 | if (fi.Attributes.ToString().IndexOf("ReadOnly") != -1) 39 | fi.Attributes = FileAttributes.Normal; 40 | File.Delete(d); 41 | } 42 | } 43 | } 44 | 45 | bool status = false; 46 | 47 | private void cancel_Click(object sender, RoutedEventArgs e) 48 | { 49 | this.Close(); 50 | } 51 | 52 | private async void confirm_Click(object sender, RoutedEventArgs e) 53 | { 54 | if (!status) 55 | { 56 | DownloadManager download = new DownloadManager(); 57 | download.ProgressChanged += DownloadManager_ProgressChanged; 58 | download.SpeedChanged += DownloadManager_SpeedChanged; 59 | download.DownloadCompleted += DownloadManager_DownloadCompleted; 60 | 61 | progressBar.Visibility = Visibility.Visible; 62 | speed.Visibility = Visibility.Visible; 63 | await download.DownloadFileAsync(url); 64 | } 65 | else 66 | { 67 | foreach (string d in Directory.GetFileSystemEntries(this.downloadPath)) 68 | { 69 | try 70 | { 71 | if (File.Exists(d)) 72 | { 73 | Process.Start(d); 74 | ToastNotificationManagerCompat.Uninstall(); 75 | Application.Current.Shutdown(); 76 | } 77 | }catch (Exception ex) 78 | { 79 | MessageBox.OpenMessageBox(LanguageHandler.GetLocalizedString("DownloadWindow_Error_title"), LanguageHandler.GetLocalizedString("DownloadWindow_Error_content")); 80 | Console.WriteLine(ex.ToString()); 81 | } 82 | 83 | } 84 | } 85 | 86 | } 87 | 88 | private void DownloadManager_DownloadCompleted(string obj) 89 | { 90 | status = true; 91 | confirm.Content = LanguageHandler.GetLocalizedString("DownloadWindow_Install"); 92 | speed.Visibility = Visibility.Hidden; 93 | } 94 | 95 | private void DownloadManager_SpeedChanged(double obj) 96 | { 97 | Dispatcher.Invoke(() => 98 | { 99 | if (obj < 1024) 100 | { 101 | double speedInKBps = obj * 1024; 102 | speed.Text = $"{speedInKBps:F2} KB/s"; 103 | } 104 | else 105 | { 106 | double speedInMBps = obj / 1024; 107 | speed.Text = $"{speedInMBps:F2} MB/s"; 108 | } 109 | }); 110 | } 111 | 112 | private void DownloadManager_ProgressChanged(double obj) 113 | { 114 | Dispatcher.Invoke(() => 115 | { 116 | progressBar.Value = obj * 100; 117 | }); 118 | } 119 | 120 | private async void UiWindow_Loaded(object sender, RoutedEventArgs e) 121 | { 122 | NewVersion newVersion = new NewVersion(); 123 | confirm.IsEnabled = false; 124 | IUpdate.Channel channel = newVersion.UpdateChannel(); 125 | string content = await newVersion.UpdateJsonInterpreter(null, IUpdate.type.Content, channel); 126 | 127 | 128 | string res = await newVersion.GetJson(channel); 129 | 130 | _version = await newVersion.UpdateJsonInterpreter(res, IUpdate.type.TagName, null); 131 | version_name.Text = LanguageHandler.GetLocalizedString("DownloadWindow_Title") + _version; 132 | url = await newVersion.UpdateJsonInterpreter(res, IUpdate.type.DownloadUrl, channel); 133 | confirm.IsEnabled = true; 134 | load_progress.Visibility = Visibility.Collapsed; 135 | update_scroll.Visibility = Visibility.Visible; 136 | update_content.Text = content; 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /Views/SettingsWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using System.Windows; 4 | using System.Windows.Controls; 5 | using Wpf.Ui.Common; 6 | using Wpf.Ui.Controls.Interfaces; 7 | using DarkMode_2.ViewModels; 8 | using Wpf.Ui.Mvvm.Contracts; 9 | using Wpf.Ui.TaskBar; 10 | using Microsoft.Win32; 11 | using Wpf.Ui.Appearance; 12 | using DarkMode_2.Models; 13 | using log4net; 14 | using System.Windows.Data; 15 | using System.Globalization; 16 | using DarkMOde_2.Services.Contracts; 17 | 18 | namespace DarkMode_2.Views; 19 | 20 | /// 21 | /// SettingsWindow.xaml 的交互逻辑 22 | /// 23 | public partial class SettingsWindow : INavigationWindow 24 | { 25 | private static readonly ILog log = LogManager.GetLogger(typeof(SettingsWindow)); 26 | private bool _initialized = false; 27 | 28 | private readonly IThemeService _themeService; 29 | 30 | private readonly ITaskBarService _taskBarService; 31 | 32 | private readonly ITestWindowService _testWindowService; 33 | 34 | 35 | public SettingsViewModel ViewModel 36 | { 37 | get; 38 | } 39 | public SettingsWindow(SettingsViewModel viewModel, IThemeService themeServices, ITestWindowService testWindowService, INavigationService navigationService, IPageService pageService, IThemeService themeService, ITaskBarService taskBarService, ISnackbarService snackbarService, IDialogService dialogService) 40 | { 41 | log.Info("DarkMode 正在运行"); 42 | ViewModel = viewModel; 43 | DataContext = this; 44 | _themeService = themeServices; 45 | _taskBarService = taskBarService; 46 | _testWindowService = testWindowService; 47 | InitializeComponent(); 48 | SetPageService(pageService); 49 | navigationService.SetNavigationControl(RootNavigation); 50 | snackbarService.SetSnackbarControl(RootSnackbar); 51 | dialogService.SetDialogControl(RootDialog); 52 | 53 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", false); 54 | if (key.GetValue("ColorMode").ToString() == "Light") 55 | { 56 | _themeService.SetTheme(ThemeType.Light); 57 | } 58 | else if (key.GetValue("ColorMode").ToString() == "Dark") 59 | { 60 | _themeService.SetTheme(ThemeType.Dark); 61 | }else if (key.GetValue("ColorMode").ToString() == "Auto") 62 | { 63 | if(DetermineSystemColorMode.GetState() == "light") 64 | { 65 | _themeService.SetTheme(ThemeType.Light); 66 | } 67 | else if(DetermineSystemColorMode.GetState() == "dark") 68 | { 69 | _themeService.SetTheme(ThemeType.Dark); 70 | } 71 | } 72 | 73 | //主题跟随系统定时器 74 | var timerGetTime = new System.Windows.Forms.Timer(); 75 | //设置定时器属性 76 | timerGetTime.Tick += new EventHandler(ChangeMonitor); 77 | timerGetTime.Interval = 100; 78 | timerGetTime.Enabled = true; 79 | //开启定时器 80 | timerGetTime.Start(); 81 | } 82 | 83 | public void ChangeMonitor(Object myObject, EventArgs myEventArgs) 84 | { 85 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", false); 86 | if (key.GetValue("ColorMode").ToString() == "Auto") 87 | { 88 | if (DetermineSystemColorMode.GetState() == "dark") 89 | { 90 | _themeService.SetTheme(ThemeType.Dark); 91 | } 92 | else if (DetermineSystemColorMode.GetState() == "light") 93 | { 94 | _themeService.SetTheme(ThemeType.Light); 95 | } 96 | } 97 | key.Close(); 98 | 99 | } 100 | public Frame GetFrame() 101 | => RootFrame; 102 | 103 | public INavigation GetNavigation() 104 | => RootNavigation; 105 | 106 | public bool Navigate(Type pageType) 107 | => RootNavigation.Navigate(pageType); 108 | 109 | public void SetPageService(IPageService pageService) 110 | => RootNavigation.PageService = pageService; 111 | 112 | public void ShowWindow() 113 | => Show(); 114 | 115 | public void CloseWindow() 116 | => Close(); 117 | 118 | 119 | private void RootNavigation_OnNavigated(INavigation sender, RoutedNavigationEventArgs e) 120 | { 121 | RootFrame.Margin = new Thickness( 122 | left: 0, 123 | top: sender?.Current?.PageTag == "settimes" ? -69 : 0, 124 | right: 0, 125 | bottom: 0); 126 | } 127 | 128 | private void UiWindow_Loaded(object sender, RoutedEventArgs e) 129 | { 130 | /// 131 | /// 打开启动窗口的界面 132 | /// 133 | if (_initialized) 134 | return; 135 | 136 | _initialized = true; 137 | 138 | RootMainGrid.Visibility = Visibility.Collapsed; 139 | 140 | _taskBarService.SetState(this, TaskBarProgressState.Indeterminate); 141 | 142 | Task.Run(async () => 143 | { 144 | await Task.Delay(100); 145 | 146 | await Dispatcher.InvokeAsync(() => 147 | { 148 | RootMainGrid.Visibility = Visibility.Visible; 149 | 150 | Navigate(typeof(Pages.SetTimes)); //页面 151 | 152 | _taskBarService.SetState(this, TaskBarProgressState.None); 153 | }); 154 | }); 155 | } 156 | 157 | } 158 | -------------------------------------------------------------------------------- /Views/Pages/SetDIY.xaml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 23 | 24 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 41 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 65 | 73 | 77 | 78 | 86 | 90 | 91 | 95 | 103 | 107 | 108 | 115 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /Views/Pages/SetWallpaper.xaml.cs: -------------------------------------------------------------------------------- 1 | using DarkMode_2.Models; 2 | using Microsoft.Win32; 3 | using System.Text.RegularExpressions; 4 | using System.Windows.Forms; 5 | using Wpf.Ui.Common; 6 | using Wpf.Ui.Mvvm.Contracts; 7 | using OpenFileDialog = System.Windows.Forms.OpenFileDialog; 8 | 9 | namespace DarkMode_2.Views.Pages; 10 | 11 | /// 12 | /// SetWallpaper.xaml 的交互逻辑 13 | /// 14 | public partial class SetWallpaper 15 | { 16 | private readonly ISnackbarService _snackbarService; 17 | public SetWallpaper(ISnackbarService snackbarService) 18 | { 19 | _snackbarService = snackbarService; 20 | InitializeComponent(); 21 | 22 | //设置初始化 23 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 24 | LightBox1.Text = key.GetValue("NativeLight").ToString(); 25 | DarkBox1.Text = key.GetValue("NativeDark").ToString(); 26 | LightBox2.Text = key.GetValue("WeLight").ToString(); 27 | DarkBox2.Text = key.GetValue("WeDark").ToString(); 28 | WePath.Text = key.GetValue("WeInstallPath").ToString(); 29 | key.Close(); 30 | 31 | } 32 | 33 | private void BrowseButton1_Click(object sender, System.Windows.RoutedEventArgs e) 34 | { 35 | OpenFileDialog dialog = new(); 36 | dialog.Multiselect = false; 37 | dialog.Title = LanguageHandler.GetLocalizedString("SetWallpaperPage_Tip1"); 38 | dialog.Filter = LanguageHandler.GetLocalizedString("SetWallpaperPage_Tip2"); 39 | if (dialog.ShowDialog() == DialogResult.OK) 40 | { 41 | LightBox1.Text = dialog.FileName; 42 | } 43 | } 44 | 45 | private void BrowseButton2_Click(object sender, System.Windows.RoutedEventArgs e) 46 | { 47 | OpenFileDialog dialog = new(); 48 | dialog.Multiselect = false; 49 | dialog.Title = LanguageHandler.GetLocalizedString("SetWallpaperPage_Tip1"); 50 | dialog.Filter = LanguageHandler.GetLocalizedString("SetWallpaperPage_Tip2"); 51 | if (dialog.ShowDialog() == DialogResult.OK) 52 | { 53 | DarkBox1.Text = dialog.FileName; 54 | } 55 | } 56 | 57 | private void Save1_Click(object sender, System.Windows.RoutedEventArgs e) 58 | { 59 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 60 | key.SetValue("NativeLight",LightBox1.Text); 61 | key.SetValue("NativeDark", DarkBox1.Text); 62 | key.Close(); 63 | } 64 | 65 | private void BrowseButton3_Click(object sender, System.Windows.RoutedEventArgs e) 66 | { 67 | OpenFileDialog dialog = new(); 68 | dialog.Multiselect = false; 69 | dialog.Title = LanguageHandler.GetLocalizedString("SetWallpaperPage_Tip3"); 70 | dialog.Filter = LanguageHandler.GetLocalizedString("SetWallpaperPage_Tip4"); 71 | if (dialog.ShowDialog() == DialogResult.OK) 72 | { 73 | LightBox2.Text = dialog.FileName; 74 | } 75 | } 76 | 77 | private void BrowseButton4_Click(object sender, System.Windows.RoutedEventArgs e) 78 | { 79 | OpenFileDialog dialog = new(); 80 | dialog.Multiselect = false; 81 | dialog.Title = LanguageHandler.GetLocalizedString("SetWallpaperPage_Tip3"); 82 | dialog.Filter = LanguageHandler.GetLocalizedString("SetWallpaperPage_Tip4"); 83 | if (dialog.ShowDialog() == DialogResult.OK) 84 | { 85 | DarkBox2.Text = dialog.FileName; 86 | } 87 | } 88 | 89 | private void Save2_Click(object sender, System.Windows.RoutedEventArgs e) 90 | { 91 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 92 | key.SetValue("WeLight", LightBox2.Text); 93 | key.SetValue("WeDark", DarkBox2.Text); 94 | key.SetValue("WeInstallPath", WePath.Text); 95 | key.Close(); 96 | } 97 | 98 | private void AutoButton_Click(object sender, System.Windows.RoutedEventArgs e) 99 | { 100 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\WallpaperEngine", false); 101 | try 102 | { 103 | string installPath32 = key.GetValue("installPath").ToString(); 104 | string installPath64; 105 | if(installPath32 != "") 106 | { 107 | installPath64 = Regex.Match(installPath32, @"((?!\\wallpaper32.exe).)*").ToString(); 108 | WePath.Text = installPath64 + "\\wallpaper64.exe"; 109 | } 110 | } 111 | catch 112 | { 113 | OpenSnackbar(LanguageHandler.GetLocalizedString("SetWallpaperPage_Tip5"), LanguageHandler.GetLocalizedString("SetWallpaperPage_Tip6")); 114 | } 115 | } 116 | 117 | private void ManualButton_Click(object sender, System.Windows.RoutedEventArgs e) 118 | { 119 | OpenFileDialog dialog = new(); 120 | dialog.Multiselect = false; 121 | dialog.Title = LanguageHandler.GetLocalizedString("SetWallpaperPage_Tip7"); 122 | dialog.Filter = LanguageHandler.GetLocalizedString("SetWallpaperPage_Tip8s"); 123 | if (dialog.ShowDialog() == DialogResult.OK) 124 | { 125 | WePath.Text = dialog.FileName; 126 | } 127 | } 128 | 129 | private void OpenSnackbar(string title, string connect) 130 | { 131 | _snackbarService.Show(title, connect, SymbolRegular.FoodCake24); 132 | } 133 | 134 | private void DeleteButton1_Click(object sender, System.Windows.RoutedEventArgs e) 135 | { 136 | LightBox1.Text = null; 137 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 138 | key.SetValue("NativeLight", ""); 139 | key.Close(); 140 | } 141 | 142 | private void DeleteButton2_Click(object sender, System.Windows.RoutedEventArgs e) 143 | { 144 | DarkBox1.Text = null; 145 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 146 | key.SetValue("NativeDark", ""); 147 | key.Close(); 148 | } 149 | 150 | private void DeleteButton3_Click(object sender, System.Windows.RoutedEventArgs e) 151 | { 152 | LightBox2.Text = null; 153 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 154 | key.SetValue("WeLight", ""); 155 | key.Close(); 156 | } 157 | 158 | private void DeleteButton4_Click(object sender, System.Windows.RoutedEventArgs e) 159 | { 160 | DarkBox2.Text = null; 161 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 162 | key.SetValue("WeDark", ""); 163 | key.Close(); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /Models/RegistryInit.cs: -------------------------------------------------------------------------------- 1 | using log4net; 2 | using Microsoft.Win32; 3 | using System; 4 | 5 | namespace DarkMode_2.Models 6 | { 7 | public static class RegistryInit 8 | { 9 | private static readonly ILog log = LogManager.GetLogger(typeof(RegistryInit)); 10 | public const string RegistryKeyPath = @"Software\DarkMode2"; 11 | public const string LanguageValueName = "Language"; 12 | public static void RegistryInitialization() 13 | { 14 | try 15 | { 16 | RegistryKey pan; 17 | RegistryKey key; 18 | pan = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2"); 19 | 20 | if (pan == null) 21 | { 22 | key = Registry.CurrentUser.CreateSubKey(@"Software\DarkMode2"); 23 | key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 24 | //软件安装路径 25 | key.SetValue("DarkModeInstallPath", AppDomain.CurrentDomain.SetupInformation.ApplicationBase); 26 | //开机自启 27 | key.SetValue("DarkMode2", "false"); 28 | //系统颜色初始化 29 | key.SetValue("IsLight", "false"); 30 | //浅色模式开始时间 31 | key.SetValue("startTime", "08:00"); 32 | //浅色模式结束时间 33 | key.SetValue("endTime", "19:00"); 34 | //软件语言 35 | key.SetValue("Language", "zh-CN"); 36 | //日出日落模式 37 | key.SetValue("SunRiseSet", "false"); 38 | //感光模式 39 | key.SetValue("PhotosensitiveMode", "false"); 40 | //自动更新日出日落时间 41 | key.SetValue("AutoUpdateTime", "false"); 42 | //消息通知 43 | key.SetValue("Notification", "true"); 44 | //托盘栏图标 45 | key.SetValue("TrayBar", "true"); 46 | //软件主题色 47 | key.SetValue("ColorMode", "Auto"); 48 | //软件自动更新 49 | key.SetValue("AutoUpdate", "false"); 50 | //原生壁纸 51 | key.SetValue("NativeLight", ""); 52 | key.SetValue("NativeDark", ""); 53 | //Wallpaper Engine壁纸 54 | key.SetValue("WeLight", ""); 55 | key.SetValue("WeDark", ""); 56 | //更新渠道 57 | key.SetValue("UpdateChannels", "Auto"); 58 | //鼠标主题 59 | key.SetValue("SwitchMouse", "false"); 60 | key.SetValue("MouseMode", "Light"); 61 | key.SetValue("LightMouse", "Light"); 62 | key.SetValue("DarkMouse", "Light"); 63 | //游戏模式 64 | key.SetValue("GameMode", "false"); 65 | //Wallpaper Engine安装路径 66 | key.SetValue("WeInstallPath", ""); 67 | //版本公告 68 | key.SetValue("AppVersion", VersionControl.Version()); 69 | key.Close(); 70 | } 71 | } 72 | catch (Exception ex) 73 | { 74 | log.Error("注册表初始化失败:"+ex); 75 | } 76 | } 77 | 78 | public static void RegistryReset() 79 | { 80 | try 81 | { 82 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 83 | //软件安装路径 84 | key.SetValue("DarkModeInstallPath", AppDomain.CurrentDomain.SetupInformation.ApplicationBase); 85 | //开机自启 86 | key.SetValue("DarkMode2", "false"); 87 | //系统颜色初始化 88 | key.SetValue("IsLight", "false"); 89 | //浅色模式开始时间 90 | key.SetValue("startTime", "08:00"); 91 | //浅色模式结束时间 92 | key.SetValue("endTime", "19:00"); 93 | //软件语言 94 | key.SetValue("Language", "zh-CN"); 95 | //日出日落模式 96 | key.SetValue("SunRiseSet", "false"); 97 | //感光模式 98 | key.SetValue("PhotosensitiveMode", "false"); 99 | //自动更新日出日落时间 100 | key.SetValue("AutoUpdateTime", "false"); 101 | //消息通知 102 | key.SetValue("Notification", "true"); 103 | //托盘栏图标 104 | key.SetValue("TrayBar", "true"); 105 | //软件主题色 106 | key.SetValue("ColorMode", "Auto"); 107 | //软件自动更新 108 | key.SetValue("AutoUpdate", "false"); 109 | //原生壁纸 110 | key.SetValue("NativeLight", ""); 111 | key.SetValue("NativeDark", ""); 112 | //Wallpaper Engine壁纸 113 | key.SetValue("WeLight", ""); 114 | key.SetValue("WeDark", ""); 115 | //更新渠道 116 | key.SetValue("UpdateChannels", "Auto"); 117 | //鼠标主题 118 | key.SetValue("SwitchMouse", "false"); 119 | key.SetValue("MouseMode", "Light"); 120 | key.SetValue("LightMouse", "Light"); 121 | key.SetValue("DarkMouse", "Light"); 122 | //游戏模式 123 | key.SetValue("GameMode", "false"); 124 | //Wallpaper Engine安装路径 125 | key.SetValue("WeInstallPath", ""); 126 | //版本公告 127 | key.SetValue("AppVersion", VersionControl.Version()); 128 | key.Close(); 129 | 130 | } 131 | catch (Exception ex) 132 | { 133 | log.Error("注册表重置失败:" + ex); 134 | } 135 | } 136 | 137 | public static void InsertRegistery(string key, string value) 138 | { 139 | try 140 | { 141 | RegistryKey appKey = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 142 | appKey.SetValue(key, value); 143 | } 144 | catch(Exception ex) 145 | { 146 | log.Error("注册表操作失败(InsertRegistery):" + ex); 147 | } 148 | } 149 | 150 | public static string GetSavedLanguageCode() 151 | { 152 | using (RegistryKey key = Registry.CurrentUser.OpenSubKey(RegistryKeyPath)) 153 | { 154 | return key?.GetValue(LanguageValueName) as string; 155 | } 156 | } 157 | 158 | public static void SaveLanguageCode(string languageCode) 159 | { 160 | using (RegistryKey key = Registry.CurrentUser.CreateSubKey(RegistryKeyPath)) 161 | { 162 | key?.SetValue(LanguageValueName, languageCode); 163 | } 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /ViewModels/ColorsViewModel.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | #nullable enable 7 | 8 | using System.Collections.Generic; 9 | using System.Windows; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using Microsoft.Toolkit.Mvvm.ComponentModel; 13 | using Microsoft.Toolkit.Mvvm.Input; 14 | using Wpf.Ui.Appearance; 15 | using Wpf.Ui.Common.Interfaces; 16 | using DarkMode_2.Models.Colors; 17 | 18 | namespace DarkMode_2.ViewModels; 19 | 20 | public class ColorsViewModel : ObservableObject, INavigationAware 21 | { 22 | private bool _dataInitialized = false; 23 | 24 | private readonly string[] _paletteResources = 25 | { 26 | "PalettePrimaryBrush", 27 | "PaletteRedBrush", 28 | "PalettePinkBrush", 29 | "PalettePurpleBrush", 30 | "PaletteDeepPurpleBrush", 31 | "PaletteIndigoBrush", 32 | "PaletteBlueBrush", 33 | "PaletteLightBlueBrush", 34 | "PaletteCyanBrush", 35 | "PaletteTealBrush", 36 | "PaletteGreenBrush", 37 | "PaletteLightGreenBrush", 38 | "PaletteLimeBrush", 39 | "PaletteYellowBrush", 40 | "PaletteAmberBrush", 41 | "PaletteOrangeBrush", 42 | "PaletteDeepOrangeBrush", 43 | "PaletteBrownBrush", 44 | "PaletteGreyBrush", 45 | "PaletteBlueGreyBrush" 46 | }; 47 | 48 | private readonly string[] _themeResources = 49 | { 50 | "SystemAccentColorPrimaryBrush", 51 | "SystemAccentColorSecondaryBrush", 52 | "SystemAccentColorTertiaryBrush", 53 | 54 | "ControlElevationBorderBrush", 55 | "CircleElevationBorderBrush", 56 | 57 | "AccentControlElevationBorderBrush", 58 | 59 | "TextFillColorPrimaryBrush", 60 | "TextFillColorSecondaryBrush", 61 | "TextFillColorTertiaryBrush", 62 | "TextFillColorDisabledBrush", 63 | "TextFillColorInverseBrush", 64 | 65 | "AccentTextFillColorDisabledBrush", 66 | "TextOnAccentFillColorSelectedTextBrush", 67 | 68 | "ControlFillColorDefaultBrush", 69 | "ControlFillColorSecondaryBrush", 70 | "ControlFillColorTertiaryBrush", 71 | "ControlFillColorDisabledBrush", 72 | "ControlSolidFillColorDefaultBrush", 73 | "AccentFillColorDisabledBrush", 74 | "MenuBorderColorDefaultBrush", 75 | 76 | "SystemFillColorSuccessBrush", 77 | "SystemFillColorCautionBrush", 78 | "SystemFillColorCriticalBrush", 79 | "SystemFillColorNeutralBrush", 80 | "SystemFillColorSolidNeutralBrush", 81 | "SystemFillColorAttentionBackgroundBrush", 82 | "SystemFillColorSuccessBackgroundBrush", 83 | "SystemFillColorCautionBackgroundBrush", 84 | "SystemFillColorCriticalBackgroundBrush", 85 | "SystemFillColorNeutralBackgroundBrush", 86 | "SystemFillColorSolidAttentionBackgroundBrush", 87 | "SystemFillColorSolidNeutralBackgroundBrush" 88 | }; 89 | 90 | private IEnumerable _paletteBrushes = new Pa__one[] { }; 91 | 92 | private IEnumerable _themeBrushes = new Pa__one[] { }; 93 | 94 | private int _columns = 8; 95 | 96 | 97 | public IEnumerable PaletteBrushes 98 | { 99 | get => _paletteBrushes; 100 | set => SetProperty(ref _paletteBrushes, value); 101 | } 102 | 103 | public IEnumerable ThemeBrushes 104 | { 105 | get => _themeBrushes; 106 | set => SetProperty(ref _themeBrushes, value); 107 | } 108 | 109 | public int Columns 110 | { 111 | get => _columns; 112 | set => SetProperty(ref _columns, value); 113 | } 114 | 115 | 116 | #pragma warning disable CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。 117 | public ColorsViewModel() 118 | #pragma warning restore CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。 119 | { 120 | Theme.Changed += OnThemeChanged; 121 | } 122 | 123 | public void OnNavigatedTo() 124 | { 125 | if (!_dataInitialized) 126 | InitializeData(); 127 | } 128 | 129 | public void OnNavigatedFrom() 130 | { 131 | } 132 | 133 | private void OnThemeChanged(ThemeType currentTheme, Color systemAccent) 134 | { 135 | FillTheme(); 136 | } 137 | 138 | private void OnCopyColor(string parameter) 139 | { 140 | System.Diagnostics.Debug.WriteLine($"Copy: {parameter}"); 141 | } 142 | 143 | private void InitializeData() 144 | { 145 | _dataInitialized = true; 146 | 147 | FillPalette(); 148 | FillTheme(); 149 | } 150 | 151 | private void FillPalette() 152 | { 153 | var pallete = new List { }; 154 | 155 | foreach (var singleBrushKey in _paletteResources) 156 | { 157 | var singleBrush = Application.Current.Resources[singleBrushKey] as Brush; 158 | 159 | if (singleBrush == null) 160 | continue; 161 | 162 | string description; 163 | 164 | if (singleBrush is SolidColorBrush solidColorBrush) 165 | description = 166 | $"R: {solidColorBrush.Color.R}, G: {solidColorBrush.Color.G}, B: {solidColorBrush.Color.B}"; 167 | else 168 | description = "Gradient"; 169 | 170 | pallete.Add(new Pa__one 171 | { 172 | Title = "PALETTE", 173 | Subtitle = description + "\n" + singleBrushKey, 174 | Brush = singleBrush, 175 | BrushKey = singleBrushKey 176 | }); 177 | } 178 | 179 | PaletteBrushes = pallete; 180 | } 181 | 182 | private void FillTheme() 183 | { 184 | var theme = new List { }; 185 | 186 | foreach (var singleBrushKey in _themeResources) 187 | { 188 | var singleBrush = Application.Current.Resources[singleBrushKey] as Brush; 189 | 190 | if (singleBrush == null) 191 | continue; 192 | 193 | string description; 194 | 195 | if (singleBrush is SolidColorBrush solidColorBrush) 196 | description = 197 | $"R: {solidColorBrush.Color.R}, G: {solidColorBrush.Color.G}, B: {solidColorBrush.Color.B}"; 198 | else 199 | description = "Gradient"; 200 | 201 | theme.Add(new Pa__one 202 | { 203 | Title = "THEME", 204 | Subtitle = description + "\n" + singleBrushKey, 205 | Brush = singleBrush, 206 | BrushKey = singleBrushKey 207 | }); 208 | } 209 | 210 | ThemeBrushes = theme; 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /Views/SettingsWindow.xaml: -------------------------------------------------------------------------------- 1 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 41 | 42 | 43 | 44 | 45 | 46 | 49 | 59 | 62 | 63 | 69 | 74 | 79 | 84 | 85 | 86 | 89 | 90 | 95 | 100 | 101 | 102 | 103 | 106 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 124 | 125 | 135 | 136 | 137 | 138 | 141 | 147 | 150 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ![Logo](./docs/dark.jpg) 2 | 3 |

Logo图标创意来源于Emoji表情合成器

4 | 5 | ![Tag](https://img.shields.io/github/tag/Melon-Studio/DarkMode2.svg) 6 | [![img](https://camo.githubusercontent.com/4c5e9973d91f9ac30425d8cdef2fb574b50f64e21cdad202be047f3848021b0a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f666f726b732f4d656c6f6e2d53747564696f2f4461726b4d6f6465323f7374796c653d666c61742d737175617265)](https://github.com/Melon-Studio/DarkMode2/blob/master) 7 | [![img](https://camo.githubusercontent.com/b76728bc1c74684ee31f0be49f10ff005cd400a1ddae507d304be940b2a51412/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f4d656c6f6e2d53747564696f2f4461726b4d6f6465323f7374796c653d666c61742d737175617265)](https://github.com/Melon-Studio/DarkMode2/blob/master) 8 | [![img](https://camo.githubusercontent.com/560c4d1a2d4d97df23b5148747dc88de44f51fdcb25254bb34144a041d7aaa22/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732f4d656c6f6e2d53747564696f2f4461726b4d6f6465323f7374796c653d666c61742d737175617265)](https://github.com/Melon-Studio/DarkMode2/blob/master) 9 | [![img](https://camo.githubusercontent.com/5977bd502d8bba7c7aa9f76c04b1fc95ec64986900044e0c4e07b19ba5b9696f/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f4d656c6f6e2d53747564696f2f4461726b4d6f6465323f7374796c653d666c61742d737175617265)](https://github.com/Melon-Studio/DarkMode2/blob/master) 10 | [![img](https://camo.githubusercontent.com/e9fbca5d0b8195869f2368539ad6eb31d979abd866bb8e4fc3165b5fae627f9a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f4d656c6f6e2d53747564696f2f4461726b4d6f6465323f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/e9fbca5d0b8195869f2368539ad6eb31d979abd866bb8e4fc3165b5fae627f9a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f4d656c6f6e2d53747564696f2f4461726b4d6f6465323f7374796c653d666c61742d737175617265) 11 | [![img](https://camo.githubusercontent.com/05e612beecc0f77dc26faecb1b367a4323d11713fbc50c9a0904cca36fd24de2/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f64697363757373696f6e732f4d656c6f6e2d53747564696f2f4461726b4d6f6465323f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/05e612beecc0f77dc26faecb1b367a4323d11713fbc50c9a0904cca36fd24de2/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f64697363757373696f6e732f4d656c6f6e2d53747564696f2f4461726b4d6f6465323f7374796c653d666c61742d737175617265) 12 | 13 | 本版本生命周期已经结束,重构版开发中,可以关注仓库了解最新动态:https://github.com/Lunova-Studio/DarkMode2-Refactor 14 | 15 | 简体中文 | [English](./README_EN.md) 16 | 17 | DarkMode2 是一个开源软件,用于自动切换 Windows 10/11 系统的颜色模式。它提供了多项主要功能,包括定时切换、日出日落切换、感光切换、以及基于系统自带壁纸和 Wallpaper Engine 壁纸的切换功能。该软件的目标是解决 Windows 操作系统不支持自动切换颜色模式的问题。此外,它还提供了众多额外的功能。晚上自动切换到深色模式有助于减少眼睛疲劳,防止过多的光线进入眼睛,本软件虽然不能完全解决眼睛疲劳问题,但可以缓解在夜间使用浅色模式带来的眼睛疲劳问题。 18 | 19 | --- 20 | 21 | ## 👁️功能特点 22 | 23 | - **定时切换功能**:基于用户定义的时间表,自动切换系统的颜色模式。 24 | - **日出日落切换功能**:根据用户所在地的日出和日落时间,自动调整颜色模式。 25 | - **感光切换功能**:根据环境光线的变化,自动切换颜色模式。 26 | - **系统原生壁纸切换功能**:根据颜色模式的变化,自动调整设置的系统原生壁纸。 27 | - **Wallpaper Engine 壁纸切换功能**:根据颜色模式的变化,自动调整设置的 Wallpaper Engine 壁纸。 28 | - 更多功能正在开发中,欢迎提交 issues 开发者将视功能需求度添加到实验室中。 29 | 30 | --- 31 | 32 | ## 📀运行环境 33 | 34 | - **操作系统**:Windows 10 / 11 35 | - **系统架构**:x64 / arm64 36 | - **必要框架**:.NET Framework 4.7.2(2.1.2及之前版本),.NET Framework 4.8(2.1.3及之后版本) 37 | 38 | 如果系统没有框架,请选择安装: 39 | [.NET Framework 4.7.2](https://dotnet.microsoft.com/en-us/download/dotnet-framework/thank-you/net472-web-installer) 40 | [.NET Framework 4.8](https://dotnet.microsoft.com/en-us/download/dotnet-framework/thank-you/net48-web-installer) 41 | 42 | --- 43 | 44 | ## 🖱️安装与使用 45 | 46 | 1. [点击此处或者右侧Release](https://github.com/Melon-Studio/DarkMode2/releases)下载最新版本: 47 | 2. 在本地文件夹中,双击运行 DarkMode 2.exe。 48 | 3. 根据需要进行配置,并保存设置。 49 | 4. DarkMode2 会在后台运行,并根据您的设置自动切换颜色模式。 50 | 51 | 推荐通过 Microsoft Store 下载。 52 | 53 | 54 | 55 | 56 | 57 | --- 58 | 59 | ## 😶‍🌫️Q&A 60 | 61 | 1. 报错,程序异常怎么办? 62 | 63 | - *推荐:在 Windows 搜索中搜索`注册表编辑器`,打开后在地址栏输入`计算机\HKEY_CURRENT_USER\Software\DarkMode2`,将这个`DarkMode2`项(文件夹)删除。* 64 | - *部分情况:在设置中心的设置中,点击最下方`重置用户配置`按钮;* 65 | 66 | 67 | 2. 经常弹出UAC弹窗怎么办? 68 | 69 | 如果你在开机时遇到 UAC 弹窗,说明是你开启了自动更新日出日落时间,因为软件在启动时就会自动更新一次日出日落时间,无法避免调用管理员权限;或者是软件在执行切换时修改系统注册表项时触发的UAC弹窗。如果想一劳永逸不在让UAC弹窗显示,你可以禁用 UAC 即可避免此问题。 70 | 71 | 3. 双击打开程序没有反应怎么办? 72 | 73 | 你可以检查你的系统UAC是否拒绝了软件的请求,并尝试关闭UAC启动软件。 74 | --- 75 | 76 | ## 🧷开源协议 77 | 78 | 本开源项目遵循国际 GPLv3 开源许可证,具体内容请详细阅读 [LICENSE](https://github.com/Melon-Studio/DarkMode2/blob/master/LICENSE.txt) 文件。你可以在个人或商业项目中使用 DarkMode2 的全部代码,但是你必须在你的引用项目中包含MIT开源许可证的副本。 79 | 80 | 本项目使用的第三方开源库: 81 | 82 | | 名称 | 作者 | 版权 | 许可 | 83 | | ----------- | --------------- | ------------------------------------------------------------ | ---------- | 84 | | NHotKey.Wpf | Thomas Levesque | Copyright © 2020 Thomas Levesque Licensed under the Apache-2.0 License. | Apache-2.0 | 85 | | WPF-UI | lepo.co | Copyright © 2022 lepo.co Licensed under the MIT License. | MIT | 86 | | Log4net | Apache | Copyright © 2022 Apache Licensed under the Apache-2.0 License. | Apache-2.0 | 87 | | ... | ... | ... | ... | 88 | 89 | 更多第三方开源库请[点击此处](https://github.com/Melon-Studio/DarkMode2/network/dependencies)查看。 90 | 91 | --- 92 | 93 | ## 🥰鸣谢 94 | 95 | DarkMode2 特别感谢 [Microsoft Visual Studio](https://visualstudio.microsoft.com/) 提供强大的开发工具和支持。 96 | 97 | ![IDE](./docs/IDE.svg) 98 | 99 | --- 100 | 101 | ## ⚡为爱发电 102 | 103 | 为了能够持续提供免费的软件服务,我们现在开通了赞助渠道。通过这个渠道,您可以选择自愿为我们的软件项目提供赞助,这种支持对我们来说非常重要。 104 | 105 | 作为开发者,我深知自己的成长和软件的发展离不开您的支持和鼓励。您的赞助将直接用于改进软件的质量、功能和用户体验,以及为我投入更多的时间和精力,开发新的特性和功能。 106 | 107 | 我们郑重承诺,我们的软件将永远免费,永远保持更新,无论是现在还是将来。我们始终相信,开源软件的力量在于共享和协作,通过免费提供软件,我们可以为更多的用户带来实用和高质量的产品。 108 | 109 | 感谢每一位愿意赞助我们的用户,无论您的赞助数额大小,您的支持都将激励我继续努力并改进软件的品质。您的赞助也将成为我们前进的动力和持续发展的保障。 110 | 111 | 赞助渠道:https://afdian.net/a/DarkMode2 112 | 113 | --- 114 | 115 | ## 🎉贡献 116 | 117 | 如果您有兴趣为 DarkMode2 做出贡献,可以按照以下步骤进行: 118 | 119 | 1. Fork该仓库,并克隆你的Forked仓库到本地: 120 | 121 | ``` 122 | git clone https://github.com/YouUserName/DarkMode2.git 123 | ``` 124 | 125 | 2. 在本地进行修改。 126 | 127 | 3. 提交您的修改,并创建一个 Pull Request(PR)。 128 | 129 | 4. 我们将审查您的 PR 并在批准后合并您的贡献。 130 | 131 | 感谢所有为 DarkMode2 做出贡献的开发者! 132 | 133 | 134 | 135 | 136 | 137 | --- 138 | 139 | ## 📶趋势 140 | 141 | 以下是本项目的最近星标趋势图: 142 | 143 | [![Star History Chart](https://api.star-history.com/svg?repos=Melon-Studio/DarkMode,Melon-Studio/DarkMode2&type=Date)](https://star-history.com/#Melon-Studio/DarkMode&Melon-Studio/DarkMode2&Date) 144 | 145 | 请注意,这只是一个示例图表,显示了项目的最近趋势,并不代表实际数据。 146 | 147 | 欢迎关注我们的项目并给予星标!非常感谢您的支持! 148 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd 364 | 365 | 366 | #other 367 | design/ 368 | design/* -------------------------------------------------------------------------------- /Models/Update.cs: -------------------------------------------------------------------------------- 1 | using log4net; 2 | using Microsoft.Win32; 3 | using Newtonsoft.Json.Linq; 4 | using System; 5 | using System.IO; 6 | using System.Net; 7 | using System.Net.Http; 8 | using System.Net.NetworkInformation; 9 | using System.Text; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | 13 | namespace DarkMode_2.Models; 14 | 15 | public class Update 16 | { 17 | public static int state; 18 | public static int useChannel; 19 | public static string need; 20 | public static string githubUrl = "https://api.github.com/repos/Melon-Studio/DarkMode2/releases/latest"; 21 | public static string giteeUrl = "https://gitee.com/api/v5/repos/melon-studio/DarkMode2/releases/latest"; 22 | private readonly HttpClient _httpClient = new HttpClient(); 23 | private static readonly ILog log = LogManager.GetLogger(typeof(Update)); 24 | 25 | private static string username = "6get-xiaofan"; 26 | private static string token = "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"; //此 Token 仅限访问公开库的基本信息 27 | private static string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{token}")); 28 | public int UpdateChannels() 29 | { 30 | RegistryKey appkey = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", false); 31 | string channel = appkey.GetValue("UpdateChannels").ToString(); 32 | if(channel == "Auto") 33 | { 34 | long x = PingIP("github"); 35 | long y = PingIP("gitee"); 36 | 37 | if(x > y) 38 | { 39 | useChannel = 1; 40 | }else if(y > x) 41 | { 42 | useChannel = 0; 43 | }else if(x == y) 44 | { 45 | useChannel = -1; 46 | } 47 | }else if(channel == "Github") 48 | { 49 | useChannel = 0; 50 | }else if(channel == "Gitee") 51 | { 52 | useChannel = 1; 53 | } 54 | return useChannel; 55 | } 56 | public async Task CheckUpdate() 57 | { 58 | int usestate = UpdateChannels(); 59 | string version =VersionControl.Version() + "." + VersionControl.InternalVersion(); 60 | 61 | if(usestate == 0) //github 62 | { 63 | string result = await Get(githubUrl, "github"); 64 | JsonSerialization jsonSerialization = new JsonSerialization(); 65 | 66 | Version oldVersion = new Version(version); 67 | Version newVersion = new Version(jsonSerialization.ParseJson(result).ToString()); 68 | string tagName = jsonSerialization.ParseTagName(result); 69 | 70 | int comparisonResult = oldVersion.CompareTo(newVersion); 71 | 72 | need = CheckVersion(comparisonResult, tagName); 73 | } 74 | else if(usestate == 1) //gitee 75 | { 76 | string result = await Get(giteeUrl, "gitee"); 77 | JsonSerialization jsonSerialization = new JsonSerialization(); 78 | 79 | Version oldVersion = new Version(version); 80 | Version newVersion = new Version(jsonSerialization.ParseJson(result).ToString()); 81 | string tagName = jsonSerialization.ParseTagName(result); 82 | 83 | int comparisonResult = oldVersion.CompareTo(newVersion); 84 | 85 | need = CheckVersion(comparisonResult, tagName); 86 | } 87 | else if(usestate == -1)//连接超时 88 | { 89 | need = LanguageHandler.GetLocalizedString("Update_Tip3"); 90 | } 91 | return need; 92 | } 93 | 94 | private static string CheckVersion(int comparisonResult, string newVersion) 95 | { 96 | string need; 97 | if (comparisonResult < 0) 98 | { 99 | // 需要更新 100 | need = newVersion.ToString(); 101 | } 102 | else if (comparisonResult == 0) 103 | { 104 | // 最新版本 105 | need = LanguageHandler.GetLocalizedString("Update_Tip1"); 106 | } 107 | else 108 | { 109 | // 旧版本比新版本新 110 | need = "不要乱动注册表!难道你在开发吗? :D :D :D"; 111 | } 112 | return need; 113 | } 114 | public long PingIP(string IP) 115 | { 116 | var githubIP = "192.30.255.113"; //GitHub 117 | var giteeIP = "212.64.63.215"; //Gitee 118 | long bRet = 99999; 119 | 120 | if(IP == "github") 121 | { 122 | try 123 | { 124 | Ping pingSend = new Ping(); 125 | PingReply reply = pingSend.Send(githubIP, 1000); 126 | bRet = reply.RoundtripTime; 127 | } 128 | catch (Exception) 129 | { 130 | bRet = 99999; 131 | } 132 | }else if(IP == "gitee") 133 | { 134 | try 135 | { 136 | Ping pingSend = new Ping(); 137 | PingReply reply = pingSend.Send(giteeIP, 1000); 138 | bRet = reply.RoundtripTime; 139 | } 140 | catch (Exception) 141 | { 142 | bRet = 99999; 143 | } 144 | } 145 | return bRet; 146 | } 147 | 148 | public async Task Get(string url, string channel) 149 | { 150 | string result = ""; 151 | if(channel == "github") 152 | { 153 | try 154 | { 155 | _httpClient.DefaultRequestHeaders.Add("User-Agent", "Code Sample Web Client"); 156 | _httpClient.DefaultRequestHeaders.Add("Authorization", $"Basic {credentials}"); 157 | 158 | HttpResponseMessage response = await _httpClient.GetAsync(url); 159 | response.EnsureSuccessStatusCode(); 160 | 161 | string responseContent = await response.Content.ReadAsStringAsync(); 162 | result = responseContent; 163 | } 164 | catch(Exception ex) 165 | { 166 | log.Error(ex); 167 | } 168 | } 169 | else 170 | { 171 | try 172 | { 173 | HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url); 174 | HttpWebResponse resp = (HttpWebResponse)req.GetResponse(); 175 | Stream stream = resp.GetResponseStream(); 176 | //获取内容 177 | using (StreamReader reader = new StreamReader(stream)) 178 | { 179 | result = reader.ReadToEnd(); 180 | } 181 | } 182 | catch (Exception ex) 183 | { 184 | log.Error(ex); 185 | } 186 | finally 187 | { 188 | HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url); 189 | HttpWebResponse resp = (HttpWebResponse)req.GetResponse(); 190 | Stream stream = resp.GetResponseStream(); 191 | stream.Close(); 192 | } 193 | } 194 | 195 | return result; 196 | } 197 | public async Task UpdateContent(string tagName) 198 | { 199 | string apiUrl = $"https://api.github.com/repos/Melon-Studio/DarkMode2/releases/tags/{tagName}"; 200 | try 201 | { 202 | _httpClient.DefaultRequestHeaders.Add("User-Agent", "Code Sample Web Client"); 203 | _httpClient.DefaultRequestHeaders.Add("Authorization", $"Basic {credentials}"); 204 | 205 | HttpResponseMessage response = await _httpClient.GetAsync(apiUrl); 206 | response.EnsureSuccessStatusCode(); 207 | 208 | string responseContent = await response.Content.ReadAsStringAsync(); 209 | JObject releaseInfo = JObject.Parse(responseContent); 210 | string releaseBody = releaseInfo["body"]?.ToString(); 211 | 212 | if (!string.IsNullOrEmpty(releaseBody)) 213 | { 214 | return releaseBody; 215 | } 216 | } 217 | catch(HttpRequestException ex) 218 | { 219 | log.Error(ex); 220 | Console.WriteLine(ex.Message); 221 | } 222 | return LanguageHandler.GetLocalizedString("Update_Tip4"); 223 | } 224 | 225 | } -------------------------------------------------------------------------------- /docs/IDE.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /Models/NewVersion.cs: -------------------------------------------------------------------------------- 1 | using DarkMode_2.Models.Interface; 2 | using log4net; 3 | using Microsoft.Win32; 4 | using Newtonsoft.Json.Linq; 5 | using System; 6 | using System.IO; 7 | using System.Net.Http; 8 | using System.Net.NetworkInformation; 9 | using System.Text.RegularExpressions; 10 | using System.Threading.Tasks; 11 | 12 | namespace DarkMode_2.Models 13 | { 14 | public class NewVersion : IUpdate 15 | { 16 | private static readonly ILog log = LogManager.GetLogger(typeof(NewVersion)); 17 | 18 | private readonly HttpClient _httpClient = new HttpClient(); 19 | 20 | private static IUpdate.Channel _nowChannel; 21 | public IUpdate.Channel PingIp() 22 | { 23 | try 24 | { 25 | Ping ping1 = new Ping(); 26 | PingReply reply1 = ping1.Send(IUpdate.Consts.githubIP, 2000); 27 | double latency1 = reply1.RoundtripTime; 28 | 29 | Ping ping2 = new Ping(); 30 | PingReply reply2 = ping2.Send(IUpdate.Consts.giteeIP, 2000); 31 | double latency2 = reply2.RoundtripTime; 32 | 33 | if (latency1 < latency2) 34 | { 35 | return IUpdate.Channel.Github; 36 | } 37 | else if (latency2 < latency1) 38 | { 39 | return IUpdate.Channel.Gitee; 40 | } 41 | else 42 | { 43 | return IUpdate.Channel.Github; 44 | } 45 | } 46 | catch { } 47 | return IUpdate.Channel.TimeOut; 48 | } 49 | 50 | public IUpdate.Channel UpdateChannel() 51 | { 52 | RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\DarkMode2", true); 53 | string channel = key.GetValue("UpdateChannels").ToString(); 54 | 55 | if (channel == "Auto") 56 | { 57 | _nowChannel = PingIp(); 58 | return _nowChannel; 59 | } 60 | if (channel == "Github") 61 | { 62 | return IUpdate.Channel.Github; 63 | } 64 | if (channel == "Gitee") 65 | { 66 | return IUpdate.Channel.Gitee; 67 | } 68 | 69 | return IUpdate.Channel.Github; 70 | } 71 | 72 | public async Task UpdateJsonInterpreter(string res, IUpdate.type type, IUpdate.Channel? channel) 73 | { 74 | string result = null; 75 | JObject keyValuePairs; 76 | switch (type) 77 | { 78 | case IUpdate.type.TagName://新版本TagName 79 | 80 | keyValuePairs = JObject.Parse(res); 81 | string tag_name = Regex.Match(keyValuePairs["tag_name"]?.ToString(), @"(.*?)(?=-)").Groups[1].Value; 82 | result = tag_name; 83 | break; 84 | 85 | case IUpdate.type.Content://新版本内容 86 | 87 | string apiUrl = null; 88 | switch (channel) 89 | { 90 | case IUpdate.Channel.Github: 91 | apiUrl = IUpdate.Consts.githubUrl; 92 | _httpClient.DefaultRequestHeaders.Add("User-Agent", "Code Sample Web Client"); 93 | _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {IUpdate.Consts.token}"); 94 | break; 95 | case IUpdate.Channel.Gitee: 96 | apiUrl = Path.Combine(IUpdate.Consts.giteeUrl, $"?access_token={IUpdate.Consts.giteeToken}"); 97 | break; 98 | } 99 | 100 | try 101 | { 102 | HttpResponseMessage response = await _httpClient.GetAsync(apiUrl); 103 | response.EnsureSuccessStatusCode(); 104 | 105 | string responseContent = await response.Content.ReadAsStringAsync(); 106 | JObject releaseInfo = JObject.Parse(responseContent); 107 | string releaseBody = releaseInfo["body"]?.ToString(); 108 | 109 | if (!string.IsNullOrEmpty(releaseBody)) 110 | { 111 | result = releaseBody; 112 | } 113 | else 114 | { 115 | result = LanguageHandler.GetLocalizedString("Update_Tip4"); 116 | } 117 | } 118 | catch (HttpRequestException ex) 119 | { 120 | log.Error(ex); 121 | Console.WriteLine(ex.Message); 122 | } 123 | break; 124 | 125 | case IUpdate.type.DownloadUrl: //下载地址 126 | 127 | keyValuePairs = JObject.Parse(res); 128 | Console.WriteLine(keyValuePairs); 129 | result = keyValuePairs["assets"][0]["browser_download_url"].ToString(); 130 | break; 131 | 132 | case IUpdate.type.Date: //发布日期 133 | 134 | keyValuePairs = JObject.Parse(res); 135 | result = Regex.Replace(keyValuePairs["created_at"].ToString(), @"(.+(?= T))", ""); 136 | break; 137 | } 138 | return result; 139 | } 140 | 141 | public string UpdateVersionCompared(Version OldV, Version NewV) 142 | { 143 | int comparisonResult = OldV.CompareTo(NewV); 144 | string need; 145 | if (comparisonResult < 0) 146 | { 147 | // 需要更新 148 | need = NewV.ToString(); 149 | } 150 | else if (comparisonResult == 0) 151 | { 152 | // 最新版本 153 | need = LanguageHandler.GetLocalizedString("Update_Tip1"); 154 | } 155 | else 156 | { 157 | // 旧版本比新版本新 158 | need = "不要乱动注册表!难道你在开发吗? :D :D :D"; 159 | } 160 | return need; 161 | } 162 | 163 | public async Task GetJson(IUpdate.Channel channel) 164 | { 165 | switch (channel) 166 | { 167 | case IUpdate.Channel.Github: 168 | try 169 | { 170 | 171 | _httpClient.DefaultRequestHeaders.Add("User-Agent", "Code Sample Web Client"); 172 | _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {IUpdate.Consts.token}"); 173 | 174 | HttpResponseMessage response = await _httpClient.GetAsync(IUpdate.Consts.githubUrl); 175 | response.EnsureSuccessStatusCode(); 176 | 177 | string responseContent = await response.Content.ReadAsStringAsync(); 178 | 179 | if (!string.IsNullOrEmpty(responseContent)) 180 | { 181 | return responseContent; 182 | } 183 | } 184 | catch 185 | { 186 | return "error"; 187 | } 188 | break; 189 | 190 | case IUpdate.Channel.Gitee: 191 | string apiUrl = null; 192 | apiUrl = Path.Combine(IUpdate.Consts.giteeUrl, $"?access_token={IUpdate.Consts.giteeToken}"); 193 | try 194 | { 195 | HttpResponseMessage response = await _httpClient.GetAsync(apiUrl); 196 | response.EnsureSuccessStatusCode(); 197 | string responseContent = await response.Content.ReadAsStringAsync(); 198 | if (!string.IsNullOrEmpty(responseContent)) 199 | { 200 | return responseContent; 201 | } 202 | } 203 | catch 204 | { 205 | return "error"; 206 | } 207 | break; 208 | 209 | case IUpdate.Channel.TimeOut: 210 | return "error"; 211 | } 212 | return "error"; 213 | } 214 | 215 | public async Task CheckUpdate() 216 | { 217 | string res = await this.GetJson(this.UpdateChannel()); 218 | if(res == "error") 219 | { 220 | return LanguageHandler.GetLocalizedString("Update_Tip3"); 221 | } 222 | Version newVersion =new Version(await this.UpdateJsonInterpreter(res, IUpdate.type.TagName, _nowChannel)); 223 | Console.WriteLine(VersionControl.Version() + "." + VersionControl.InternalVersion()); 224 | Version oldVersion = new Version(VersionControl.Version()+"."+VersionControl.InternalVersion()); 225 | return this.UpdateVersionCompared(oldVersion, newVersion); 226 | } 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /Views/Pages/SetSetting.xaml: -------------------------------------------------------------------------------- 1 | 21 | 22 | 27 | 28 | 29 | 30 | 31 | 35 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 51 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 67 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 83 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 99 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 115 | 119 | 120 | 121 | 126 | 127 | 128 | 129 | 130 | 131 | 135 | 139 | 140 | 141 | 146 | 147 | 148 | 149 | 150 | 151 | 155 | 159 | 160 | 161 | 166 | 167 | 168 | 174 | 175 | 179 | 183 | 184 | 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | # ![Logo](./docs/dark.jpg) 2 | 3 |

The idea of Logo comes from Emoji fusion device

4 | 5 | ![Tag](https://img.shields.io/github/tag/Melon-Studio/DarkMode2.svg) 6 | [![img](https://camo.githubusercontent.com/4c5e9973d91f9ac30425d8cdef2fb574b50f64e21cdad202be047f3848021b0a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f666f726b732f4d656c6f6e2d53747564696f2f4461726b4d6f6465323f7374796c653d666c61742d737175617265)](https://github.com/Melon-Studio/DarkMode2/blob/master) 7 | [![img](https://camo.githubusercontent.com/b76728bc1c74684ee31f0be49f10ff005cd400a1ddae507d304be940b2a51412/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f4d656c6f6e2d53747564696f2f4461726b4d6f6465323f7374796c653d666c61742d737175617265)](https://github.com/Melon-Studio/DarkMode2/blob/master) 8 | [![img](https://camo.githubusercontent.com/560c4d1a2d4d97df23b5148747dc88de44f51fdcb25254bb34144a041d7aaa22/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732f4d656c6f6e2d53747564696f2f4461726b4d6f6465323f7374796c653d666c61742d737175617265)](https://github.com/Melon-Studio/DarkMode2/blob/master) 9 | [![img](https://camo.githubusercontent.com/5977bd502d8bba7c7aa9f76c04b1fc95ec64986900044e0c4e07b19ba5b9696f/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f4d656c6f6e2d53747564696f2f4461726b4d6f6465323f7374796c653d666c61742d737175617265)](https://github.com/Melon-Studio/DarkMode2/blob/master) 10 | [![img](https://camo.githubusercontent.com/e9fbca5d0b8195869f2368539ad6eb31d979abd866bb8e4fc3165b5fae627f9a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f4d656c6f6e2d53747564696f2f4461726b4d6f6465323f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/e9fbca5d0b8195869f2368539ad6eb31d979abd866bb8e4fc3165b5fae627f9a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f4d656c6f6e2d53747564696f2f4461726b4d6f6465323f7374796c653d666c61742d737175617265) 11 | [![img](https://camo.githubusercontent.com/05e612beecc0f77dc26faecb1b367a4323d11713fbc50c9a0904cca36fd24de2/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f64697363757373696f6e732f4d656c6f6e2d53747564696f2f4461726b4d6f6465323f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/05e612beecc0f77dc26faecb1b367a4323d11713fbc50c9a0904cca36fd24de2/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f64697363757373696f6e732f4d656c6f6e2d53747564696f2f4461726b4d6f6465323f7374796c653d666c61742d737175617265) 12 | 13 | [简体中文](./README.md) | English 14 | 15 | DarkMode2 is an open-source software designed to automatically switch the color mode of Windows 10/11 systems. It offers several key features, including scheduled switching, sunrise-sunset switching, ambient light-based switching, and switching based on system native wallpapers and Wallpaper Engine wallpapers. The software aims to address the lack of automatic color mode switching in the Windows operating system. Additionally, it provides various extra functionalities. Automatically switching to dark mode at night helps reduce eye fatigue and prevents excessive light from entering the eyes. While this software cannot completely solve eye fatigue, it can alleviate the eye strain caused by using light mode at night. 16 | 17 | --- 18 | 19 | ## 👁️Features 20 | 21 | - **Scheduled Switching**: Automatically switches the system's color mode based on a user-defined schedule. 22 | - **Sunrise-Sunset Switching**: Adjusts the color mode automatically based on the user's location's sunrise and sunset times. 23 | - **Ambient Light-based Switching**: Automatically switches the color mode based on changes in ambient light. 24 | - **System Native Wallpaper Switching**: Automatically adjusts the set system native wallpaper based on the color mode. 25 | - **Wallpaper Engine Wallpaper Switching**: Automatically adjusts the set Wallpaper Engine wallpaper based on the color mode. 26 | 27 | More features are in development; feel free to submit issues to add functionality suggestions to the lab. 28 | 29 | --- 30 | 31 | ## 📀System Requirements 32 | 33 | - **Operating System**: Windows 10 / 11 34 | - **System Architecture**: x64 / arm64 35 | - **Required Framework**: .NET Framework 4.7.2 36 | 37 | If your system doesn't have the framework, [click here](https://dotnet.microsoft.com/en-us/download/dotnet-framework/thank-you/net472-web-installer) to install it. 38 | 39 | --- 40 | 41 | ## 🖱️Installation and Usage 42 | 43 | 1. [Click here](https://github.com/Melon-Studio/DarkMode2/releases) or on the right for Releases to download the latest version. 44 | 2. In the local folder, double-click to run `DarkMode 2.exe`. 45 | 3. Configure as needed and save the settings. 46 | 4. DarkMode2 will run in the background and automatically switch the color mode based on your settings. 47 | 48 | 49 | 50 | 51 | 52 | --- 53 | 54 | ## 😶‍🌫️Q&A 55 | 56 | 1. What should I do if there are errors or program exceptions? 57 | 58 | - Recommended: Search for 59 | Registry Editor in Windows search, open it, and enter 60 | `Computer\HKEY_CURRENT_USER\Software\DarkMode2` in the address bar. Delete the 61 | `DarkMode2` entry (folder). 62 | - In some cases: In the settings center, click the 63 | `Reset User Configuration button` 64 | 65 | 2. How can I avoid frequent UAC prompts? 66 | 67 | If you encounter UAC prompts when starting up, it means you have enabled automatic sunrise-sunset time updates. This is because the software automatically updates sunrise-sunset time on startup, and it cannot avoid invoking administrator privileges. Alternatively, it might be triggered by UAC prompts when modifying system registry items during switching. If you want to prevent UAC prompts permanently, you can right-click on 68 | 69 | `DarkMode 2.exe` -> select `Properties` -> select `Run this program as an administrator`. 70 | 71 | ## 🧷Open Source License 72 | 73 | This open-source project follows the international GPLv3 open-source license. Please read the LICENSE file for details. You can use all the code of DarkMode2 in personal or commercial projects, but you must include a copy of the MIT open-source license in your referenced project. 74 | 75 | This project uses third-party open-source libraries: 76 | 77 | | Name | Author | Copyright | License | 78 | | ----------- | --------------- | ------------------------------------------------------------ | ---------- | 79 | | NHotKey.Wpf | Thomas Levesque | Copyright © 2020 Thomas Levesque Licensed under the Apache-2.0 License. | Apache-2.0 | 80 | | WPF-UI | lepo.co | Copyright © 2022 lepo.co Licensed under the MIT License. | MIT | 81 | | Log4net | Apache | Copyright © 2022 Apache Licensed under the Apache-2.0 License. | Apache-2.0 | 82 | | ... | ... | ... | ... | 83 | 84 | 85 | For more dependencies, please check [here](https://github.com/Melon-Studio/DarkMode2/network/dependencies). 86 | 87 | --- 88 | 89 | ## 🥰Acknowledgments 90 | 91 | DarkMode2 extends special thanks to [Microsoft Visual Studio](https://visualstudio.microsoft.com/) for providing powerful development tools and support. 92 | 93 | ![IDE](./docs/IDE.svg) 94 | 95 | --- 96 | 97 | ## ⚡Support the Project 98 | 99 | To continue providing free software services, we have opened up sponsorship channels. Through this channel, you can voluntarily sponsor our software project, which is very important for our development. 100 | 101 | As developers, we know that our growth and software development are inseparable from your support and encouragement. Your sponsorship will be directly used to improve the quality, functionality, and user experience of the software, as well as to invest more time and effort in developing new features and functionalities. 102 | 103 | We solemnly promise that our software will always be free and will remain updated, whether now or in the future. We always believe that the power of open-source software lies in sharing and collaboration. By providing free software, we can bring practical and high-quality products to more users. 104 | 105 | Thank you to every user willing to sponsor us, regardless of the amount of your sponsorship. Your support will inspire me to continue working hard and improving the quality of the software. Your sponsorship will also be the driving force behind our progress and ongoing development. 106 | 107 | Sponsorship Channel: https://afdian.net/a/DarkMode2 108 | 109 | --- 110 | 111 | ## 🎉Contribution 112 | 113 | If you're interested in contributing to DarkMode2, you can follow these steps: 114 | 115 | 1. Fork the warehouse and clone your Forked warehouse locally: 116 | ``` 117 | git clone https://github.com/YouUserName/DarkMode2.git 118 | ``` 119 | 2. Make your modifications locally. 120 | 3. Commit your changes and create a Pull Request (PR). 121 | 4. We'll review your PR and merge your contributions once approved. 122 | 123 | Thanks to all developers who contribute to DarkMode2! 124 | 125 | 126 | 127 | 128 | 129 | --- 130 | 131 | ## 📶Trends 132 | Here's the recent star trend chart for this project: 133 | 134 | [![Star History Chart](https://api.star-history.com/svg?repos=Melon-Studio/DarkMode,Melon-Studio/DarkMode2&type=Date)](https://star-history.com/#Melon-Studio/DarkMode&Melon-Studio/DarkMode2&Date) 135 | 136 | Please note that this is just a sample chart showing recent trends for the project, and does not represent actual data. 137 | 138 | Feel free to follow and star our project! Your support is greatly appreciated! 139 | --------------------------------------------------------------------------------