初始版本

This commit is contained in:
ShaoHua
2025-12-31 04:06:10 +08:00
parent 57cfd16e7b
commit 83ad246708
16 changed files with 363 additions and 965 deletions

3
.gitignore vendored
View File

@@ -360,4 +360,5 @@ MigrationBackup/
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
FodyWeavers.xsd
/Setup/Output

151
README.md Normal file
View File

@@ -0,0 +1,151 @@
# TodoList 待办事项管理应用
一个基于 C# WPF 开发的轻量、高效桌面待办事项管理应用,专注于通过全局快捷键提供极致的快速记录体验。
## 🚀 功能特点
### 核心功能
- **全局快捷键快速记录**:支持系统级全局快捷键(如 `Ctrl + Alt + A`),随时唤起记录窗口
- **优先级管理**:支持高、中、低三种优先级设置,通过颜色直观区分
- **任务状态跟踪**:清晰标记任务完成状态,默认隐藏已完成任务
- **本地数据持久化**:使用 SQLite 数据库保存数据,支持完全离线使用
### 技术特性
- **响应式界面**:基于 WPF 构建的现代化用户界面
- **MVVM 架构**:采用 CommunityToolkit.Mvvm 实现清晰的架构分层
- **自包含发布**:支持单文件发布,无需额外依赖
- **一键打包**:内置自动构建和打包脚本
## 🛠️ 技术栈
- **开发语言**C# 10+
- **UI 框架**WPF (Windows Presentation Foundation)
- **目标框架**.NET 8.0
- **架构模式**MVVM (Model-View-ViewModel)
- **数据存储**SQLite (sqlite-net-pcl)
- **打包工具**Inno Setup 6
- **依赖管理**NuGet
## 📦 安装与使用
### 直接安装
1.`Output` 目录下载最新的安装包:`TodoList_Setup_vX.X.X.exe`
2. 双击运行安装程序,按照提示完成安装
3. 启动应用后,在系统托盘找到应用图标
### 使用说明
- **快速记录**:按下预设的全局快捷键(默认为 `Ctrl + Alt + A`
- **添加任务**:在快速记录窗口中输入任务内容,设置优先级,按 Enter 保存
- **管理任务**:在主界面中查看、编辑和标记任务完成状态
- **隐藏完成任务**:默认自动隐藏已完成任务,可通过界面开关显示
## 🔧 开发指南
### 环境要求
- Visual Studio 2022 或更高版本
- .NET 8.0 SDK
- Inno Setup 6用于打包
### 快速开始
1. **克隆或下载项目**
```bash
git clone <仓库地址>
cd TodoList
```
2. **打开项目**
- 使用 Visual Studio 打开 `TodoList.slnx` 解决方案
- 或直接打开 `TodoList/TodoList.csproj` 项目文件
3. **安装依赖**
```bash
dotnet restore
```
4. **运行项目**
```bash
dotnet run --project TodoList/TodoList.csproj
```
### 构建与发布
使用内置的发布脚本进行一键构建和打包:
```bash
cd TodoList/TodoList
powershell -ExecutionPolicy Bypass -File "BuildSetup.ps1"
```
脚本功能:
- 自动递增版本号
- 更新项目文件和安装脚本版本
- 编译 Release 版本
- 生成单文件可执行文件
- 创建安装程序(输出到 `Output` 目录)
## 📁 项目结构
```
TodoList/
├── TodoList/ # 主项目目录
│ ├── Models/ # 数据模型
│ ├── Services/ # 服务层(数据访问、快捷键等)
│ ├── ViewModels/ # 视图模型
│ ├── Views/ # 界面视图
│ ├── TodoList.csproj # 项目文件
│ ├── BuildSetup.ps1 # 发布脚本
│ └── setup.iss # Inno Setup 安装脚本
├── TodoList.slnx # 解决方案文件
├── PRD.md # 产品需求文档
└── README.md # 项目说明文档
```
## 🎯 核心模块说明
### QuickEntryWindow
快速记录窗口,通过全局快捷键唤起,提供极简的任务输入体验。
### MainWindow
主界面,展示任务列表,支持任务管理和状态切换。
### GlobalShortcutService
全局快捷键服务,负责注册和监听系统级快捷键。
### SqliteDataService
SQLite 数据服务,实现本地数据持久化。
## 🔄 版本更新
### 版本策略
- 采用语义化版本号:`MAJOR.MINOR.PATCH`
- 每次运行发布脚本自动递增 PATCH 版本
### 更新日志
| 版本 | 日期 | 描述 |
|------|------|------|
| 1.0.17 | 2024-01-XX | 修复发布脚本和安装路径问题 |
| 1.0.16 | 2024-01-XX | 完善任务优先级显示 |
| 1.0.0 | 2024-01-XX | 初始版本发布 |
## 🤝 贡献指南
1. Fork 项目
2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 打开 Pull Request
## 📄 许可证
本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情
## 📞 联系方式
- 项目作者ShaoHua
- 项目地址:<https://git.we965.cn/Tools/TodoList>
---
**TodoList** - 让任务管理更高效!

View File

@@ -1,956 +0,0 @@
"DeployProject"
{
"VSVersion" = "3:800"
"ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}"
"IsWebType" = "8:FALSE"
"ProjectName" = "8:Setup"
"LanguageId" = "3:2052"
"CodePage" = "3:936"
"UILanguageId" = "3:2052"
"SccProjectName" = "8:"
"SccLocalPath" = "8:"
"SccAuxPath" = "8:"
"SccProvider" = "8:"
"Hierarchy"
{
"Entry"
{
"MsmKey" = "8:_17BA67E2733E421586A690779AE10839"
"OwnerKey" = "8:_UNDEFINED"
"MsmSig" = "8:_UNDEFINED"
}
"Entry"
{
"MsmKey" = "8:_1E301C03308E4C0AADE54375ACCA27E9"
"OwnerKey" = "8:_UNDEFINED"
"MsmSig" = "8:_UNDEFINED"
}
"Entry"
{
"MsmKey" = "8:_34EE79020CA44431B5F09CF100F2B372"
"OwnerKey" = "8:_UNDEFINED"
"MsmSig" = "8:_UNDEFINED"
}
"Entry"
{
"MsmKey" = "8:_42AD4BACEFC94D43B5DE5DDF9177EFAD"
"OwnerKey" = "8:_UNDEFINED"
"MsmSig" = "8:_UNDEFINED"
}
"Entry"
{
"MsmKey" = "8:_4C87263B310A4D3F8CC1BD3265F5B929"
"OwnerKey" = "8:_UNDEFINED"
"MsmSig" = "8:_UNDEFINED"
}
"Entry"
{
"MsmKey" = "8:_65835E291AAA6A7D2371E2E621AF3DC9"
"OwnerKey" = "8:_17BA67E2733E421586A690779AE10839"
"MsmSig" = "8:_UNDEFINED"
}
"Entry"
{
"MsmKey" = "8:_6792D68F0F43409CADA40277C6FE4B43"
"OwnerKey" = "8:_UNDEFINED"
"MsmSig" = "8:_UNDEFINED"
}
"Entry"
{
"MsmKey" = "8:_D50F9EB4AAE7436FBAD775A446017958"
"OwnerKey" = "8:_UNDEFINED"
"MsmSig" = "8:_UNDEFINED"
}
"Entry"
{
"MsmKey" = "8:_UNDEFINED"
"OwnerKey" = "8:_17BA67E2733E421586A690779AE10839"
"MsmSig" = "8:_UNDEFINED"
}
}
"Configurations"
{
"Debug"
{
"DisplayName" = "8:Debug"
"IsDebugOnly" = "11:TRUE"
"IsReleaseOnly" = "11:FALSE"
"OutputFilename" = "8:Debug\\Setup.msi"
"PackageFilesAs" = "3:2"
"PackageFileSize" = "3:-2147483648"
"CabType" = "3:1"
"Compression" = "3:2"
"SignOutput" = "11:FALSE"
"CertificateFile" = "8:"
"PrivateKeyFile" = "8:"
"TimeStampServer" = "8:"
"InstallerBootstrapper" = "3:2"
}
"Release"
{
"DisplayName" = "8:Release"
"IsDebugOnly" = "11:FALSE"
"IsReleaseOnly" = "11:TRUE"
"OutputFilename" = "8:Release\\Setup.msi"
"PackageFilesAs" = "3:2"
"PackageFileSize" = "3:-2147483648"
"CabType" = "3:1"
"Compression" = "3:2"
"SignOutput" = "11:FALSE"
"CertificateFile" = "8:"
"PrivateKeyFile" = "8:"
"TimeStampServer" = "8:"
"InstallerBootstrapper" = "3:2"
"BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}"
{
"Enabled" = "11:FALSE"
"PromptEnabled" = "11:TRUE"
"PrerequisitesLocation" = "2:1"
"Url" = "8:"
"ComponentsUrl" = "8:"
"Items"
{
"{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2"
{
"Name" = "8:Microsoft .NET Framework 4.7.2 (x86 和 x64)"
"ProductCode" = "8:.NETFramework,Version=v4.7.2"
}
}
}
}
}
"Deployable"
{
"CustomAction"
{
}
"DefaultFeature"
{
"Name" = "8:DefaultFeature"
"Title" = "8:"
"Description" = "8:"
}
"ExternalPersistence"
{
"LaunchCondition"
{
"{A06ECF26-33A3-4562-8140-9B0E340D4F24}:_3DB760AE720B4C9DB0261DBC0A13DD96"
{
"Name" = "8:.NET Framework"
"Message" = "8:[VSDNETMSG]"
"FrameworkVersion" = "8:.NETFramework,Version=v4.7.2"
"AllowLaterVersions" = "11:FALSE"
"InstallUrl" = "8:http://go.microsoft.com/fwlink/?LinkId=863262"
}
}
}
"File"
{
"{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_17BA67E2733E421586A690779AE10839"
{
"AssemblyRegister" = "3:1"
"AssemblyIsInGAC" = "11:FALSE"
"AssemblyAsmDisplayName" = "8:TodoList, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"
"ScatterAssemblies"
{
"_17BA67E2733E421586A690779AE10839"
{
"Name" = "8:TodoList.dll"
"Attributes" = "3:512"
}
}
"SourcePath" = "8:..\\TodoList\\bin\\Debug\\net10.0-windows\\TodoList.dll"
"TargetName" = "8:"
"Tag" = "8:"
"Folder" = "8:_8A20A7DDF24B44E8AC7BBB584966EEF1"
"Condition" = "8:"
"Transitive" = "11:FALSE"
"Vital" = "11:TRUE"
"ReadOnly" = "11:FALSE"
"Hidden" = "11:FALSE"
"System" = "11:FALSE"
"Permanent" = "11:FALSE"
"SharedLegacy" = "11:FALSE"
"PackageAs" = "3:1"
"Register" = "3:1"
"Exclude" = "11:FALSE"
"IsDependency" = "11:FALSE"
"IsolateTo" = "8:"
}
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1E301C03308E4C0AADE54375ACCA27E9"
{
"SourcePath" = "8:..\\TodoList\\bin\\Debug\\net10.0-windows\\TodoList.exe"
"TargetName" = "8:TodoList.exe"
"Tag" = "8:"
"Folder" = "8:_8A20A7DDF24B44E8AC7BBB584966EEF1"
"Condition" = "8:"
"Transitive" = "11:FALSE"
"Vital" = "11:TRUE"
"ReadOnly" = "11:FALSE"
"Hidden" = "11:FALSE"
"System" = "11:FALSE"
"Permanent" = "11:FALSE"
"SharedLegacy" = "11:FALSE"
"PackageAs" = "3:1"
"Register" = "3:1"
"Exclude" = "11:FALSE"
"IsDependency" = "11:FALSE"
"IsolateTo" = "8:"
}
"{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_34EE79020CA44431B5F09CF100F2B372"
{
"AssemblyRegister" = "3:1"
"AssemblyIsInGAC" = "11:FALSE"
"AssemblyAsmDisplayName" = "8:CommunityToolkit.Mvvm, Version=8.4.0.0, Culture=neutral, PublicKeyToken=4aff67a105548ee2, processorArchitecture=MSIL"
"ScatterAssemblies"
{
"_34EE79020CA44431B5F09CF100F2B372"
{
"Name" = "8:CommunityToolkit.Mvvm.dll"
"Attributes" = "3:512"
}
}
"SourcePath" = "8:..\\TodoList\\bin\\Debug\\net10.0-windows\\CommunityToolkit.Mvvm.dll"
"TargetName" = "8:"
"Tag" = "8:"
"Folder" = "8:_8A20A7DDF24B44E8AC7BBB584966EEF1"
"Condition" = "8:"
"Transitive" = "11:FALSE"
"Vital" = "11:TRUE"
"ReadOnly" = "11:FALSE"
"Hidden" = "11:FALSE"
"System" = "11:FALSE"
"Permanent" = "11:FALSE"
"SharedLegacy" = "11:FALSE"
"PackageAs" = "3:1"
"Register" = "3:1"
"Exclude" = "11:FALSE"
"IsDependency" = "11:FALSE"
"IsolateTo" = "8:"
}
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_42AD4BACEFC94D43B5DE5DDF9177EFAD"
{
"SourcePath" = "8:..\\TodoList\\bin\\Debug\\net10.0-windows\\TodoList.runtimeconfig.json"
"TargetName" = "8:TodoList.runtimeconfig.json"
"Tag" = "8:"
"Folder" = "8:_8A20A7DDF24B44E8AC7BBB584966EEF1"
"Condition" = "8:"
"Transitive" = "11:FALSE"
"Vital" = "11:TRUE"
"ReadOnly" = "11:FALSE"
"Hidden" = "11:FALSE"
"System" = "11:FALSE"
"Permanent" = "11:FALSE"
"SharedLegacy" = "11:FALSE"
"PackageAs" = "3:1"
"Register" = "3:1"
"Exclude" = "11:FALSE"
"IsDependency" = "11:FALSE"
"IsolateTo" = "8:"
}
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4C87263B310A4D3F8CC1BD3265F5B929"
{
"SourcePath" = "8:..\\TodoList\\bin\\Debug\\net10.0-windows\\TodoList.deps.json"
"TargetName" = "8:TodoList.deps.json"
"Tag" = "8:"
"Folder" = "8:_8A20A7DDF24B44E8AC7BBB584966EEF1"
"Condition" = "8:"
"Transitive" = "11:FALSE"
"Vital" = "11:TRUE"
"ReadOnly" = "11:FALSE"
"Hidden" = "11:FALSE"
"System" = "11:FALSE"
"Permanent" = "11:FALSE"
"SharedLegacy" = "11:FALSE"
"PackageAs" = "3:1"
"Register" = "3:1"
"Exclude" = "11:FALSE"
"IsDependency" = "11:FALSE"
"IsolateTo" = "8:"
}
"{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_65835E291AAA6A7D2371E2E621AF3DC9"
{
"AssemblyRegister" = "3:1"
"AssemblyIsInGAC" = "11:FALSE"
"AssemblyAsmDisplayName" = "8:CommunityToolkit.Mvvm, Version=8.4.0.0, Culture=neutral, PublicKeyToken=4aff67a105548ee2, processorArchitecture=MSIL"
"ScatterAssemblies"
{
"_65835E291AAA6A7D2371E2E621AF3DC9"
{
"Name" = "8:CommunityToolkit.Mvvm.dll"
"Attributes" = "3:512"
}
}
"SourcePath" = "8:CommunityToolkit.Mvvm.dll"
"TargetName" = "8:"
"Tag" = "8:"
"Folder" = "8:_8A20A7DDF24B44E8AC7BBB584966EEF1"
"Condition" = "8:"
"Transitive" = "11:FALSE"
"Vital" = "11:TRUE"
"ReadOnly" = "11:FALSE"
"Hidden" = "11:FALSE"
"System" = "11:FALSE"
"Permanent" = "11:FALSE"
"SharedLegacy" = "11:FALSE"
"PackageAs" = "3:1"
"Register" = "3:1"
"Exclude" = "11:FALSE"
"IsDependency" = "11:TRUE"
"IsolateTo" = "8:"
}
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D50F9EB4AAE7436FBAD775A446017958"
{
"SourcePath" = "8:..\\TodoList\\bin\\Debug\\net10.0-windows\\icon.ico"
"TargetName" = "8:icon.ico"
"Tag" = "8:"
"Folder" = "8:_8A20A7DDF24B44E8AC7BBB584966EEF1"
"Condition" = "8:"
"Transitive" = "11:FALSE"
"Vital" = "11:TRUE"
"ReadOnly" = "11:FALSE"
"Hidden" = "11:FALSE"
"System" = "11:FALSE"
"Permanent" = "11:FALSE"
"SharedLegacy" = "11:FALSE"
"PackageAs" = "3:1"
"Register" = "3:1"
"Exclude" = "11:FALSE"
"IsDependency" = "11:FALSE"
"IsolateTo" = "8:"
}
}
"FileType"
{
}
"Folder"
{
"{1525181F-901A-416C-8A58-119130FE478E}:_4CF5CB48101445E3B47CD2485BDDA511"
{
"Name" = "8:#1916"
"AlwaysCreate" = "11:FALSE"
"Condition" = "8:"
"Transitive" = "11:FALSE"
"Property" = "8:DesktopFolder"
"Folders"
{
}
}
"{3C67513D-01DD-4637-8A68-80971EB9504F}:_8A20A7DDF24B44E8AC7BBB584966EEF1"
{
"DefaultLocation" = "8:[ProgramFilesFolder][Manufacturer]\\[ProductName]"
"Name" = "8:#1925"
"AlwaysCreate" = "11:FALSE"
"Condition" = "8:"
"Transitive" = "11:FALSE"
"Property" = "8:TARGETDIR"
"Folders"
{
}
}
"{1525181F-901A-416C-8A58-119130FE478E}:_BF5ADB1EDBF04FA0A47DA23313C521B9"
{
"Name" = "8:#1919"
"AlwaysCreate" = "11:FALSE"
"Condition" = "8:"
"Transitive" = "11:FALSE"
"Property" = "8:ProgramMenuFolder"
"Folders"
{
}
}
}
"LaunchCondition"
{
}
"Locator"
{
}
"MsiBootstrapper"
{
"LangId" = "3:2052"
"RequiresElevation" = "11:FALSE"
}
"Product"
{
"Name" = "8:Microsoft Visual Studio"
"ProductName" = "8:TodoList"
"ProductCode" = "8:{146611B1-AB9F-46C3-8FD4-EE7BCEC54C33}"
"PackageCode" = "8:{151EF683-7149-4D7A-9134-3092572B04CD}"
"UpgradeCode" = "8:{82F2F6EB-C24C-477B-81E6-43EDB0EE36B0}"
"AspNetVersion" = "8:4.0.30319.0"
"RestartWWWService" = "11:FALSE"
"RemovePreviousVersions" = "11:TRUE"
"DetectNewerInstalledVersion" = "11:TRUE"
"InstallAllUsers" = "11:TRUE"
"ProductVersion" = "8:1.0.0"
"Manufacturer" = "8:ShaoHua"
"ARPHELPTELEPHONE" = "8:"
"ARPHELPLINK" = "8:"
"Title" = "8:TodoList"
"Subject" = "8:"
"ARPCONTACT" = "8:ShaoHua"
"Keywords" = "8:"
"ARPCOMMENTS" = "8:"
"ARPURLINFOABOUT" = "8:"
"ARPPRODUCTICON" = "8:"
"ARPIconIndex" = "3:0"
"SearchPath" = "8:"
"UseSystemSearchPath" = "11:TRUE"
"TargetPlatform" = "3:0"
"PreBuildEvent" = "8:"
"PostBuildEvent" = "8:"
"RunPostBuildEvent" = "3:0"
}
"Registry"
{
"HKLM"
{
"Keys"
{
"{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_8522CD2219284FA48C170669A2A3D9B3"
{
"Name" = "8:Software"
"Condition" = "8:"
"AlwaysCreate" = "11:FALSE"
"DeleteAtUninstall" = "11:FALSE"
"Transitive" = "11:FALSE"
"Keys"
{
"{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_2553544E11294AD0ACF21B6F2D65909C"
{
"Name" = "8:[Manufacturer]"
"Condition" = "8:"
"AlwaysCreate" = "11:FALSE"
"DeleteAtUninstall" = "11:FALSE"
"Transitive" = "11:FALSE"
"Keys"
{
}
"Values"
{
}
}
}
"Values"
{
}
}
}
}
"HKCU"
{
"Keys"
{
"{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_BD961664BECD4769871995ED2576A507"
{
"Name" = "8:Software"
"Condition" = "8:"
"AlwaysCreate" = "11:FALSE"
"DeleteAtUninstall" = "11:FALSE"
"Transitive" = "11:FALSE"
"Keys"
{
"{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_885FDEC4E0C3484CA36F1A96BEAD1D41"
{
"Name" = "8:[Manufacturer]"
"Condition" = "8:"
"AlwaysCreate" = "11:FALSE"
"DeleteAtUninstall" = "11:FALSE"
"Transitive" = "11:FALSE"
"Keys"
{
}
"Values"
{
}
}
}
"Values"
{
}
}
}
}
"HKCR"
{
"Keys"
{
}
}
"HKU"
{
"Keys"
{
}
}
"HKPU"
{
"Keys"
{
}
}
}
"Sequences"
{
}
"Shortcut"
{
"{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_0D031B70CF7542448AC7303C2ED6DC6A"
{
"Name" = "8:TodoList"
"Arguments" = "8:"
"Description" = "8:"
"ShowCmd" = "3:1"
"IconIndex" = "3:0"
"Transitive" = "11:FALSE"
"Target" = "8:_1E301C03308E4C0AADE54375ACCA27E9"
"Folder" = "8:_BF5ADB1EDBF04FA0A47DA23313C521B9"
"WorkingFolder" = "8:_8A20A7DDF24B44E8AC7BBB584966EEF1"
"Icon" = "8:_D50F9EB4AAE7436FBAD775A446017958"
"Feature" = "8:"
}
"{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_AE6A93A941DD4EEDA219EAF034A157CC"
{
"Name" = "8:todoList主输出"
"Arguments" = "8:"
"Description" = "8:"
"ShowCmd" = "3:1"
"IconIndex" = "3:0"
"Transitive" = "11:FALSE"
"Target" = "8:_6792D68F0F43409CADA40277C6FE4B43"
"Folder" = "8:_BF5ADB1EDBF04FA0A47DA23313C521B9"
"WorkingFolder" = "8:_8A20A7DDF24B44E8AC7BBB584966EEF1"
"Icon" = "8:_D50F9EB4AAE7436FBAD775A446017958"
"Feature" = "8:"
}
}
"UserInterface"
{
"{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_1A5922191B3444D2ADBFAAAEE654AFBE"
{
"UseDynamicProperties" = "11:FALSE"
"IsDependency" = "11:FALSE"
"SourcePath" = "8:<VsdDialogDir>\\VsdBasicDialogs.wim"
}
"{DF760B10-853B-4699-99F2-AFF7185B4A62}:_1A7F6DF07CA34F1290B53C77E9A24DCD"
{
"Name" = "8:#1901"
"Sequence" = "3:1"
"Attributes" = "3:2"
"Dialogs"
{
"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_12C9A09546FF47E89C2F76E5857982C5"
{
"Sequence" = "3:100"
"DisplayName" = "8:进度"
"UseDynamicProperties" = "11:TRUE"
"IsDependency" = "11:FALSE"
"SourcePath" = "8:<VsdDialogDir>\\VsdProgressDlg.wid"
"Properties"
{
"BannerBitmap"
{
"Name" = "8:BannerBitmap"
"DisplayName" = "8:#1001"
"Description" = "8:#1101"
"Type" = "3:8"
"ContextData" = "8:Bitmap"
"Attributes" = "3:4"
"Setting" = "3:1"
"UsePlugInResources" = "11:TRUE"
}
"ShowProgress"
{
"Name" = "8:ShowProgress"
"DisplayName" = "8:#1009"
"Description" = "8:#1109"
"Type" = "3:5"
"ContextData" = "8:1;True=1;False=0"
"Attributes" = "3:0"
"Setting" = "3:0"
"Value" = "3:1"
"DefaultValue" = "3:1"
"UsePlugInResources" = "11:TRUE"
}
}
}
}
}
"{DF760B10-853B-4699-99F2-AFF7185B4A62}:_1BED33199298468C95ACE087FD867323"
{
"Name" = "8:#1902"
"Sequence" = "3:1"
"Attributes" = "3:3"
"Dialogs"
{
"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_3F862D9E99F34183BC0479F9A6500399"
{
"Sequence" = "3:100"
"DisplayName" = "8:已完成"
"UseDynamicProperties" = "11:TRUE"
"IsDependency" = "11:FALSE"
"SourcePath" = "8:<VsdDialogDir>\\VsdFinishedDlg.wid"
"Properties"
{
"BannerBitmap"
{
"Name" = "8:BannerBitmap"
"DisplayName" = "8:#1001"
"Description" = "8:#1101"
"Type" = "3:8"
"ContextData" = "8:Bitmap"
"Attributes" = "3:4"
"Setting" = "3:1"
"UsePlugInResources" = "11:TRUE"
}
"UpdateText"
{
"Name" = "8:UpdateText"
"DisplayName" = "8:#1058"
"Description" = "8:#1158"
"Type" = "3:15"
"ContextData" = "8:"
"Attributes" = "3:0"
"Setting" = "3:1"
"Value" = "8:#1258"
"DefaultValue" = "8:#1258"
"UsePlugInResources" = "11:TRUE"
}
}
}
}
}
"{DF760B10-853B-4699-99F2-AFF7185B4A62}:_2579AFB8C446463A9A8BCBDE6897AF55"
{
"Name" = "8:#1901"
"Sequence" = "3:2"
"Attributes" = "3:2"
"Dialogs"
{
"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_1F08E1AAFAC14C4BA560722C839F686C"
{
"Sequence" = "3:100"
"DisplayName" = "8:进度"
"UseDynamicProperties" = "11:TRUE"
"IsDependency" = "11:FALSE"
"SourcePath" = "8:<VsdDialogDir>\\VsdAdminProgressDlg.wid"
"Properties"
{
"BannerBitmap"
{
"Name" = "8:BannerBitmap"
"DisplayName" = "8:#1001"
"Description" = "8:#1101"
"Type" = "3:8"
"ContextData" = "8:Bitmap"
"Attributes" = "3:4"
"Setting" = "3:1"
"UsePlugInResources" = "11:TRUE"
}
"ShowProgress"
{
"Name" = "8:ShowProgress"
"DisplayName" = "8:#1009"
"Description" = "8:#1109"
"Type" = "3:5"
"ContextData" = "8:1;True=1;False=0"
"Attributes" = "3:0"
"Setting" = "3:0"
"Value" = "3:1"
"DefaultValue" = "3:1"
"UsePlugInResources" = "11:TRUE"
}
}
}
}
}
"{DF760B10-853B-4699-99F2-AFF7185B4A62}:_669B474BCA014E7C9871D52674DC793E"
{
"Name" = "8:#1900"
"Sequence" = "3:1"
"Attributes" = "3:1"
"Dialogs"
{
"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_0EFA62CCD2C843EAA044829F13217B57"
{
"Sequence" = "3:300"
"DisplayName" = "8:确认安装"
"UseDynamicProperties" = "11:TRUE"
"IsDependency" = "11:FALSE"
"SourcePath" = "8:<VsdDialogDir>\\VsdConfirmDlg.wid"
"Properties"
{
"BannerBitmap"
{
"Name" = "8:BannerBitmap"
"DisplayName" = "8:#1001"
"Description" = "8:#1101"
"Type" = "3:8"
"ContextData" = "8:Bitmap"
"Attributes" = "3:4"
"Setting" = "3:1"
"UsePlugInResources" = "11:TRUE"
}
}
}
"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_860D684F21184955A2394B2FAE3B85B3"
{
"Sequence" = "3:200"
"DisplayName" = "8:安装文件夹"
"UseDynamicProperties" = "11:TRUE"
"IsDependency" = "11:FALSE"
"SourcePath" = "8:<VsdDialogDir>\\VsdFolderDlg.wid"
"Properties"
{
"BannerBitmap"
{
"Name" = "8:BannerBitmap"
"DisplayName" = "8:#1001"
"Description" = "8:#1101"
"Type" = "3:8"
"ContextData" = "8:Bitmap"
"Attributes" = "3:4"
"Setting" = "3:1"
"UsePlugInResources" = "11:TRUE"
}
"InstallAllUsersVisible"
{
"Name" = "8:InstallAllUsersVisible"
"DisplayName" = "8:#1059"
"Description" = "8:#1159"
"Type" = "3:5"
"ContextData" = "8:1;True=1;False=0"
"Attributes" = "3:0"
"Setting" = "3:0"
"Value" = "3:1"
"DefaultValue" = "3:1"
"UsePlugInResources" = "11:TRUE"
}
}
}
"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_F62A5F384AC4466DAA5560FD53102C9B"
{
"Sequence" = "3:100"
"DisplayName" = "8:欢迎使用"
"UseDynamicProperties" = "11:TRUE"
"IsDependency" = "11:FALSE"
"SourcePath" = "8:<VsdDialogDir>\\VsdWelcomeDlg.wid"
"Properties"
{
"BannerBitmap"
{
"Name" = "8:BannerBitmap"
"DisplayName" = "8:#1001"
"Description" = "8:#1101"
"Type" = "3:8"
"ContextData" = "8:Bitmap"
"Attributes" = "3:4"
"Setting" = "3:1"
"UsePlugInResources" = "11:TRUE"
}
"CopyrightWarning"
{
"Name" = "8:CopyrightWarning"
"DisplayName" = "8:#1002"
"Description" = "8:#1102"
"Type" = "3:3"
"ContextData" = "8:"
"Attributes" = "3:0"
"Setting" = "3:1"
"Value" = "8:#1202"
"DefaultValue" = "8:#1202"
"UsePlugInResources" = "11:TRUE"
}
"Welcome"
{
"Name" = "8:Welcome"
"DisplayName" = "8:#1003"
"Description" = "8:#1103"
"Type" = "3:3"
"ContextData" = "8:"
"Attributes" = "3:0"
"Setting" = "3:1"
"Value" = "8:#1203"
"DefaultValue" = "8:#1203"
"UsePlugInResources" = "11:TRUE"
}
}
}
}
}
"{DF760B10-853B-4699-99F2-AFF7185B4A62}:_B97CCC8EE8F848C2A4276A2E58150A45"
{
"Name" = "8:#1902"
"Sequence" = "3:2"
"Attributes" = "3:3"
"Dialogs"
{
"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_1CDE38F50B454FFA8F5C722E23D7165D"
{
"Sequence" = "3:100"
"DisplayName" = "8:已完成"
"UseDynamicProperties" = "11:TRUE"
"IsDependency" = "11:FALSE"
"SourcePath" = "8:<VsdDialogDir>\\VsdAdminFinishedDlg.wid"
"Properties"
{
"BannerBitmap"
{
"Name" = "8:BannerBitmap"
"DisplayName" = "8:#1001"
"Description" = "8:#1101"
"Type" = "3:8"
"ContextData" = "8:Bitmap"
"Attributes" = "3:4"
"Setting" = "3:1"
"UsePlugInResources" = "11:TRUE"
}
}
}
}
}
"{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_F85F3CEDA84E4C21AA1D2BEB630006E7"
{
"UseDynamicProperties" = "11:FALSE"
"IsDependency" = "11:FALSE"
"SourcePath" = "8:<VsdDialogDir>\\VsdUserInterface.wim"
}
"{DF760B10-853B-4699-99F2-AFF7185B4A62}:_F879EDB3FFCC474E9059D6DC3BED5CBE"
{
"Name" = "8:#1900"
"Sequence" = "3:2"
"Attributes" = "3:1"
"Dialogs"
{
"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_4384C55A823E4238A33E43C392ADB6C2"
{
"Sequence" = "3:200"
"DisplayName" = "8:安装文件夹"
"UseDynamicProperties" = "11:TRUE"
"IsDependency" = "11:FALSE"
"SourcePath" = "8:<VsdDialogDir>\\VsdAdminFolderDlg.wid"
"Properties"
{
"BannerBitmap"
{
"Name" = "8:BannerBitmap"
"DisplayName" = "8:#1001"
"Description" = "8:#1101"
"Type" = "3:8"
"ContextData" = "8:Bitmap"
"Attributes" = "3:4"
"Setting" = "3:1"
"UsePlugInResources" = "11:TRUE"
}
}
}
"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_4D730CD1E9A541A9A0357FD14F274504"
{
"Sequence" = "3:100"
"DisplayName" = "8:欢迎使用"
"UseDynamicProperties" = "11:TRUE"
"IsDependency" = "11:FALSE"
"SourcePath" = "8:<VsdDialogDir>\\VsdAdminWelcomeDlg.wid"
"Properties"
{
"BannerBitmap"
{
"Name" = "8:BannerBitmap"
"DisplayName" = "8:#1001"
"Description" = "8:#1101"
"Type" = "3:8"
"ContextData" = "8:Bitmap"
"Attributes" = "3:4"
"Setting" = "3:1"
"UsePlugInResources" = "11:TRUE"
}
"CopyrightWarning"
{
"Name" = "8:CopyrightWarning"
"DisplayName" = "8:#1002"
"Description" = "8:#1102"
"Type" = "3:3"
"ContextData" = "8:"
"Attributes" = "3:0"
"Setting" = "3:1"
"Value" = "8:#1202"
"DefaultValue" = "8:#1202"
"UsePlugInResources" = "11:TRUE"
}
"Welcome"
{
"Name" = "8:Welcome"
"DisplayName" = "8:#1003"
"Description" = "8:#1103"
"Type" = "3:3"
"ContextData" = "8:"
"Attributes" = "3:0"
"Setting" = "3:1"
"Value" = "8:#1203"
"DefaultValue" = "8:#1203"
"UsePlugInResources" = "11:TRUE"
}
}
}
"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_88BC734F7F1D4494AEE5F11E9797CD6B"
{
"Sequence" = "3:300"
"DisplayName" = "8:确认安装"
"UseDynamicProperties" = "11:TRUE"
"IsDependency" = "11:FALSE"
"SourcePath" = "8:<VsdDialogDir>\\VsdAdminConfirmDlg.wid"
"Properties"
{
"BannerBitmap"
{
"Name" = "8:BannerBitmap"
"DisplayName" = "8:#1001"
"Description" = "8:#1101"
"Type" = "3:8"
"ContextData" = "8:Bitmap"
"Attributes" = "3:4"
"Setting" = "3:1"
"UsePlugInResources" = "11:TRUE"
}
}
}
}
}
}
"MergeModule"
{
}
"ProjectOutput"
{
"{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_6792D68F0F43409CADA40277C6FE4B43"
{
"SourcePath" = "8:..\\TodoList\\obj\\Debug\\net10.0-windows\\TodoList.dll"
"TargetName" = "8:"
"Tag" = "8:"
"Folder" = "8:_8A20A7DDF24B44E8AC7BBB584966EEF1"
"Condition" = "8:"
"Transitive" = "11:FALSE"
"Vital" = "11:TRUE"
"ReadOnly" = "11:FALSE"
"Hidden" = "11:FALSE"
"System" = "11:FALSE"
"Permanent" = "11:FALSE"
"SharedLegacy" = "11:FALSE"
"PackageAs" = "3:1"
"Register" = "3:1"
"Exclude" = "11:FALSE"
"IsDependency" = "11:FALSE"
"IsolateTo" = "8:"
"ProjectOutputGroupRegister" = "3:1"
"OutputConfiguration" = "8:"
"OutputGroupCanonicalName" = "8:Built"
"OutputProjectGuid" = "8:{6CD40A2D-545E-C111-D437-1BE9E9C2C98C}"
"ShowKeyOutput" = "11:TRUE"
"ExcludeFilters"
{
}
}
}
}
}

View File

@@ -5,6 +5,5 @@
<Platform Name="x64" />
<Platform Name="x86" />
</Configurations>
<Project Path="Setup/Setup.vdproj" Type="Installer" />
<Project Path="TodoList/TodoList.csproj" />
</Solution>

View File

@@ -101,7 +101,7 @@ namespace TodoList
try
{
_settingsService = new SettingsService();
_dataService = new FileDataService();
_dataService = new SqliteDataService();
_shortcutService = new GlobalShortcutService();
var mainViewModel = new MainViewModel(_dataService, _settingsService);

55
TodoList/BuildSetup.ps1 Normal file
View File

@@ -0,0 +1,55 @@
$ErrorActionPreference = "Stop"
# Basic configuration
$ScriptPath = $PSScriptRoot
$ProjectFile = (Get-ChildItem -Path $ScriptPath -Filter "*.csproj" -File)[0].FullName
$SetupScript = Join-Path $ScriptPath "setup.iss"
# Read version from project file
$currentVersion = "1.0.0"
[xml]$csproj = Get-Content $ProjectFile
if ($csproj.Project.PropertyGroup.Version) {
$currentVersion = $csproj.Project.PropertyGroup.Version
}
# Increment version
$versionParts = $currentVersion.Split(".")
$patch = [int]$versionParts[2] + 1
$newVersion = $versionParts[0] + "." + $versionParts[1] + "." + $patch
# Update project version
$content = Get-Content $ProjectFile -Raw
$content = $content -replace "<Version>.*</Version>", "<Version>$newVersion</Version>"
Set-Content $ProjectFile -Value $content
# Update setup script version
if (Test-Path $SetupScript) {
$issContent = Get-Content $SetupScript
for ($i = 0; $i -lt $issContent.Count; $i++) {
if ($issContent[$i] -like '#define MyAppVersion *') {
$issContent[$i] = '#define MyAppVersion "' + $newVersion + '"'
break
}
}
Set-Content $SetupScript -Value $issContent
}
# Build project
dotnet publish $ProjectFile -c Release -r win-x64 --self-contained false -p:PublishSingleFile=true
if ($LASTEXITCODE -ne 0) {
Write-Error "Build failed"
exit 1
}
# Package
$ISCC = "${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe"
if (Test-Path $ISCC) {
& $ISCC $SetupScript
if ($LASTEXITCODE -eq 0) {
Write-Host "Setup package created successfully!" -ForegroundColor Green
} else {
Write-Error "Packaging failed"
}
} else {
Write-Error "Inno Setup compiler not found"
}

View File

@@ -25,6 +25,7 @@ namespace TodoList.Models
public partial class TodoItem : ObservableObject
{
[ObservableProperty]
[property: SQLite.PrimaryKey]
private string id = Guid.NewGuid().ToString();
[ObservableProperty]

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using SQLite;
using TodoList.Models;
namespace TodoList.Services
{
public class SqliteDataService : IDataService
{
private readonly SQLiteAsyncConnection _database;
public SqliteDataService()
{
var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var folder = Path.Combine(appData, "TodoListApp");
Directory.CreateDirectory(folder);
var databasePath = Path.Combine(folder, "TodoList.sqlite");
_database = new SQLiteAsyncConnection(databasePath);
_database.CreateTableAsync<TodoItem>().Wait();
}
public async Task<List<TodoItem>> LoadTasksAsync()
{
return await _database.Table<TodoItem>().ToListAsync();
}
public async Task SaveTaskAsync(TodoItem task)
{
await _database.InsertOrReplaceAsync(task);
}
public async Task SaveAllAsync(List<TodoItem> tasks)
{
await _database.RunInTransactionAsync(tran =>
{
foreach (var task in tasks)
{
tran.InsertOrReplace(task);
}
});
}
public async Task DeleteTaskAsync(string id)
{
await _database.DeleteAsync<TodoItem>(id);
}
}
}

View File

@@ -1,17 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows</TargetFramework>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>icon.ico</ApplicationIcon>
<Version>1.0.18</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
</ItemGroup>
<ItemGroup>
@@ -19,3 +21,21 @@
</ItemGroup>
</Project>

View File

@@ -37,6 +37,8 @@ namespace TodoList.ViewModels
[NotifyPropertyChangedFor(nameof(FullShortcut))]
private string shortcutModifiers;
public string AppVersion => System.Reflection.Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "1.0.0";
public string FullShortcut
{
get

View File

@@ -7,10 +7,11 @@
xmlns:models="clr-namespace:TodoList.Models"
xmlns:converters="clr-namespace:TodoList.Converters"
mc:Ignorable="d"
Title="待办事项" Height="600" Width="450"
Title="{Binding AppVersion, StringFormat='待办事项 v{0}'}" Height="600" Width="450"
Background="#F5F5F7"
Icon="/icon.ico"
WindowStartupLocation="CenterScreen">
WindowStartupLocation="CenterScreen"
PreviewKeyDown="Window_PreviewKeyDown">
<Window.Resources>
<ObjectDataProvider x:Key="PriorityEnum" MethodName="GetValues"

View File

@@ -19,6 +19,25 @@ namespace TodoList.Views
// Verify if app shuts down? No, ShutdownMode is Explicit.
}
private void Window_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
// If settings are open, close settings?
// But user requirement is "Equals pressing X button", which usually means Close/Hide window.
// However, if we want better UX:
if (DataContext is MainViewModel vm && vm.IsSettingsOpen)
{
vm.IsSettingsOpen = false;
e.Handled = true;
return;
}
// Default behavior: Close (Hide) Window
Close();
}
}
private void ShortcutBox_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
e.Handled = true;

56
TodoList/setup.iss Normal file
View File

@@ -0,0 +1,56 @@
#define MyAppName "TodoList"
#define MyAppVersion "1.0.18"
#define MyAppPublisher "ShaoHua"
#define MyAppURL "https://git.we965.cn/Tools/TodoList"
#define MyAppExeName "TodoList.exe"
[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{8B8A6E3F-1234-5678-9ABC-DEF012345678}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={autopf}\{#MyAppName}
DisableProgramGroupPage=yes
; Remove the following line to run in administrative install mode (install for all users.)
PrivilegesRequired=lowest
OutputDir=Output
OutputBaseFilename={#MyAppName}_Setup_v{#MyAppVersion}
SetupIconFile=icon.ico
Compression=lzma
SolidCompression=yes
WizardStyle=modern
[Languages]
Name: "chinesesimplified"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "bin\Release\net8.0-windows\win-x64\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent

View File

@@ -1,2 +0,0 @@
dotnet publish -c Release -r win-x64 -p:PublishSingleFile=true --self-contained true -p:IncludeNativeLibrariesForSelfExtract=true -o bin\PublishSingleFile
dotnet new wpf -n TodoList.Installer -o TodoList.Installer