├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ └── feature_request.yml
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ ├── build.yml
│ └── release.yml
├── CHANGELOG.md
├── COPYING
├── README.md
├── lipui.sln
├── runtimes
├── win10-arm64
│ └── native
│ │ └── Microsoft.WindowsAppRuntime.Bootstrap.dll
├── win10-x64
│ └── native
│ │ └── Microsoft.WindowsAppRuntime.Bootstrap.dll
└── win10-x86
│ └── native
│ └── Microsoft.WindowsAppRuntime.Bootstrap.dll
├── src
├── AutoUpdate
│ ├── AutoUpdate.csproj
│ └── Program.cs
└── LipUI
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── Assets
│ ├── Images.Designer.cs
│ ├── Images.resx
│ ├── SplashScreen.scale-200.png
│ ├── Square150x150Logo.scale-200.png
│ ├── Square44x44Logo.scale-200.png
│ ├── Square44x44Logo.targetsize-24_altform-unplated.png
│ ├── StoreLogo.png
│ ├── Wide310x150Logo.scale-200.png
│ ├── WindowIcon.ico
│ ├── applicationIcon-1024.png
│ ├── applicationIcon-256.png
│ ├── glass.png
│ ├── grass_block.png
│ └── netherrack.png
│ ├── BuiltInPlugins
│ ├── DefaultLipProxySetter
│ │ └── DefaultLipProxySetter.cs
│ ├── LipPanel
│ │ ├── LipPanel.cs
│ │ ├── LipPanelPage.xaml
│ │ └── LipPanelPage.xaml.cs
│ └── LipuiTips
│ │ └── LipuiTips.cs
│ ├── Language
│ ├── en-US
│ │ └── Resources.resw
│ └── zh-CN
│ │ └── Resources.resw
│ ├── LipUI.csproj
│ ├── MainWindow
│ ├── MainWIndowWin32Invoke.cs
│ ├── MainWindow.xaml
│ ├── MainWindow.xaml.cs
│ ├── MainWindowInfoBarController.cs
│ ├── MainWindowNavigationView.cs
│ └── MainWindowPluginsHandler.cs
│ ├── Models
│ ├── Config.cs
│ ├── GlobalIcons.cs
│ ├── InternalServices.cs
│ ├── Lip
│ │ ├── LipCommand.cs
│ │ ├── LipCommandContext.cs
│ │ ├── LipCommandOption.cs
│ │ ├── LipConsole.cs
│ │ └── LipConsoleInstance.cs
│ ├── Main.cs
│ ├── PackageInstaller.cs
│ ├── Plugin
│ │ ├── ConfigCollection.cs
│ │ ├── IHomePageModule.cs
│ │ ├── IPlugin.cs
│ │ ├── IUIPlugin.cs
│ │ ├── LipuiRuntimeInfo.cs
│ │ ├── LipuiServices.cs
│ │ ├── PluginConfigManager.cs
│ │ └── PluginSystem.cs
│ ├── ServerIcon.cs
│ └── ServerInstance.cs
│ ├── Package.appxmanifest
│ ├── Pages
│ ├── Home
│ │ ├── HomePage.xaml
│ │ ├── HomePage.xaml.cs
│ │ └── Modules
│ │ │ ├── AllowListViewerPage.xaml
│ │ │ ├── AllowListViewerPage.xaml.cs
│ │ │ ├── BdsPropertiesEditorPage.xaml
│ │ │ ├── BdsPropertiesEditorPage.xaml.cs
│ │ │ ├── ModuleIcon.xaml
│ │ │ ├── ModuleIcon.xaml.cs
│ │ │ ├── ModulesPage.xaml
│ │ │ └── ModulesPage.xaml.cs
│ ├── Index
│ │ ├── IndexPage.xaml
│ │ ├── IndexPage.xaml.cs
│ │ ├── LipIndexToothView.xaml
│ │ └── LipIndexToothView.xaml.cs
│ ├── LipExecutionPanel
│ │ ├── ConsoleLineView.xaml
│ │ ├── ConsoleLineView.xaml.cs
│ │ ├── EulaAcceptView.xaml
│ │ ├── EulaAcceptView.xaml.cs
│ │ ├── LipExecutionPanelPage.xaml
│ │ ├── LipExecutionPanelPage.xaml.cs
│ │ ├── LipInstallerView.xaml
│ │ └── LipInstallerView.xaml.cs
│ ├── LocalPackage
│ │ ├── LocalPackagePage.xaml
│ │ ├── LocalPackagePage.xaml.cs
│ │ ├── LocalToothView.xaml
│ │ └── LocalToothView.xaml.cs
│ ├── ModuleManager
│ │ ├── LipuiPluginsView.xaml
│ │ ├── LipuiPluginsView.xaml.cs
│ │ ├── ModuleManagerPage.xaml
│ │ └── ModuleManagerPage.xaml.cs
│ ├── ServerSelection
│ │ ├── ServerInstanceEditView.xaml
│ │ ├── ServerInstanceEditView.xaml.cs
│ │ ├── ServerInstanceView.xaml
│ │ ├── ServerInstanceView.xaml.cs
│ │ ├── ServerSelectionPage.xaml
│ │ └── ServerSelectionPage.xaml.cs
│ ├── Settings
│ │ ├── GeneralSettingsView.xaml
│ │ ├── GeneralSettingsView.xaml.cs
│ │ ├── LipSettingsView.xaml
│ │ ├── LipSettingsView.xaml.cs
│ │ ├── PersonalizationSettingsView.xaml
│ │ ├── PersonalizationSettingsView.xaml.cs
│ │ ├── SettingsAndAboutView.xaml
│ │ ├── SettingsAndAboutView.xaml.cs
│ │ ├── SettingsPage.xaml
│ │ └── SettingsPage.xaml.cs
│ ├── ToothInfoPage.xaml
│ └── ToothInfoPage.xaml.cs
│ ├── Properties
│ ├── PublishProfiles
│ │ ├── win10-arm64.pubxml
│ │ ├── win10-x64.pubxml
│ │ └── win10-x86.pubxml
│ └── launchSettings.json
│ ├── Protocol
│ ├── LipIndex.cs
│ ├── LipTooth.cs
│ └── LocalToothItem.cs
│ └── app.manifest
└── tooth.json
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: Create a report to help us improve
3 | title: "[Bug]: "
4 | labels: ["bug"]
5 | body:
6 | - type: textarea
7 | attributes:
8 | label: Describe the bug
9 | description: A clear and concise description of what the bug is.
10 | validations:
11 | required: true
12 |
13 | - type: textarea
14 | attributes:
15 | label: To Reproduce
16 | description: Steps to reproduce the behavior.
17 | validations:
18 | required: true
19 |
20 | - type: textarea
21 | attributes:
22 | label: Expected behavior
23 | description: A clear and concise description of what you expected to happen.
24 | validations:
25 | required: true
26 |
27 | - type: textarea
28 | attributes:
29 | label: Screenshots
30 | description: If applicable, add screenshots to help explain your problem.
31 |
32 | - type: input
33 | attributes:
34 | label: Platform
35 | description: The platform you are using. (e.g. Windows 10, macOS 10.15, Ubuntu 20.04)
36 |
37 | - type: input
38 | attributes:
39 | label: Version
40 | description: The version of the application you are using. (e.g. 1.0.0)
41 |
42 | - type: textarea
43 | attributes:
44 | label: Additional context
45 | description: Add any other context about the problem here.
46 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: Feature request
2 | description: Suggest an idea for this project
3 | title: "[Feature]: "
4 | labels: ["enhancement"]
5 | body:
6 | - type: textarea
7 | attributes:
8 | label: Is your feature request related to a problem? Please describe.
9 | description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
10 | validations:
11 | required: true
12 |
13 | - type: textarea
14 | attributes:
15 | label: Describe the solution you'd like
16 | description: A clear and concise description of what you want to happen.
17 | validations:
18 | required: true
19 |
20 | - type: textarea
21 | attributes:
22 | label: Describe alternatives you've considered
23 | description: A clear and concise description of any alternative solutions or features you've considered.
24 |
25 | - type: textarea
26 | attributes:
27 | label: Additional context
28 | description: Add any other context or screenshots about the feature request here.
29 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## What does this PR do?
2 |
3 |
4 |
5 | ## Which issues does this PR resolve?
6 |
7 |
8 |
9 | ## Checklist before merging
10 |
11 | Thank you for your contribution to the repository.
12 | Before submitting this PR, please make sure:
13 |
14 | - [ ] Your code builds clean without any errors or warnings
15 | - [ ] Your code follows the code style of [Common C# code conventions](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions)
16 | - [ ] You have tested all functions
17 | - [ ] You have not used code without license
18 | - [ ] You have added statement for third-party code
19 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | pull_request:
4 | workflow_dispatch:
5 |
6 | jobs:
7 | build:
8 | strategy:
9 | matrix:
10 | include:
11 | - runtime: win-arm64
12 | platform: arm64
13 | - runtime: win-x64
14 | platform: x64
15 | runs-on: windows-latest
16 | steps:
17 | - uses: actions/checkout@v4
18 |
19 | - uses: actions/setup-dotnet@v4
20 | with:
21 | dotnet-version: 8.0.x
22 |
23 | - run: |
24 | dotnet publish src/AutoUpdate/AutoUpdate.csproj -c Release -o bin/lipui -r ${{ matrix.runtime }}
25 |
26 | dotnet build src/LipUI/LipUI.csproj -c Release -o bin/lipui -r ${{ matrix.runtime }} `
27 | -p:DebugType=none -p:Platform=${{ matrix.platform }}
28 |
29 | copy runtimes/win10-${{ matrix.platform }}/native/Microsoft.WindowsAppRuntime.Bootstrap.dll bin/lipui
30 |
31 | - uses: actions/upload-artifact@v4
32 | with:
33 | name: LipUI-${{ matrix.runtime }}-${{ github.sha }}
34 | path: bin
35 |
36 | check-style:
37 | runs-on: windows-latest
38 | steps:
39 | - uses: actions/checkout@v4
40 |
41 | - uses: actions/setup-dotnet@v4
42 | with:
43 | dotnet-version: 8.0.x
44 |
45 | - run: dotnet format --verify-no-changes src/LipUI
46 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | on:
2 | release:
3 | types:
4 | - published
5 |
6 | jobs:
7 | build:
8 | strategy:
9 | matrix:
10 | include:
11 | - runtime: win-arm64
12 | platform: arm64
13 | - runtime: win-x64
14 | platform: x64
15 | runs-on: windows-latest
16 | steps:
17 | - uses: actions/checkout@v4
18 |
19 | - uses: actions/setup-dotnet@v4
20 | with:
21 | dotnet-version: 8.0.x
22 |
23 | - run: |
24 | dotnet publish src/AutoUpdate/AutoUpdate.csproj -c Release -o bin/lipui -r ${{ matrix.runtime }}
25 |
26 | dotnet build src/LipUI/LipUI.csproj -c Release -o bin/lipui -r ${{ matrix.runtime }} `
27 | -p:DebugType=none -p:Platform=${{ matrix.platform }}
28 |
29 | copy runtimes/win10-${{ matrix.platform }}/native/Microsoft.WindowsAppRuntime.Bootstrap.dll bin/lipui
30 |
31 | - uses: actions/upload-artifact@v4
32 | with:
33 | name: LipUI-${{ matrix.runtime }}-${{ github.sha }}
34 | path: bin
35 |
36 | update-changelog:
37 | permissions:
38 | contents: write
39 | runs-on: ubuntu-latest
40 | steps:
41 | - uses: actions/checkout@v4
42 |
43 | - id: extract-release-notes
44 | uses: ffurrer2/extract-release-notes@v2
45 |
46 | - uses: softprops/action-gh-release@v1
47 | with:
48 | body: |
49 | ${{ steps.extract-release-notes.outputs.release_notes }}
50 |
51 | upload-to-release:
52 | needs:
53 | - build
54 | permissions:
55 | contents: write
56 | runs-on: ubuntu-latest
57 | strategy:
58 | matrix:
59 | runtime:
60 | - win-arm64
61 | - win-x64
62 | steps:
63 | - uses: actions/checkout@v4
64 |
65 | - uses: actions/download-artifact@v4
66 | with:
67 | name: LipUI-${{ matrix.runtime }}-${{ github.sha }}
68 | path: bin
69 |
70 | - run: |
71 | cp CHANGELOG.md COPYING README.md bin/
72 |
73 | - name: Create archive
74 | run: |
75 | cd bin
76 | zip -r ../LipUI-${{ matrix.runtime }}.zip *
77 | cd ..
78 |
79 | - uses: softprops/action-gh-release@v1
80 | with:
81 | files: |
82 | LipUI-${{ matrix.runtime }}.zip
83 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 |
8 | ## [0.4.1] - 2024-03-05
9 |
10 | ### Added
11 |
12 | - Introduce support for .NET 8.0.
13 | - Provide a built-in default proxy setter for users in Mainland China.
14 | - Introduce a plugin configuration system.
15 | - Add an auto-update feature.
16 |
17 | ### Changed
18 |
19 | - Refactor the display logic of the info bar based on queue information.
20 |
21 | ### Fixed
22 |
23 | - Fix related bugs.
24 |
25 | ## [0.4.0] - 2024-02-04
26 |
27 | ### Added
28 |
29 | - Install teeth by dragging and dropping the package file into the window.
30 |
31 | ### Changed
32 |
33 | - Adapt to lip-index 0.8.0.
34 |
35 | ### Fixed
36 |
37 | - Crash under some conditions.
38 |
39 | ## [0.3.0] - 2024-01-18
40 |
41 | ### Changed
42 |
43 | - Rewrite all the code.
44 |
45 | ## [0.2.7] - 2023-06-27
46 |
47 | ### Added
48 |
49 | - Cache purge.
50 |
51 | ### Changed
52 |
53 | - Adapt to lip 0.15.0.
54 |
55 | ### Fixed
56 |
57 | - Crash on deleting working directory.
58 |
59 | ## [0.2.6] - 2023-04-24
60 |
61 | ### Fixed
62 |
63 | - Wrong visibility of the `skip dependency` texts.
64 |
65 | ## [0.2.5] - 2023-04-04
66 |
67 | ### Added
68 |
69 | - i18n support.
70 |
71 | ### Changed
72 |
73 | - Optimize the UI.
74 | - Optimize the UI.
75 |
76 | ## [0.2.4] - 2023-03-11
77 |
78 | ### Added
79 |
80 | - Animations.
81 |
82 | ### Changed
83 |
84 | - Optimize user experience.
85 |
86 | ### Removed
87 |
88 | - Icon at status bar.
89 |
90 | ### Fixed
91 |
92 | - Unicode encoding.
93 |
94 | ## [0.2.3] - 2023-03-07
95 |
96 | ### Added
97 |
98 | - Pop up EULA.
99 | - Packages now can be filtered by tags.
100 | - Upgrade support for packages.
101 |
102 | ### Changed
103 |
104 | - Optimize the UI.
105 |
106 | ## [0.2.2] - 2023-02-19
107 |
108 | ### Fixed
109 |
110 | - Some bugs.
111 |
112 | ## [0.2.1] - 2023-02-18
113 |
114 | ### Fixed
115 |
116 | - Some bugs.
117 |
118 | ## [0.2.0] - 2023-02-15
119 |
120 | ### Added
121 |
122 | - More functionalities.
123 |
124 | ## [0.1.0] - 2023-02-13
125 |
126 | - Initial release.
127 |
128 | [0.4.0]: https://github.com/lippkg/LipUI/compare/v0.3.0...v0.4.0
129 | [0.3.0]: https://github.com/lippkg/LipUI/compare/v0.2.7...v0.3.0
130 | [0.2.7]: https://github.com/lippkg/LipUI/compare/v0.2.6...v0.2.7
131 | [0.2.6]: https://github.com/lippkg/LipUI/compare/v0.2.5...v0.2.6
132 | [0.2.5]: https://github.com/lippkg/LipUI/compare/v0.2.4...v0.2.5
133 | [0.2.4]: https://github.com/lippkg/LipUI/compare/v0.2.3...v0.2.4
134 | [0.2.3]: https://github.com/lippkg/LipUI/compare/v0.2.2...v0.2.3
135 | [0.2.2]: https://github.com/lippkg/LipUI/compare/v0.2.1...v0.2.2
136 | [0.2.1]: https://github.com/lippkg/LipUI/compare/v0.2.0...v0.2.1
137 | [0.2.0]: https://github.com/lippkg/LipUI/compare/v0.1.0...v0.2.0
138 | [0.1.0]: https://github.com/lippkg/LipUI/releases/tag/v0.1.0
139 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > [!IMPORTANT]
2 | > I'm refactoring lip and lipui will be integrated within lip. Go to [lip repo](https://github.com/futrime/lip) to keep track.
3 |
4 | # LipUI
5 |
6 | A GUI client for lip
7 |
8 | ## Install
9 |
10 | 1. Download the latest release from [here](https://github.com/lippkg/LipUI/releases).
11 |
12 | 2. Extract the archive.
13 |
14 | 3. Run `LipUI.exe`.
15 |
16 | ## Usage
17 |
18 | Just follow the instructions on the screen.
19 |
20 | ## Contributing
21 |
22 | If you have any suggestions or improvements, please [submit an issue](https://github.com/lippkg/LipUI/issues) or a pull request.
23 |
24 | LipUI follows the [Contributor Covenant](https://www.contributor-covenant.org/version/2/1/code_of_conduct/) Code of Conduct.
25 |
26 | ## License
27 |
28 | GPL-3.0-only © lippkg
29 |
--------------------------------------------------------------------------------
/lipui.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.8.34408.163
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LipUI", "src\LipUI\LipUI.csproj", "{E0A3F349-6972-4266-8730-9E983EEFCA0D}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoUpdate", "src\AutoUpdate\AutoUpdate.csproj", "{184A05DC-72A5-47D9-AFCB-0228CD8C563F}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Debug|ARM64 = Debug|ARM64
14 | Debug|x64 = Debug|x64
15 | Release|Any CPU = Release|Any CPU
16 | Release|ARM64 = Release|ARM64
17 | Release|x64 = Release|x64
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Debug|Any CPU.ActiveCfg = Debug|x64
21 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Debug|Any CPU.Build.0 = Debug|x64
22 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Debug|Any CPU.Deploy.0 = Debug|x64
23 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Debug|ARM64.ActiveCfg = Debug|ARM64
24 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Debug|ARM64.Build.0 = Debug|ARM64
25 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Debug|ARM64.Deploy.0 = Debug|ARM64
26 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Debug|x64.ActiveCfg = Debug|x64
27 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Debug|x64.Build.0 = Debug|x64
28 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Debug|x64.Deploy.0 = Debug|x64
29 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Release|Any CPU.ActiveCfg = Release|x64
30 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Release|Any CPU.Build.0 = Release|x64
31 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Release|Any CPU.Deploy.0 = Release|x64
32 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Release|ARM64.ActiveCfg = Release|ARM64
33 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Release|ARM64.Build.0 = Release|ARM64
34 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Release|ARM64.Deploy.0 = Release|ARM64
35 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Release|x64.ActiveCfg = Release|x64
36 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Release|x64.Build.0 = Release|x64
37 | {E0A3F349-6972-4266-8730-9E983EEFCA0D}.Release|x64.Deploy.0 = Release|x64
38 | {184A05DC-72A5-47D9-AFCB-0228CD8C563F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {184A05DC-72A5-47D9-AFCB-0228CD8C563F}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {184A05DC-72A5-47D9-AFCB-0228CD8C563F}.Debug|ARM64.ActiveCfg = Debug|Any CPU
41 | {184A05DC-72A5-47D9-AFCB-0228CD8C563F}.Debug|ARM64.Build.0 = Debug|Any CPU
42 | {184A05DC-72A5-47D9-AFCB-0228CD8C563F}.Debug|x64.ActiveCfg = Debug|Any CPU
43 | {184A05DC-72A5-47D9-AFCB-0228CD8C563F}.Debug|x64.Build.0 = Debug|Any CPU
44 | {184A05DC-72A5-47D9-AFCB-0228CD8C563F}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 | {184A05DC-72A5-47D9-AFCB-0228CD8C563F}.Release|Any CPU.Build.0 = Release|Any CPU
46 | {184A05DC-72A5-47D9-AFCB-0228CD8C563F}.Release|ARM64.ActiveCfg = Release|Any CPU
47 | {184A05DC-72A5-47D9-AFCB-0228CD8C563F}.Release|ARM64.Build.0 = Release|Any CPU
48 | {184A05DC-72A5-47D9-AFCB-0228CD8C563F}.Release|x64.ActiveCfg = Release|Any CPU
49 | {184A05DC-72A5-47D9-AFCB-0228CD8C563F}.Release|x64.Build.0 = Release|Any CPU
50 | EndGlobalSection
51 | GlobalSection(SolutionProperties) = preSolution
52 | HideSolutionNode = FALSE
53 | EndGlobalSection
54 | GlobalSection(ExtensibilityGlobals) = postSolution
55 | SolutionGuid = {19C83D64-AA9C-4A55-9A1F-D035A212D14F}
56 | EndGlobalSection
57 | EndGlobal
58 |
--------------------------------------------------------------------------------
/runtimes/win10-arm64/native/Microsoft.WindowsAppRuntime.Bootstrap.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/futrime/lipui/f5d2e51f434dcdc0424a3ef6284d5feb490bc99d/runtimes/win10-arm64/native/Microsoft.WindowsAppRuntime.Bootstrap.dll
--------------------------------------------------------------------------------
/runtimes/win10-x64/native/Microsoft.WindowsAppRuntime.Bootstrap.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/futrime/lipui/f5d2e51f434dcdc0424a3ef6284d5feb490bc99d/runtimes/win10-x64/native/Microsoft.WindowsAppRuntime.Bootstrap.dll
--------------------------------------------------------------------------------
/runtimes/win10-x86/native/Microsoft.WindowsAppRuntime.Bootstrap.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/futrime/lipui/f5d2e51f434dcdc0424a3ef6284d5feb490bc99d/runtimes/win10-x86/native/Microsoft.WindowsAppRuntime.Bootstrap.dll
--------------------------------------------------------------------------------
/src/AutoUpdate/AutoUpdate.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | enable
7 | enable
8 | true
9 | true
10 |
11 |
12 |
13 | none
14 |
15 |
16 |
17 | none
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/AutoUpdate/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 | using System.CommandLine;
3 | using System.Diagnostics;
4 |
5 | using var factory = LoggerFactory.Create(builder => builder.AddConsole());
6 | var logger = factory.CreateLogger("AutoUpdate");
7 |
8 | var lipuiDirOption = new Option("--lipui-dir", "LipUI directory")
9 | {
10 | IsRequired = true,
11 | };
12 | var lipuiPid = new Option("--lipui-pid", "LipUI process ID")
13 | {
14 | IsRequired = true
15 | };
16 |
17 | RootCommand rootCommand = [lipuiDirOption, lipuiPid];
18 | rootCommand.SetHandler((lipuiPath, pid) =>
19 | {
20 | var lipuiProcess = Process.GetProcessById(pid);
21 |
22 | lipuiProcess.Kill();
23 | lipuiProcess.WaitForExit();
24 | logger.LogInformation("Waiting for lipui process {pid} to exit", pid);
25 |
26 | Task.Delay(TimeSpan.FromSeconds(2)).Wait();
27 |
28 | var currentDir = new FileInfo(Environment.ProcessPath!).Directory ?? throw new InvalidOperationException("Current directory not found");
29 |
30 | var lipuiDir = new DirectoryInfo(lipuiPath);
31 |
32 | if (lipuiDir.FullName == currentDir.FullName)
33 | {
34 | logger.LogError("LipUI directory cannot be the same as the current directory");
35 | logger.LogError("lipuiDir: {lipuiDir.FullName} currentDir: {currentDir.FullName}", lipuiDir.FullName, currentDir.FullName);
36 | return;
37 | }
38 |
39 | var lipuiExeFile = new FileInfo(Path.Combine(lipuiDir.FullName, "LipUI.exe"));
40 | if (lipuiExeFile.Exists is false)
41 | {
42 | logger.LogError("LipUI.exe file not found");
43 | return;
44 | }
45 |
46 | foreach (var dir in currentDir.EnumerateDirectories())
47 | {
48 | var temp = Path.Combine(lipuiDir.FullName, dir.Name);
49 | if (Directory.Exists(temp))
50 | Directory.Delete(temp, true);
51 | Directory.Move(dir.FullName, temp);
52 | logger.LogInformation("Moved {dir} to {lipuiDir}", dir.Name, lipuiDir.FullName);
53 | }
54 |
55 | foreach (var file in currentDir.EnumerateFiles())
56 | {
57 | File.Move(file.FullName, Path.Combine(lipuiDir.FullName, file.Name), true);
58 | logger.LogInformation("Moved {file} to {lipuiWorkingDir}", file.Name, lipuiDir.FullName);
59 | }
60 |
61 | Task.Delay(TimeSpan.FromSeconds(2)).Wait();
62 |
63 | Process.Start(lipuiExeFile.FullName);
64 | Environment.Exit(0);
65 |
66 | }, lipuiDirOption, lipuiPid);
67 |
68 | rootCommand.Invoke(args);
--------------------------------------------------------------------------------
/src/LipUI/App.xaml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/LipUI/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using LipUI.Models;
2 | using Microsoft.UI.Xaml;
3 | // To learn more about WinUI, the WinUI project structure,
4 | // and more about our project templates, see: http://aka.ms/winui-project-info.
5 |
6 | namespace LipUI
7 | {
8 | ///
9 | /// Provides application-specific behavior to supplement the default Application class.
10 | ///
11 | public partial class App : Application
12 | {
13 | ///
14 | /// Initializes the singleton application object. This is the first line of authored code
15 | /// executed, and as such is the logical equivalent of main() or WinMain().
16 | ///
17 | public App()
18 | {
19 | InitializeComponent();
20 |
21 | Current.RequestedTheme = InternalServices.ApplicationTheme = Main.Config.PersonalizationSettings.ColorTheme switch
22 | {
23 | ElementTheme.Dark => ApplicationTheme.Dark,
24 | ElementTheme.Light => ApplicationTheme.Light,
25 | ElementTheme.Default or _ => Current.RequestedTheme
26 | };
27 | }
28 |
29 | ///
30 | /// Invoked when the application is launched.
31 | ///
32 | /// Details about the launch request and process.
33 | protected override void OnLaunched(LaunchActivatedEventArgs args)
34 | {
35 |
36 | m_window = new MainWindow();
37 | m_window.Activate();
38 |
39 | UnhandledException += App_UnhandledException;
40 | }
41 |
42 | private async void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
43 | {
44 | static async ValueTask _exp(Exception ex)
45 | {
46 | await InternalServices.ShowInfoBarAsync(ex, containsStacktrace: true);
47 | if (ex.InnerException is not null)
48 | await _exp(ex.InnerException);
49 | }
50 |
51 | if (InternalServices.MainWindow is not null)
52 | {
53 | e.Handled = true;
54 | await _exp(e.Exception);
55 | }
56 | }
57 |
58 | internal Window? m_window;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/LipUI/Assets/Images.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace LipUI.Assets {
12 | using System;
13 |
14 |
15 | ///
16 | /// 一个强类型的资源类,用于查找本地化的字符串等。
17 | ///
18 | // 此类是由 StronglyTypedResourceBuilder
19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
21 | // (以 /str 作为命令选项),或重新生成 VS 项目。
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Images {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Images() {
33 | }
34 |
35 | ///
36 | /// 返回此类使用的缓存的 ResourceManager 实例。
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LipUI.Assets.Images", typeof(Images).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// 重写当前线程的 CurrentUICulture 属性,对
51 | /// 使用此强类型资源类的所有资源查找执行重写。
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// 查找 System.Byte[] 类型的本地化资源。
65 | ///
66 | internal static byte[] applicationIcon_1024 {
67 | get {
68 | object obj = ResourceManager.GetObject("applicationIcon_1024", resourceCulture);
69 | return ((byte[])(obj));
70 | }
71 | }
72 |
73 | ///
74 | /// 查找 System.Byte[] 类型的本地化资源。
75 | ///
76 | internal static byte[] applicationIcon_256 {
77 | get {
78 | object obj = ResourceManager.GetObject("applicationIcon_256", resourceCulture);
79 | return ((byte[])(obj));
80 | }
81 | }
82 |
83 | ///
84 | /// 查找 System.Byte[] 类型的本地化资源。
85 | ///
86 | internal static byte[] glass {
87 | get {
88 | object obj = ResourceManager.GetObject("glass", resourceCulture);
89 | return ((byte[])(obj));
90 | }
91 | }
92 |
93 | ///
94 | /// 查找 System.Byte[] 类型的本地化资源。
95 | ///
96 | internal static byte[] grass_block {
97 | get {
98 | object obj = ResourceManager.GetObject("grass_block", resourceCulture);
99 | return ((byte[])(obj));
100 | }
101 | }
102 |
103 | ///
104 | /// 查找 System.Byte[] 类型的本地化资源。
105 | ///
106 | internal static byte[] netherrack {
107 | get {
108 | object obj = ResourceManager.GetObject("netherrack", resourceCulture);
109 | return ((byte[])(obj));
110 | }
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/LipUI/Assets/SplashScreen.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/futrime/lipui/f5d2e51f434dcdc0424a3ef6284d5feb490bc99d/src/LipUI/Assets/SplashScreen.scale-200.png
--------------------------------------------------------------------------------
/src/LipUI/Assets/Square150x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/futrime/lipui/f5d2e51f434dcdc0424a3ef6284d5feb490bc99d/src/LipUI/Assets/Square150x150Logo.scale-200.png
--------------------------------------------------------------------------------
/src/LipUI/Assets/Square44x44Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/futrime/lipui/f5d2e51f434dcdc0424a3ef6284d5feb490bc99d/src/LipUI/Assets/Square44x44Logo.scale-200.png
--------------------------------------------------------------------------------
/src/LipUI/Assets/Square44x44Logo.targetsize-24_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/futrime/lipui/f5d2e51f434dcdc0424a3ef6284d5feb490bc99d/src/LipUI/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
--------------------------------------------------------------------------------
/src/LipUI/Assets/StoreLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/futrime/lipui/f5d2e51f434dcdc0424a3ef6284d5feb490bc99d/src/LipUI/Assets/StoreLogo.png
--------------------------------------------------------------------------------
/src/LipUI/Assets/Wide310x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/futrime/lipui/f5d2e51f434dcdc0424a3ef6284d5feb490bc99d/src/LipUI/Assets/Wide310x150Logo.scale-200.png
--------------------------------------------------------------------------------
/src/LipUI/Assets/WindowIcon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/futrime/lipui/f5d2e51f434dcdc0424a3ef6284d5feb490bc99d/src/LipUI/Assets/WindowIcon.ico
--------------------------------------------------------------------------------
/src/LipUI/Assets/applicationIcon-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/futrime/lipui/f5d2e51f434dcdc0424a3ef6284d5feb490bc99d/src/LipUI/Assets/applicationIcon-1024.png
--------------------------------------------------------------------------------
/src/LipUI/Assets/applicationIcon-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/futrime/lipui/f5d2e51f434dcdc0424a3ef6284d5feb490bc99d/src/LipUI/Assets/applicationIcon-256.png
--------------------------------------------------------------------------------
/src/LipUI/Assets/glass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/futrime/lipui/f5d2e51f434dcdc0424a3ef6284d5feb490bc99d/src/LipUI/Assets/glass.png
--------------------------------------------------------------------------------
/src/LipUI/Assets/grass_block.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/futrime/lipui/f5d2e51f434dcdc0424a3ef6284d5feb490bc99d/src/LipUI/Assets/grass_block.png
--------------------------------------------------------------------------------
/src/LipUI/Assets/netherrack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/futrime/lipui/f5d2e51f434dcdc0424a3ef6284d5feb490bc99d/src/LipUI/Assets/netherrack.png
--------------------------------------------------------------------------------
/src/LipUI/BuiltInPlugins/DefaultLipProxySetter/DefaultLipProxySetter.cs:
--------------------------------------------------------------------------------
1 | using LipUI.Models.Lip;
2 | using LipUI.Models.Plugin;
3 | using Microsoft.UI.Xaml;
4 | using Microsoft.UI.Xaml.Controls;
5 |
6 | namespace LipUI.BuiltInPlugins.DefaultLipProxySetter;
7 |
8 | [LipUIModule]
9 | internal class DefaultLipProxySetter : IPlugin
10 | {
11 | private static class Strings
12 | {
13 | public const string PluginName = "Lip默认代理配置器";
14 | public const string ConfirmButtonContent = "是";
15 | public const string CancelButtonContent = "否";
16 | public const string InfoBarMessage = "检测到系统默认语言为简体中文,是否设置默认代理?";
17 | public const string NullLipConsoleInstance = "无法获取LipConsole";
18 | public const string SettingUp = "设置中";
19 | public const string Complete = "设置完成";
20 | }
21 |
22 | public string PluginName => Strings.PluginName;
23 |
24 | public bool DefaultEnabled => System.Globalization.CultureInfo.CurrentCulture.Name.ToLower() is "zh-cn";
25 |
26 | public Guid Guid => new("4A909307-3571-5020-681D-2491B045A8B5");
27 |
28 |
29 | private static class DefaultProxies
30 | {
31 | public const string Github_LipInstaller = "https://mirror.ghproxy.com";
32 | public const string Github_Lip = "https://github.bibk.top";
33 | public const string GoProxy_Lip = "https://goproxy.cn";
34 | }
35 |
36 | void IPlugin.OnInitlalize(LipuiServices services)
37 | {
38 | var config = services.GetPluginConfig(this);
39 |
40 | var selfDisabled = config["SelfDisabled"];
41 | if (selfDisabled.IsNull)
42 | config["SelfDisabled"] = false;
43 | }
44 |
45 | void IPlugin.OnEnable(LipuiServices services)
46 | {
47 | var config = services.GetPluginConfig(this);
48 | if (config["SelfDisabled"].As())
49 | return;
50 |
51 | config["SelfDisabled"] = true;
52 |
53 | if (System.Globalization.CultureInfo.CurrentCulture.Name.ToLower() is "zh-cn")
54 | {
55 | services.DispatcherQueue.TryEnqueue(async () =>
56 | {
57 | var cts = new CancellationTokenSource();
58 | var confirmButton = new Button()
59 | {
60 | Content = Strings.ConfirmButtonContent,
61 | };
62 | var cancelButton = new Button()
63 | {
64 | Content = Strings.CancelButtonContent,
65 | };
66 |
67 | confirmButton.Click += async (sender, _) =>
68 | {
69 | services.LipuiConfig.GeneralSettings.GithubProxy = DefaultProxies.Github_LipInstaller;
70 | var lip = await services.CreateLipConsoleAsync((sender as Button)!.XamlRoot, string.Empty);
71 |
72 | if (lip is null)
73 | {
74 | cts.Cancel();
75 | services.ShowInfoBar(
76 | message: Strings.NullLipConsoleInstance,
77 | severity: InfoBarSeverity.Error);
78 | return;
79 | }
80 |
81 | cts.Cancel();
82 |
83 | services.ShowInfoBar(
84 | message: Strings.SettingUp,
85 | severity: InfoBarSeverity.Informational,
86 | interval: TimeSpan.FromSeconds(2));
87 |
88 | await lip.Run(LipCommand.CreateCommand() + LipCommand.Config + $"GitHubMirrorURL {DefaultProxies.Github_Lip}");
89 |
90 | await lip.Run(LipCommand.CreateCommand() + LipCommand.Config + $"GoModuleProxyURL {DefaultProxies.GoProxy_Lip}");
91 |
92 | services.ShowInfoBar(
93 | message: Strings.Complete,
94 | severity: InfoBarSeverity.Success,
95 | interval: TimeSpan.FromSeconds(3));
96 | };
97 | cancelButton.Click += (_, _) => cts.Cancel();
98 |
99 | var stackPanel = new StackPanel()
100 | {
101 | Orientation = Orientation.Horizontal,
102 | Children = { confirmButton, cancelButton },
103 | Margin = new(4),
104 | Spacing = 8,
105 | HorizontalAlignment = HorizontalAlignment.Center,
106 | VerticalAlignment = VerticalAlignment.Center
107 | };
108 |
109 | await services.ShowInfoBarAsync(
110 | severity: InfoBarSeverity.Warning,
111 | message: Strings.InfoBarMessage,
112 | interval: TimeSpan.FromSeconds(30),
113 | barContent: stackPanel,
114 | cancellationToken: cts.Token);
115 | });
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/LipUI/BuiltInPlugins/LipPanel/LipPanel.cs:
--------------------------------------------------------------------------------
1 | using LipUI.Models.Plugin;
2 | using Microsoft.UI;
3 | using Microsoft.UI.Xaml;
4 | using Microsoft.UI.Xaml.Controls;
5 | using Microsoft.UI.Xaml.Media;
6 |
7 | namespace LipUI.BuiltInPlugins.LipPanel;
8 |
9 | //[LipUIModule]
10 | internal class LipPanel : IHomePageModule
11 | {
12 | public Type PageType => typeof(LipPanelPage);
13 |
14 | public string PluginName => "LipPanel";
15 |
16 | public bool DefaultEnabled => true;
17 |
18 | public Guid Guid => new("21A13C74-BEC2-41BE-782F-1EF4BD7701AB");
19 |
20 | FrameworkElement IHomePageModule.IconContent => new SymbolIcon(Symbol.Remote)
21 | {
22 | Height = 32,
23 | Width = 32,
24 | };
25 |
26 | Brush IHomePageModule.IconBackground =>
27 | LipuiServices.ApplicationTheme is ApplicationTheme.Light ?
28 | new SolidColorBrush(Colors.LightGray) :
29 | new SolidColorBrush(Colors.DarkGray);
30 | }
31 |
--------------------------------------------------------------------------------
/src/LipUI/BuiltInPlugins/LipPanel/LipPanelPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/LipUI/BuiltInPlugins/LipPanel/LipPanelPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.UI.Xaml.Controls;
2 |
3 | // To learn more about WinUI, the WinUI project structure,
4 | // and more about our project templates, see: http://aka.ms/winui-project-info.
5 |
6 | namespace LipUI.BuiltInPlugins.LipPanel
7 | {
8 | ///
9 | /// An empty page that can be used on its own or navigated to within a Frame.
10 | ///
11 | public sealed partial class LipPanelPage : Page
12 | {
13 | public LipPanelPage()
14 | {
15 | this.InitializeComponent();
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/LipUI/BuiltInPlugins/LipuiTips/LipuiTips.cs:
--------------------------------------------------------------------------------
1 | using LipUI.Models.Plugin;
2 |
3 | namespace LipUI.BuiltInPlugins.LipuiTips;
4 |
5 | //[LipUIModule]
6 | internal class LipuiTips : IPlugin
7 | {
8 | public string PluginName => "Tips";
9 |
10 | public bool DefaultEnabled => true;
11 |
12 | public Guid Guid => new("9116AABC-6448-9933-DE77-D477EB10B857");
13 |
14 | void IPlugin.OnEnable(LipuiServices services)
15 | {
16 | }
17 | }
--------------------------------------------------------------------------------
/src/LipUI/LipUI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | WinExe
4 | net8.0-windows10.0.19041.0
5 | 10.0.17763.0
6 | LipUI
7 | Assets/WindowIcon.ico
8 | app.manifest
9 | x64;arm64
10 | win-x64;win-arm64
11 | enable
12 | enable
13 | true
14 | true
15 | None
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | true
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/LipUI/MainWindow/MainWIndowWin32Invoke.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 | using WinRT;
3 | using static PInvoke.User32;
4 |
5 | namespace LipUI;
6 |
7 | internal partial class MainWindow
8 | {
9 | private readonly int MinWidth = 800;
10 | private readonly int MinHeight = 450;
11 |
12 | private NativeMethods.WinProc? newWndProc = null;
13 | private nint oldWndProc = nint.Zero;
14 |
15 | private void SubClassing()
16 | {
17 | var hwnd = this.As().WindowHandle;
18 | if (hwnd == nint.Zero)
19 | {
20 | int error = Marshal.GetLastWin32Error();
21 | throw new InvalidOperationException($"Failed to get window handler: error code {error}");
22 | }
23 |
24 | newWndProc = new(NewWindowProc);
25 |
26 | // Here we use the NativeMethods class 👇
27 | oldWndProc = NativeMethods.SetWindowLong(hwnd, WindowLongIndexFlags.GWL_WNDPROC, newWndProc);
28 | if (oldWndProc == nint.Zero)
29 | {
30 | int error = Marshal.GetLastWin32Error();
31 | throw new InvalidOperationException($"Failed to set GWL_WNDPROC: error code {error}");
32 | }
33 | }
34 |
35 | private nint NewWindowProc(nint hWnd, WindowMessage Msg, nint wParam, nint lParam)
36 | {
37 | [DllImport("user32.dll")]
38 | static extern nint CallWindowProc(nint lpPrevWndFunc, nint hWnd, WindowMessage Msg, nint wParam, nint lParam);
39 |
40 | switch (Msg)
41 | {
42 | case WindowMessage.WM_GETMINMAXINFO:
43 | var dpi = GetDpiForWindow(hWnd);
44 | float scalingFactor = (float)dpi / 96;
45 |
46 | MINMAXINFO minMaxInfo = Marshal.PtrToStructure(lParam);
47 | minMaxInfo.ptMinTrackSize.x = (int)(MinWidth * scalingFactor);
48 | minMaxInfo.ptMinTrackSize.y = (int)(MinHeight * scalingFactor);
49 | Marshal.StructureToPtr(minMaxInfo, lParam, true);
50 | break;
51 |
52 | }
53 | return CallWindowProc(oldWndProc, hWnd, Msg, wParam, lParam);
54 | }
55 |
56 | private static class NativeMethods
57 | {
58 | [StructLayout(LayoutKind.Sequential)]
59 | struct MINMAXINFO
60 | {
61 | public PInvoke.POINT ptReserved;
62 | public PInvoke.POINT ptMaxSize;
63 | public PInvoke.POINT ptMaxPosition;
64 | public PInvoke.POINT ptMinTrackSize;
65 | public PInvoke.POINT ptMaxTrackSize;
66 | }
67 |
68 |
69 | public delegate nint WinProc(nint hWnd, WindowMessage Msg, nint wParam, nint lParam);
70 |
71 | // We have to handle the 32-bit and 64-bit functions separately.
72 | // 'SetWindowLongPtr' is the 64-bit version of 'SetWindowLong', and isn't available in user32.dll for 32-bit processes.
73 | [DllImport("user32.dll", EntryPoint = "SetWindowLong")]
74 | private static extern nint SetWindowLong32(nint hWnd, WindowLongIndexFlags nIndex, WinProc newProc);
75 |
76 | [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
77 | private static extern nint SetWindowLong64(nint hWnd, WindowLongIndexFlags nIndex, WinProc newProc);
78 |
79 | public static nint SetWindowLong(nint hWnd, WindowLongIndexFlags nIndex, WinProc newProc)
80 | => nint.Size is 4 ? SetWindowLong32(hWnd, nIndex, newProc) : SetWindowLong64(hWnd, nIndex, newProc);
81 |
82 | [ComImport]
83 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
84 | [Guid("EECDBF0E-BAE9-4CB6-A68E-9598E1CB57BB")]
85 | internal interface IWindowNative
86 | {
87 | nint WindowHandle { get; }
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/LipUI/MainWindow/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
39 |
40 |
42 |
43 |
48 |
49 |
56 |
57 |
58 |
59 |
68 |
69 |
70 |
71 |
75 |
76 |
80 |
81 |
85 |
86 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
102 |
103 |
104 |
105 |
106 |
107 |
112 |
113 |
114 |
115 |
121 |
122 |
123 |
124 |
126 |
128 |
129 |
130 |
132 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
--------------------------------------------------------------------------------
/src/LipUI/MainWindow/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using LipUI.Models;
2 | using LipUI.Models.Lip;
3 | using LipUI.Models.Plugin;
4 | using LipUI.Pages.LipExecutionPanel;
5 | using LipUI.Pages.Settings;
6 | using Microsoft.UI.Dispatching;
7 | using Microsoft.UI.Xaml;
8 | using Microsoft.UI.Xaml.Controls;
9 | using Windows.ApplicationModel.DataTransfer;
10 | using Windows.Storage;
11 | using Windows.System;
12 |
13 | // To learn more about WinUI, the WinUI project structure,
14 | // and more about our project templates, see: http://aka.ms/winui-project-info.
15 |
16 | namespace LipUI;
17 |
18 | ///
19 | /// An empty window that can be used on its own or navigated to within a Frame.
20 | ///
21 | internal sealed partial class MainWindow : Window
22 | {
23 | public MainWindow()
24 | {
25 | InitializeComponent();
26 |
27 | AppWindow.Closing += (_, _) => InternalServices.OnWindowClosed();
28 |
29 | ExtendsContentIntoTitleBar = true;
30 | SetTitleBar(AppTitleBar);
31 |
32 | SubClassing();
33 |
34 | AppWindow.Resize(new(1600, 900));
35 |
36 | InternalServices.MainWindow = this;
37 |
38 | PersonalizationSettingsView.Initialize(Main.Config.PersonalizationSettings);
39 |
40 | enabled = PluginEnabled;
41 | disabled = PluginDisabled;
42 | }
43 |
44 | private async void RootBorder_Drop(object sender, DragEventArgs e)
45 | {
46 | if (e.DataView.Contains(StandardDataFormats.StorageItems) is false)
47 | return;
48 |
49 | foreach (var item in await e.DataView.GetStorageItemsAsync())
50 | {
51 | if (item is StorageFile file && Path.GetExtension(file.Path) is ".tth")
52 | {
53 | var lip = await Main.CreateLipConsole(RootBorder.XamlRoot);
54 | if (lip is null)
55 | {
56 | InternalServices.ShowInfoBar(
57 | "infobar$error".GetLocalized(),
58 | Main.Config.SelectedServer is null ?
59 | "lipExecution$nullServerPath".GetLocalized() :
60 | "lipExecution$nullLipPath".GetLocalized(),
61 | InfoBarSeverity.Error);
62 |
63 | return;
64 | }
65 | var cmd = LipCommand.CreateCommand() + LipCommand.Install + file.Path;
66 | var info = new List();
67 |
68 | ContentFrame.Navigate(
69 | typeof(LipExecutionPanelPage),
70 | new LipExecutionPanelPage.NavigationArgs(file.Path, info, lip, cmd));
71 | }
72 | else
73 | {
74 | await InternalServices.ShowInfoBarAsync(
75 | "infobar$error".GetLocalized(),
76 | @$"{item.Name} is not a '.tth' file.",
77 | InfoBarSeverity.Error);
78 | }
79 | }
80 | }
81 |
82 | private void RootBorder_DragOver(object sender, DragEventArgs e)
83 | {
84 | e.AcceptedOperation = DataPackageOperation.Move;
85 | e.DragUIOverride.IsCaptionVisible = false;
86 | e.DragUIOverride.IsGlyphVisible = false;
87 | }
88 |
89 | private void RootBorder_Loaded(object sender, RoutedEventArgs e)
90 | {
91 | Task.Run(PluginSystem.LoadAsync);
92 |
93 | var timer = DispatcherQueue.CreateTimer();
94 | timer.Interval = TimeSpan.FromSeconds(60);
95 | timer.IsRepeating = true;
96 | timer.Tick += (_sender, e) => Task.Run(Main.SaveConfig);
97 | timer.Start();
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/LipUI/MainWindow/MainWindowInfoBarController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.UI.Xaml;
2 | using Microsoft.UI.Xaml.Controls;
3 |
4 | namespace LipUI;
5 |
6 | internal partial class MainWindow
7 | {
8 | private record struct InfoBarTask(
9 | ManualResetEvent Mre,
10 | string? Title,
11 | string? Message,
12 | InfoBarSeverity Severity,
13 | TimeSpan Interval,
14 | UIElement? Content,
15 | Action? Completed,
16 | CancellationToken CancellationToken);
17 |
18 | private readonly Queue InfoBarTaskQueue = new();
19 | private bool IsRunning = false;
20 |
21 | private void ShowInfoBar(InfoBarTask task)
22 | {
23 | DispatcherQueue.TryEnqueue(() =>
24 | {
25 | GlobalInfoBar.Title = task.Title;
26 | GlobalInfoBar.Message = task.Message;
27 | GlobalInfoBar.Severity = task.Severity;
28 | GlobalInfoBar.IsClosable = false;
29 | GlobalInfoBar.Content = task.Content;
30 | GlobalInfoBar.IsOpen = true;
31 |
32 | void set(object? sender, object e)
33 | {
34 | InfoBarPopInStoryboard.Completed -= set;
35 | task.Mre.Set();
36 | }
37 | InfoBarPopInStoryboard.Completed += set;
38 |
39 | InfoBarPopInStoryboard.Begin();
40 | });
41 | }
42 |
43 | private void CloseInfoBar(ManualResetEvent mre)
44 | {
45 | InfoBarPopOutStoryboard.Begin();
46 |
47 | void task(object? sender, object e)
48 | {
49 | InfoBarPopOutStoryboard.Completed -= task;
50 | GlobalInfoBar.IsOpen = false;
51 | mre.Set();
52 | }
53 | InfoBarPopOutStoryboard.Completed += task;
54 | }
55 |
56 | private void StartShowInfoBarLoop()
57 | => Task.Run(async () =>
58 | {
59 | InfoBarTask task;
60 | bool dequeued;
61 |
62 | IsRunning = true;
63 | LOOP:
64 | lock (InfoBarTaskQueue)
65 | {
66 | dequeued = InfoBarTaskQueue.TryDequeue(out task);
67 | }
68 |
69 | if (dequeued)
70 | {
71 | DispatcherQueue.TryEnqueue(() => ShowInfoBar(task));
72 |
73 | try
74 | {
75 | await Task.Delay(task.Interval, task.CancellationToken);
76 | }
77 | catch (TaskCanceledException) { }
78 |
79 | task.Mre.Reset();
80 | DispatcherQueue.TryEnqueue(() => CloseInfoBar(task.Mre));
81 | task.Mre.WaitOne();
82 | task.Mre.Dispose();
83 | task.Completed?.Invoke();
84 |
85 | goto LOOP;
86 | }
87 | IsRunning = false;
88 | });
89 |
90 | internal void ShowInfoBar(
91 | string? title,
92 | string? message,
93 | InfoBarSeverity severity,
94 | TimeSpan interval = default,
95 | UIElement? barContent = null,
96 | Action? completed = null,
97 | CancellationToken cancellationToken = default)
98 | {
99 | Task.Run(() =>
100 | {
101 | var mre = new ManualResetEvent(false);
102 | InfoBarTaskQueue.Enqueue(new(mre, title, message, severity,
103 | interval, barContent, completed, cancellationToken));
104 | if (IsRunning is false)
105 | StartShowInfoBarLoop();
106 | mre.WaitOne();
107 | }, CancellationToken.None);
108 | }
109 |
110 | internal async ValueTask ShowInfoBarAsync(string? title,
111 | string? message,
112 | InfoBarSeverity severity,
113 | TimeSpan interval = default,
114 | UIElement? barContent = null,
115 | CancellationToken cancellationToken = default)
116 | {
117 | await Task.Run(() =>
118 | {
119 | var mre = new ManualResetEvent(false);
120 | InfoBarTaskQueue.Enqueue(new(mre, title, message, severity,
121 | interval, barContent, null, cancellationToken));
122 | if (IsRunning is false)
123 | StartShowInfoBarLoop();
124 | mre.WaitOne();
125 | }, CancellationToken.None);
126 | }
127 |
128 | }
--------------------------------------------------------------------------------
/src/LipUI/MainWindow/MainWindowNavigationView.cs:
--------------------------------------------------------------------------------
1 | using LipUI.Models;
2 | using LipUI.Models.Plugin;
3 | using LipUI.Pages.Home;
4 | using LipUI.Pages.Index;
5 | using LipUI.Pages.LocalPackage;
6 | using LipUI.Pages.Settings;
7 | using LipUI.Pages.ToothPack;
8 | using Microsoft.UI.Xaml;
9 | using Microsoft.UI.Xaml.Controls;
10 | using Microsoft.UI.Xaml.Media.Animation;
11 | using Microsoft.UI.Xaml.Navigation;
12 | using System.ComponentModel;
13 |
14 | namespace LipUI;
15 |
16 | internal partial class MainWindow
17 | {
18 | private record NavigationPages(string HomePage, string IndexPage, string ModuleManagerPage, string LocalPackagePage, string SettingsPage);
19 |
20 |
21 | private readonly NavigationPages NavigationPage = new(
22 | typeof(HomePage).FullName!,
23 | typeof(IndexPage).FullName!,
24 | typeof(ModuleManagerPage).FullName!,
25 | typeof(LocalPackagePage).FullName!,
26 | typeof(SettingsPage).FullName!);
27 |
28 | private readonly HashSet NavigationPageTypes = [
29 | typeof(HomePage),
30 | typeof(IndexPage),
31 | typeof(ModuleManagerPage),
32 | typeof(LocalPackagePage),
33 | typeof(SettingsPage)
34 | ];
35 |
36 |
37 |
38 | private void ContentFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
39 | {
40 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
41 | }
42 |
43 | private void NavView_Loading(FrameworkElement sender, object args)
44 | {
45 | sender.Resources["NavigationViewContentBackground"]
46 | = PersonalizationSettingsView.MyRes.ApplicationNavigationViewContentBackground;
47 | sender.Resources["NavigationViewContentGridBorderBrush"]
48 | = PersonalizationSettingsView.MyRes.ApplicationNavigationViewContentBorder;
49 |
50 | PersonalizationSettingsView.MyRes.PropertyChanged += (object? _sender, PropertyChangedEventArgs e) =>
51 | {
52 | switch (e.PropertyName)
53 | {
54 | case nameof(GlobalResources.ApplicationNavigationViewContentBackground):
55 | sender.Resources["NavigationViewContentBackground"]
56 | = PersonalizationSettingsView.MyRes.ApplicationNavigationViewContentBackground;
57 | break;
58 |
59 | case nameof(GlobalResources.ApplicationNavigationViewContentBorder):
60 | sender.Resources["NavigationViewContentGridBorderBrush"]
61 | = PersonalizationSettingsView.MyRes.ApplicationNavigationViewContentBorder;
62 | break;
63 |
64 | case nameof(GlobalResources.ApplicationBackground):
65 | RootBorder.Background = PersonalizationSettingsView.MyRes.ApplicationBackground;
66 | break;
67 | }
68 | };
69 | }
70 |
71 | private void NavView_Loaded(object sender, RoutedEventArgs e)
72 | {
73 | // You can also add items in code.
74 |
75 | // Add handler for ContentFrame navigation.
76 | ContentFrame.Navigated += On_Navigated;
77 |
78 | // NavView doesn't load any page by default, so load home page.
79 | NavView.SelectedItem = NavView.MenuItems[0];
80 | // If navigation occurs on SelectionChanged, this isn't needed.
81 | // Because we use ItemInvoked to navigate, we need to call Navigate
82 | // here to load the home page.
83 | NavView_Navigate(typeof(HomePage), null, new EntranceNavigationTransitionInfo());
84 | }
85 |
86 | private async void NavView_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
87 | {
88 |
89 | if (args.IsSettingsInvoked == true)
90 | {
91 | NavView_Navigate(typeof(SettingsPage), null, args.RecommendedNavigationTransitionInfo);
92 | }
93 | else if (args.InvokedItemContainer != null)
94 | {
95 | if (args.InvokedItemContainer.Tag is null)
96 | return;
97 |
98 | if (args.InvokedItemContainer.Tag is IUIPlugin plugin)
99 | {
100 | try
101 | {
102 | NavView_Navigate(
103 | plugin.PageType, plugin.PageParameterRequsted(), args.RecommendedNavigationTransitionInfo);
104 | }
105 | catch (Exception ex) { await InternalServices.ShowInfoBarAsync(ex); }
106 | }
107 | else
108 | {
109 | NavView_Navigate(
110 | Type.GetType(args.InvokedItemContainer.Tag.ToString()!)!,
111 | null,
112 | args.RecommendedNavigationTransitionInfo);
113 | }
114 | }
115 | }
116 |
117 | private void NavView_Navigate(
118 | Type navPageType,
119 | object? parameter,
120 | NavigationTransitionInfo transitionInfo)
121 | {
122 | Type preNavPageType = ContentFrame.CurrentSourcePageType;
123 |
124 | if (navPageType is not null && !Equals(preNavPageType, navPageType))
125 | {
126 | ContentFrame.Navigate(navPageType, parameter, transitionInfo);
127 | }
128 | }
129 |
130 | private void NavView_BackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args)
131 | {
132 | TryGoBack();
133 | }
134 |
135 | private bool TryGoBack()
136 | {
137 | if (!ContentFrame.CanGoBack)
138 | return false;
139 |
140 | if (NavView.IsPaneOpen &&
141 | (NavView.DisplayMode is NavigationViewDisplayMode.Compact ||
142 | NavView.DisplayMode is NavigationViewDisplayMode.Minimal))
143 | return false;
144 |
145 | ContentFrame.TryGoBack();
146 | return true;
147 | }
148 |
149 | private void On_Navigated(object sender, NavigationEventArgs e)
150 | {
151 | NavView.IsBackEnabled = ContentFrame.CanGoBack;
152 |
153 | if (ContentFrame.SourcePageType == typeof(SettingsPage))
154 | {
155 | NavView.SelectedItem = (NavigationViewItem)NavView.SettingsItem;
156 | }
157 | else if (ContentFrame.SourcePageType != null)
158 | {
159 |
160 | if (NavigationPageTypes.Contains(ContentFrame.SourcePageType))
161 | NavView.SelectedItem = NavView.MenuItems
162 | .OfType()
163 | .First(i => i.Tag.Equals(ContentFrame.SourcePageType.FullName!.ToString()));
164 | }
165 | }
166 |
167 | }
168 |
--------------------------------------------------------------------------------
/src/LipUI/MainWindow/MainWindowPluginsHandler.cs:
--------------------------------------------------------------------------------
1 | using LipUI.Models;
2 | using LipUI.Models.Plugin;
3 | using Microsoft.UI.Xaml.Controls;
4 |
5 | namespace LipUI;
6 |
7 | internal partial class MainWindow
8 | {
9 | public static void InitEventHandlers()
10 | {
11 | PluginSystem.PluginEnabled += PluginSystem_PluginEnabled;
12 | PluginSystem.PluginDisabled += PluginSystem_PluginDisabled;
13 | }
14 |
15 | private static readonly HashSet enabledModules = [];
16 | private static void PluginSystem_PluginEnabled(IPlugin obj)
17 | {
18 | lock (enabledModules)
19 | {
20 | if (obj is IUIPlugin uiPlugin)
21 | {
22 | enabledModules.Add(uiPlugin);
23 | enabled?.Invoke(uiPlugin);
24 | }
25 | }
26 | }
27 |
28 | private static void PluginSystem_PluginDisabled(IPlugin obj)
29 | {
30 | lock (enabledModules)
31 | {
32 | if (obj is IUIPlugin uiPlugin)
33 | {
34 | enabledModules.Remove(uiPlugin);
35 | disabled?.Invoke(uiPlugin);
36 | }
37 | }
38 | }
39 |
40 | private static Action? enabled;
41 | private static Action? disabled;
42 |
43 | private readonly object _lock = new();
44 | private uint navViewBarEnabledPluginsCount;
45 |
46 | private readonly Dictionary views = [];
47 |
48 | private void PluginEnabled(IUIPlugin plugin)
49 | {
50 | DispatcherQueue.TryEnqueue(async () =>
51 | {
52 | try
53 | {
54 | lock (_lock)
55 | {
56 | IList