├── .github
├── ISSUE_TEMPLATE
│ └── cn-bug-report.yaml
└── workflows
│ ├── Release.yml
│ ├── mirrorchyan.yml
│ └── mirrorchyan_release_note.yml
├── .gitignore
├── App.config
├── App.xaml
├── App.xaml.cs
├── AssemblyInfo.cs
├── Assets
├── Localization
│ ├── Strings.Designer.cs
│ ├── Strings.en-us.resx
│ ├── Strings.resx
│ └── Strings.zh-hant.resx
├── Primary
│ ├── Magenta.xaml
│ └── Primary.xaml
├── Properties
│ ├── AutoScroll.cs
│ └── ScrollViewerBinding.cs
├── Style.xaml
├── Style
│ ├── MainStyle.xaml
│ ├── MdXaml.xaml
│ └── Styles
│ │ ├── Brush.xaml
│ │ ├── Color.xaml
│ │ └── Geometry.xaml
├── Theme.xaml
└── Theme
│ ├── DarkTheme.xaml
│ └── LightTheme.xaml
├── Configuration
├── ConfigurationHelper.cs
├── ConfigurationKeys.cs
├── GlobalConfiguration.cs
├── MFAConfiguration.cs
└── MaaFWConfiguration.cs
├── Custom
├── AnomalyDetectionAction.cs
├── ChooseOperatorAciton.cs
├── ChooseTeamAction.cs
├── FinshAction.cs
├── InputParameterAction.cs
├── LevelRecognitionAction.cs
└── SaveMoneyAction.cs
├── DLL
├── msvcp140.dll
└── vcruntime140.dll
├── Extensions
├── ComboBoxExtensions.cs
├── MFAExtensions.cs
└── Maa
│ ├── MaaControllerTypes.cs
│ ├── MaaCustomAction.cs
│ ├── MaaInterface.cs
│ ├── MaaInterfaceAdvancedOption.cs
│ └── MaaProcessor.cs
├── Helper
├── AutoInitDictionary.cs
├── BrushConverterHelper.cs
├── Converters
│ ├── AutoConverter.cs
│ ├── CustomIsEnabledConverter.cs
│ ├── ListDoubleStringConverter.cs
│ ├── ListIntStringConverter.cs
│ ├── ListStringArrayConverter.cs
│ ├── ListStringConverter.cs
│ ├── MaaInterfaceSelectAdvancedConverter.cs
│ ├── MaaInterfaceSelectOptionConverter.cs
│ ├── MaaResourceVersionConverter.cs
│ ├── NullStringConverter.cs
│ ├── NullableDoubleConverter.cs
│ ├── NullableIntConverter.cs
│ ├── NullableStringConverter.cs
│ ├── NullableUIntConverter.cs
│ ├── NullableUIntOrObjectConverter.cs
│ ├── NullableUIntStringConverter.cs
│ ├── ReplaceConverter.cs
│ ├── SingleIntListConverter.cs
│ ├── SingleIntListOrAutoConverter.cs
│ ├── SingleOrDoubleListConverter.cs
│ ├── SingleOrIntListConverter.cs
│ ├── SingleOrListConverter.cs
│ ├── SingleOrNestedListConverter.cs
│ ├── StrictPlaceholderConverter.cs
│ ├── StringOrBoolOrObjectConverter.cs
│ ├── StringOrObjectConverter.cs
│ ├── SubtractConverter.cs
│ ├── UIntOrObjectConverter.cs
│ └── UniversalEnumConverter.cs
├── DeviceWindowTemplateSelector.cs
├── DispatcherHelper.cs
├── DragDropHandler.cs
├── Editor
│ ├── ListAutoStringEditor.cs
│ ├── ListDoubleStringEditor.cs
│ ├── ListIntStringEditor.cs
│ ├── ListStringArrayEditor.cs
│ ├── ListStringEditor.cs
│ ├── NullableDoubleEditor.cs
│ ├── NullableIntEditor.cs
│ ├── NullableStringEditor.cs
│ ├── NullableUIntEditor.cs
│ ├── NullableUIntOrObjectEditor.cs
│ ├── NullableUIntStringEditor.cs
│ ├── SingleIntListEditor.cs
│ ├── SingleIntListOrAutoEditor.cs
│ └── StringComboBoxEditor.cs
├── EmulatorHelper.cs
├── Exceptions
│ ├── MaaErrorHandleException.cs
│ └── MaaStopException.cs
├── ExternalNotificationHelper.cs
├── GrowlHelper.cs
├── HotKeyHelper.cs
├── IconHelper.cs
├── Instances.cs
├── JsonHelper.cs
├── LanguageHelper.cs
├── LoggerService.cs
├── MFAUrls.cs
├── MessageBoxHelper.cs
├── Notification
│ ├── INotificationPoster.cs
│ ├── NotificationAction.cs
│ ├── NotificationContent.cs
│ ├── NotificationHint.cs
│ ├── NotificationImplWinRT.cs
│ └── NotificationImplWpf.cs
├── OCRHelper.cs
├── ServiceProviderExtension.cs
├── SimpleEncryptionHelper.cs
├── TaskManager.cs
├── ThemeHelper.cs
├── ToastNotification.cs
├── ValueType
│ ├── Attribute.cs
│ ├── CustomValue.cs
│ ├── MFAHotKey.cs
│ ├── MFATask.cs
│ ├── ObservableQueue.cs
│ ├── TaskInterfaceItem.cs
│ ├── TaskModel.cs
│ └── ValueBoxes.cs
└── VersionChecker.cs
├── LICENSE
├── MFAWPF.csproj
├── MFAWPF.sln
├── MFAWPF.sln.DotSettings.user
├── NuGet.Config
├── Properties
└── launchSettings.json
├── README.md
├── README_en.md
├── Resource
├── base
│ └── model
│ │ └── ocr
│ │ ├── README.md
│ │ ├── det.onnx
│ │ ├── keys.txt
│ │ └── rec.onnx
└── pipeline.schema.json
├── Services
└── ApplicationHostService.cs
├── ViewModels
├── Tool
│ ├── DragItemViewModel.cs
│ ├── LocalizationViewModel.cs
│ ├── LogItemViewModel.cs
│ └── TaskItemViewModel.cs
├── UI
│ ├── AnnouncementViewModel.cs
│ ├── ConnectingViewModel.cs
│ ├── Dialog
│ │ ├── AddTaskDialogViewModel.cs
│ │ └── EditTaskDialogViewModel.cs
│ ├── RootViewModel.cs
│ ├── SettingsViewModel.cs
│ └── TaskQueueViewModel.cs
├── UserControl
│ └── Settings
│ │ ├── ConnectSettingsUserControlModel.cs
│ │ ├── ExternalNotificationSettingsUserControlModel.cs
│ │ ├── GameSettingsUserControlModel.cs
│ │ ├── GuiSettingsUserControlModel.cs
│ │ ├── PerformanceUserControlModel.cs
│ │ ├── StartSettingsUserControlModel.cs
│ │ ├── TimerSettingsUserControlModel.cs
│ │ └── VersionUpdateSettingsUserControlModel.cs
└── ViewModel.cs
├── Views
├── UI
│ ├── AnnouncementView.xaml
│ ├── AnnouncementView.xaml.cs
│ ├── ConnectingView.xaml
│ ├── ConnectingView.xaml.cs
│ ├── Dialog
│ │ ├── AdbEditorDialog.xaml
│ │ ├── AdbEditorDialog.xaml.cs
│ │ ├── AddTaskDialog.xaml
│ │ ├── AddTaskDialog.xaml.cs
│ │ ├── ColorExtractionDialog.xaml
│ │ ├── ColorExtractionDialog.xaml.cs
│ │ ├── CropImageDialog.xaml
│ │ ├── CropImageDialog.xaml.cs
│ │ ├── DownloadDialog.xaml
│ │ ├── DownloadDialog.xaml.cs
│ │ ├── EditTaskDialog.xaml
│ │ ├── EditTaskDialog.xaml.cs
│ │ ├── RecognitionTextDialog.xaml
│ │ ├── RecognitionTextDialog.xaml.cs
│ │ ├── SelectionRegionDialog.xaml
│ │ ├── SelectionRegionDialog.xaml.cs
│ │ ├── SwipeDialog.xaml
│ │ ├── SwipeDialog.xaml.cs
│ │ ├── TaskFlowChartDialog.xaml
│ │ └── TaskFlowChartDialog.xaml.cs
│ ├── ErrorView.xaml
│ ├── ErrorView.xaml.cs
│ ├── NotifyIcon.xaml
│ ├── NotifyIcon.xaml.cs
│ ├── RootView.xaml
│ ├── RootView.xaml.cs
│ ├── SettingsView.xaml
│ ├── SettingsView.xaml.cs
│ ├── TaskQueueView.xaml
│ └── TaskQueueView.xaml.cs
└── UserControl
│ ├── AttributeButton.cs
│ ├── AttributeTag.cs
│ ├── CardControl.xaml
│ ├── CardControl.xaml.cs
│ ├── CustomAutoCompleteTextBox.cs
│ ├── CustomAutoListControl.xaml
│ ├── CustomAutoListControl.xaml.cs
│ ├── CustomListControl.xaml
│ ├── CustomListControl.xaml.cs
│ ├── CustomTextBlock.cs
│ ├── CustomWindow.cs
│ ├── HotKeyEditorUserControl.xaml
│ ├── HotKeyEditorUserControl.xaml.cs
│ ├── PinButton.cs
│ └── Settings
│ ├── AboutUserControl.xaml
│ ├── AboutUserControl.xaml.cs
│ ├── ConfigurationMgrUserControl.xaml
│ ├── ConfigurationMgrUserControl.xaml.cs
│ ├── ConnectSettingsUserControl.xaml
│ ├── ConnectSettingsUserControl.xaml.cs
│ ├── ExternalNotificationSettingsUserControl.xaml
│ ├── ExternalNotificationSettingsUserControl.xaml.cs
│ ├── GameSettingsUserControl.xaml
│ ├── GameSettingsUserControl.xaml.cs
│ ├── GuiSettingsUserControl.xaml
│ ├── GuiSettingsUserControl.xaml.cs
│ ├── HotKeySettingsUserControl.xaml
│ ├── HotKeySettingsUserControl.xaml.cs
│ ├── PerformanceUserControl.xaml
│ ├── PerformanceUserControl.xaml.cs
│ ├── StartSettingsUserControl.xaml
│ ├── StartSettingsUserControl.xaml.cs
│ ├── TaskOptionSettingsUserControl.xaml
│ ├── TaskOptionSettingsUserControl.xaml.cs
│ ├── TaskQueueSettingsUserControl.xaml
│ ├── TaskQueueSettingsUserControl.xaml.cs
│ ├── TimerSettingsUserControl.xaml
│ ├── TimerSettingsUserControl.xaml.cs
│ ├── VersionUpdateSettingsUserControl.xaml
│ └── VersionUpdateSettingsUserControl.xaml.cs
├── cliff.toml
├── docs
├── en_us
│ └── CustomRecognition_Action.md
└── zh_cn
│ └── 自定义识别_操作.md
├── logo.ico
├── logo.png
└── workflows
└── install.yml
/.github/ISSUE_TEMPLATE/cn-bug-report.yaml:
--------------------------------------------------------------------------------
1 | name: Bug 反馈(使用中文)
2 | description: 运行错误、操作异常、连接错误等
3 | labels: ["bug"]
4 | body:
5 | - type: checkboxes
6 | id: checks
7 | attributes:
8 | label: 在提问之前...
9 | description: |
10 | 请确认自己完成了要求之后再进行勾选
11 | options:
12 | - label: 我知道这个项目是独立的通用GUI项目,在这里反馈资源问题(如M9A)并不正确
13 | required: true
14 | - label: 我理解 Issue 是用于反馈和解决问题的,而非吐槽评论区,将尽可能提供更多信息帮助问题解决
15 | required: true
16 | - label: 我填写了简短且清晰明确的标题,以便开发者在翻阅 Issue 列表时能快速确定大致问题。而不是“一个建议”、“卡住了”等
17 | required: true
18 | - label: 我使用的是当前更新版本的最新版,且已查看版本发布至今和 Pull Requests 中尚未发布的更新内容,并未提及该 Bug 已被修复的情况
19 | required: true
20 | - label: 我已检查了置顶议题(Pinned Issue)(公告)、活跃议题(Open Issue)、已关闭议题(Closed Issue),确认我的问题未被提及
21 | required: true
22 | - type: textarea
23 | id: describe
24 | attributes:
25 | label: 问题描述
26 | description: 描述问题时请尽可能详细
27 | validations:
28 | required: true
29 | - type: textarea
30 | id: version
31 | attributes:
32 | label: Version
33 | description: >-
34 | 请提供 MFA 版本。可在 MFA -> 设置 -> 软件更新中找到。
35 | placeholder: |
36 | MFA Version:
37 | validations:
38 | required: true
39 | - type: textarea
40 | id: logs
41 | attributes:
42 | label: 日志和配置文件
43 | description: |
44 | **请在关闭 MFA 后,上传以下 5 个文件:**
45 | 1. `debug` 文件夹中的 `maa.log` 日志文件,并说明问题出现的大致时间点
46 | 2. `log` 文件夹中的最新log
47 |
48 | 如果你在使用 MacBook,请点击屏幕左上角的“文件”,点击“打开日志文件夹”
49 | **请直接将完整的文件拖拽进来,而非自己裁切或复制的片段;若文件体积过大可压缩后再上传**
50 | placeholder: |
51 | 请确认上传文件前已关闭 MFA
52 | validations:
53 | required: true
54 | - type: textarea
55 | id: configuration
56 | attributes:
57 | label: 配置信息
58 | description: |
59 | 请说明操作系统及版本、模拟器品牌、模拟器分辨率、DPI、帧率;
60 | 最后请说明 GPU 加速推理是否开启,若开启请提供 GPU 型号。
61 | validations:
62 | required: true
63 | - type: textarea
64 | id: screenshots
65 | attributes:
66 | label: 截图或录屏
67 | description: |
68 | 可上传屏幕截图或录制以帮助解释你的问题,包括但不限于 MFA 软件截图、游戏画面截图
69 | 若是**识别相关问题**,请尽可能提供模拟器自带的截图工具截取的无遮挡的**原图**(或通过 adb 截取原图)
70 | 用其他的工具(如QQ/微信)截取的图片包含窗口边框且长宽比、分辨率不固定,不利于我们排除bug
71 | 若文件体积过大可压缩后再上传
72 | validations:
73 | required: false
74 | - type: textarea
75 | id: others
76 | attributes:
77 | label: 还有别的吗?
78 | description: |
79 | 任何能让我们对你所遇到的问题有更多了解的东西
80 | validations:
81 | required: false
82 |
--------------------------------------------------------------------------------
/.github/workflows/Release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'v*' # 匹配以'v'开头的tag
7 |
8 | jobs:
9 | changelog:
10 | name: Generate changelog
11 | runs-on: ubuntu-latest
12 | outputs:
13 | release_body: ${{ steps.git-cliff.outputs.content }}
14 | steps:
15 | - name: Checkout
16 | uses: actions/checkout@v4
17 | with:
18 | fetch-depth: 0
19 |
20 | - name: Generate a changelog
21 | uses: orhun/git-cliff-action@v4
22 | id: git-cliff
23 | with:
24 | config: cliff.toml
25 | args: -vv --latest --strip header
26 | env:
27 | OUTPUT: CHANGES.md
28 | GITHUB_REPO: ${{ github.repository }}
29 |
30 | build:
31 | runs-on: ubuntu-latest
32 | name: Upload the release
33 | needs: changelog
34 | steps:
35 | - name: Checkout code
36 | uses: actions/checkout@v4
37 | with:
38 | fetch-depth: 0 # 获取完整历史记录以访问所有tags
39 |
40 | - name: .NET Core
41 | uses: actions/setup-dotnet@v1
42 | with:
43 | dotnet-version: 8.0.x
44 |
45 | - name: Install dependencies
46 | run: dotnet restore
47 |
48 | - name: Build
49 | run: dotnet publish -c Release
50 |
51 | - name: Zip
52 | run: |
53 | cd /home/runner/work/MFAWPF/bin/AnyCPU/Release/win-x64/publish/
54 | zip -r ../MFAWPF-${{ github.ref_name }}.zip *
55 |
56 | - name: Release
57 | uses: softprops/action-gh-release@v1
58 | with:
59 | tag_name: ${{ github.ref_name }}
60 | files: |
61 | /home/runner/work/MFAWPF/bin/AnyCPU/Release/win-x64/*.zip
62 | body: ${{ needs.changelog.outputs.release_body }}
63 | draft: false
64 | prerelease: false
65 |
66 | - name: Trigger MirrorChyan
67 | run: |
68 | gh workflow run --repo $GITHUB_REPOSITORY mirrorchyan
69 | gh workflow run --repo $GITHUB_REPOSITORY mirrorchyan_release_note
70 | env:
71 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
72 |
--------------------------------------------------------------------------------
/.github/workflows/mirrorchyan.yml:
--------------------------------------------------------------------------------
1 | name: mirrorchyan
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | jobs:
7 | mirrorchyan:
8 | runs-on: macos-latest
9 | strategy:
10 | matrix:
11 | os: [win]
12 | arch: [x86_64]
13 |
14 | steps:
15 | - id: uploading
16 | uses: MirrorChyan/uploading-action@v1
17 | with:
18 | filetype: latest-release
19 | filename: "MFA*.zip"
20 | mirrorchyan_rid: MFAWPF
21 |
22 | github_token: ${{ secrets.GITHUB_TOKEN }}
23 | owner: ${{ github.repository_owner }}
24 | repo: ${{ github.event.repository.name }}
25 | upload_token: ${{ secrets.MirrorChyanUploadToken }}
26 | os: ${{ matrix.os }}
27 | arch: ${{ matrix.arch }}
28 |
--------------------------------------------------------------------------------
/.github/workflows/mirrorchyan_release_note.yml:
--------------------------------------------------------------------------------
1 | name: mirrorchyan_release_note
2 |
3 | on:
4 | workflow_dispatch:
5 | release:
6 | types: [edited]
7 |
8 | jobs:
9 | mirrorchyan:
10 | runs-on: macos-latest
11 |
12 | steps:
13 | - id: uploading
14 | uses: MirrorChyan/release-note-action@v1
15 | with:
16 | mirrorchyan_rid: MFAWPF
17 |
18 | upload_token: ${{ secrets.MirrorChyanUploadToken }}
19 | github_token: ${{ secrets.GITHUB_TOKEN }}
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 |
11 | [Dd]ebug/
12 | [Rr]elease/
13 | x64/
14 | [Bb]in/
15 | [Oo]bj/
16 | !Resource/pipeline.schema.json
17 | !Resource/controller_config.json
18 | !Resource/MaaAgentBinary/
19 |
20 | # MSTest test Results
21 | [Tt]est[Rr]esult*/
22 | [Bb]uild[Ll]og.*
23 |
24 | *_i.c
25 | *_p.c
26 | *_i.h
27 | *.ilk
28 | *.meta
29 | *.obj
30 | *.pch
31 | *.pdb
32 | *.pgc
33 | *.pgd
34 | *.rsp
35 | *.sbr
36 | *.tlb
37 | *.tli
38 | *.tlh
39 | *.tmp
40 | *.tmp_proj
41 | *.log
42 | *.vspscc
43 | *.vssscc
44 | .builds
45 | *.pidb
46 | *.log
47 | *.svclog
48 | *.scc
49 |
50 | # Visual C++ cache files
51 | ipch/
52 | *.aps
53 | *.ncb
54 | *.opensdf
55 | *.sdf
56 | *.cachefile
57 |
58 | # Visual Studio profiler
59 | *.psess
60 | *.vsp
61 | *.vspx
62 |
63 | # Guidance Automation Toolkit
64 | *.gpState
65 |
66 | # ReSharper is a .NET coding add-in
67 | _ReSharper*/
68 | *.[Rr]e[Ss]harper
69 | *.DotSettings.user
70 |
71 | # Click-Once directory
72 | publish/
73 |
74 | # Publish Web Output
75 | *.Publish.xml
76 | *.pubxml
77 | *.azurePubxml
78 |
79 | # NuGet Packages Directory
80 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
81 | packages/
82 | ## TODO: If the tool you use requires repositories.config, also uncomment the next line
83 | !packages/repositories.config
84 |
85 | # Windows Azure Build Output
86 | csx/
87 | *.build.csdef
88 |
89 | # Windows Store app package directory
90 | AppPackages/
91 |
92 | # Others
93 | sql/
94 | *.Cache
95 | ClientBin/
96 | [Ss]tyle[Cc]op.*
97 | ![Ss]tyle[Cc]op.targets
98 | ~$*
99 | *~
100 | *.dbmdl
101 | *.[Pp]ublish.xml
102 |
103 | *.publishsettings
104 |
105 | # RIA/Silverlight projects
106 | Generated_Code/
107 |
108 | # Backup & report files from converting an old project file to a newer
109 | # Visual Studio version. Backup files are not needed, because we have git ;-)
110 | _UpgradeReport_Files/
111 | Backup*/
112 | UpgradeLog*.XML
113 | UpgradeLog*.htm
114 |
115 | # SQL Server files
116 | App_Data/*.mdf
117 | App_Data/*.ldf
118 |
119 | # =========================
120 | # Windows detritus
121 | # =========================
122 |
123 | # Windows image file caches
124 | Thumbs.db
125 | ehthumbs.db
126 | .vs
127 |
128 | # Folder config file
129 | Desktop.ini
130 |
131 | # Recycle Bin used on file shares
132 | $RECYCLE.BIN/
133 |
134 | # Mac desktop service store files
135 | .DS_Store
136 |
137 | _NCrunch*
138 |
139 |
140 | # 钉钉的token和secret
141 | auth.txt
--------------------------------------------------------------------------------
/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/App.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
--------------------------------------------------------------------------------
/Assets/Primary/Magenta.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 | #FFD80073
5 | #FFD80073
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | #FFD80073
18 | #FFD80073
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Assets/Primary/Primary.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 | #FF326CF3
5 | #FF326CF3
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | #FF326CF3
18 | #FF326CF3
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Assets/Properties/AutoScroll.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Specialized;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 |
5 | namespace MFAWPF.Styles.Properties
6 | {
7 |
8 | public static class AutoScroll
9 | {
10 | private static bool _autoScroll;
11 |
12 | public static bool GetAutoScroll(DependencyObject obj)
13 | {
14 | return (bool)obj.GetValue(AutoScrollProperty);
15 | }
16 |
17 | public static void SetAutoScroll(DependencyObject obj, bool value)
18 | {
19 | obj.SetValue(AutoScrollProperty, value);
20 | }
21 |
22 | public static readonly DependencyProperty AutoScrollProperty =
23 | DependencyProperty.RegisterAttached("AutoScroll", typeof(bool), typeof(AutoScroll), new PropertyMetadata(false, AutoScrollPropertyChanged));
24 |
25 | private static void AutoScrollPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
26 | {
27 | if (d is ScrollViewer scrollViewer)
28 | {
29 | bool alwaysScrollToEnd = (e.NewValue != null) && (bool)e.NewValue;
30 | if (alwaysScrollToEnd)
31 | {
32 | scrollViewer.ScrollToEnd();
33 | scrollViewer.ScrollChanged += ScrollChanged;
34 | }
35 | else
36 | {
37 | scrollViewer.ScrollChanged -= ScrollChanged;
38 | }
39 | }
40 | else if (d is ListBox listBox)
41 | {
42 | INotifyCollectionChanged view = listBox.Items;
43 | view.CollectionChanged += (_, arg) =>
44 | {
45 | switch (arg.Action)
46 | {
47 | case NotifyCollectionChangedAction.Add:
48 | listBox.ScrollIntoView(listBox.Items[arg.NewStartingIndex]);
49 | break;
50 | }
51 | };
52 | }
53 | else
54 | {
55 | throw new InvalidOperationException("The attached AlwaysScrollToEnd property can only be applied to ScrollViewer instances.");
56 | }
57 | }
58 |
59 | private static void ScrollChanged(object sender, ScrollChangedEventArgs e)
60 | {
61 | if (sender is not ScrollViewer scroll)
62 | {
63 | throw new InvalidOperationException("The attached AlwaysScrollToEnd property can only be applied to ScrollViewer instances.");
64 | }
65 |
66 | if (e.ExtentHeightChange == 0)
67 | {
68 | _autoScroll = Math.Abs(scroll.VerticalOffset - scroll.ScrollableHeight) < 1e-6;
69 | }
70 |
71 | if (_autoScroll && e.ExtentHeightChange != 0)
72 | {
73 | scroll.ScrollToVerticalOffset(scroll.ExtentHeight);
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/Assets/Style.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Assets/Style/Styles/Brush.xaml:
--------------------------------------------------------------------------------
1 |
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 |
--------------------------------------------------------------------------------
/Assets/Style/Styles/Color.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 | #FFDB3340
5 | #FFDB3340
6 |
7 | #FFE9AF20
8 | #FFE9AF20
9 |
10 | #FF00BCD4
11 | #FF00BCD4
12 |
13 | #FF2DB84d
14 | #FF2DB84d
15 |
16 | #FFD80073
17 | #FF9F0055
18 | #FFBB33FF
19 | #FF7D00BC
20 |
21 |
--------------------------------------------------------------------------------
/Assets/Theme.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
12 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Configuration/GlobalConfiguration.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper;
2 | using System.Configuration;
3 |
4 |
5 | namespace MFAWPF.Configuration;
6 |
7 | public static class GlobalConfiguration
8 | {
9 | private static System.Configuration.Configuration GetConfigurationInstance()
10 | {
11 | return ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
12 | }
13 |
14 | public static void SetValue(string key, string value)
15 | {
16 | var config = GetConfigurationInstance();
17 | if (config.AppSettings.Settings[key] == null)
18 | {
19 | config.AppSettings.Settings.Add(key, value);
20 | }
21 | else
22 | {
23 | config.AppSettings.Settings[key].Value = value;
24 | }
25 |
26 | try
27 | {
28 | config.Save(ConfigurationSaveMode.Modified);
29 | ConfigurationManager.RefreshSection("appSettings");
30 | }
31 | catch (ConfigurationErrorsException ex)
32 | {
33 | LoggerService.LogError(new InvalidOperationException("Failed to save configuration.", ex));
34 | }
35 | }
36 |
37 | public static string GetValue(string key, string defaultValue = "")
38 | {
39 | var config = GetConfigurationInstance();
40 | return config.AppSettings.Settings[key]?.Value ?? defaultValue;
41 | }
42 |
43 | public static string GetTimer(int i, string defaultValue)
44 | {
45 | return GetValue($"Timer.Timer{i + 1}", defaultValue);
46 | }
47 |
48 | public static void SetTimer(int i, string value)
49 | {
50 | SetValue($"Timer.Timer{i + 1}", value);
51 | }
52 |
53 | public static string GetTimerHour(int i, string defaultValue)
54 | {
55 |
56 | return GetValue($"Timer.Timer{i + 1}Hour", defaultValue);
57 | }
58 |
59 | public static void SetTimerHour(int i, string value)
60 | {
61 | SetValue($"Timer.Timer{i + 1}Hour", value);
62 | }
63 |
64 | public static string GetTimerMin(int i, string defaultValue)
65 | {
66 | return GetValue($"Timer.Timer{i + 1}Min", defaultValue);
67 | }
68 |
69 | public static void SetTimerMin(int i, string value)
70 | {
71 | SetValue($"Timer.Timer{i + 1}Min", value);
72 | }
73 |
74 | public static string GetTimerConfig(int i, string defaultValue)
75 | {
76 | return GetValue($"Timer.Timer{i + 1}.Config", defaultValue);
77 | }
78 |
79 | public static void SetTimerConfig(int i, string value)
80 | {
81 | SetValue($"Timer.Timer{i + 1}.Config", value);
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Configuration/MFAConfiguration.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using CommunityToolkit.Mvvm.Input;
3 | using MFAWPF.Helper;
4 |
5 |
6 | namespace MFAWPF.Configuration;
7 |
8 | public partial class MFAConfiguration : ObservableObject
9 | {
10 | [ObservableProperty] public string _name;
11 | [ObservableProperty] public string _fileName;
12 | [ObservableProperty] public Dictionary _config;
13 |
14 |
15 | [RelayCommand]
16 | public void DeleteConfiguration(MFAConfiguration configuration)
17 | {
18 | var configName = configuration.Name;
19 | if (!ConfigurationHelper.Configs.Any(c => c.Name.Equals(configName, StringComparison.OrdinalIgnoreCase)))
20 | {
21 | LoggerService.LogError($"Configuration {configName} does not exist");
22 | return;
23 | }
24 |
25 | if (ConfigurationHelper.ConfigName == configName)
26 | {
27 | LoggerService.LogError($"Configuration {configName} is current configuration, cannot delete");
28 | return;
29 | }
30 | Instances.SettingsViewModel.ConfigurationList.Remove(configuration);
31 | ConfigurationHelper.DeleteConfig(configName);
32 | }
33 |
34 | public override string ToString()
35 | => Name;
36 | }
37 |
--------------------------------------------------------------------------------
/Configuration/MaaFWConfiguration.cs:
--------------------------------------------------------------------------------
1 | using MaaFramework.Binding;
2 | using MFAWPF.Extensions.Maa;
3 | using MFAWPF.Helper;
4 |
5 | namespace MFAWPF.Configuration;
6 |
7 | public class MaaFWConfiguration
8 | {
9 | public AdbDeviceCoreConfig AdbDevice { get; set; } = new();
10 | public DesktopWindowCoreConfig DesktopWindow { get; set; } = new();
11 |
12 | }
13 |
14 | public class DesktopWindowCoreConfig
15 | {
16 | public string Name { get; set; } = string.Empty;
17 | public nint HWnd { get; set; }
18 |
19 | public Win32InputMethod Input { get; set; } = Win32InputMethod.SendMessage;
20 |
21 | public Win32ScreencapMethod ScreenCap { get; set; } = Win32ScreencapMethod.FramePool;
22 | public LinkOption Link { get; set; } = LinkOption.Start;
23 | public CheckStatusOption Check { get; set; } = CheckStatusOption.ThrowIfNotSucceeded;
24 | }
25 |
26 | public class AdbDeviceCoreConfig
27 | {
28 | public string Name { get; set; } = string.Empty;
29 | public string AdbPath { get; set; } = "adb";
30 | public string AdbSerial { get; set; } = "";
31 | public string Config { get; set; } = "{}";
32 | public AdbInputMethods Input { get; set; } = AdbInputMethods.Maatouch;
33 | public AdbScreencapMethods ScreenCap { get; set; } = AdbScreencapMethods.Default;
34 | }
--------------------------------------------------------------------------------
/Custom/ChooseOperatorAciton.cs:
--------------------------------------------------------------------------------
1 | using MaaFramework.Binding;
2 | using MaaFramework.Binding.Custom;
3 | using MFAWPF.Extensions;
4 | using MFAWPF.Extensions.Maa;
5 | using MFAWPF.Helper;
6 | using MFAWPF.ViewModels;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System;
12 | using System.Runtime;
13 |
14 | namespace MFAWPF.Custom;
15 |
16 | public class ChooseOperatorAciton : MaaCustomAction
17 | {
18 | public override string Name { get; set; } = nameof(ChooseOperatorAciton);
19 |
20 |
21 | protected override void ErrorHandle(IMaaContext context, RunArgs args)
22 | {
23 | context.OverrideNext(args.NodeName, ["启动检测"]);
24 | }
25 |
26 | protected override bool Execute(IMaaContext context, RunArgs args)
27 | {
28 | int i = 0;
29 | context.OverrideNext(args.NodeName, []);
30 | var choosing = () =>
31 | {
32 | var image = context.GetImage();
33 | RecognitionDetail detail;
34 | if (context.TemplateMatch("Sarkaz@Roguelike@EnterAfterRecruit.png", image, out detail, 0.7, 1050, 226, 220, 250))
35 | {
36 | context.Click(detail.HitBox.X, detail.HitBox.Y);
37 | var enterMap = () =>
38 | {
39 | context.GetImage(ref image);
40 | if (context.TemplateMatch("rougelikeInfo.png", image, out detail, 0.8, 53, 1, 178, 64))
41 | {
42 | return true;
43 | }
44 | context.Click(1142, 369);
45 | return false;
46 | };
47 | enterMap.Until();
48 | return true;
49 | }
50 | bool catchO = false;
51 | if (i++ == 0)
52 | {
53 | if (args.RecognitionDetail.HitBox != null)
54 | {
55 | context.Click(args.RecognitionDetail.HitBox.X, args.RecognitionDetail.HitBox.Y);
56 | catchO = true;
57 | }
58 | }
59 | else
60 | {
61 | if (context.TemplateMatch("Sarkaz@Roguelike@Recruit.png", image, out detail, 0.7, 198, 468, 951, 84))
62 | {
63 | context.Click(detail.HitBox.X, detail.HitBox.Y);
64 | catchO = true;
65 | }
66 | }
67 |
68 | var abandonOp = () =>
69 | {
70 | context.GetImage(ref image);
71 | if (context.TemplateMatch("abandon.png", image, out detail, 0.8, 912, 654, 120, 50))
72 | {
73 | context.Click(detail.HitBox.X, detail.HitBox.Y);
74 | return true;
75 | }
76 | return false;
77 | };
78 | var confirmAbandon = () =>
79 | {
80 | context.GetImage(ref image);
81 | if (context.TemplateMatch("Sarkaz@Roguelike@StageTraderRefreshConfirm.png", image, out detail, 0.8, 640, 414, 504, 154))
82 | {
83 | context.Click(detail.HitBox.X, detail.HitBox.Y);
84 | return true;
85 | }
86 | return false;
87 | };
88 |
89 | if (catchO)
90 | {
91 | abandonOp.Until();
92 | confirmAbandon.Until();
93 | }
94 | return false;
95 | };
96 | choosing.Until();
97 | context.OverrideNext(args.NodeName, ["关卡检测"]);
98 | return true;
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/Custom/FinshAction.cs:
--------------------------------------------------------------------------------
1 | using MaaFramework.Binding;
2 | using MaaFramework.Binding.Custom;
3 | using MFAWPF.Extensions;
4 | using MFAWPF.Extensions.Maa;
5 | using MFAWPF.Helper;
6 | using MFAWPF.ViewModels;
7 | using MFAWPF.Views;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using System.Collections.Generic;
11 | using System.Linq;
12 |
13 | namespace MFAWPF.Custom;
14 |
15 | public class FinshAction : MaaCustomAction
16 | {
17 | public override string Name { get; set; } = nameof(FinshAction);
18 |
19 |
20 | protected override void ErrorHandle(IMaaContext context, RunArgs args)
21 | {
22 | context.OverrideNext(args.NodeName, ["启动检测"]);
23 | }
24 |
25 | protected override bool Execute(IMaaContext context, RunArgs args)
26 | {
27 | Thread.Sleep(1000);
28 | var confirm = () =>
29 | {
30 | var image = context.GetImage();
31 | if (context.TemplateMatch("money.png", image, out _, 0.92, 0, 429, 78, 72))
32 | {
33 | return true;
34 | }
35 | context.Click(631, 610);
36 | return false;
37 | };
38 | confirm.Until(150);
39 | context.OverrideNext(args.NodeName, ["启动检测"]);
40 | return true;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Custom/InputParameterAction.cs:
--------------------------------------------------------------------------------
1 | using MaaFramework.Binding;
2 | using MaaFramework.Binding.Custom;
3 | using MFAWPF.Extensions;
4 | using MFAWPF.Extensions.Maa;
5 | using MFAWPF.Helper;
6 | using MFAWPF.ViewModels;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 |
12 | namespace MFAWPF.Custom;
13 |
14 | public class InputParameterAction : MaaCustomAction
15 | {
16 | public override string Name { get; set; } = nameof(InputParameterAction);
17 |
18 |
19 | protected override void ErrorHandle(IMaaContext context, RunArgs args)
20 | {
21 | context.OverrideNext(args.NodeName, ["启动检测"]);
22 | }
23 |
24 | protected override bool Execute(IMaaContext context, RunArgs args)
25 | {
26 | var shouldRun = true;
27 | var enter1 = () =>
28 | {
29 | if (shouldRun)
30 | return true;
31 | var image = context.GetImage();
32 | RecognitionDetail detail;
33 | if (context.OCR("启用参数", image, out detail, 847, 570, 98, 28))
34 | {
35 | context.Click(detail.HitBox.X, detail.HitBox.Y);
36 | return true;
37 | }
38 | if (context.OCR("参数已启用", image, out detail, 852, 569, 104, 29))
39 | {
40 | shouldRun = true;
41 | return true;
42 | }
43 | return false;
44 | };
45 | enter1.Until();
46 |
47 | if (shouldRun)
48 | {
49 | context.OverrideNext(args.NodeName, ["开始探险"]);
50 | return true;
51 | }
52 | var enter2 = () =>
53 | {
54 | var image = context.GetImage();
55 | if (context.TemplateMatch("fh2.png", image, out var detail, 0.8, 185, 124, 72, 71))
56 | {
57 | context.Click(701, 226);
58 | return true;
59 | }
60 | return false;
61 | };
62 | enter2.Until();
63 | var enter3 = () =>
64 | {
65 | var image = context.GetImage();
66 | if (context.TemplateMatch("editconfirm.png", image, out var detail, 0.8, 686, 399, 562, 171))
67 | {
68 | context.Click(258, 332);
69 | return true;
70 | }
71 | return false;
72 | };
73 | enter3.Until();
74 |
75 |
76 | Thread.Sleep(150);
77 | var confirm = () =>
78 | {
79 | var image = context.GetImage();
80 | if (context.TemplateMatch("editconfirm.png", image, out var detail, 0.8, 693, 379, 551, 218))
81 | {
82 | context.InputText("[U1eIA1I29844Ae925i,rogue_4,6]");
83 | Thread.Sleep(300);
84 | context.Click(detail.HitBox.X, detail.HitBox.Y);
85 | Thread.Sleep(600);
86 | context.Click(detail.HitBox.X, detail.HitBox.Y);
87 | return true;
88 | }
89 | return false;
90 | };
91 | confirm.Until();
92 | var leaving = () =>
93 | {
94 | var image = context.GetImage();
95 | if (context.TemplateMatch("fh2.png", image, out var detail, 0.8, 185, 124, 72, 71))
96 | {
97 | context.Click(966, 322);
98 | Thread.Sleep(700);
99 | context.Click(1167, 338);
100 | return true;
101 | }
102 | return false;
103 | };
104 | leaving.Until();
105 | context.OverrideNext(args.NodeName, ["开始探险"]);
106 | return true;
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/DLL/msvcp140.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SweetSmellFox/MFAWPF/12e65484cf483e7bb68aca3e8e749406c52398c8/DLL/msvcp140.dll
--------------------------------------------------------------------------------
/DLL/vcruntime140.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SweetSmellFox/MFAWPF/12e65484cf483e7bb68aca3e8e749406c52398c8/DLL/vcruntime140.dll
--------------------------------------------------------------------------------
/Extensions/ComboBoxExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 | using System.Windows.Input;
4 |
5 | namespace MFAWPF.Extensions;
6 |
7 | public static class ComboBoxExtensions
8 | {
9 | public static readonly DependencyProperty DisableNavigationOnLostFocusProperty =
10 | DependencyProperty.RegisterAttached(
11 | "DisableNavigationOnLostFocus",
12 | typeof(bool),
13 | typeof(ComboBoxExtensions),
14 | new PropertyMetadata(false, OnDisableNavigationOnLostFocusChanged));
15 |
16 | public static bool GetDisableNavigationOnLostFocus(DependencyObject obj) =>
17 | (bool)obj.GetValue(DisableNavigationOnLostFocusProperty);
18 |
19 | public static void SetDisableNavigationOnLostFocus(DependencyObject obj, bool value) =>
20 | obj.SetValue(DisableNavigationOnLostFocusProperty, value);
21 |
22 | private static void OnDisableNavigationOnLostFocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
23 | {
24 | if (d is ComboBox comboBox)
25 | {
26 | comboBox.PreviewKeyDown -= HandlePreviewKeyDown;
27 | comboBox.PreviewMouseWheel -= HandlePreviewMouseWheel;
28 |
29 | if ((bool)e.NewValue)
30 | {
31 | comboBox.PreviewKeyDown += HandlePreviewKeyDown;
32 | comboBox.PreviewMouseWheel += HandlePreviewMouseWheel;
33 | }
34 | }
35 | }
36 |
37 | private static bool IsInputAllowed(ComboBox comboBox) =>
38 | comboBox.IsDropDownOpen;
39 |
40 | private static void HandlePreviewKeyDown(object sender, KeyEventArgs e)
41 | {
42 | var comboBox = (ComboBox)sender;
43 | if (!IsInputAllowed(comboBox) && (e.Key == Key.Up || e.Key == Key.Down))
44 | {
45 | e.Handled = true;
46 | }
47 | }
48 |
49 | private static void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e)
50 | {
51 | var comboBox = (ComboBox)sender;
52 | if (!IsInputAllowed(comboBox))
53 | {
54 | e.Handled = true;
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/Extensions/Maa/MaaControllerTypes.cs:
--------------------------------------------------------------------------------
1 | namespace MFAWPF.Extensions.Maa;
2 |
3 | public enum MaaControllerTypes
4 | {
5 | None = 0,
6 | Win32,
7 | Adb
8 | }
9 |
10 | public static class MaaControllerHelper
11 | {
12 | public static string ToResourceKey(this MaaControllerTypes type)
13 | {
14 | return type switch
15 | {
16 | MaaControllerTypes.Win32 => "TabWin32",
17 | MaaControllerTypes.Adb => "TabADB",
18 | _ => "TabADB"
19 | };
20 | }
21 |
22 | public static MaaControllerTypes ToMaaControllerTypes(this string? type, MaaControllerTypes defaultValue = MaaControllerTypes.Adb)
23 | {
24 | if (string.IsNullOrWhiteSpace(type))
25 | return defaultValue;
26 | if (type.Contains("win32", StringComparison.OrdinalIgnoreCase))
27 | return MaaControllerTypes.Win32;
28 | if (type.Contains("adb", StringComparison.OrdinalIgnoreCase))
29 | return MaaControllerTypes.Adb;
30 | return defaultValue;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Extensions/Maa/MaaCustomAction.cs:
--------------------------------------------------------------------------------
1 | using MaaFramework.Binding;
2 | using MaaFramework.Binding.Custom;
3 | using MFAWPF.Helper;
4 | using MFAWPF.Helper.Exceptions;
5 |
6 | namespace MFAWPF.Extensions.Maa;
7 |
8 | public abstract class MaaCustomAction : IMaaCustomAction
9 | {
10 | public abstract string Name { get; set; }
11 |
12 | public bool Run(in IMaaContext inContext, in RunArgs inArgs,in RunResults runResults)
13 | {
14 | var context = inContext;
15 | var args = inArgs;
16 | try
17 | {
18 | return Execute(context, args);
19 | }
20 | catch (OperationCanceledException)
21 | {
22 | LoggerService.LogInfo("Stopping MaaCustomAction");
23 | return false;
24 | }
25 | catch (MaaStopException)
26 | {
27 | LoggerService.LogInfo("Stopping MaaCustomAction");
28 | return false;
29 | }
30 | catch (MaaErrorHandleException)
31 | {
32 | LoggerService.LogInfo("ErrorHandle MaaCustomAction");
33 | ErrorHandle(context, args);
34 | return true;
35 | }
36 | }
37 |
38 | protected abstract bool Execute(IMaaContext context, RunArgs args);
39 |
40 | protected virtual void ErrorHandle(IMaaContext context, RunArgs args) {}
41 | }
42 |
--------------------------------------------------------------------------------
/Helper/AutoInitDictionary.cs:
--------------------------------------------------------------------------------
1 | namespace MFAWPF.Helper;
2 |
3 | public class AutoInitDictionary : Dictionary
4 | {
5 | public AutoInitDictionary()
6 | {
7 | this["exploreCount"] = 0;
8 | }
9 |
10 | // 重写索引器,确保不存在的键被访问时初始化为0
11 | public new int this[string key]
12 | {
13 | get
14 | {
15 | if (!ContainsKey(key))
16 | {
17 | this[key] = 0;
18 | }
19 |
20 | return base[key];
21 | }
22 | set => base[key] = value;
23 | }
24 | }
--------------------------------------------------------------------------------
/Helper/Converters/AutoConverter.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class AutoConverter : JsonConverter
7 | {
8 | public override bool CanConvert(Type objectType)
9 | {
10 | return objectType == typeof(object); // We are converting to object as it can be any type.
11 | }
12 |
13 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
14 | JsonSerializer serializer)
15 | {
16 | JToken token = JToken.Load(reader);
17 |
18 | switch (token.Type)
19 | {
20 | case JTokenType.Boolean:
21 | return token.ToObject();
22 |
23 | case JTokenType.Integer:
24 | long longValue = token.ToObject();
25 | if (longValue is >= uint.MinValue and <= uint.MaxValue)
26 | return (uint)longValue;
27 |
28 | return longValue;
29 |
30 | case JTokenType.Float:
31 | return token.ToObject();
32 |
33 | case JTokenType.String:
34 | return token.ToString();
35 |
36 | case JTokenType.Array:
37 | var firstElement = token.First;
38 | if (firstElement?.Type == JTokenType.Integer)
39 | return token.ToObject>();
40 | if (firstElement?.Type == JTokenType.String)
41 | return token.ToObject>();
42 | if (firstElement?.Type == JTokenType.Array)
43 | return token.ToObject>>();
44 |
45 | break;
46 | }
47 |
48 | throw new JsonSerializationException($"Invalid JSON format for AutoConverter. Unexpected Type \"{objectType}\"");
49 | }
50 |
51 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
52 | {
53 | switch (value)
54 | {
55 | case bool booleanValue:
56 | writer.WriteValue(booleanValue);
57 | break;
58 |
59 | case int intValue:
60 | writer.WriteValue(intValue);
61 | break;
62 |
63 | case uint uintValue:
64 | writer.WriteValue(uintValue);
65 | break;
66 |
67 | case double doubleValue:
68 | writer.WriteValue(doubleValue);
69 | break;
70 |
71 | case string stringValue:
72 | writer.WriteValue(stringValue);
73 | break;
74 |
75 | case List intList:
76 | serializer.Serialize(writer, intList);
77 | break;
78 |
79 | case List stringList:
80 | serializer.Serialize(writer, stringList);
81 | break;
82 |
83 | case List> nestedIntList:
84 | serializer.Serialize(writer, nestedIntList);
85 | break;
86 |
87 | default:
88 | throw new JsonSerializationException($"Unexpected value type \"{value?.GetType()}\" for AutoConverter.");
89 | }
90 | }
91 | }
--------------------------------------------------------------------------------
/Helper/Converters/CustomIsEnabledConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using System.Windows.Data;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class CustomIsEnabledConverter : IMultiValueConverter
7 | {
8 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
9 | {
10 | if (values is [bool isChecked, bool idle])
11 | {
12 | bool isCheckedValue = isChecked;
13 | return (isCheckedValue && idle) || !isCheckedValue;
14 | }
15 |
16 | return false;
17 | }
18 |
19 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
20 | {
21 | return [];
22 | }
23 | }
--------------------------------------------------------------------------------
/Helper/Converters/ListDoubleStringConverter.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper.ValueType;
2 | using System.Collections.ObjectModel;
3 | using System.Globalization;
4 | using System.Windows;
5 | using System.Windows.Data;
6 |
7 | namespace MFAWPF.Helper.Converters;
8 |
9 | public class ListDoubleStringConverter : IValueConverter
10 | {
11 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
12 | {
13 | if (value is double d)
14 | {
15 | return new ObservableCollection>
16 | {
17 | new(d.ToString(CultureInfo.InvariantCulture))
18 | };
19 | }
20 |
21 | if (value is IEnumerable doubles)
22 | {
23 | return new ObservableCollection>(
24 | doubles.Select(dx => new CustomValue(dx.ToString(CultureInfo.InvariantCulture))));
25 | }
26 |
27 | return new ObservableCollection>();
28 | }
29 |
30 |
31 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
32 | {
33 | if (value is IEnumerable> customValueList)
34 | {
35 | var list = customValueList.ToList();
36 |
37 | try
38 | {
39 | var result = list
40 | .Select(cv => double.Parse(cv.Value ?? string.Empty))
41 | .ToList();
42 | if (result.Count == 1)
43 | return result[0];
44 | return result.Count > 0 ? result : null;
45 | }
46 | catch
47 | {
48 | return DependencyProperty.UnsetValue;
49 | }
50 | }
51 |
52 | return null;
53 | }
54 | }
--------------------------------------------------------------------------------
/Helper/Converters/ListIntStringConverter.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper.ValueType;
2 | using System.Collections.ObjectModel;
3 | using System.Globalization;
4 | using System.Windows;
5 | using System.Windows.Data;
6 |
7 | namespace MFAWPF.Helper.Converters;
8 |
9 | public class ListIntStringConverter : IValueConverter
10 | {
11 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
12 | {
13 | if (value is IEnumerable intCollection)
14 | {
15 | return new ObservableCollection>()
16 | {
17 | new(string.Join(",", intCollection.ToList()))
18 | };
19 | }
20 |
21 | if (value is IEnumerable> intCCollection)
22 | {
23 | return new ObservableCollection>(
24 | intCCollection.Select(ic => new CustomValue(string.Join(",", ic.ToList()))));
25 | }
26 |
27 | return new ObservableCollection>();
28 | }
29 |
30 |
31 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
32 | {
33 | if (value is IEnumerable> customValueList)
34 | {
35 | var list = customValueList.ToList();
36 | if (list.Count == 1)
37 | {
38 | if (bool.TryParse(list[0].Value, out var result) && result)
39 | return result;
40 | }
41 |
42 | try
43 | {
44 | var result = list
45 | .Where(cv => cv.Value != null)
46 | .Select(cv => cv.Value?
47 | .Split(',')
48 | .Select(int.Parse)
49 | .ToList())
50 | .ToList();
51 | return result.Count > 0 ? result : null;
52 | }
53 | catch
54 | {
55 | return DependencyProperty.UnsetValue;
56 | }
57 | }
58 |
59 |
60 | return null;
61 | }
62 | }
--------------------------------------------------------------------------------
/Helper/Converters/ListStringArrayConverter.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper.ValueType;
2 | using System.Collections.ObjectModel;
3 | using System.Globalization;
4 | using System.Windows;
5 | using System.Windows.Data;
6 |
7 | namespace MFAWPF.Helper.Converters;
8 |
9 | public class ListStringArrayConverter : IValueConverter
10 | {
11 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
12 | {
13 | if (value is IEnumerable ls)
14 | {
15 | return new ObservableCollection>(
16 | ls.Select(array => new CustomValue($"[{string.Join(",", array)}]")).ToList()
17 | );
18 | }
19 |
20 | return new ObservableCollection>();
21 | }
22 |
23 |
24 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
25 | {
26 | if (value is IEnumerable> collection)
27 | {
28 | var result = collection.Select(customValue =>
29 | {
30 | var trimmed = customValue.Value?.Trim('[', ']');
31 | var splitArray = trimmed?.Split(",");
32 | return splitArray?.Length == 2 ? splitArray : null;
33 | }).ToList();
34 |
35 | if (result.Any(array => array == null))
36 | {
37 | return DependencyProperty.UnsetValue;
38 | }
39 |
40 | return result;
41 | }
42 |
43 |
44 | return null;
45 | }
46 | }
--------------------------------------------------------------------------------
/Helper/Converters/ListStringConverter.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper.ValueType;
2 | using System.Collections.ObjectModel;
3 | using System.Globalization;
4 | using System.Windows.Data;
5 |
6 | namespace MFAWPF.Helper.Converters;
7 |
8 | public class ListStringConverter : IValueConverter
9 | {
10 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
11 | {
12 | if (value is IEnumerable stringCollection)
13 | {
14 | return new ObservableCollection>(stringCollection
15 | .Select(s => new CustomValue(s)).ToList());
16 | }
17 |
18 | if (value is string sx)
19 | {
20 | return new ObservableCollection>
21 | {
22 | new(sx)
23 | };
24 | }
25 |
26 | return new ObservableCollection>();
27 | }
28 |
29 |
30 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
31 | {
32 | if (value is IEnumerable> customValueList)
33 | {
34 | var list = customValueList.Select(cv => cv.Value).ToList();
35 | return list.Count > 0 ? list : null;
36 | }
37 |
38 | return null;
39 | }
40 | }
--------------------------------------------------------------------------------
/Helper/Converters/MaaInterfaceSelectAdvancedConverter.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Extensions.Maa;
2 | using Newtonsoft.Json;
3 | using Newtonsoft.Json.Linq;
4 |
5 | namespace MFAWPF.Helper.Converters;
6 |
7 |
8 | public class MaaInterfaceSelectAdvancedConverter(bool serializeAsStringArray) : JsonConverter
9 | {
10 | public override bool CanConvert(Type objectType)
11 | {
12 | return objectType == typeof(List);
13 | }
14 |
15 |
16 | public override object ReadJson(JsonReader reader,
17 | Type objectType,
18 | object existingValue,
19 | JsonSerializer serializer)
20 | {
21 | var token = JToken.Load(reader);
22 |
23 | switch (token.Type)
24 | {
25 | case JTokenType.Array:
26 | var firstElement = token.First;
27 |
28 | if (firstElement?.Type == JTokenType.String)
29 | {
30 | var list = new List();
31 | foreach (var item in token)
32 | {
33 | list.Add(new MaaInterface.MaaInterfaceSelectAdvanced
34 | {
35 | Name = item.ToString(),
36 | });
37 | }
38 |
39 | return list;
40 | }
41 |
42 | if (firstElement?.Type == JTokenType.Object)
43 | {
44 | return token.ToObject>(serializer);
45 | }
46 |
47 | break;
48 | case JTokenType.String:
49 | var oName = token.ToObject(serializer);
50 | return new List
51 | {
52 | new()
53 | {
54 | Name = oName ?? ""
55 | }
56 | };
57 | case JTokenType.None:
58 | return null;
59 | }
60 |
61 | Console.WriteLine($"Invalid JSON format for MaaInterfaceSelectAdvancedConverter. Unexpected type {objectType}.");
62 | return null;
63 | }
64 |
65 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
66 | {
67 | var array = new JArray();
68 |
69 | if (value is List selectOptions)
70 | {
71 | if (serializeAsStringArray)
72 | {
73 | foreach (var option in selectOptions)
74 | {
75 | array.Add(option.Name);
76 | }
77 | }
78 | else
79 | {
80 | foreach (var option in selectOptions)
81 | {
82 | var obj = JObject.FromObject(option);
83 | array.Add(obj);
84 | }
85 | }
86 |
87 | array.WriteTo(writer);
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Helper/Converters/MaaInterfaceSelectOptionConverter.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Extensions.Maa;
2 | using Newtonsoft.Json;
3 | using Newtonsoft.Json.Linq;
4 |
5 | namespace MFAWPF.Helper.Converters;
6 |
7 | public class MaaInterfaceSelectOptionConverter : JsonConverter
8 | {
9 | private readonly bool _serializeAsStringArray;
10 |
11 | public MaaInterfaceSelectOptionConverter(bool serializeAsStringArray)
12 | {
13 | _serializeAsStringArray = serializeAsStringArray;
14 | }
15 |
16 | public override bool CanConvert(Type objectType)
17 | {
18 | return objectType == typeof(List);
19 | }
20 |
21 |
22 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
23 | JsonSerializer serializer)
24 | {
25 | JToken token = JToken.Load(reader);
26 | switch (token.Type)
27 | {
28 | case JTokenType.Array:
29 | var firstElement = token.First;
30 |
31 | if (firstElement?.Type == JTokenType.String)
32 | {
33 | var list = new List();
34 | foreach (var item in token)
35 | {
36 | list.Add(new MaaInterface.MaaInterfaceSelectOption
37 | {
38 | Name = item.ToString(),
39 | Index = 0
40 | });
41 | }
42 |
43 | return list;
44 | }
45 |
46 | if (firstElement?.Type == JTokenType.Object)
47 | {
48 | return token.ToObject>(serializer);
49 | }
50 |
51 | break;
52 | case JTokenType.String:
53 | var oName = token.ToObject(serializer);
54 | return new List
55 | {
56 | new()
57 | {
58 | Name = oName ?? "", Index = 0
59 | }
60 | };
61 | case JTokenType.None:
62 | return null;
63 | }
64 |
65 | Console.WriteLine($"Invalid JSON format for MaaInterfaceSelectOptionConverter. Unexpected type {objectType}.");
66 | return null;
67 | }
68 |
69 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
70 | {
71 | var array = new JArray();
72 |
73 | if (value is List selectOptions)
74 | {
75 | if (_serializeAsStringArray)
76 | {
77 | foreach (var option in selectOptions)
78 | {
79 | array.Add(option.Name);
80 | }
81 | }
82 | else
83 | {
84 | foreach (var option in selectOptions)
85 | {
86 | JObject obj = new JObject
87 | {
88 | ["name"] = option.Name,
89 | ["index"] = option.Index
90 | };
91 | array.Add(obj);
92 | }
93 | }
94 |
95 | array.WriteTo(writer);
96 | }
97 | }
98 | }
--------------------------------------------------------------------------------
/Helper/Converters/MaaResourceVersionConverter.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Extensions.Maa;
2 | using Newtonsoft.Json;
3 | using Newtonsoft.Json.Linq;
4 |
5 | namespace MFAWPF.Helper.Converters;
6 |
7 | public class MaaResourceVersionConverter : JsonConverter
8 | {
9 | public override bool CanConvert(Type objectType)
10 | {
11 | return objectType == typeof(string) || objectType == typeof(MaaInterface.MaaResourceVersion);
12 | }
13 |
14 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
15 | JsonSerializer serializer)
16 | {
17 | var token = JToken.Load(reader);
18 | var res = token.ToString();
19 | if (res.Contains('{') || res.Contains('}'))
20 | {
21 | var version = token.ToObject(serializer);
22 | return version?.Version;
23 | }
24 |
25 | return res;
26 | }
27 |
28 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
29 | {
30 | if (value is string strValue)
31 | {
32 | writer.WriteValue(strValue);
33 | }
34 |
35 | if (value is MaaInterface.MaaResourceVersion mrv)
36 | writer.WriteValue(mrv.Version);
37 | }
38 | }
--------------------------------------------------------------------------------
/Helper/Converters/NullStringConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using System.Windows.Data;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class NullStringConverter : IValueConverter
7 | {
8 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
9 | {
10 | return value?.ToString() ?? string.Empty;
11 | }
12 |
13 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
14 | {
15 | return string.IsNullOrEmpty(value?.ToString()) ? null : value;
16 | }
17 | }
--------------------------------------------------------------------------------
/Helper/Converters/NullableDoubleConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Data;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class NullableDoubleConverter : IValueConverter
7 | {
8 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
9 | {
10 | if (value == null)
11 | return string.Empty;
12 | return value.ToString();
13 | }
14 |
15 | public object ConvertBack(object value, Type targetType, object parameter,
16 | System.Globalization.CultureInfo culture)
17 | {
18 | var strValue = value as string;
19 | if (string.IsNullOrWhiteSpace(strValue))
20 | return null;
21 | if (double.TryParse(strValue, out var result))
22 | return result;
23 | return DependencyProperty.UnsetValue;
24 | }
25 | }
--------------------------------------------------------------------------------
/Helper/Converters/NullableIntConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Data;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class NullableIntConverter : IValueConverter
7 | {
8 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
9 | {
10 | if (value == null)
11 | return string.Empty;
12 | return value.ToString();
13 | }
14 |
15 | public object ConvertBack(object value, Type targetType, object parameter,
16 | System.Globalization.CultureInfo culture)
17 | {
18 | var strValue = value as string;
19 | if (string.IsNullOrWhiteSpace(strValue))
20 | return null;
21 | if (int.TryParse(strValue, out var result))
22 | return result;
23 | return DependencyProperty.UnsetValue;
24 | }
25 | }
--------------------------------------------------------------------------------
/Helper/Converters/NullableStringConverter.cs:
--------------------------------------------------------------------------------
1 |
2 | using System.Windows.Data;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class NullableStringConverter : IValueConverter
7 | {
8 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
9 | {
10 | if (value == null)
11 | return string.Empty;
12 | return value.ToString();
13 | }
14 |
15 | public object ConvertBack(object value, Type targetType, object parameter,
16 | System.Globalization.CultureInfo culture)
17 | {
18 | var strValue = value as string;
19 | if (string.IsNullOrWhiteSpace(strValue))
20 | return null;
21 | return strValue;
22 | }
23 | }
--------------------------------------------------------------------------------
/Helper/Converters/NullableUIntConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Data;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class NullableUIntConverter : IValueConverter
7 | {
8 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
9 | {
10 | if (value == null)
11 | return string.Empty;
12 | return value.ToString();
13 | }
14 |
15 | public object ConvertBack(object value, Type targetType, object parameter,
16 | System.Globalization.CultureInfo culture)
17 | {
18 |
19 | var strValue = value as string;
20 | if (string.IsNullOrWhiteSpace(strValue))
21 | return null;
22 | if (uint.TryParse(strValue, out var result))
23 | return result;
24 | return DependencyProperty.UnsetValue;
25 | }
26 | }
--------------------------------------------------------------------------------
/Helper/Converters/NullableUIntOrObjectConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Data;
3 | using Newtonsoft.Json;
4 |
5 | namespace MFAWPF.Helper.Converters;
6 |
7 | public class NullableUIntOrObjectConverter : IValueConverter
8 | {
9 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
10 | {
11 | if (value == null)
12 | return string.Empty;
13 | return value.ToString();
14 | }
15 |
16 | public object ConvertBack(object value, Type targetType, object parameter,
17 | System.Globalization.CultureInfo culture)
18 | {
19 | var strValue = value as string;
20 | if (string.IsNullOrWhiteSpace(strValue))
21 | return null;
22 | if (uint.TryParse(strValue, out var result))
23 | return result;
24 | if (strValue.Contains('{') && strValue.Contains('}'))
25 | {
26 | return JsonConvert.DeserializeObject(strValue);
27 | }
28 |
29 | return DependencyProperty.UnsetValue;
30 | }
31 | }
--------------------------------------------------------------------------------
/Helper/Converters/NullableUIntStringConverter.cs:
--------------------------------------------------------------------------------
1 |
2 | using System.Windows.Data;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class NullableUIntStringConverter : IValueConverter
7 | {
8 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
9 | {
10 | if (value == null)
11 | return string.Empty;
12 | return value.ToString();
13 | }
14 |
15 | public object ConvertBack(object value, Type targetType, object parameter,
16 | System.Globalization.CultureInfo culture)
17 | {
18 | var strValue = value as string;
19 | if (string.IsNullOrWhiteSpace(strValue))
20 | return null;
21 | if (uint.TryParse(strValue, out var result))
22 | return result;
23 | return strValue;
24 | }
25 | }
--------------------------------------------------------------------------------
/Helper/Converters/ReplaceConverter.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class ReplaceConverter : JsonConverter
7 | {
8 | public override bool CanConvert(Type objectType)
9 | {
10 | return objectType == typeof(List);
11 | }
12 |
13 | public override object ReadJson(JsonReader reader,
14 | Type objectType,
15 | object existingValue,
16 | JsonSerializer serializer)
17 | {
18 | var token = JToken.Load(reader);
19 | if (token.Type == JTokenType.Array)
20 | {
21 | if (token.First?.Type == JTokenType.Array)
22 | {
23 | return token.ToObject>();
24 | }
25 |
26 | var list = new List
27 | {
28 | token.ToObject() ?? []
29 | };
30 | return list;
31 | }
32 |
33 | throw new JsonSerializationException("Unexpected token type: " + token.Type);
34 | }
35 |
36 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
37 | {
38 | if (value is List list)
39 | {
40 | if (list.Count == 1)
41 | {
42 | serializer.Serialize(writer, list[0]);
43 | }
44 | else
45 | {
46 | serializer.Serialize(writer, list);
47 | }
48 | }
49 | else
50 | {
51 | writer.WriteValue(value?.ToString() ?? string.Empty);
52 | }
53 |
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Helper/Converters/SingleIntListConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Data;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class SingleIntListConverter : IValueConverter
7 | {
8 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
9 | {
10 | if (value == null)
11 | return string.Empty;
12 | if (value is List li)
13 | {
14 | return string.Join(",", li);
15 | }
16 |
17 | return value.ToString();
18 | }
19 |
20 | public object ConvertBack(object value, Type targetType, object parameter,
21 | System.Globalization.CultureInfo culture)
22 | {
23 | var strValue = value as string;
24 | if (string.IsNullOrWhiteSpace(strValue))
25 | return null;
26 |
27 | try
28 | {
29 | var result = strValue
30 | .Split(',')
31 | .Select(int.Parse)
32 | .ToList();
33 | return result;
34 | }
35 | catch
36 | {
37 | return DependencyProperty.UnsetValue;
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/Helper/Converters/SingleIntListOrAutoConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Data;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class SingleIntListOrAutoConverter : IValueConverter
7 | {
8 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
9 | {
10 | if (value == null)
11 | return string.Empty;
12 | if (value is List li)
13 | {
14 | return string.Join(",", li);
15 | }
16 |
17 | if (value is bool b)
18 | return b.ToString();
19 | if (value is string s)
20 | return s;
21 | return value.ToString();
22 | }
23 |
24 | public object ConvertBack(object value, Type targetType, object parameter,
25 | System.Globalization.CultureInfo culture)
26 | {
27 | var strValue = value as string;
28 | if (string.IsNullOrWhiteSpace(strValue))
29 | return null;
30 | if (bool.TryParse(strValue, out var b) && b)
31 | return true;
32 | if (!strValue.Contains(","))
33 | {
34 | return strValue;
35 | }
36 |
37 | try
38 | {
39 | var result = strValue
40 | .Split(',')
41 | .Select(int.Parse)
42 | .ToList();
43 | return result;
44 | }
45 | catch
46 | {
47 | return DependencyProperty.UnsetValue;
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/Helper/Converters/SingleOrDoubleListConverter.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class SingleOrDoubleListConverter : JsonConverter
7 | {
8 | public override bool CanConvert(Type objectType)
9 | {
10 | return objectType == typeof(object) || objectType == typeof(double);
11 | }
12 |
13 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
14 | JsonSerializer serializer)
15 | {
16 | JToken token = JToken.Load(reader);
17 | if (token.Type == JTokenType.Float)
18 | {
19 | return token.ToObject();
20 | }
21 |
22 | if (token.Type == JTokenType.Array)
23 | {
24 | return token.ToObject>();
25 | }
26 |
27 | return null;
28 | }
29 |
30 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
31 | {
32 | if (value is null)
33 | {
34 | return;
35 | }
36 |
37 | if (value is double d)
38 | {
39 | writer.WriteValue(d);
40 | return;
41 | }
42 |
43 | if (value is List list)
44 | {
45 | if (list.Count == 1)
46 | {
47 | writer.WriteValue(list[0]);
48 | }
49 | else
50 | {
51 | serializer.Serialize(writer, list);
52 | }
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/Helper/Converters/SingleOrIntListConverter.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class SingleOrIntListConverter : JsonConverter
7 | {
8 | public override bool CanConvert(Type objectType)
9 | {
10 | return objectType == typeof(object);
11 | }
12 |
13 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
14 | {
15 | JToken token = JToken.Load(reader);
16 | if (token.Type == JTokenType.Integer)
17 | {
18 | return new List { token.ToObject() };
19 | }
20 |
21 | if (token.Type == JTokenType.Array)
22 | {
23 | return token.ToObject>();
24 | }
25 |
26 | return null;
27 | }
28 |
29 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
30 | {
31 | if (value is List list)
32 | {
33 | if (list.Count == 1)
34 | {
35 | writer.WriteValue(list[0]);
36 | }
37 | else
38 | {
39 | serializer.Serialize(writer, list);
40 | }
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/Helper/Converters/SingleOrListConverter.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class SingleOrListConverter : JsonConverter
7 | {
8 | public override bool CanConvert(Type objectType)
9 | {
10 | return objectType == typeof(object);
11 | }
12 |
13 | public override object ReadJson(JsonReader reader,
14 | Type objectType,
15 | object existingValue,
16 | JsonSerializer serializer)
17 | {
18 | JToken token = JToken.Load(reader);
19 | if (token is { Type: JTokenType.String })
20 | {
21 | return new List
22 | {
23 | token.ToString()
24 | };
25 | }
26 |
27 | if (token is { Type: JTokenType.Array })
28 | {
29 | return token.ToObject>();
30 | }
31 |
32 | return null;
33 | }
34 |
35 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
36 | {
37 | if (value is List list)
38 | {
39 | serializer.Serialize(writer, list);
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Helper/Converters/SingleOrNestedListConverter.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 | using System.Collections;
4 | using System.Text;
5 | using System.Windows.Documents;
6 |
7 | namespace MFAWPF.Helper.Converters;
8 |
9 | public class SingleOrNestedListConverter : JsonConverter
10 | {
11 | public override bool CanConvert(Type objectType)
12 | {
13 | return objectType == typeof(List) || objectType == typeof(List>) || objectType == typeof(string) || objectType == typeof(bool);
14 | }
15 |
16 | public override object ReadJson(JsonReader reader,
17 | Type objectType,
18 | object existingValue,
19 | JsonSerializer serializer)
20 | {
21 | JToken token = JToken.Load(reader);
22 |
23 | if (token.Type == JTokenType.Array)
24 | {
25 | if (token.First is { Type: JTokenType.Array })
26 | return token.ToObject>>();
27 |
28 | return token.ToObject>();
29 | }
30 |
31 | if (token.Type == JTokenType.String)
32 | {
33 | return token.ToString();
34 | }
35 |
36 | if (token.Type == JTokenType.Boolean)
37 | {
38 | return token.ToString();
39 | }
40 |
41 | throw new JsonSerializationException($"Invalid JSON format for SingleOrNestedListConverter. Unexpected Type \"{objectType}\"");
42 | }
43 |
44 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
45 | {
46 | if (value is IEnumerable> nestedList)
47 | {
48 | serializer.Serialize(writer, nestedList);
49 | }
50 | else if (value is IEnumerable singleList)
51 | {
52 | serializer.Serialize(writer, singleList);
53 | }
54 | else if (value is string s)
55 | {
56 | writer.WriteValue(s);
57 | }
58 | else if (value is bool b)
59 | {
60 | writer.WriteValue(b);
61 | }
62 | else
63 | {
64 | throw new JsonSerializationException($"Unexpected value type \"{value?.GetType()}\" for CustomListConverter.");
65 | }
66 | }
67 |
68 | private List FlattenMultiDimArray(Array multiDimArray)
69 | {
70 | List result = new List();
71 | if (multiDimArray.Rank == 1)
72 | {
73 | foreach (int element in multiDimArray)
74 | {
75 | result.Add(element);
76 | }
77 | }
78 | else
79 | {
80 | foreach (var element in multiDimArray)
81 | {
82 | if (element is Array subArray)
83 | {
84 | result.AddRange(FlattenMultiDimArray(subArray));
85 | }
86 | }
87 | }
88 | return result;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Helper/Converters/StrictPlaceholderConverter.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class StrictPlaceholderConverter: JsonConverter
7 | {
8 | public override bool CanConvert(Type objectType) => true;
9 |
10 | public override object ReadJson(JsonReader reader, Type objectType,
11 | object existingValue, JsonSerializer serializer)
12 | {
13 | var token = JToken.Load(reader);
14 |
15 | if (token.Type == JTokenType.String &&
16 | token.Value() == "[placeholder]")
17 | {
18 | return GetDefaultValue(objectType); // 根据目标类型返回安全值
19 | }
20 |
21 | return token.ToObject(objectType);
22 | }
23 |
24 | private object GetDefaultValue(Type targetType) =>
25 | Type.GetTypeCode(targetType) switch {
26 | TypeCode.Int32 => 0,
27 | TypeCode.Boolean => false,
28 | TypeCode.String => "[placeholder]", // 保持字符串形式
29 | _ => Activator.CreateInstance(targetType)
30 | };
31 |
32 | public override void WriteJson(JsonWriter writer, object value,
33 | JsonSerializer serializer) => serializer.Serialize(writer, value);
34 | }
--------------------------------------------------------------------------------
/Helper/Converters/StringOrBoolOrObjectConverter.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 |
5 | namespace MFAWPF.Helper.Converters;
6 |
7 | public class StringOrBoolOrObjectConverter : JsonConverter
8 | {
9 | // 允许转换的类型:字符串或动态对象
10 | public override bool CanConvert(Type objectType)
11 | {
12 | return objectType == typeof(string) || objectType == typeof(bool) || objectType == typeof(object);
13 | }
14 |
15 | // 反序列化逻辑
16 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
17 | {
18 | JToken token = JToken.Load(reader);
19 |
20 | // 情况 1:JSON 值为字符串
21 | if (token.Type == JTokenType.String)
22 | {
23 | return token.ToObject();
24 | }
25 | if (token.Type == JTokenType.Boolean)
26 | {
27 | return token.ToObject();
28 | }
29 |
30 | // 情况 2:JSON 值为对象(动态解析为 JObject)
31 | if (token.Type == JTokenType.Object)
32 | {
33 | // 使用 JObject 动态处理任意结构
34 | return token.ToObject();
35 | }
36 |
37 | throw new JsonSerializationException($"不支持的 JSON 类型:{token.Type}");
38 | }
39 |
40 | // 序列化逻辑
41 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
42 | {
43 | // 情况 1:输入为字符串类型
44 | if (value is string str)
45 | {
46 | writer.WriteValue(str);
47 | return;
48 | }
49 | if (value is bool b)
50 | {
51 | writer.WriteValue(b);
52 | return;
53 | }
54 | // 情况 2:输入为动态对象(如 JObject 或自定义类型)
55 | if (value is JObject jObj)
56 | {
57 | jObj.WriteTo(writer);
58 | }
59 | else
60 | {
61 | // 处理其他动态对象(如字典)
62 | JToken.FromObject(value, serializer).WriteTo(writer);
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Helper/Converters/StringOrObjectConverter.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class StringOrObjectConverter : JsonConverter
7 | {
8 | // 允许转换的类型:字符串或动态对象
9 | public override bool CanConvert(Type objectType)
10 | {
11 | return objectType == typeof(string) || objectType == typeof(object);
12 | }
13 |
14 | // 反序列化逻辑
15 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
16 | {
17 | JToken token = JToken.Load(reader);
18 |
19 | // 情况 1:JSON 值为字符串
20 | if (token.Type == JTokenType.String)
21 | {
22 | return token.ToObject();
23 | }
24 |
25 | // 情况 2:JSON 值为对象(动态解析为 JObject)
26 | if (token.Type == JTokenType.Object)
27 | {
28 | // 使用 JObject 动态处理任意结构
29 | return token.ToObject();
30 | }
31 |
32 | throw new JsonSerializationException($"不支持的 JSON 类型:{token.Type}");
33 | }
34 |
35 | // 序列化逻辑
36 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
37 | {
38 | // 情况 1:输入为字符串类型
39 | if (value is string str)
40 | {
41 | writer.WriteValue(str);
42 | return;
43 | }
44 |
45 | // 情况 2:输入为动态对象(如 JObject 或自定义类型)
46 | if (value is JObject jObj)
47 | {
48 | jObj.WriteTo(writer);
49 | }
50 | else
51 | {
52 | // 处理其他动态对象(如字典)
53 | JToken.FromObject(value, serializer).WriteTo(writer);
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/Helper/Converters/SubtractConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using System.Windows.Data;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class SubtractConverter : IValueConverter
7 | {
8 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
9 | {
10 | if (value is double originalWidth && parameter is string parameterString && double.TryParse(parameterString, out double subtractValue))
11 | {
12 | return originalWidth - subtractValue;
13 | }
14 | return value;
15 | }
16 |
17 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
18 | {
19 | throw new Exception("Type not exists!");
20 | }
21 | }
--------------------------------------------------------------------------------
/Helper/Converters/UniversalEnumConverter.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.Numerics;
3 |
4 | namespace MFAWPF.Helper.Converters;
5 |
6 | public class UniversalEnumConverter : JsonConverter where T : struct, Enum
7 | {
8 | public override T ReadJson(JsonReader reader, Type objectType, T existingValue, bool hasExistingValue, JsonSerializer serializer)
9 | {
10 | if (reader.Value is BigInteger bigInt)
11 | return ConvertFromBigInteger(bigInt);
12 | if (reader.Value != null && reader.TokenType == JsonToken.Integer)
13 | return (T)Enum.ToObject(typeof(T), reader.Value);
14 | if (reader.TokenType == JsonToken.String)
15 | return Enum.Parse(reader.Value?.ToString() ?? string.Empty, true);
16 | throw new JsonException($"无法转换 {reader.Value} 到 {typeof(T)}");
17 | }
18 | private T ConvertFromBigInteger(BigInteger bigInt)
19 | {
20 | Type underlyingType = Enum.GetUnderlyingType(typeof(T));
21 |
22 | try
23 | {
24 | checked
25 | {
26 | return underlyingType switch
27 | {
28 | _ when underlyingType == typeof(ulong) => (T)Enum.ToObject(typeof(T), (ulong)bigInt),
29 | _ when underlyingType == typeof(long) => (T)Enum.ToObject(typeof(T), (long)bigInt),
30 | _ when underlyingType == typeof(uint) => (T)Enum.ToObject(typeof(T), (uint)bigInt),
31 | _ when underlyingType == typeof(int) => (T)Enum.ToObject(typeof(T), (int)bigInt),
32 | _ => throw new NotSupportedException($"不支持的底层类型: {underlyingType.Name}")
33 | };
34 | }
35 | }
36 | catch (OverflowException)
37 | {
38 | throw new JsonException($"数值 {bigInt} 超过 {underlyingType.Name} 的范围");
39 | }
40 | }
41 | public override void WriteJson(JsonWriter writer, T value, JsonSerializer serializer)
42 | {
43 | writer.WriteValue(value.ToString());
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Helper/DeviceWindowTemplateSelector.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 | using MaaFramework.Binding;
4 |
5 | namespace MFAWPF.Helper;
6 |
7 | public class DeviceWindowTemplateSelector : DataTemplateSelector
8 | {
9 | public DataTemplate DeviceInfoTemplate { get; set; }
10 | public DataTemplate WindowInfoTemplate { get; set; }
11 |
12 | public override DataTemplate? SelectTemplate(object item, DependencyObject container)
13 | {
14 | if (item is AdbDeviceInfo)
15 | return DeviceInfoTemplate ;
16 |
17 | if (item is DesktopWindowInfo)
18 | return WindowInfoTemplate;
19 |
20 |
21 | return base.SelectTemplate(item, container);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Helper/DispatcherHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Threading;
3 |
4 | namespace MFAWPF.Helper;
5 |
6 | public static class DispatcherHelper
7 | {
8 | public static void RunOnMainThread(Action action)
9 | {
10 | RunOnUIThread(Application.Current, action);
11 | }
12 |
13 | public static void RunOnUIThread(this DispatcherObject d, Action action)
14 | {
15 | var dispatcher = d?.Dispatcher;
16 | if (dispatcher!=null)
17 | {
18 | if (dispatcher.CheckAccess())
19 | {
20 | action();
21 | }
22 | else
23 | {
24 | dispatcher.BeginInvoke(action);
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Helper/DragDropHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.ObjectModel;
3 | using GongSolutions.Wpf.DragDrop;
4 | using MFAWPF.Configuration;
5 | using MFAWPF.Extensions.Maa;
6 | using MFAWPF.Helper.ValueType;
7 | using MFAWPF.ViewModels;
8 | using MFAWPF.Views;
9 | using MFAWPF.Views.UI;
10 | using DragItemViewModel = MFAWPF.ViewModels.Tool.DragItemViewModel;
11 |
12 |
13 | namespace MFAWPF.Helper;
14 |
15 | public class DragDropHandler : IDropTarget
16 | {
17 | public void DragOver(IDropInfo dropInfo)
18 | {
19 | // 确保拖动有效性并显示可视化反馈
20 | if (dropInfo is { Data: not null, TargetCollection: not null })
21 | {
22 | dropInfo.Effects = System.Windows.DragDropEffects.Move;
23 | dropInfo.DropTargetAdorner = DropTargetAdorners.Insert;
24 | }
25 | }
26 |
27 | public void Drop(IDropInfo dropInfo)
28 | {
29 | // 当拖放完成后
30 | if (dropInfo is { Data: not null, TargetCollection: IList targetCollection })
31 | {
32 | var insertIndex = dropInfo.InsertIndex;
33 |
34 | // 确保移除和插入顺序正确,处理新索引
35 | if (dropInfo.Data is IEnumerable items)
36 | {
37 | foreach (var item in items)
38 | {
39 | var oldIndex = targetCollection.IndexOf(item);
40 |
41 | if (oldIndex != -1)
42 | {
43 | // 如果拖拽在向下移动,则需要修正插入索引
44 | if (insertIndex > oldIndex)
45 | {
46 | insertIndex--;
47 | }
48 |
49 | targetCollection.RemoveAt(oldIndex);
50 | targetCollection.Insert(insertIndex, item);
51 | }
52 | }
53 | }
54 | else
55 | {
56 | // 处理单个项目的拖拽
57 | var item = dropInfo.Data;
58 | var oldIndex = targetCollection.IndexOf(item);
59 |
60 | if (oldIndex != -1)
61 | {
62 | if (insertIndex > oldIndex)
63 | {
64 | insertIndex--;
65 | }
66 |
67 | targetCollection.RemoveAt(oldIndex);
68 | targetCollection.Insert(insertIndex, item);
69 | }
70 | }
71 |
72 |
73 | if (targetCollection is ObservableCollection dragItemViewModels)
74 | {
75 | List tasks = new();
76 | foreach (var dragItem in dragItemViewModels)
77 | {
78 | if (dragItem.InterfaceItem != null)
79 | tasks.Add(dragItem.InterfaceItem);
80 | }
81 |
82 | if (MaaInterface.Instance != null)
83 | MaaInterface.Instance.Task = tasks;
84 | // 保存当前的 ItemsSource 到 JSON
85 | ConfigurationHelper.SetValue(ConfigurationKeys.TaskItems,
86 | Instances.TaskQueueViewModel.TaskItemViewModels.ToList().Select(model => model.InterfaceItem));
87 | }
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/Helper/Editor/ListAutoStringEditor.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.ObjectModel;
3 | using System.Windows;
4 | using System.Windows.Data;
5 | using HandyControl.Controls;
6 | using MFAWPF.Views.UserControl;
7 | using MFAWPF.Helper.Converters;
8 | using MFAWPF.ViewModels;
9 | using MFAWPF.ViewModels.Tool;
10 | using MFAWPF.Views.UI;
11 |
12 | namespace MFAWPF.Helper.Editor;
13 |
14 | public class ListAutoStringEditor : PropertyEditorBase
15 | {
16 | public override FrameworkElement CreateElement(PropertyItem propertyItem)
17 | {
18 | var autoListControl = new CustomAutoListControl
19 | {
20 | MinHeight = 50, TaskDialogDataList = GetItemsSource(propertyItem),
21 | DisplayMemberPath = GetDisplayMemberPath(propertyItem)
22 | };
23 |
24 | return autoListControl;
25 | }
26 |
27 | // 实现抽象方法,返回 ItemsProperty 作为绑定的 DependencyProperty
28 | public override DependencyProperty GetDependencyProperty() => CustomAutoListControl.ItemsProperty;
29 |
30 | // 动态设置 ItemsSource,根据字段名称定制选项
31 | public static List AutoProperty()
32 | {
33 | return ["Roi", "Next", "OnError", "Interrupt", "Begin", "End", "Target"];
34 | }
35 |
36 | private IEnumerable GetItemsSource(PropertyItem propertyItem)
37 | {
38 | if (propertyItem.PropertyName == "Roi" || propertyItem.PropertyName == "Next" ||
39 | propertyItem.PropertyName == "OnError" || propertyItem.PropertyName == "Interrupt")
40 | {
41 | return RootView.TaskDialog?.Data?.DataList;
42 | }
43 |
44 | if (AutoProperty().Contains(propertyItem.PropertyName))
45 | {
46 | var originalDataList = RootView.TaskDialog?.Data?.DataList;
47 | if (originalDataList != null)
48 | {
49 | var newDataList = new ObservableCollection(originalDataList);
50 | newDataList.Add(new TaskItemViewModel { Name = "True" });
51 | return newDataList;
52 | }
53 |
54 | return null;
55 | }
56 |
57 | if (propertyItem.PropertyName.Contains("Color"))
58 | {
59 | return RootView.TaskDialog?.Data?.Colors;
60 | }
61 |
62 | return new ObservableCollection();
63 | }
64 |
65 | // 根据属性的字段名称,动态返回不同的 DisplayMemberPath
66 | private string GetDisplayMemberPath(PropertyItem propertyItem)
67 | {
68 | if (AutoProperty().Contains(propertyItem.PropertyName))
69 | {
70 | return "Name";
71 | }
72 |
73 | if (propertyItem.PropertyName.Contains("Color"))
74 | {
75 | return "Name";
76 | }
77 |
78 | return string.Empty; // 默认的 DisplayMemberPath
79 | }
80 |
81 |
82 | protected override IValueConverter GetConverter(PropertyItem propertyItem) => new ListStringConverter();
83 | }
--------------------------------------------------------------------------------
/Helper/Editor/ListDoubleStringEditor.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Data;
2 | using HandyControl.Controls;
3 | using MFAWPF.Helper.Converters;
4 |
5 | namespace MFAWPF.Helper.Editor;
6 |
7 | public class ListDoubleStringEditor: ListStringEditor
8 | {
9 | protected override IValueConverter GetConverter(PropertyItem propertyItem) => new ListDoubleStringConverter();
10 | }
--------------------------------------------------------------------------------
/Helper/Editor/ListIntStringEditor.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Data;
2 | using HandyControl.Controls;
3 | using MFAWPF.Helper.Converters;
4 |
5 | namespace MFAWPF.Helper.Editor;
6 |
7 | public class ListIntStringEditor : ListStringEditor
8 | {
9 | protected override IValueConverter GetConverter(PropertyItem propertyItem) => new ListIntStringConverter();
10 | }
--------------------------------------------------------------------------------
/Helper/Editor/ListStringArrayEditor.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Data;
2 | using HandyControl.Controls;
3 | using MFAWPF.Helper.Converters;
4 |
5 | namespace MFAWPF.Helper.Editor;
6 |
7 | public class ListStringArrayEditor : ListStringEditor
8 | {
9 | protected override IValueConverter GetConverter(PropertyItem propertyItem) => new ListStringArrayConverter();
10 | }
--------------------------------------------------------------------------------
/Helper/Editor/ListStringEditor.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Data;
3 | using HandyControl.Controls;
4 | using MFAWPF.Views.UserControl;
5 | using MFAWPF.Helper.Converters;
6 |
7 | namespace MFAWPF.Helper.Editor;
8 |
9 | public class ListStringEditor : PropertyEditorBase
10 | {
11 | public override FrameworkElement CreateElement(PropertyItem propertyItem) => new CustomListControl
12 | {
13 | MinHeight = 50
14 | };
15 |
16 | public override BindingMode GetBindingMode(PropertyItem propertyItem) => BindingMode.TwoWay;
17 |
18 | public override DependencyProperty GetDependencyProperty() => CustomListControl.ItemsProperty;
19 |
20 | protected override IValueConverter GetConverter(PropertyItem propertyItem) => new ListStringConverter();
21 | }
--------------------------------------------------------------------------------
/Helper/Editor/NullableDoubleEditor.cs:
--------------------------------------------------------------------------------
1 |
2 | using System.Windows.Data;
3 | using HandyControl.Controls;
4 | using MFAWPF.Helper.Converters;
5 |
6 | namespace MFAWPF.Helper.Editor;
7 |
8 | public class NullableDoubleEditor : NullableStringEditor
9 | {
10 | protected override IValueConverter GetConverter(PropertyItem propertyItem) => new NullableDoubleConverter();
11 | }
--------------------------------------------------------------------------------
/Helper/Editor/NullableIntEditor.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Data;
3 | using HandyControl.Controls;
4 | using MFAWPF.Helper.Converters;
5 |
6 | namespace MFAWPF.Helper.Editor;
7 |
8 | public class NullableIntEditor : NullableStringEditor
9 | {
10 | protected override IValueConverter GetConverter(PropertyItem propertyItem) => new NullableIntConverter();
11 | }
--------------------------------------------------------------------------------
/Helper/Editor/NullableStringEditor.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Data;
3 | using HandyControl.Controls;
4 | using MFAWPF.Helper.Converters;
5 |
6 | namespace MFAWPF.Helper.Editor;
7 |
8 | public class NullableStringEditor : PropertyEditorBase
9 | {
10 | public override FrameworkElement CreateElement(PropertyItem propertyItem)
11 | {
12 | var ctrl = new System.Windows.Controls.TextBox
13 | {
14 | IsReadOnly = propertyItem.IsReadOnly
15 | };
16 | InfoElement.SetShowClearButton(ctrl, true);
17 | return ctrl;
18 | }
19 |
20 | public override DependencyProperty GetDependencyProperty() => System.Windows.Controls.TextBox.TextProperty;
21 |
22 | protected override IValueConverter GetConverter(PropertyItem propertyItem) => new NullableStringConverter();
23 | }
--------------------------------------------------------------------------------
/Helper/Editor/NullableUIntEditor.cs:
--------------------------------------------------------------------------------
1 |
2 | using System.Windows.Data;
3 | using HandyControl.Controls;
4 | using MFAWPF.Helper.Converters;
5 |
6 | namespace MFAWPF.Helper.Editor;
7 |
8 | public class NullableUIntEditor : NullableStringEditor
9 | {
10 | protected override IValueConverter GetConverter(PropertyItem propertyItem) => new NullableUIntConverter();
11 | }
--------------------------------------------------------------------------------
/Helper/Editor/NullableUIntOrObjectEditor.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Data;
2 | using HandyControl.Controls;
3 | using MFAWPF.Helper.Converters;
4 |
5 | namespace MFAWPF.Helper.Editor;
6 |
7 | public class NullableUIntOrObjectEditor: NullableStringEditor
8 | {
9 | protected override IValueConverter GetConverter(PropertyItem propertyItem) => new NullableUIntOrObjectConverter();
10 | }
--------------------------------------------------------------------------------
/Helper/Editor/NullableUIntStringEditor.cs:
--------------------------------------------------------------------------------
1 |
2 | using System.Windows.Data;
3 | using HandyControl.Controls;
4 | using MFAWPF.Helper.Converters;
5 |
6 | namespace MFAWPF.Helper.Editor;
7 |
8 | public class NullableUIntStringEditor : NullableStringEditor
9 | {
10 | protected override IValueConverter GetConverter(PropertyItem propertyItem) => new NullableUIntStringConverter();
11 | }
--------------------------------------------------------------------------------
/Helper/Editor/SingleIntListEditor.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Data;
2 | using HandyControl.Controls;
3 | using MFAWPF.Helper.Converters;
4 |
5 | namespace MFAWPF.Helper.Editor;
6 |
7 | public class SingleIntListEditor : NullableStringEditor
8 | {
9 | protected override IValueConverter GetConverter(PropertyItem propertyItem) => new SingleIntListConverter();
10 | }
--------------------------------------------------------------------------------
/Helper/Editor/SingleIntListOrAutoEditor.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.ObjectModel;
3 | using System.Windows;
4 | using System.Windows.Data;
5 | using HandyControl.Controls;
6 | using MFAWPF.Views.UserControl;
7 | using MFAWPF.Helper.Converters;
8 | using MFAWPF.ViewModels;
9 | using MFAWPF.ViewModels.Tool;
10 | using MFAWPF.Views.UI;
11 | using ComboBox = System.Windows.Controls.ComboBox;
12 |
13 | namespace MFAWPF.Helper.Editor;
14 |
15 | public class SingleIntListOrAutoEditor : PropertyEditorBase
16 | {
17 | public override FrameworkElement CreateElement(PropertyItem propertyItem)
18 | {
19 | var ctrl = new CustomAutoCompleteTextBox
20 | {
21 | IsReadOnly = propertyItem.IsReadOnly, DataList = GetItemsSource(propertyItem),
22 | DisplayMemberPath = GetDisplayMemberPath(propertyItem)
23 | };
24 | InfoElement.SetShowClearButton(ctrl, true);
25 | return ctrl;
26 | }
27 |
28 | public static List AutoProperty()
29 | {
30 | return ["Roi", "Begin", "End", "Target"];
31 | }
32 |
33 | private IEnumerable GetItemsSource(PropertyItem propertyItem)
34 | {
35 | if (AutoProperty().Contains(propertyItem.PropertyName))
36 | {
37 | var originalDataList = RootView.TaskDialog?.Data?.DataList;
38 | if (originalDataList != null)
39 | {
40 | var newDataList = new ObservableCollection(originalDataList);
41 | if (propertyItem.PropertyName != "Roi")
42 | newDataList.Add(new TaskItemViewModel { Name = "True" });
43 | return newDataList;
44 | }
45 |
46 | return null;
47 | }
48 |
49 | return new ObservableCollection();
50 | }
51 |
52 | private string GetDisplayMemberPath(PropertyItem propertyItem)
53 | {
54 | if (AutoProperty().Contains(propertyItem.PropertyName))
55 | {
56 | return "Name";
57 | }
58 |
59 | return string.Empty;
60 | }
61 |
62 | public override DependencyProperty GetDependencyProperty() => ComboBox.TextProperty;
63 |
64 | protected override IValueConverter GetConverter(PropertyItem propertyItem) => new SingleIntListOrAutoConverter();
65 | }
--------------------------------------------------------------------------------
/Helper/Editor/StringComboBoxEditor.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls.Primitives;
3 | using System.Windows.Data;
4 | using HandyControl.Controls;
5 | using MFAWPF.Helper.Converters;
6 |
7 | namespace MFAWPF.Helper.Editor;
8 |
9 | public class StringComboBoxEditor : PropertyEditorBase
10 | {
11 | // 重写编辑器的控件类型
12 | public override FrameworkElement CreateElement(PropertyItem propertyItem)
13 | {
14 | var comboBox = new System.Windows.Controls.ComboBox
15 | {
16 | IsEditable = false,
17 | IsSynchronizedWithCurrentItem = true,
18 | SelectedItem = propertyItem.Value
19 | };
20 |
21 | // 动态设置 ItemsSource,根据字段名称定制选项
22 | comboBox.ItemsSource = GetItemsSource(propertyItem);
23 |
24 | comboBox.SelectionChanged += (_, _) => { propertyItem.Value = comboBox.SelectedItem; };
25 |
26 | return comboBox;
27 | }
28 |
29 | // 实现抽象方法,返回 ComboBox.SelectedItemProperty 作为绑定的 DependencyProperty
30 | public override DependencyProperty GetDependencyProperty() => Selector.SelectedItemProperty;
31 |
32 |
33 | // 根据属性的字段名称,设置不同的ItemsSource
34 | private IEnumerable GetItemsSource(PropertyItem propertyItem)
35 | {
36 | // 根据字段名称,动态返回选项
37 | if (propertyItem.PropertyName == "Recognition")
38 | {
39 | return new List
40 | {
41 | "",
42 | "DirectHit",
43 | "TemplateMatch",
44 | "FeatureMatch",
45 | "ColorMatch",
46 | "OCR",
47 | "NeuralNetworkClassify",
48 | "NeuralNetworkDetect",
49 | "Custom"
50 | };
51 | }
52 |
53 | if (propertyItem.PropertyName == "Action")
54 | {
55 | return new List
56 | {
57 | "",
58 | "DoNothing",
59 | "Click",
60 | "Swipe",
61 | "MultiSwipe",
62 | "Key",
63 | "Text",
64 | "StartApp",
65 | "StopApp",
66 | "StopTask",
67 | "Command",
68 | "Custom"
69 | };
70 | }
71 |
72 | if (propertyItem.PropertyName == "OrderBy")
73 | {
74 | return new List
75 | {
76 | "",
77 | "Horizontal",
78 | "Vertical",
79 | "Score",
80 | "Random",
81 | "Area",
82 | "Length"
83 | };
84 | }
85 |
86 | if (propertyItem.PropertyName == "Detector")
87 | {
88 | return new List
89 | {
90 | "",
91 | "SIFT",
92 | "KAZE",
93 | "AKAZE",
94 | "BRISK",
95 | "ORB"
96 | };
97 | }
98 |
99 | // 如果没有匹配的字段名称,返回空选项
100 | return new List { "" };
101 | }
102 |
103 | // 重写GetConverter来实现IValueConverter
104 | protected override IValueConverter GetConverter(PropertyItem propertyItem) => new NullStringConverter();
105 | }
--------------------------------------------------------------------------------
/Helper/Exceptions/MaaErrorHandleException.cs:
--------------------------------------------------------------------------------
1 | namespace MFAWPF.Helper.Exceptions;
2 |
3 | public class MaaErrorHandleException : Exception
4 | {
5 |
6 | }
7 |
--------------------------------------------------------------------------------
/Helper/Exceptions/MaaStopException.cs:
--------------------------------------------------------------------------------
1 | namespace MFAWPF.Helper.Exceptions;
2 |
3 | public class MaaStopException : Exception
4 | {
5 |
6 | }
7 |
--------------------------------------------------------------------------------
/Helper/GrowlHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using HandyControl.Controls;
3 | using HandyControl.Data;
4 |
5 |
6 | namespace MFAWPF.Helper;
7 |
8 | public static class GrowlHelper
9 | {
10 | public static void Warning(string message, string token = "")
11 | {
12 | DispatcherHelper.RunOnMainThread(() =>
13 | {
14 | Growl.Warning(new GrowlInfo
15 | {
16 | IsCustom = true,
17 | Message = message,
18 | WaitTime = 3,
19 | Token = token,
20 | IconKey = ResourceToken.WarningGeometry,
21 | IconBrushKey = ResourceToken.WarningBrush,
22 | });
23 | });
24 | }
25 |
26 | public static void WarningGlobal(string message, string token = "")
27 | {
28 | HandyControl.Tools.DispatcherHelper.RunOnMainThread(() =>
29 | {
30 | Growl.InfoGlobal(new GrowlInfo
31 | {
32 | IsCustom = true,
33 | Message = message,
34 | WaitTime = 3,
35 | IconKey = ResourceToken.WarningGeometry,
36 | IconBrushKey = ResourceToken.WarningBrush,
37 | Token = token
38 | });
39 | });
40 | }
41 |
42 | public static void Error(string message, string token = "")
43 | {
44 | DispatcherHelper.RunOnMainThread(() =>
45 | {
46 | Growl.Info(new GrowlInfo
47 | {
48 | IsCustom = true,
49 | Message = message,
50 | WaitTime = 6,
51 | IconKey = ResourceToken.ErrorGeometry,
52 | IconBrushKey = ResourceToken.DangerBrush,
53 | Icon = null,
54 | Token = token
55 | });
56 |
57 | });
58 | }
59 |
60 | public static void ErrorGlobal(string message, string token = "")
61 | {
62 | DispatcherHelper.RunOnMainThread(() =>
63 | {
64 | Growl.InfoGlobal(new GrowlInfo
65 | {
66 | IsCustom = true,
67 | Message = message,
68 | WaitTime = 6,
69 | IconKey = ResourceToken.ErrorGeometry,
70 | IconBrushKey = ResourceToken.DangerBrush,
71 | Icon = null,
72 | Token = token
73 | });
74 | });
75 | }
76 | public static void InfoGlobal(string message, string token = "")
77 | {
78 | DispatcherHelper.RunOnMainThread(() =>
79 | {
80 | Growl.InfoGlobal(message);
81 | });
82 | }
83 |
84 | public static void Info(string message, string token = "")
85 | {
86 | DispatcherHelper.RunOnMainThread(() =>
87 | {
88 | Growl.Info(message);
89 | });
90 | }
91 |
92 | public static void SuccessGlobal(string message, string token = "")
93 | {
94 | DispatcherHelper.RunOnMainThread(() =>
95 | {
96 | Growl.SuccessGlobal(message);
97 | });
98 | }
99 |
100 | public static void Success(string message, string token = "")
101 | {
102 | DispatcherHelper.RunOnMainThread(() =>
103 | {
104 | Growl.Success(message);
105 | });
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/Helper/HotKeyHelper.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper.ValueType;
2 | using System.Runtime.InteropServices;
3 | using System.Security;
4 | using System.Windows;
5 | using System.Windows.Input;
6 | using System.Windows.Interop;
7 |
8 | namespace MFAWPF.Helper;
9 |
10 | public static class HotKeyHelper
11 | {
12 | #region Windows API 封装
13 | private const int WM_HOTKEY = 0x0312;
14 | private const int ERROR_HOTKEY_ALREADY_REGISTERED = 1409;
15 | private const int ERROR_ACCESS_DENIED = 5;
16 |
17 | [DllImport("user32.dll", SetLastError = true)]
18 | private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
19 |
20 | [DllImport("user32.dll", SetLastError = true)]
21 | private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
22 |
23 | [DllImport("kernel32", SetLastError = true)]
24 | private static extern ushort GlobalAddAtom(string lpString);
25 |
26 | [DllImport("kernel32", SetLastError = true)]
27 | private static extern ushort GlobalDeleteAtom(ushort nAtom);
28 |
29 | private static uint ConvertModifiers(ModifierKeys modifiers)
30 | {
31 | uint fsModifiers = 0;
32 | if ((modifiers & ModifierKeys.Alt) != 0) fsModifiers |= 0x0001;
33 | if ((modifiers & ModifierKeys.Control) != 0) fsModifiers |= 0x0002;
34 | if ((modifiers & ModifierKeys.Shift) != 0) fsModifiers |= 0x0004;
35 | if ((modifiers & ModifierKeys.Windows) != 0) fsModifiers |= 0x0008;
36 | return fsModifiers;
37 | }
38 | #endregion
39 |
40 |
41 | #region 热键管理
42 | private static readonly Dictionary _hotkeyCallbacks = new();
43 | private static int _hotkeyIdCounter = 0x0000;
44 | private static readonly Dictionary, int> _registeredKeyCombos = new();
45 |
46 | public static bool RegisterHotKey(Window? window, MFAHotKey hotKey, Action callback)
47 | {
48 | if (window == null || hotKey.IsTip)
49 | return false;
50 |
51 | var hWnd = new WindowInteropHelper(window).EnsureHandle();
52 | var fsModifiers = ConvertModifiers(hotKey.Modifiers);
53 | var vk = (uint)KeyInterop.VirtualKeyFromKey(hotKey.Key);
54 | var keyCombo = Tuple.Create(fsModifiers, vk);
55 |
56 | if (_registeredKeyCombos.ContainsKey(keyCombo))
57 | {
58 | LoggerService.LogWarning($"重复注册热键: {hotKey}");
59 | return false;
60 | }
61 |
62 | var id = _hotkeyIdCounter++;
63 | if (!RegisterHotKey(hWnd, id, fsModifiers, vk))
64 | {
65 | int errorCode = Marshal.GetLastWin32Error();
66 | if (errorCode == ERROR_HOTKEY_ALREADY_REGISTERED)
67 | LoggerService.LogError($"热键已被其他程序占用: {hotKey}");
68 | return false;
69 | }
70 |
71 | _registeredKeyCombos[keyCombo] = id;
72 | _hotkeyCallbacks[id] = callback;
73 | return true;
74 | }
75 |
76 | public static void UnregisterHotKey(Window? window, MFAHotKey hotKey)
77 | {
78 | if (window == null || hotKey.IsTip)
79 | return;
80 |
81 | var hWnd = new WindowInteropHelper(window).Handle;
82 | var fsModifiers = ConvertModifiers(hotKey.Modifiers);
83 | var vk = (uint)KeyInterop.VirtualKeyFromKey(hotKey.Key);
84 | var keyCombo = Tuple.Create(fsModifiers, vk);
85 |
86 | if (_registeredKeyCombos.TryGetValue(keyCombo, out int id))
87 | {
88 | UnregisterHotKey(hWnd, id);
89 |
90 | _registeredKeyCombos.Remove(keyCombo);
91 | _hotkeyCallbacks.Remove(id);
92 | }
93 | }
94 | #endregion
95 | }
--------------------------------------------------------------------------------
/Helper/IconHelper.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using System.IO;
3 | using System.Windows;
4 | using System.Windows.Media.Imaging;
5 |
6 | namespace MFAWPF.Helper;
7 |
8 | public class IconHelper
9 | {
10 | private static readonly Lazy LazyIcon = new(LoadIconWithFallback);
11 | public static BitmapSource ICON => LazyIcon.Value;
12 |
13 | private static BitmapSource LoadIconWithFallback()
14 | {
15 | try
16 | {
17 | string exeDirectory = AppContext.BaseDirectory;
18 | string iconPath = Path.Combine(exeDirectory, "logo.ico");
19 |
20 | if (File.Exists(iconPath))
21 | {
22 | using var fileStream = File.OpenRead(iconPath);
23 | return CreateBitmapSource(fileStream);
24 | }
25 |
26 | var sri = Application.GetResourceStream(new Uri("pack://application:,,,/logo.ico"));
27 | if (sri != null)
28 | {
29 | using var resourceStream = sri.Stream;
30 | return CreateBitmapSource(resourceStream);
31 | }
32 |
33 | LoggerService.LogWarning("未找到内嵌图标资源");
34 | return CreateEmptyImage();
35 | }
36 | catch (Exception ex)
37 | {
38 | LoggerService.LogError($"图标加载失败: {ex}");
39 | return CreateEmptyImage();
40 | }
41 | }
42 |
43 | private static BitmapSource CreateBitmapSource(Stream stream)
44 | {
45 | var decoder = BitmapDecoder.Create(
46 | stream,
47 | BitmapCreateOptions.PreservePixelFormat,
48 | BitmapCacheOption.OnLoad
49 | );
50 | return decoder.Frames[0];
51 | }
52 |
53 | private static BitmapSource CreateEmptyImage()
54 | {
55 | return new BitmapImage(); // 返回空图像避免NullReference
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Helper/LoggerService.cs:
--------------------------------------------------------------------------------
1 | using Serilog;
2 |
3 | namespace MFAWPF.Helper;
4 |
5 | public static class LoggerService
6 | {
7 | private static readonly ILogger Logger = new LoggerConfiguration()
8 | .WriteTo.File(
9 | $"logs/log-{DateTime.Now.ToString("yyyy-MM-dd")}.txt",
10 | outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}][{Level:u3}] {Message:lj}{NewLine}{Exception}").CreateLogger();
11 |
12 | public static void LogInfo(string message)
13 | {
14 | Logger.Information(message);
15 | Console.WriteLine("[INFO]" + message);
16 | }
17 |
18 | public static void LogInfo(object message)
19 | {
20 | Logger.Information(message.ToString());
21 | Console.WriteLine("[INFO]" + message);
22 | }
23 | public static void LogError(object e)
24 | {
25 | Logger.Error(e?.ToString() ?? string.Empty);
26 |
27 | Console.WriteLine("[ERROR]" + e);
28 | }
29 |
30 | public static void LogError(string message)
31 | {
32 | Logger.Error(message);
33 | Console.WriteLine("[ERROR]" + message);
34 | }
35 |
36 | public static void LogWarning(string message)
37 | {
38 | Logger.Warning(message);
39 | Console.WriteLine("[WARN]" + message);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Helper/MFAUrls.cs:
--------------------------------------------------------------------------------
1 | namespace MFAWPF.Helper;
2 |
3 | public static class MFAUrls
4 | {
5 | public const string GitHub = "https://github.com/SweetSmellFox/MFAWPF";
6 |
7 | public const string GitHubIssues = $"{GitHub}/issues";
8 |
9 | public const string NewIssueUri = $"{GitHubIssues}/new?assignees=&labels=bug&template=cn-bug-report.yaml";
10 |
11 | public const string PurchaseLink = "https://mirrorchyan.com";
12 | }
13 |
--------------------------------------------------------------------------------
/Helper/Notification/INotificationPoster.cs:
--------------------------------------------------------------------------------
1 | //
2 | // MaaWpfGui - A part of the MaaCoreArknights project
3 | // Copyright (C) 2021 MistEO and Contributors
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU Affero General Public License v3.0 only as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY
12 | //
13 |
14 |
15 | using System;
16 |
17 | namespace MFAWPF.Helper.Notification;
18 |
19 | internal interface INotificationPoster
20 | {
21 | void ShowNotification(NotificationContent content);
22 |
23 | event EventHandler ActionActivated;
24 | }
25 |
--------------------------------------------------------------------------------
/Helper/Notification/NotificationAction.cs:
--------------------------------------------------------------------------------
1 | //
2 | // MaaWpfGui - A part of the MaaCoreArknights project
3 | // Copyright (C) 2021 MistEO and Contributors
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU Affero General Public License v3.0 only as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY
12 | //
13 |
14 | namespace MFAWPF.Helper.Notification;
15 |
16 | internal record class NotificationAction(string Label, string Tag);
17 |
--------------------------------------------------------------------------------
/Helper/Notification/NotificationContent.cs:
--------------------------------------------------------------------------------
1 | //
2 | // MaaWpfGui - A part of the MaaCoreArknights project
3 | // Copyright (C) 2021 MistEO and Contributors
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU Affero General Public License v3.0 only as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY
12 | //
13 |
14 | using System.Collections.Generic;
15 |
16 | namespace MFAWPF.Helper.Notification;
17 |
18 | internal class NotificationContent
19 | {
20 | public string Summary { get; set; }
21 |
22 | public string Body { get; set; }
23 |
24 | private readonly List _actions = [];
25 |
26 | public IList Actions => _actions;
27 |
28 | private readonly List _hints = [];
29 |
30 | public IList Hints => _hints;
31 | }
32 |
--------------------------------------------------------------------------------
/Helper/Notification/NotificationHint.cs:
--------------------------------------------------------------------------------
1 | //
2 | // MaaWpfGui - A part of the MaaCoreArknights project
3 | // Copyright (C) 2021 MistEO and Contributors
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU Affero General Public License v3.0 only as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY
12 | //
13 |
14 | using System;
15 |
16 | namespace MFAWPF.Helper.Notification;
17 |
18 | public class NotificationHint
19 | {
20 | public static NotificationHint Expandable { get; } = new NotificationHint();
21 |
22 | public static NotificationHint NewVersion { get; } = new NotificationHint();
23 |
24 | internal class NotificationHintRowCount : NotificationHint
25 | {
26 | public int Value { get; }
27 |
28 | public NotificationHintRowCount(int rowCount)
29 | {
30 | Value = rowCount;
31 | }
32 | }
33 |
34 | internal class NotificationHintExpirationTime : NotificationHint
35 | {
36 | public TimeSpan Value { get; }
37 |
38 | public NotificationHintExpirationTime(TimeSpan value)
39 | {
40 | Value = value;
41 | }
42 | }
43 |
44 | public static NotificationHint RowCount(int rowCount) => new NotificationHintRowCount(rowCount);
45 |
46 | public static NotificationHint ExpirationTime(TimeSpan value) => new NotificationHintExpirationTime(value);
47 | }
48 |
--------------------------------------------------------------------------------
/Helper/Notification/NotificationImplWinRT.cs:
--------------------------------------------------------------------------------
1 | //
2 | // MaaWpfGui - A part of the MaaCoreArknights project
3 | // Copyright (C) 2021 MistEO and Contributors
4 | //
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU Affero General Public License v3.0 only as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY
12 | //
13 |
14 | using MFAWPF.Helper;
15 | using System;
16 | using System.Windows;
17 | using Microsoft.Toolkit.Uwp.Notifications;
18 | using Notification.Wpf;
19 | using Serilog;
20 | using Windows.UI.Notifications;
21 | using ToastNotification = MFAWPF.Helper.ToastNotification;
22 |
23 |
24 | namespace MFAWPF.Helper.Notification;
25 |
26 | internal class NotificationImplWinRT : INotificationPoster, IDisposable
27 | {
28 | public event EventHandler? ActionActivated;
29 |
30 | public NotificationImplWinRT()
31 | {
32 | ToastNotificationManagerCompat.OnActivated += OnWinRTActivated;
33 | }
34 |
35 | public void Dispose()
36 | {
37 | ToastNotificationManagerCompat.OnActivated -= OnWinRTActivated;
38 |
39 | // ToastNotificationManagerCompat.History.Clear();
40 | }
41 |
42 | private void OnWinRTActivated(ToastNotificationActivatedEventArgsCompat args)
43 | {
44 | ActionActivated?.Invoke(this, args.Argument);
45 | }
46 |
47 | public void ShowNotification(NotificationContent content)
48 | {
49 | try
50 | {
51 | DispatcherHelper.RunOnMainThread(() =>
52 | {
53 |
54 | var builder = new ToastContentBuilder().AddText(content.Body).AddText(content.Summary);
55 |
56 | foreach (var action in content.Actions)
57 | {
58 | builder.AddButton(new ToastButton()
59 | .SetContent(action.Label)
60 | .AddArgument(action.Tag));
61 | }
62 | builder.Show();
63 | });
64 | }
65 | catch (Exception e)
66 | {
67 | LoggerService.LogError(e);
68 | // ignored
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Helper/ServiceProviderExtension.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using System.Windows.Markup;
3 |
4 | namespace MFAWPF.Helper;
5 |
6 | public class ServiceProviderExtension : MarkupExtension
7 | {
8 | public Type ServiceType { get; set; }
9 |
10 | public override object ProvideValue(IServiceProvider serviceProvider)
11 | {
12 | return App.Services.GetRequiredService(ServiceType);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Helper/SimpleEncryptionHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Security.Cryptography;
2 | using System.Text;
3 |
4 | namespace MFAWPF.Helper;
5 |
6 | public static class SimpleEncryptionHelper
7 | {
8 |
9 | public static string Encrypt(string plainText, DataProtectionScope dataProtectionScope = DataProtectionScope.CurrentUser)
10 | {
11 | if (string.IsNullOrEmpty(plainText))
12 | {
13 | return string.Empty;
14 | }
15 |
16 | try
17 | {
18 | var data = Encoding.UTF8.GetBytes(plainText);
19 | var encryptedData = ProtectedData.Protect(data, null, dataProtectionScope);
20 | return Convert.ToBase64String(encryptedData);
21 | }
22 | catch (Exception e)
23 | {
24 | LoggerService.LogError("Failed to encrypt text: " + e.Message);
25 | return plainText;
26 | }
27 | }
28 |
29 | public static string Decrypt(string encryptedText, DataProtectionScope dataProtectionScope = DataProtectionScope.CurrentUser)
30 | {
31 | if (string.IsNullOrEmpty(encryptedText))
32 | {
33 | return string.Empty;
34 | }
35 |
36 | try
37 | {
38 | var data = Convert.FromBase64String(encryptedText);
39 | var decryptedData = ProtectedData.Unprotect(data, null, dataProtectionScope);
40 | return Encoding.UTF8.GetString(decryptedData);
41 | }
42 | catch (Exception e)
43 | {
44 | LoggerService.LogError("Failed to decrypt text: " + e.Message);
45 | return encryptedText;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Helper/ThemeHelper.cs:
--------------------------------------------------------------------------------
1 | using HandyControl.Themes;
2 | using System.Runtime.InteropServices;
3 | using Microsoft.Win32;
4 |
5 | namespace MFAWPF.Helper;
6 |
7 | public class ThemeHelper
8 | {
9 | public static void UpdateThemeIndexChanged(int value)
10 | {
11 | switch (value)
12 | {
13 | case 0:
14 | ThemeManager.Current.UsingWindowsAppTheme = false;
15 | ThemeManager.Current.ApplicationTheme = ApplicationTheme.Light;
16 | break;
17 | case 1:
18 | ThemeManager.Current.UsingWindowsAppTheme = false;
19 | ThemeManager.Current.ApplicationTheme = ApplicationTheme.Dark;
20 | break;
21 | default:
22 | ThemeManager.Current.UsingWindowsAppTheme = true;
23 | break;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Helper/ValueType/Attribute.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper.Converters;
2 | using Newtonsoft.Json;
3 |
4 | namespace MFAWPF.Helper.ValueType;
5 |
6 | public class Attribute
7 | {
8 | public string Key { get; set; }
9 | [JsonConverter(typeof(AutoConverter))] public object Value { get; set; }
10 |
11 | public Attribute(string key, object value)
12 | {
13 | Key = key;
14 | Value = value;
15 | }
16 |
17 | public Attribute()
18 | {
19 | }
20 |
21 | static string ConvertListToString(List> listOfLists)
22 | {
23 | var formattedLists = listOfLists
24 | .Select(innerList => $"[{string.Join(",", innerList)}]");
25 | return string.Join(",", formattedLists);
26 | }
27 |
28 | public override string ToString()
29 | {
30 | if (Value is List> lli)
31 | return $"\"{Key}\" : [{ConvertListToString(lli)}]";
32 |
33 | if (Value is List li)
34 | return $"\"{Key}\" : [{string.Join(",", li)}]";
35 |
36 | if (Value is List ls)
37 | return $"\"{Key}\" : [{string.Join(",", ls)}]";
38 |
39 | if (Value is string s)
40 | return $"\"{Key}\" : \"{s}\"";
41 |
42 | return $"\"{Key}\" : {Value}";
43 | }
44 |
45 | public string GetKey()
46 | {
47 | return $"{Key}";
48 | }
49 |
50 | public string GetValue()
51 | {
52 | if (Value is List> lli)
53 | return $"{ConvertListToString(lli)}";
54 |
55 | if (Value is List li)
56 | return $"{string.Join(",", li)}";
57 |
58 | if (Value is List ls)
59 | return $"{string.Join(",", ls)}";
60 |
61 | if (Value is string s)
62 | return s;
63 |
64 | return $"{Value}";
65 | }
66 |
67 | public static bool operator ==(Attribute a1, object a2)
68 | {
69 | return a2 is Attribute attribute && a1?.Key?.Equals(attribute.Key) == true && a1.Value == attribute.Value;
70 | }
71 |
72 | public static bool operator !=(Attribute a1, object a2)
73 | {
74 | return a2 is not Attribute attribute || a1?.Key?.Equals(attribute.Key) != true || a1.Value != attribute.Value;
75 | }
76 |
77 | public override bool Equals(object obj)
78 | {
79 | return this == obj;
80 | }
81 |
82 | private int _cachedHashCode;
83 |
84 | public override int GetHashCode()
85 | {
86 | return HashCode.Combine(Key, Value);
87 | }
88 | }
--------------------------------------------------------------------------------
/Helper/ValueType/CustomValue.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 |
3 | namespace MFAWPF.Helper.ValueType;
4 |
5 | public class CustomValue : ObservableObject
6 | {
7 | public CustomValue(T value)
8 | {
9 | Value = value;
10 | }
11 | public CustomValue(string name,T value)
12 | {
13 | Name = name;
14 | Value = value;
15 | }
16 |
17 | private T _value;
18 |
19 | public T Value
20 | {
21 | get => _value;
22 | set => SetProperty(ref _value, value);
23 | }
24 |
25 | private string _name;
26 |
27 | public string Name
28 | {
29 | get => _name;
30 | set => SetProperty(ref _name, value);
31 | }
32 |
33 | public override string ToString()
34 | {
35 | return Value?.ToString() ?? string.Empty;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Helper/ValueType/MFATask.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using MaaFramework.Binding;
3 | using MFAWPF.Extensions.Maa;
4 | using MFAWPF.Views.UI;
5 |
6 | namespace MFAWPF.Helper.ValueType;
7 |
8 | public partial class MFATask : ObservableObject
9 | {
10 | public enum MFATaskType
11 | {
12 | MFA,
13 | MAAFW
14 | }
15 |
16 | [ObservableProperty] private string? _name = string.Empty;
17 | [ObservableProperty] private MFATaskType _type = MFATaskType.MFA;
18 | [ObservableProperty] private int _count = 1;
19 | [ObservableProperty] private Func _action;
20 | [ObservableProperty] private Dictionary _tasks = new();
21 |
22 |
23 | public async Task Run(CancellationToken token)
24 | {
25 | try
26 | {
27 | for (int i = 0; i < Count; i++)
28 | {
29 | token.ThrowIfCancellationRequested();
30 | if (Type == MFATaskType.MAAFW)
31 | RootView.AddLogByKey("TaskStart", null,true, Name ?? string.Empty);
32 | await Action();
33 | }
34 | return true;
35 | }
36 | catch (OperationCanceledException)
37 | {
38 | return false;
39 | }
40 | catch (Exception ex)
41 | {
42 | Console.WriteLine($"捕获异常: {ex.Message}");
43 | return false;
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Helper/ValueType/ObservableQueue.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 |
3 | namespace MFAWPF.Helper.ValueType;
4 |
5 | public partial class ObservableQueue : ObservableObject
6 | {
7 | private readonly Queue _queue = new();
8 |
9 | [ObservableProperty] private int _count;
10 |
11 | public EventHandler? CountChanged;
12 |
13 | public ObservableQueue()
14 | {
15 | Count = _queue.Count;
16 | }
17 | partial void OnCountChanged(int oldValue, int newValue)
18 | {
19 | CountChanged?.Invoke(this, new CountChangedEventArgs(oldValue, newValue));
20 | }
21 |
22 | public void Enqueue(T task)
23 | {
24 | _queue.Enqueue(task);
25 | Count = _queue.Count;
26 | }
27 |
28 | public T Dequeue()
29 | {
30 | var task = _queue.Dequeue();
31 | Count = _queue.Count;
32 | return task;
33 | }
34 |
35 | public void Clear()
36 | {
37 | _queue.Clear();
38 | Count = _queue.Count;
39 | }
40 |
41 | public class CountChangedEventArgs(int oldValue, int newValue) : EventArgs
42 | {
43 | public int OldValue => oldValue;
44 | public int NewValue => newValue;
45 | }
46 | }
--------------------------------------------------------------------------------
/Helper/ValueType/TaskInterfaceItem.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Extensions.Maa;
2 | using MFAWPF.Helper.Converters;
3 | using Newtonsoft.Json;
4 |
5 | namespace MFAWPF.Helper.ValueType;
6 |
7 | public class TaskInterfaceItem
8 | {
9 | [JsonProperty("name")] public string? Name;
10 | [JsonProperty("entry")] public string? Entry;
11 | [JsonConverter(typeof(SingleOrListConverter))] [JsonProperty("doc")]
12 | public List? Document;
13 | [JsonProperty("check",
14 | NullValueHandling = NullValueHandling.Include,
15 | DefaultValueHandling = DefaultValueHandling.Include)]
16 | public bool? Check = false;
17 | [JsonProperty("repeatable")] public bool? Repeatable;
18 | [JsonProperty("repeat_count")] public int? RepeatCount;
19 |
20 | [JsonProperty("advanced")] public List? Advanced;
21 |
22 | [JsonProperty("option")] public List? Option;
23 |
24 | [JsonProperty("pipeline_override")] public Dictionary? PipelineOverride;
25 |
26 | public override string ToString()
27 | {
28 | var settings = new JsonSerializerSettings
29 | {
30 | Formatting = Formatting.Indented,
31 | NullValueHandling = NullValueHandling.Ignore,
32 | DefaultValueHandling = DefaultValueHandling.Ignore
33 | };
34 |
35 | return JsonConvert.SerializeObject(this, settings);
36 | }
37 |
38 | ///
39 | /// Creates a deep copy of the current instance.
40 | ///
41 | /// A new instance that is a deep copy of the current instance.
42 | public TaskInterfaceItem Clone()
43 | {
44 | return JsonConvert.DeserializeObject(ToString()) ?? new TaskInterfaceItem();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Helper/ValueType/ValueBoxes.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 |
4 | namespace MFAWPF.Helper.ValueType;
5 |
6 | internal static class ValueBoxes
7 | {
8 | internal static object TrueBox = true;
9 |
10 | internal static object FalseBox = false;
11 |
12 | internal static object VerticalBox = Orientation.Vertical;
13 |
14 | internal static object HorizontalBox = Orientation.Horizontal;
15 |
16 | internal static object VisibleBox = Visibility.Visible;
17 |
18 | internal static object CollapsedBox = Visibility.Collapsed;
19 |
20 | internal static object HiddenBox = Visibility.Hidden;
21 |
22 | internal static object Double01Box = .1;
23 |
24 | internal static object Double0Box = .0;
25 |
26 | internal static object Double1Box = 1.0;
27 |
28 | internal static object Double10Box = 10.0;
29 |
30 | internal static object Double20Box = 20.0;
31 |
32 | internal static object Double100Box = 100.0;
33 |
34 | internal static object Double200Box = 200.0;
35 |
36 | internal static object Double300Box = 300.0;
37 |
38 | internal static object DoubleNeg1Box = -1.0;
39 |
40 | internal static object Int0Box = 0;
41 |
42 | internal static object Int1Box = 1;
43 |
44 | internal static object Int2Box = 2;
45 |
46 | internal static object Int5Box = 5;
47 |
48 | internal static object Int99Box = 99;
49 |
50 | internal static object BooleanBox(bool value) => value ? TrueBox : FalseBox;
51 |
52 | internal static object OrientationBox(Orientation value) =>
53 | value == Orientation.Horizontal ? HorizontalBox : VerticalBox;
54 |
55 | internal static object VisibilityBox(Visibility value)
56 | {
57 | return value switch
58 | {
59 | Visibility.Visible => VisibleBox,
60 | Visibility.Hidden => HiddenBox,
61 | Visibility.Collapsed => CollapsedBox,
62 | _ => throw new ArgumentOutOfRangeException(nameof(value), value, null)
63 | };
64 | }
65 | }
--------------------------------------------------------------------------------
/MFAWPF.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MFAWPF", "MFAWPF.csproj", "{B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}"
4 | EndProject
5 | Global
6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
7 | Debug|Any CPU = Debug|Any CPU
8 | Debug|ARM64 = Debug|ARM64
9 | Debug|x64 = Debug|x64
10 | Release|Any CPU = Release|Any CPU
11 | Release|ARM64 = Release|ARM64
12 | Release|x64 = Release|x64
13 | RelWithDebInfo|Any CPU = RelWithDebInfo|Any CPU
14 | RelWithDebInfo|ARM64 = RelWithDebInfo|ARM64
15 | RelWithDebInfo|x64 = RelWithDebInfo|x64
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.Debug|ARM64.ActiveCfg = Debug|ARM64
21 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.Debug|ARM64.Build.0 = Debug|ARM64
22 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.Debug|x64.ActiveCfg = Debug|x64
23 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.Debug|x64.Build.0 = Debug|x64
24 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.Release|ARM64.ActiveCfg = Release|ARM64
27 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.Release|ARM64.Build.0 = Release|ARM64
28 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.Release|x64.ActiveCfg = Release|x64
29 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.Release|x64.Build.0 = Release|x64
30 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|Any CPU
31 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.RelWithDebInfo|Any CPU.Build.0 = RelWithDebInfo|Any CPU
32 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.RelWithDebInfo|ARM64.ActiveCfg = RelWithDebInfo|ARM64
33 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.RelWithDebInfo|ARM64.Build.0 = RelWithDebInfo|ARM64
34 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
35 | {B9FDFBC8-AA6F-49C9-A7BB-A6AE1FCB4476}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "MFAWPF": {
4 | "commandName": "Project"
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/Resource/base/model/ocr/README.md:
--------------------------------------------------------------------------------
1 | # PaddleOCR model
2 |
3 | 2023/09/29
4 |
5 | from
6 |
7 | ## det model
8 |
9 | ch_PP-OCRv4_det
10 | 【最新】原始超轻量模型,支持中英文、多语种文本检测
11 |
12 |
13 |
14 | ## rec model
15 |
16 | ch_PP-OCRv4_rec
17 | 【最新】超轻量模型,支持中英文、数字识别
18 |
19 |
20 |
21 | ## rec label
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Resource/base/model/ocr/det.onnx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SweetSmellFox/MFAWPF/12e65484cf483e7bb68aca3e8e749406c52398c8/Resource/base/model/ocr/det.onnx
--------------------------------------------------------------------------------
/Resource/base/model/ocr/rec.onnx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SweetSmellFox/MFAWPF/12e65484cf483e7bb68aca3e8e749406c52398c8/Resource/base/model/ocr/rec.onnx
--------------------------------------------------------------------------------
/Services/ApplicationHostService.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Views;
2 | using MFAWPF.Views.UI;
3 | using Microsoft.Extensions.Hosting;
4 | using System.Windows;
5 |
6 | namespace MFAWPF.Services;
7 |
8 | public class ApplicationHostService(IServiceProvider serviceProvider) : IHostedService
9 | {
10 | private Window _window;
11 |
12 | ///
13 | /// Triggered when the application host is ready to start the service.
14 | ///
15 | /// Indicates that the start process has been aborted.
16 | public async Task StartAsync(CancellationToken cancellationToken)
17 | {
18 | await HandleActivationAsync();
19 | }
20 |
21 | ///
22 | /// Triggered when the application host is performing a graceful shutdown.
23 | ///
24 | /// Indicates that the shutdown process should no longer be graceful.
25 | public async Task StopAsync(CancellationToken cancellationToken)
26 | {
27 | await Task.CompletedTask;
28 | }
29 |
30 | ///
31 | /// Creates main window during activation.
32 | ///
33 | async private Task HandleActivationAsync()
34 | {
35 | await Task.CompletedTask;
36 |
37 | if (!Application.Current.Windows.OfType().Any())
38 | {
39 | _window = (serviceProvider.GetService(typeof(RootView)) as Window)!;
40 | _window!.Show();
41 |
42 | }
43 |
44 | await Task.CompletedTask;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ViewModels/Tool/LocalizationViewModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using MFAWPF.Extensions;
3 | using MFAWPF.Helper;
4 |
5 | namespace MFAWPF.ViewModels.Tool;
6 |
7 | public partial class LocalizationViewModel : ViewModel
8 | {
9 | [ObservableProperty] private string _resourceKey = string.Empty;
10 |
11 | partial void OnResourceKeyChanged(string value)
12 | {
13 | UpdateName();
14 | }
15 |
16 | public LocalizationViewModel() { }
17 |
18 | private readonly string[]? _formatArgsKeys;
19 |
20 | public LocalizationViewModel(string resourceKey)
21 | {
22 | ResourceKey = resourceKey;
23 | LanguageHelper.LanguageChanged += OnLanguageChanged;
24 | }
25 |
26 | public LocalizationViewModel(string resourceKey, params string[] keys)
27 | {
28 | ResourceKey = resourceKey;
29 | _formatArgsKeys = keys;
30 | LanguageHelper.LanguageChanged += OnLanguageChanged;
31 | }
32 | private void OnLanguageChanged(object sender, EventArgs e)
33 | {
34 | UpdateName();
35 | }
36 | [ObservableProperty] private string _name = string.Empty;
37 | [ObservableProperty] private object? _other;
38 |
39 | private void UpdateName()
40 | {
41 | if (string.IsNullOrWhiteSpace(ResourceKey))
42 | return;
43 | if (_formatArgsKeys != null && _formatArgsKeys.Length != 0)
44 | Name = ResourceKey.ToLocalizationFormatted(true, _formatArgsKeys);
45 | else
46 | Name = ResourceKey.ToLocalization();
47 | }
48 |
49 |
50 | public override string ToString()
51 | => ResourceKey;
52 | }
53 |
--------------------------------------------------------------------------------
/ViewModels/Tool/TaskItemViewModel.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper;
2 | using MFAWPF.Helper.ValueType;
3 | using Newtonsoft.Json;
4 |
5 | namespace MFAWPF.ViewModels.Tool;
6 |
7 | public class TaskItemViewModel : ViewModel
8 | {
9 | private string _name = "未命名";
10 |
11 | public string Name
12 | {
13 | get => _name;
14 | set
15 | {
16 | if (Task != null)
17 | Task.Name = value;
18 | SetProperty(ref _name, value);
19 | }
20 | }
21 |
22 | private TaskModel _task;
23 |
24 | ///
25 | /// Gets or sets the time.
26 | ///
27 | public TaskModel Task
28 | {
29 | get => _task;
30 | set
31 | {
32 | if (value != null)
33 | Name = value.Name;
34 | SetProperty(ref _task, value);
35 | }
36 | }
37 |
38 | public override string ToString()
39 | {
40 | var settings = new JsonSerializerSettings
41 | {
42 | Formatting = Formatting.Indented,
43 | NullValueHandling = NullValueHandling.Ignore,
44 | DefaultValueHandling = DefaultValueHandling.Ignore
45 | };
46 | Dictionary taskModels = new Dictionary();
47 | if (Task != null)
48 | {
49 | taskModels.Add(Name, Task);
50 | }
51 |
52 | return JsonConvert.SerializeObject(taskModels, settings);
53 | }
54 |
55 | }
--------------------------------------------------------------------------------
/ViewModels/UI/AnnouncementViewModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using HandyControl.Tools.Extension;
3 | using MFAWPF.Configuration;
4 | using MFAWPF.Helper;
5 | using MFAWPF.Views.UI;
6 | using System.IO;
7 | using System.Windows;
8 | using Exception = System.Exception;
9 |
10 | namespace MFAWPF.ViewModels.UI;
11 |
12 | public partial class AnnouncementViewModel : ViewModel
13 | {
14 | public static readonly string AnnouncementFileName = "Announcement.md";
15 | [ObservableProperty] private string _announcementInfo = string.Empty;
16 |
17 | [ObservableProperty] private bool _doNotRemindThisAnnouncementAgain = Convert.ToBoolean(GlobalConfiguration.GetValue(ConfigurationKeys.DoNotShowAgain, bool.FalseString));
18 | partial void OnDoNotRemindThisAnnouncementAgainChanged(bool value)
19 | {
20 | GlobalConfiguration.SetValue(ConfigurationKeys.DoNotShowAgain, value.ToString());
21 | }
22 |
23 |
24 | public void CheckAnnouncement()
25 | {
26 | if (DoNotRemindThisAnnouncementAgain) return;
27 | try
28 | {
29 | var resourcePath = Path.Combine(AppContext.BaseDirectory, "resource");
30 | var mdPath = Path.Combine(resourcePath, AnnouncementFileName);
31 |
32 | if (File.Exists(mdPath))
33 | {
34 | var content = File.ReadAllText(mdPath);
35 | AnnouncementInfo = content;
36 | }
37 | }
38 | catch (Exception ex)
39 | {
40 | LoggerService.LogError($"读取公告文件失败: {ex.Message}");
41 | AnnouncementInfo = "";
42 | }
43 | finally
44 | {
45 |
46 | if (!string.IsNullOrWhiteSpace(AnnouncementInfo) && !AnnouncementInfo.Trim().Equals("placeholder", StringComparison.OrdinalIgnoreCase))
47 | {
48 | var announcementView = new AnnouncementView();
49 | announcementView.Show();
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/ViewModels/UI/Dialog/AddTaskDialogViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.ObjectModel;
2 |
3 | namespace MFAWPF.ViewModels.UI.Dialog;
4 |
5 | public class AddTaskDialogViewModel: ViewModel
6 | {
7 | private ObservableCollection _dataList = new ();
8 |
9 | public ObservableCollection DataList
10 | {
11 | get => _dataList;
12 | set => SetProperty(ref _dataList, value);
13 | }
14 |
15 | private int _selectedIndex ;
16 |
17 | public int SelectedIndex
18 | {
19 | get => _selectedIndex;
20 | set =>
21 | SetProperty(ref _selectedIndex, value);
22 | }
23 |
24 |
25 | public AddTaskDialogViewModel()
26 | {
27 | SelectedIndex = -1;
28 | }
29 | }
--------------------------------------------------------------------------------
/ViewModels/UI/RootViewModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using HandyControl.Controls;
3 | using HandyControl.Data;
4 | using HandyControl.Tools.Command;
5 | using MFAWPF.Configuration;
6 | using MFAWPF.Helper;
7 | using MFAWPF.ViewModels.Tool;
8 | using System.Collections.ObjectModel;
9 | using System.Text.RegularExpressions;
10 | using System.Windows;
11 | using System.Windows.Media;
12 |
13 | namespace MFAWPF.ViewModels.UI;
14 |
15 | public partial class RootViewModel : ViewModel
16 | {
17 | [ObservableProperty] private bool _idle = true;
18 |
19 | [ObservableProperty] private bool _lockController = true;
20 |
21 | [ObservableProperty] private bool _isRunning;
22 | partial void OnIsRunningChanged(bool value)
23 | {
24 | Idle = !value;
25 | }
26 |
27 | public void SetIdle(bool value)
28 | {
29 | Idle = value;
30 | }
31 |
32 | [ObservableProperty] private bool _enableEdit = ConfigurationHelper.GetValue(ConfigurationKeys.EnableEdit, false);
33 |
34 | partial void OnEnableEditChanged(bool value)
35 | {
36 | ConfigurationHelper.SetValue(ConfigurationKeys.EnableEdit, value);
37 | }
38 |
39 | [ObservableProperty] private bool _isUpdating;
40 |
41 | [ObservableProperty] private bool _isVisible = true;
42 |
43 | public void SetUpdating(bool isUpdating)
44 | {
45 | IsUpdating = isUpdating;
46 | }
47 | public void ToggleVisible()
48 | {
49 | IsVisible = !IsVisible;
50 | }
51 |
52 | partial void OnIsVisibleChanged(bool value)
53 | {
54 | if (value)
55 | {
56 | Application.Current.MainWindow?.Show();
57 | }
58 | else
59 | {
60 | Application.Current.MainWindow?.Hide();
61 | }
62 | }
63 |
64 |
65 |
66 | [ObservableProperty] private string? _resourceName;
67 |
68 | [ObservableProperty] private bool _isResourceNameVisible;
69 |
70 | [ObservableProperty] private string? _resourceVersion;
71 |
72 | [ObservableProperty] private bool _isResourceVersionVisible;
73 |
74 | [ObservableProperty] private string? _customTitle;
75 |
76 | [ObservableProperty] private bool _isCustomTitleVisible;
77 |
78 | [ObservableProperty] private bool _isDefaultTitleVisible = true;
79 |
80 | [ObservableProperty] private bool _isVersionVisible = true;
81 |
82 | public void ShowResourceName(string name)
83 | {
84 | ResourceName = name;
85 | IsResourceNameVisible = true;
86 | }
87 |
88 | public void ShowResourceVersion(string version)
89 | {
90 | ResourceVersion = version;
91 | IsResourceVersionVisible = true;
92 | }
93 |
94 | public void ShowCustomTitle(string title)
95 | {
96 | CustomTitle = title;
97 | IsCustomTitleVisible = true;
98 | IsDefaultTitleVisible = false;
99 | IsVersionVisible = false;
100 | IsResourceNameVisible = false;
101 | IsResourceVersionVisible = false;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/ViewModels/UserControl/Settings/GameSettingsUserControlModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using MaaFramework.Binding;
3 | using MFAWPF.Configuration;
4 | using MFAWPF.Extensions;
5 | using MFAWPF.Extensions.Maa;
6 | using MFAWPF.Helper;
7 | using System.Collections.ObjectModel;
8 | using System.Windows;
9 |
10 | namespace MFAWPF.ViewModels.UserControl.Settings;
11 |
12 | public partial class GameSettingsUserControlModel : ViewModel
13 | {
14 | [ObservableProperty] private bool _enableRecording = ConfigurationHelper.MaaConfig.GetConfig(ConfigurationKeys.Recording, false);
15 |
16 | [ObservableProperty] private bool _enableSaveDraw = ConfigurationHelper.MaaConfig.GetConfig(ConfigurationKeys.SaveDraw, false);
17 |
18 | [ObservableProperty] private bool _showHitDraw = ConfigurationHelper.MaaConfig.GetConfig(ConfigurationKeys.ShowHitDraw, false);
19 |
20 | [ObservableProperty] private string _prescript = ConfigurationHelper.GetValue(ConfigurationKeys.Prescript, string.Empty);
21 |
22 | [ObservableProperty] private string _postScript = ConfigurationHelper.GetValue(ConfigurationKeys.Postscript, string.Empty);
23 |
24 | [ObservableProperty] private bool _isDebugMode = ConfigurationHelper.MaaConfig.GetConfig(ConfigurationKeys.Recording, false)
25 | || ConfigurationHelper.MaaConfig.GetConfig(ConfigurationKeys.SaveDraw, false)
26 | || ConfigurationHelper.MaaConfig.GetConfig(ConfigurationKeys.ShowHitDraw, false);
27 | private bool _shouldTip = true;
28 |
29 | partial void OnIsDebugModeChanged(bool value)
30 | {
31 | if (value && _shouldTip)
32 | {
33 | MessageBoxHelper.Show("DebugModeWarning".ToLocalization(), "Tip".ToLocalization(), MessageBoxButton.OK, MessageBoxImage.Warning);
34 | _shouldTip = false;
35 | }
36 | }
37 |
38 | partial void OnEnableRecordingChanged(bool value)
39 | {
40 | ConfigurationHelper.MaaConfig.SetConfig(ConfigurationKeys.Recording, value);
41 | MaaProcessor.MaaUtility.SetOption_Recording(value);
42 | IsDebugMode = EnableSaveDraw || EnableRecording || ShowHitDraw;
43 | }
44 |
45 | partial void OnEnableSaveDrawChanged(bool value)
46 | {
47 | ConfigurationHelper.MaaConfig.SetConfig(ConfigurationKeys.SaveDraw, value);
48 | MaaProcessor.MaaUtility.SetOption_SaveDraw(value);
49 | IsDebugMode = EnableSaveDraw || EnableRecording || ShowHitDraw;
50 | }
51 |
52 | partial void OnShowHitDrawChanged(bool value)
53 | {
54 | ConfigurationHelper.MaaConfig.SetConfig(ConfigurationKeys.ShowHitDraw, value);
55 | MaaProcessor.MaaUtility.SetOption_ShowHitDraw(value);
56 | IsDebugMode = EnableSaveDraw || EnableRecording || ShowHitDraw;
57 | }
58 |
59 | partial void OnPrescriptChanged(string value)
60 | {
61 | ConfigurationHelper.SetValue(ConfigurationKeys.Prescript, value);
62 | }
63 |
64 | partial void OnPostScriptChanged(string value)
65 | {
66 | ConfigurationHelper.SetValue(ConfigurationKeys.Postscript, value);
67 | }
68 |
69 | [ObservableProperty] private ObservableCollection _currentResources = [];
70 |
71 | [ObservableProperty] private string _currentResource = ConfigurationHelper.GetValue(ConfigurationKeys.Resource, string.Empty);
72 |
73 | partial void OnCurrentResourceChanged(string value)
74 | {
75 | ConfigurationHelper.SetValue(ConfigurationKeys.Resource, value);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/ViewModels/UserControl/Settings/GuiSettingsUserControlModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using MFAWPF.Configuration;
3 | using MFAWPF.Helper;
4 | using System.Collections.ObjectModel;
5 |
6 | namespace MFAWPF.ViewModels.UserControl.Settings;
7 |
8 | public partial class GuiSettingsUserControlModel: ViewModel
9 | {
10 | public ObservableCollection SupportedLanguages => LanguageHelper.SupportedLanguages;
11 |
12 | [ObservableProperty] private int _languageIndex = ConfigurationHelper.GetValue(ConfigurationKeys.LangIndex, 0);
13 |
14 | partial void OnLanguageIndexChanged(int value)
15 | {
16 | LanguageHelper.ChangeLanguage(SupportedLanguages[value]);
17 | ConfigurationHelper.SetValue(ConfigurationKeys.LangIndex, value);
18 | }
19 |
20 | [ObservableProperty] private ObservableCollection _themes =
21 | [
22 | new("LightColor"),
23 | new("DarkColor"),
24 | new("FollowingSystem"),
25 | ];
26 |
27 | [ObservableProperty] private int _themeIndex = ConfigurationHelper.GetValue(ConfigurationKeys.ThemeIndex, 0);
28 |
29 | partial void OnThemeIndexChanged(int value)
30 | {
31 | ThemeHelper.UpdateThemeIndexChanged(value);
32 | ConfigurationHelper.SetValue(ConfigurationKeys.ThemeIndex, value);
33 | }
34 |
35 | private bool _shouldMinimizeToTray = ConfigurationHelper.GetValue(ConfigurationKeys.ShouldMinimizeToTray, false);
36 |
37 | public bool ShouldMinimizeToTray
38 | {
39 | set
40 | {
41 | SetProperty(ref _shouldMinimizeToTray, value);
42 | ConfigurationHelper.SetValue(ConfigurationKeys.ShouldMinimizeToTray, value);
43 | }
44 | get => _shouldMinimizeToTray;
45 | }
46 |
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/ViewModels/UserControl/Settings/PerformanceUserControlModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using MaaFramework.Binding;
3 | using MFAWPF.Configuration;
4 | using MFAWPF.Helper.Converters;
5 | using System.Collections.ObjectModel;
6 |
7 | namespace MFAWPF.ViewModels.UserControl.Settings;
8 |
9 | public partial class PerformanceUserControlModel : ViewModel
10 | {
11 | public static ObservableCollection GpuOptions =>
12 | [
13 | new("GpuOptionAuto")
14 | {
15 | Other = InferenceDevice.Auto
16 | },
17 | new("GpuOptionDisable")
18 | {
19 | Other = InferenceDevice.CPU
20 | }
21 | ];
22 |
23 | [ObservableProperty] private InferenceDevice _gpuOption = ConfigurationHelper.GetValue(ConfigurationKeys.GPUOption, InferenceDevice.Auto, new UniversalEnumConverter());
24 |
25 | partial void OnGpuOptionChanged(InferenceDevice value)
26 | {
27 | ConfigurationHelper.SetValue(ConfigurationKeys.GPUOption, value.ToString());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/ViewModels/UserControl/Settings/StartSettingsUserControlModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using CommunityToolkit.Mvvm.Input;
3 | using MFAWPF.Configuration;
4 | using MFAWPF.Extensions;
5 | using Microsoft.Win32;
6 |
7 | namespace MFAWPF.ViewModels.UserControl.Settings;
8 |
9 | public partial class StartSettingsUserControlModel: ViewModel
10 | {
11 | [ObservableProperty] private bool _autoMinimize = ConfigurationHelper.GetValue(ConfigurationKeys.AutoMinimize, false);
12 |
13 | [ObservableProperty] private bool _autoHide = ConfigurationHelper.GetValue(ConfigurationKeys.AutoHide, false);
14 |
15 | [ObservableProperty] private string _softwarePath = ConfigurationHelper.GetValue(ConfigurationKeys.SoftwarePath, string.Empty);
16 |
17 | [ObservableProperty] private string _emulatorConfig = ConfigurationHelper.GetValue(ConfigurationKeys.EmulatorConfig, string.Empty);
18 |
19 | [ObservableProperty] private double _waitSoftwareTime = ConfigurationHelper.GetValue(ConfigurationKeys.WaitSoftwareTime, 60.0);
20 |
21 |
22 | partial void OnAutoMinimizeChanged(bool value)
23 | {
24 | ConfigurationHelper.SetValue(ConfigurationKeys.AutoMinimize, value);
25 | }
26 |
27 | partial void OnAutoHideChanged(bool value)
28 | {
29 | ConfigurationHelper.SetValue(ConfigurationKeys.AutoHide, value);
30 | }
31 |
32 | partial void OnSoftwarePathChanged(string value)
33 | {
34 | ConfigurationHelper.SetValue(ConfigurationKeys.SoftwarePath, value);
35 | }
36 |
37 | partial void OnEmulatorConfigChanged(string value)
38 | {
39 | ConfigurationHelper.SetValue(ConfigurationKeys.EmulatorConfig, value);
40 | }
41 |
42 | partial void OnWaitSoftwareTimeChanged(double value)
43 | {
44 | ConfigurationHelper.SetValue(ConfigurationKeys.WaitSoftwareTime, value);
45 | }
46 |
47 |
48 | [RelayCommand]
49 | private void SelectSoft()
50 | {
51 | var openFileDialog = new OpenFileDialog
52 | {
53 | Title = "SelectExecutableFile".ToLocalization(),
54 | Filter = "ExeFilter".ToLocalization()
55 | };
56 |
57 | if (openFileDialog.ShowDialog().IsTrue())
58 | {
59 | SoftwarePath = openFileDialog.FileName;
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/ViewModels/ViewModel.cs:
--------------------------------------------------------------------------------
1 | using CommunityToolkit.Mvvm.ComponentModel;
2 | using System.Diagnostics.CodeAnalysis;
3 | using System.Runtime.CompilerServices;
4 |
5 | namespace MFAWPF.ViewModels;
6 |
7 | public class ViewModel : ObservableObject
8 | {
9 | protected bool SetCurrentProperty([NotNullIfNotNull("newValue")] ref T field, T newValue, [CallerMemberName] string propertyName = null)
10 | {
11 | OnPropertyChanging(propertyName);
12 | field = newValue;
13 | OnPropertyChanged(propertyName);
14 | return true;
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/Views/UI/AnnouncementView.xaml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
53 |
54 |
61 |
62 |
--------------------------------------------------------------------------------
/Views/UI/AnnouncementView.xaml.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper;
2 | using MFAWPF.ViewModels.UI;
3 | using System.Windows;
4 | using System.Windows.Controls;
5 | using System.Windows.Input;
6 |
7 | namespace MFAWPF.Views.UI;
8 |
9 | public partial class AnnouncementView
10 | {
11 | public AnnouncementViewModel ViewModel { get; set; }
12 | public AnnouncementView()
13 | {
14 | DataContext = this;
15 | ViewModel = Instances.AnnouncementViewModel;
16 | InitializeComponent();
17 | }
18 |
19 | public void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e)
20 | {
21 | if (e.Handled)
22 | {
23 | return;
24 | }
25 |
26 | e.Handled = true;
27 | var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
28 | {
29 | RoutedEvent = MouseWheelEvent,
30 | };
31 | var parent = ((Control)sender).Parent as UIElement;
32 | parent?.RaiseEvent(eventArg);
33 | }
34 | private void Close(object sender, RoutedEventArgs e) => Close();
35 | }
36 |
--------------------------------------------------------------------------------
/Views/UI/ConnectingView.xaml.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper;
2 | using MFAWPF.ViewModels.UI;
3 |
4 |
5 |
6 | namespace MFAWPF.Views.UI;
7 |
8 | public partial class ConnectingView
9 | {
10 | public ConnectingViewModel ViewModel { get; set; }
11 | public ConnectingView()
12 | {
13 | ViewModel = Instances.ConnectingViewModel;
14 | DataContext = this;
15 | InitializeComponent();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Views/UI/Dialog/AdbEditorDialog.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using MaaFramework.Binding;
3 | using MFAWPF.Extensions;
4 | using MFAWPF.Helper;
5 | using Microsoft.Win32;
6 |
7 | namespace MFAWPF.Views.UI.Dialog;
8 |
9 | public partial class AdbEditorDialog
10 | {
11 | public AdbEditorDialog(AdbDeviceInfo? info = null)
12 | {
13 | InitializeComponent();
14 | if (info != null)
15 | {
16 | AdbName = info.Name;
17 | AdbPath = info.AdbPath;
18 | AdbSerial = info.AdbSerial;
19 | AdbConfig = info.Config;
20 | }
21 | }
22 |
23 | private void Load(object sender, RoutedEventArgs e)
24 | {
25 | OpenFileDialog openFileDialog = new OpenFileDialog
26 | {
27 | Title = "LoadFileTitle".ToLocalization(),
28 | Filter = "AllFilter".ToLocalization()
29 | };
30 |
31 | if (openFileDialog.ShowDialog().IsTrue())
32 | {
33 | AdbPath = openFileDialog.FileName;
34 | }
35 | }
36 |
37 | private void Save(object sender, RoutedEventArgs e)
38 | {
39 | DialogResult = true;
40 | }
41 |
42 | private void Cancel(object sender, RoutedEventArgs e)
43 | {
44 | Close();
45 | }
46 |
47 | public static readonly DependencyProperty AdbNameProperty =
48 | DependencyProperty.Register(
49 | nameof(AdbName),
50 | typeof(string),
51 | typeof(AdbEditorDialog),
52 | new FrameworkPropertyMetadata(
53 | "Emulator".ToLocalization(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
54 |
55 | public string AdbName
56 | {
57 | get => (string)GetValue(AdbNameProperty);
58 | set => SetValue(AdbNameProperty, value);
59 | }
60 |
61 | public static readonly DependencyProperty AdbPathProperty =
62 | DependencyProperty.Register(
63 | nameof(AdbPath),
64 | typeof(string),
65 | typeof(AdbEditorDialog),
66 | new FrameworkPropertyMetadata(
67 | string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
68 |
69 | public string AdbPath
70 | {
71 | get => (string)GetValue(AdbPathProperty);
72 | set => SetValue(AdbPathProperty, value);
73 | }
74 |
75 | public static readonly DependencyProperty AdbSerialProperty =
76 | DependencyProperty.Register(
77 | nameof(AdbSerial),
78 | typeof(string),
79 | typeof(AdbEditorDialog),
80 | new FrameworkPropertyMetadata(
81 | string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
82 |
83 | public string AdbSerial
84 | {
85 | get => (string)GetValue(AdbSerialProperty);
86 | set => SetValue(AdbSerialProperty, value);
87 | }
88 |
89 | public static readonly DependencyProperty AdbConfigProperty =
90 | DependencyProperty.Register(
91 | nameof(AdbConfig),
92 | typeof(string),
93 | typeof(AdbEditorDialog),
94 | new FrameworkPropertyMetadata(
95 | "{}", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
96 |
97 | public string AdbConfig
98 | {
99 | get => (string)GetValue(AdbConfigProperty);
100 | set => SetValue(AdbConfigProperty, value);
101 | }
102 |
103 | public AdbDeviceInfo Output => new (AdbName, AdbPath, AdbSerial, AdbScreencapMethods.Default,
104 | AdbInputMethods.MinitouchAndAdbKey, AdbConfig);
105 | }
--------------------------------------------------------------------------------
/Views/UI/Dialog/AddTaskDialog.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.ObjectModel;
2 | using System.Windows;
3 | using HandyControl.Data;
4 | using MFAWPF.Extensions;
5 | using MFAWPF.Helper;
6 | using MFAWPF.ViewModels;
7 | using MFAWPF.ViewModels.UI;
8 | using MFAWPF.ViewModels.UI.Dialog;
9 | using MFAWPF.Views.UI;
10 | using DragItemViewModel = MFAWPF.ViewModels.Tool.DragItemViewModel;
11 |
12 | namespace MFAWPF.Views.UI.Dialog;
13 |
14 | public partial class AddTaskDialog
15 | {
16 |
17 | public AddTaskDialogViewModel?
18 | Data;
19 |
20 | public DragItemViewModel? OutputContent
21 | {
22 | get;
23 | set;
24 | }
25 |
26 | private readonly ObservableCollection _source = new();
27 |
28 | public AddTaskDialog(IList? dragItemViewModels)
29 | {
30 | InitializeComponent();
31 | Data = DataContext as AddTaskDialogViewModel;
32 | _source.AddRange(dragItemViewModels);
33 | if (Data != null)
34 | {
35 | Data.DataList.Clear();
36 | Data.DataList.AddRange(_source);
37 | }
38 | }
39 |
40 | private void Add(object sender, RoutedEventArgs e)
41 | {
42 | DialogResult = true;
43 | OutputContent = ListBoxDemo.SelectedValue as DragItemViewModel;
44 | Close();
45 | }
46 |
47 | protected override void OnClosed(EventArgs e)
48 | {
49 | Instances.RootViewModel.SetIdle(true);
50 | base.OnClosed(e);
51 | }
52 |
53 | private void SearchBar_OnSearchStarted(object sender, FunctionEventArgs e)
54 | {
55 | string key = e.Info;
56 |
57 | if (string.IsNullOrEmpty(key))
58 | {
59 | if (Data != null)
60 | {
61 | Data.DataList.Clear();
62 | Data.DataList.AddRange(_source);
63 | }
64 | }
65 | else
66 | {
67 | key = key.ToLower();
68 | Data?.DataList.Clear();
69 | foreach (DragItemViewModel item in _source)
70 | {
71 | string name = item.Name.ToLower();
72 | if (name.Contains(key))
73 | Data?.DataList.Add(item);
74 | }
75 | }
76 | }
77 | }
--------------------------------------------------------------------------------
/Views/UI/Dialog/DownloadDialog.xaml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
27 |
31 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Views/UI/Dialog/DownloadDialog.xaml.cs:
--------------------------------------------------------------------------------
1 |
2 | using MFAWPF.Helper;
3 | using System.Diagnostics;
4 | using System.Windows;
5 | using System.Windows.Controls;
6 |
7 | namespace MFAWPF.Views.UI.Dialog;
8 |
9 | public partial class DownloadDialog
10 | {
11 | public DownloadDialog(string title)
12 | {
13 | Title = title;
14 | InitializeComponent();
15 | }
16 |
17 | public void UpdateProgress(double progressPercentage)
18 | {
19 | Dispatcher.Invoke(() =>
20 | {
21 | ProgressBar.Value = progressPercentage;
22 | });
23 | }
24 |
25 | public void SetText(string text)
26 | {
27 | Dispatcher.Invoke(() =>
28 | {
29 | TextBlock.Text = text;
30 | });
31 | }
32 | public void SetRestartButtonVisibility(bool value)
33 | {
34 | Dispatcher.Invoke(() =>
35 | {
36 | RestartButton.Visibility = value ? Visibility.Visible : Visibility.Collapsed;
37 | });
38 | }
39 |
40 | private void Restart(object sender, RoutedEventArgs e)
41 | {
42 | Process.Start(Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty);
43 | DispatcherHelper.RunOnMainThread(Application.Current.Shutdown);
44 | }
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/Views/UI/NotifyIcon.xaml:
--------------------------------------------------------------------------------
1 |
19 |
23 |
24 |
25 |
29 |
33 |
34 |
38 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Views/UI/NotifyIcon.xaml.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Configuration;
2 | using MFAWPF.Helper;
3 | using MFAWPF.ViewModels;
4 | using System.Windows;
5 | using System.Windows.Controls;
6 |
7 | namespace MFAWPF.Views.UI;
8 |
9 | public partial class NotifyIcon
10 | {
11 | private readonly int _menuItemNum;
12 |
13 | public NotifyIcon()
14 | {
15 | InitializeComponent();
16 |
17 | InitIcon();
18 |
19 | if (notifyIcon.ContextMenu is not null)
20 | {
21 | _menuItemNum = notifyIcon.ContextMenu.Items.Count;
22 | }
23 |
24 | }
25 |
26 | private void InitIcon()
27 | {
28 | notifyIcon.Icon = IconHelper.ICON;
29 | notifyIcon.Visibility = ConfigurationHelper.GetValue(ConfigurationKeys.EnableShowIcon, true) ? Visibility.Visible : Visibility.Collapsed;
30 |
31 | notifyIcon.Click += NotifyIcon_MouseClick;
32 | notifyIcon.MouseDoubleClick += NotifyIcon_MouseClick;
33 |
34 | startMenu.Click += StartTask;
35 | stopMenu.Click += StopTask;
36 | exitMenu.Click += App_exit;
37 | hideMenu.Click += App_hide;
38 | showMenu.Click += App_show;
39 | foreach (var lang in LanguageHelper.SupportedLanguages)
40 | {
41 | var langMenu = new MenuItem
42 | {
43 | Header = lang.Name
44 | };
45 | langMenu.Click += (_, _) =>
46 | {
47 | LanguageHelper.ChangeLanguage(lang);
48 | var index = LanguageHelper.SupportedLanguages.ToList().FindIndex(language => language.Key == lang.Key);
49 | ConfigurationHelper.SetValue(ConfigurationKeys.LangIndex, index == -1 ? 0 : index);
50 | };
51 |
52 | switchLangMenu.Items.Add(langMenu);
53 | }
54 | }
55 |
56 | // 不知道是干嘛的,先留着
57 | // ReSharper disable once UnusedMember.Local
58 | private void AddMenuItemOnFirst(string text, Action action)
59 | {
60 | var menuItem = new MenuItem
61 | {
62 | Header = text
63 | };
64 | menuItem.Click += (_, _) => { action?.Invoke(); };
65 | if (notifyIcon.ContextMenu is null)
66 | {
67 | return;
68 | }
69 |
70 | if (notifyIcon.ContextMenu.Items.Count == _menuItemNum)
71 | {
72 | notifyIcon.ContextMenu.Items.Insert(0, menuItem);
73 | }
74 | else
75 | {
76 | notifyIcon.ContextMenu.Items[0] = menuItem;
77 | }
78 | }
79 |
80 | private static void NotifyIcon_MouseClick(object sender, RoutedEventArgs e) =>
81 | Instances.RootView.ShowWindow();
82 |
83 |
84 | private static void StartTask(object sender, RoutedEventArgs e) =>
85 | Instances.TaskQueueView.Start();
86 |
87 |
88 | private static void StopTask(object sender, RoutedEventArgs e) =>
89 | Instances.TaskQueueView.Stop();
90 |
91 |
92 | private static void App_exit(object sender, RoutedEventArgs e)
93 | {
94 | if (Instances.RootView.ConfirmExit())
95 | Application.Current.Shutdown();
96 | }
97 |
98 | private void App_hide(object sender, RoutedEventArgs e) =>
99 | Instances.RootViewModel.IsVisible = false;
100 |
101 |
102 | private void App_show(object sender, RoutedEventArgs e)
103 | => Instances.RootViewModel.IsVisible = true;
104 | }
105 |
--------------------------------------------------------------------------------
/Views/UI/SettingsView.xaml.cs:
--------------------------------------------------------------------------------
1 | using HandyControl.Controls;
2 | using MFAWPF.Helper;
3 | using MFAWPF.ViewModels;
4 | using Microsoft.Extensions.DependencyInjection;
5 | using System.Windows;
6 | using System.Windows.Controls;
7 | using ComboBox = System.Windows.Controls.ComboBox;
8 | using ScrollViewer = HandyControl.Controls.ScrollViewer;
9 | using SettingsViewModel = MFAWPF.ViewModels.UI.SettingsViewModel;
10 | using TextBox = System.Windows.Controls.TextBox;
11 |
12 | namespace MFAWPF.Views.UI;
13 |
14 | public partial class SettingsView
15 | {
16 | public SettingsViewModel ViewModel { get; set; }
17 | public SettingsView()
18 | {
19 | ViewModel = Instances.SettingsViewModel;
20 | DataContext = this;
21 | InitializeComponent();
22 | Loaded += (_, _) => { UpdateDividerPositions(); };
23 | }
24 |
25 | private void UpdateDividerPositions()
26 | {
27 | if (Viewer.Content is Grid grid)
28 | {
29 | var stackPanel = grid.Children.OfType().FirstOrDefault();
30 | if (stackPanel == null) return;
31 |
32 | double currentY = 0;
33 | var dividerPositions = new List();
34 | foreach (var child in stackPanel.Children)
35 | {
36 | if (child is FrameworkElement element)
37 | {
38 | if (child is Divider)
39 | {
40 | dividerPositions.Add(currentY);
41 | }
42 | currentY += element.ActualHeight + element.Margin.Top + element.Margin.Bottom;
43 | }
44 | }
45 | ViewModel.DividerVerticalOffsetList = dividerPositions;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Views/UserControl/CardControl.xaml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
35 |
36 |
41 |
42 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Views/UserControl/CardControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using HandyControl.Controls;
2 | using System.ComponentModel;
3 | using System.Windows;
4 | using System.Windows.Controls;
5 | using System.Windows.Shapes;
6 |
7 | namespace MFAWPF.Views.UserControl;
8 |
9 | public partial class CardControl
10 | {
11 | public CardControl()
12 | {
13 | DataContext = this;
14 | InitializeComponent();
15 | }
16 |
17 | public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
18 | nameof(Header),
19 | typeof(object),
20 | typeof(CardControl),
21 | new PropertyMetadata(null)
22 | );
23 |
24 | /// Identifies the dependency property.
25 | public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
26 | nameof(Icon),
27 | typeof(object),
28 | typeof(CardControl),
29 | new PropertyMetadata(null)
30 | );
31 |
32 | /// Identifies the dependency property.
33 | public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(
34 | nameof(CornerRadius),
35 | typeof(CornerRadius),
36 | typeof(CardControl),
37 | new PropertyMetadata(new CornerRadius(4))
38 | );
39 |
40 |
41 | ///
42 | /// Gets or sets header which is used for each item in the control.
43 | ///
44 | [Bindable(true)]
45 | public object? Header
46 | {
47 | get => GetValue(HeaderProperty);
48 | set => SetValue(HeaderProperty, value);
49 | }
50 |
51 | ///
52 | /// Gets or sets displayed .
53 | ///
54 | [Bindable(true)]
55 | [Category("Appearance")]
56 | public object? Icon
57 | {
58 | get => (object?)GetValue(IconProperty);
59 | set => SetValue(IconProperty, value);
60 | }
61 |
62 | ///
63 | /// Gets or sets the corner radius of the control.
64 | ///
65 | [Bindable(true)]
66 | [Category("Appearance")]
67 | public CornerRadius CornerRadius
68 | {
69 | get => (CornerRadius)GetValue(CornerRadiusProperty);
70 | set => SetValue(CornerRadiusProperty, value);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Views/UserControl/HotKeyEditorUserControl.xaml:
--------------------------------------------------------------------------------
1 |
12 |
20 |
--------------------------------------------------------------------------------
/Views/UserControl/HotKeyEditorUserControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper;
2 | using MFAWPF.Helper.ValueType;
3 | using System.Windows;
4 | using System.Windows.Controls;
5 | using System.Windows.Input;
6 | using System.Windows.Threading;
7 |
8 | namespace MFAWPF.Views.UserControl;
9 |
10 | public partial class HotKeyEditorUserControl
11 | {
12 | public static readonly DependencyProperty HotKeyProperty =
13 | DependencyProperty.Register(nameof(HotKey), typeof(MFAHotKey),
14 | typeof(HotKeyEditorUserControl),
15 | new FrameworkPropertyMetadata(null,
16 | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
17 |
18 | public MFAHotKey HotKey
19 | {
20 | get => (MFAHotKey)GetValue(HotKeyProperty);
21 | set => SetValue(HotKeyProperty, value);
22 | }
23 |
24 | public HotKeyEditorUserControl()
25 | {
26 | InitializeComponent();
27 | }
28 |
29 | private void HotKey_PreviewKeyDown(object sender, KeyEventArgs e)
30 | {
31 | // Get modifiers and key data
32 | var modifiers = Keyboard.Modifiers;
33 | var key = e.Key;
34 |
35 | // When Alt is pressed, SystemKey is used instead
36 | if (key == Key.System)
37 | {
38 | key = e.SystemKey;
39 | }
40 |
41 | // Remove hotKey if no modifiers
42 | if (modifiers == ModifierKeys.None)
43 | {
44 | HotKey = MFAHotKey.NOTSET;
45 | return;
46 | }
47 |
48 | // If no actual key was pressed - return
49 | if (key == Key.LeftCtrl
50 | || key == Key.RightCtrl
51 | || key == Key.LeftAlt
52 | || key == Key.RightAlt
53 | || key == Key.LeftShift
54 | || key == Key.RightShift
55 | || key == Key.LWin
56 | || key == Key.RWin
57 | || key == Key.Clear
58 | || key == Key.OemClear
59 | || key == Key.Apps)
60 | {
61 | return;
62 | }
63 |
64 | HotKey = new MFAHotKey(key, modifiers);
65 | Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
66 | {
67 | Keyboard.ClearFocus();
68 |
69 | var parent = Keyboard.FocusedElement as FrameworkElement;
70 | parent?.MoveFocus(new TraversalRequest(FocusNavigationDirection.Previous));
71 | }));
72 | }
73 |
74 | private void HotKey_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
75 | {
76 | if (e.LeftButton != MouseButtonState.Pressed)
77 | return;
78 | HotKeyHelper.UnregisterHotKey(Application.Current.MainWindow, HotKey);
79 | HotKey = MFAHotKey.PRESSING;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Views/UserControl/PinButton.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 |
4 | namespace MFAWPF.Views.UserControl;
5 |
6 | public class PinButton : Button
7 | {
8 | public static readonly DependencyProperty IsCheckedProperty =
9 | DependencyProperty.Register(nameof(IsChecked), typeof(bool), typeof(PinButton),
10 | new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
11 | OnIsCheckedChanged));
12 |
13 | public bool IsChecked
14 | {
15 | get => (bool)GetValue(IsCheckedProperty);
16 | set => SetValue(IsCheckedProperty, value);
17 | }
18 |
19 | public event RoutedPropertyChangedEventHandler CheckedChanged;
20 |
21 | private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
22 | {
23 | if (d is PinButton pinButton)
24 | {
25 | pinButton.OnCheckedChanged(pinButton.IsChecked, (bool)e.NewValue);
26 | }
27 | }
28 |
29 | private void OnCheckedChanged(bool oldValue, bool newValue)
30 | {
31 |
32 | CheckedChanged?.Invoke(this, new RoutedPropertyChangedEventArgs(oldValue, newValue));
33 | }
34 |
35 | static PinButton()
36 | {
37 | DefaultStyleKeyProperty.OverrideMetadata(typeof(PinButton), new FrameworkPropertyMetadata(typeof(PinButton)));
38 | }
39 |
40 | // Constructor
41 | public PinButton()
42 | {
43 | // Set the default content to 📌
44 | Content = "📌";
45 | Click += (_, _) => { IsChecked = !IsChecked; };
46 | }
47 | }
--------------------------------------------------------------------------------
/Views/UserControl/Settings/AboutUserControl.xaml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
34 |
35 |
36 |
37 |
38 |
39 |
43 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/AboutUserControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace MFAWPF.Views.UserControl.Settings;
4 |
5 | public partial class AboutUserControl
6 | {
7 | public AboutUserControl()
8 | {
9 | InitializeComponent();
10 | }
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/ConfigurationMgrUserControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace MFAWPF.Views.UserControl.Settings;
4 |
5 | public partial class ConfigurationMgrUserControl
6 | {
7 | public ConfigurationMgrUserControl()
8 | {
9 | InitializeComponent();
10 | }
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/ConnectSettingsUserControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper;
2 | using MFAWPF.ViewModels.UserControl.Settings;
3 | using System.Windows.Controls;
4 |
5 | namespace MFAWPF.Views.UserControl.Settings;
6 |
7 | public partial class ConnectSettingsUserControl
8 | {
9 | public ConnectSettingsUserControlModel ViewModel { get; set; }
10 | public ConnectSettingsUserControl()
11 | {
12 | DataContext = this;
13 | ViewModel = Instances.ConnectSettingsUserControlModel;
14 | InitializeComponent();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/ExternalNotificationSettingsUserControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper;
2 | using MFAWPF.ViewModels.UserControl.Settings;
3 | using System.Windows.Controls;
4 |
5 | namespace MFAWPF.Views.UserControl.Settings;
6 |
7 | public partial class ExternalNotificationSettingsUserControl
8 | {
9 | public ExternalNotificationSettingsUserControlModel ViewModel { get; set; }
10 | public ExternalNotificationSettingsUserControl()
11 | {
12 | DataContext = this;
13 | ViewModel = Instances.ExternalNotificationSettingsUserControlModel;
14 | InitializeComponent();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/GameSettingsUserControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper;
2 | using MFAWPF.ViewModels.UserControl.Settings;
3 | using System.Windows;
4 |
5 | namespace MFAWPF.Views.UserControl.Settings;
6 |
7 | public partial class GameSettingsUserControl
8 | {
9 | public GameSettingsUserControlModel ViewModel { get; set; }
10 | public GameSettingsUserControl()
11 | {
12 | ViewModel = Instances.GameSettingsUserControlModel;
13 | DataContext = this;
14 | InitializeComponent();
15 | }
16 |
17 | private void StartsWithScript_Drop(object sender, DragEventArgs e)
18 | {
19 | if (!e.Data.GetDataPresent(DataFormats.FileDrop))
20 | {
21 | return;
22 | }
23 |
24 | // Note that you can have more than one file.
25 | var files = (string[])e.Data.GetData(DataFormats.FileDrop);
26 | BeforeTaskSettings.Text = files?[0] ?? string.Empty;
27 | }
28 |
29 | private void EndsWithScript_Drop(object sender, DragEventArgs e)
30 | {
31 | if (!e.Data.GetDataPresent(DataFormats.FileDrop))
32 | {
33 | return;
34 | }
35 |
36 | // Note that you can have more than one file.
37 | var files = (string[])e.Data.GetData(DataFormats.FileDrop);
38 | AfterTaskSettings.Text = files?[0] ?? string.Empty;
39 | }
40 |
41 | private void TextBox_PreviewDragOver(object sender, DragEventArgs e)
42 | {
43 | e.Handled = true;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/GuiSettingsUserControl.xaml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
37 |
38 |
39 |
43 |
53 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/GuiSettingsUserControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper;
2 | using MFAWPF.ViewModels.UserControl.Settings;
3 | using System.Windows.Controls;
4 |
5 | namespace MFAWPF.Views.UserControl.Settings;
6 |
7 | public partial class GuiSettingsUserControl
8 | {
9 | public GuiSettingsUserControlModel ViewModel { get; set; }
10 | public GuiSettingsUserControl()
11 | {
12 | ViewModel = Instances.GuiSettingsUserControlModel;
13 | DataContext = this;
14 | InitializeComponent();
15 | }
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/HotKeySettingsUserControl.xaml:
--------------------------------------------------------------------------------
1 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
34 |
39 |
44 |
48 |
49 |
54 |
59 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/HotKeySettingsUserControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace MFAWPF.Views.UserControl.Settings;
4 |
5 | public partial class HotKeySettingsUserControl
6 | {
7 | public HotKeySettingsUserControl()
8 | {
9 | InitializeComponent();
10 | }
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/PerformanceUserControl.xaml:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
35 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/PerformanceUserControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper;
2 | using MFAWPF.ViewModels.UserControl.Settings;
3 | using System.Windows.Controls;
4 |
5 | namespace MFAWPF.Views.UserControl.Settings;
6 |
7 | public partial class PerformanceUserControl
8 | {
9 | public PerformanceUserControlModel ViewModel { get; set; }
10 | public PerformanceUserControl()
11 | {
12 | ViewModel = Instances.PerformanceUserControlModel;
13 | DataContext = this;
14 | InitializeComponent();
15 | }
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/StartSettingsUserControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper;
2 | using MFAWPF.ViewModels.UserControl.Settings;
3 | using System.Windows;
4 | using System.Windows.Controls;
5 |
6 | namespace MFAWPF.Views.UserControl.Settings;
7 |
8 | public partial class StartSettingsUserControl
9 | {
10 | public StartSettingsUserControlModel ViewModel { get; set; }
11 | public StartSettingsUserControl()
12 | {
13 | ViewModel = Instances.StartSettingsUserControlModel;
14 | DataContext = this;
15 | InitializeComponent();
16 | }
17 | private void TextBox_PreviewDragOver(object sender, DragEventArgs e)
18 | {
19 | e.Handled = true;
20 | }
21 | private void File_Drop(object sender, DragEventArgs e)
22 | {
23 | if (!e.Data.GetDataPresent(DataFormats.FileDrop))
24 | {
25 | return;
26 | }
27 |
28 | // Note that you can have more than one file.
29 | var files = (string[])e.Data.GetData(DataFormats.FileDrop);
30 | if (sender is TextBox textBox)
31 | textBox.Text = files?[0] ?? string.Empty;
32 | }
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/TaskOptionSettingsUserControl.xaml:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
31 |
32 |
36 |
37 |
38 |
39 |
40 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/TaskQueueSettingsUserControl.xaml:
--------------------------------------------------------------------------------
1 |
18 |
23 |
24 |
33 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/TaskQueueSettingsUserControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace MFAWPF.Views.UserControl.Settings;
4 |
5 | public partial class TaskQueueSettingsUserControl
6 | {
7 | public TaskQueueSettingsUserControl()
8 | {
9 | InitializeComponent();
10 | }
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/TimerSettingsUserControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper;
2 | using MFAWPF.ViewModels.UserControl.Settings;
3 | using System.Windows.Controls;
4 |
5 | namespace MFAWPF.Views.UserControl.Settings;
6 |
7 | public partial class TimerSettingsUserControl
8 | {
9 | public TimerSettingsUserControlModel ViewModel { get; set; }
10 | public TimerSettingsUserControl()
11 | {
12 | ViewModel = Instances.TimerSettingsUserControlModel;
13 | DataContext = this;
14 | InitializeComponent();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Views/UserControl/Settings/VersionUpdateSettingsUserControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using MFAWPF.Helper;
2 | using MFAWPF.ViewModels.UserControl.Settings;
3 | using System.Diagnostics;
4 | using System.Windows;
5 | using System.Windows.Documents;
6 |
7 | namespace MFAWPF.Views.UserControl.Settings;
8 |
9 | public partial class VersionUpdateSettingsUserControl
10 | {
11 | public VersionUpdateSettingsUserControlModel ViewModel { get; set; }
12 | public VersionUpdateSettingsUserControl()
13 | {
14 | ViewModel = Instances.VersionUpdateSettingsUserControlModel;
15 | DataContext = this;
16 | InitializeComponent();
17 | }
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/cliff.toml:
--------------------------------------------------------------------------------
1 | [remote.github]
2 | owner = "SweetSmellFox"
3 | repo = "MFAWPF"
4 |
5 | [git]
6 | # parse the commits based on https://www.conventionalcommits.org
7 | conventional_commits = true
8 | # filter out the commits that are not conventional
9 | filter_unconventional = true
10 | # process each line of a commit as an individual commit
11 | split_commits = false
12 | # regex for preprocessing the commit messages
13 |
14 | # regex for parsing and grouping commits
15 | commit_parsers = [
16 | { message = "^feat", group = "新增 | Feat" },
17 | { message = "^fix", group = "修复 | Fix" },
18 | { message = "^docs", group = "文档 | Docs" },
19 | { message = "^perf", group = "优化 | Perf" },
20 | { message = "^refactor\\(clippy\\)", skip = true },
21 | { message = "^refactor", group = "重构 | Refactor" },
22 | { message = "^style", group = "样式 | Style" },
23 | { message = "^test", group = "测试 | Test" },
24 | { message = "^chore\\(release\\): prepare for", skip = true },
25 | { message = "^chore\\(deps.*\\)", skip = true },
26 | { message = "^chore\\(pr\\)", skip = true },
27 | { message = "^chore\\(pull\\)", skip = true },
28 | { message = "^chore\\(npm\\).*yarn\\.lock", skip = true },
29 | { message = "^chore", group = "杂项 | Chore" },
30 | { message = "^other", group = "其它 | Other" },
31 | { message = "^ci", group = "集成 | CI" },
32 | ]
33 | # protect breaking changes from being skipped due to matching a skipping commit_parser
34 | protect_breaking_commits = false
35 | # filter out the commits that are not matched by commit parsers
36 | filter_commits = false
37 | # regex for matching git tags
38 | tag_pattern = "v[0-9].*"
39 | # regex for skipping tags
40 | skip_tags = "beta|alpha"
41 | # regex for ignoring tags
42 | ignore_tags = "rc|v2.1.0|v2.1.1"
43 | # sort the tags topologically
44 | topo_order = false
45 | # sort the commits inside sections by oldest/newest order
46 | sort_commits = "newest"
47 |
--------------------------------------------------------------------------------
/docs/zh_cn/自定义识别_操作.md:
--------------------------------------------------------------------------------
1 | # 自定义识别/操作
2 |
3 | > 注意: 本文档是关于如何使用 C# 进行注册相应的自定义识别/操作
4 |
5 | ## 自定义识别
6 |
7 | ```json
8 | {
9 | "Task": {
10 | "recognition": "Custom",
11 | "custom_recognition": "MoneyRecognition",
12 | "custom_recognition_param": {
13 | "msg": "Hello world!"
14 | }
15 | }
16 | }
17 | ```
18 |
19 | ```csharp
20 | using MFAWPF.Utils;
21 | using MFAWPF.Views;
22 | using MaaFramework.Binding;
23 | using MaaFramework.Binding.Custom;
24 |
25 | namespace MFAWPF.Custom;
26 |
27 | public class MoneyRecognition : IMaaCustomRecognition
28 | {
29 | public string Name { get; set; } = nameof(MoneyRecognition);
30 |
31 | private const string DiffEntry = "TemplateMatch";
32 |
33 | public bool Analyze(in IMaaContext context, in AnalyzeArgs args, in AnalyzeResults results)
34 | {
35 | // var param = args.RecognitionParam; 获取custom_recognition_param传入的参数,为String
36 | // var imageBuffer = args.Image; 获取截图图片
37 | // var roi = args.Roi; 获取坐标数组
38 | // LoggerService.LogInfo("消息"); 日志输出信息
39 | // LoggerService.LogWarning("警告"); 日志输出警告
40 | // LoggerService.LogError("错误"); 日志输出错误
41 | // Growls.Info("消息"); 提示信息
42 | // Growls.InfoGlobal("全局消息"); 全局提示信息
43 | // Growls.Warning("警告"); 提示警告
44 | // Growls.WarningGlobal("全局警告"); 全局提示警告
45 | // Growls.Error("错误"); 提示错误
46 | // Growls.ErrorGlobal("全局错误"); 全局提示错误
47 | // context.Click(980, 495); 点击
48 | // context.Swipe(980, 495, 0, 0, 1000); 滑动
49 | // context.TouchDown(1, 980, 495, 5); 按下
50 | // context.TouchMove(1); 移动
51 | // context.PressKey(0); 按下按键
52 | // context.Screencap(); 再次截图
53 | // context.GetCachedImage(imageBuffer); 获取截图后图片
54 | // var text = context.GetText(578, 342, 131, 57, imageBuffer); 识别imageBuffer截图的指定roi的文字
55 | // MainWindow.AddLog("消息","LightSeaGreen"); 在MFA右侧日志输出消息,二号参数填写消息颜色,可以不写,默认为Gray
56 |
57 | // TaskModel t1 = new()
58 | // {
59 | // Name = DiffEntry,
60 | // Recognition = "TemplateMatch",
61 | // Roi = new List
62 | // {
63 | // 454,
64 | // 191,
65 | // 355,
66 | // 279
67 | // },
68 | // Template = ["Roguelike@StageTraderInvestSystemError.png"],
69 | // Threshold = 0.9
70 | // }
71 | // var rd1 = context.RunRecognition(t1, imageBuffer);
72 | // if (rd1.IsHit())
73 | // {
74 | // break;
75 | // }
76 | // 执行特定识别器,IsHit()用来判断是否识别到
77 |
78 | return true;
79 | }
80 | }
81 | ```
82 |
83 | ## 自定义操作
84 |
85 | ```json
86 | {
87 | "Task": {
88 | "action": "Custom",
89 | "custom_action": "MoneyAction",
90 | "custom_action_param": {
91 | "msg": "Hello world!"
92 | }
93 | }
94 | }
95 | ```
96 |
97 | ```csharp
98 | using MFAWPF.Utils;
99 | using MFAWPF.Views;
100 | using MaaFramework.Binding;
101 | using MaaFramework.Binding.Custom;
102 |
103 | namespace MFAWPF.Custom;
104 |
105 | public class MoneyAction : IMaaCustomAction
106 | {
107 | public string Name { get; set; } = nameof(MoneyAction);
108 |
109 | public bool Run(in IMaaContext context, in RunArgs args)
110 | {
111 | // var param = args.ActionParam; 获取custom_action_param
112 | return false;
113 | }
114 |
115 | public void Abort()
116 | {
117 | }
118 | }
119 | ```
120 |
121 |
--------------------------------------------------------------------------------
/logo.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SweetSmellFox/MFAWPF/12e65484cf483e7bb68aca3e8e749406c52398c8/logo.ico
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SweetSmellFox/MFAWPF/12e65484cf483e7bb68aca3e8e749406c52398c8/logo.png
--------------------------------------------------------------------------------