mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-20 02:55:38 +08:00
feat: 同时启动多个模拟器时使用自动检测连接时提供弹窗选择 (#16020)
feat: 同时启动多个模拟器时使用自动检测连接时提供弹窗选择 https://github.com/user-attachments/assets/0b424e4d-6704-4d63-84dc-64916df6220b ## Summary by Sourcery 添加通用的项目选择对话框,并使用它在自动检测期间处理多个已检测到的模拟器和连接地址。 New Features: - 引入可复用的项目选择对话框和视图模型,可以显示带有可自定义标题和提示语的项目列表,并返回所选项目。 - 当检测到多个模拟器或多个 ADB 路径时,允许用户选择要连接的模拟器实例。 - 当检测到多个非默认的 ADB 连接地址时,允许用户选择要使用的连接地址。 Bug Fixes: - 当发现多个候选项时,通过明确要求用户进行选择,防止产生含糊不清或错误的模拟器/ADB 选择。 - 当不存在有效目录时,将已配置路径初始化为空,避免强制使用硬编码的默认模拟器安装路径。 - 确保选择对话框始终在 UI 线程调度器上创建和显示,以避免潜在的线程问题。 Enhancements: - 优化模拟器检测逻辑,以同时跟踪模拟器名称和解析后的 ADB 路径,对结果去重,并在选择界面中展示这些信息。 - 使用通用项目选择对话框替换特定于模拟器路径的对话框,并简化相关视图模型的职责。 - 通过可在不同选择场景中复用的通用选择与提示字符串,改进本地化支持。 <details> <summary>Original summary in English</summary> ## Summary by Sourcery Add generic item selection dialog and use it to handle multiple detected emulators and connection addresses during auto-detection. New Features: - Introduce a reusable item selection dialog and view model that can display a list of items with customizable title and prompt and return the selected item. - Allow users to choose which emulator instance to connect to when multiple emulators or ADB paths are detected. - Allow users to choose which connection address to use when multiple non-default ADB addresses are detected. Bug Fixes: - Prevent ambiguous or incorrect emulator/ADB selection by explicitly requiring a user choice when multiple candidates are found. - Avoid forcing hard-coded default emulator installation paths by initializing configured paths as empty when no valid directory exists. - Ensure selection dialogs are always created and shown on the UI thread dispatcher to avoid potential threading issues. Enhancements: - Refine emulator detection to track both emulator name and resolved ADB path, deduplicate results, and surface this information in the selection UI. - Replace the emulator-path-specific dialog with a generic item selection dialog and simplify related view model responsibilities. - Improve localization support with generic selection and prompt strings that can be reused across different selection scenarios. </details>
This commit is contained in:
@@ -11,6 +11,8 @@
|
||||
// but WITHOUT ANY WARRANTY
|
||||
// </copyright>
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@@ -27,6 +29,17 @@ public class WinAdapter
|
||||
{
|
||||
private static readonly ILogger _logger = Log.ForContext<WinAdapter>();
|
||||
|
||||
public sealed class DetectedEmulatorInfo(string emulatorName, string? adbPath)
|
||||
{
|
||||
public string EmulatorName { get; } = emulatorName;
|
||||
|
||||
public string? AdbPath { get; } = adbPath;
|
||||
|
||||
public string SelectionDisplayText => string.IsNullOrEmpty(AdbPath)
|
||||
? EmulatorName
|
||||
: $"{EmulatorName} ({AdbPath})";
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, string> _emulatorIdDict = new()
|
||||
{
|
||||
{ "HD-Player", "BlueStacks" },
|
||||
@@ -59,16 +72,15 @@ public class WinAdapter
|
||||
{ "XYAZ", [@".\adb.exe"] },
|
||||
};
|
||||
|
||||
private readonly Dictionary<string, string> _adbAbsolutePathDict = new();
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes emulator information.
|
||||
/// </summary>
|
||||
/// <returns>The list of emulators.</returns>
|
||||
public List<string> RefreshEmulatorsInfo()
|
||||
/// <returns>The detected emulator infos.</returns>
|
||||
public List<DetectedEmulatorInfo> RefreshEmulatorsInfo()
|
||||
{
|
||||
var allProcess = Process.GetProcesses();
|
||||
var emulators = new List<string>();
|
||||
var emulators = new List<DetectedEmulatorInfo>();
|
||||
var detectedEmulators = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var process in allProcess)
|
||||
{
|
||||
if (!_emulatorIdDict.TryGetValue(process.ProcessName, out var emulatorId))
|
||||
@@ -76,13 +88,11 @@ public class WinAdapter
|
||||
continue;
|
||||
}
|
||||
|
||||
emulators.Add(emulatorId);
|
||||
var processPath = process.MainModule?.FileName;
|
||||
foreach (string adbPath in _adbRelativePathDict[emulatorId]
|
||||
.Select(path => Path.GetDirectoryName(processPath) + "\\" + path)
|
||||
.Where(File.Exists))
|
||||
var adbPath = GetAdbPathByProcessPath(process.MainModule?.FileName, emulatorId);
|
||||
var detectionKey = $"{emulatorId}\n{adbPath}";
|
||||
if (detectedEmulators.Add(detectionKey))
|
||||
{
|
||||
_adbAbsolutePathDict[emulatorId] = adbPath;
|
||||
emulators.Add(new DetectedEmulatorInfo(emulatorId, adbPath));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,13 +100,22 @@ public class WinAdapter
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets ADB path by emulator name.
|
||||
/// Gets the preferred ADB path for a process.
|
||||
/// </summary>
|
||||
/// <param name="processPath">The emulator executable path.</param>
|
||||
/// <param name="emulatorName">The name of the emulator.</param>
|
||||
/// <returns>The ADB path of the emulator.</returns>
|
||||
public string GetAdbPathByEmulatorName(string emulatorName)
|
||||
private static string? GetAdbPathByProcessPath(string? processPath, string emulatorName)
|
||||
{
|
||||
return _adbAbsolutePathDict.GetValueOrDefault(emulatorName);
|
||||
var processDirectory = Path.GetDirectoryName(processPath);
|
||||
if (string.IsNullOrEmpty(processDirectory))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return _adbRelativePathDict[emulatorName]
|
||||
.Select(path => Path.GetFullPath(Path.Combine(processDirectory, path)))
|
||||
.FirstOrDefault(File.Exists);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1843,9 +1843,16 @@ If you want to run multiple MAA at the same time, please copy the whole MAA and
|
||||
<system:String x:Key="BadModules.ResetSuccess">Hardware rendering mode has been restored. Restart MAA to apply changes. Restart now?</system:String>
|
||||
<!-- !BadModules -->
|
||||
|
||||
<!-- EmulatorPathSelection -->
|
||||
<!-- ItemSelection -->
|
||||
<system:String x:Key="SelectItem">Select Item</system:String>
|
||||
<system:String x:Key="SelectEmulatorPath">Select Emulator Path</system:String>
|
||||
<system:String x:Key="SelectEmulator">Select Emulator</system:String>
|
||||
<system:String x:Key="SelectConnectionAddress">Select Connection Address</system:String>
|
||||
<system:String x:Key="MultipleEmulatorsDetected">Multiple emulator installation paths detected, please select the path you want to use:</system:String>
|
||||
<system:String x:Key="MultipleEmulatorsDetectedForConnection">Multiple emulators detected, please select the emulator you want to connect to:</system:String>
|
||||
<system:String x:Key="MultipleAddressesDetected">Multiple connection addresses detected, please select the address you want to use:</system:String>
|
||||
<system:String x:Key="PleaseSelectPath">Please select a path</system:String>
|
||||
<!-- !EmulatorPathSelection -->
|
||||
<system:String x:Key="PleaseSelectItem">Please select an item</system:String>
|
||||
<system:String x:Key="EmulatorSelectionCancelled">Emulator selection cancelled</system:String>
|
||||
<!-- !ItemSelection -->
|
||||
</ResourceDictionary>
|
||||
|
||||
@@ -1844,9 +1844,16 @@ MAA を複数開くには、新しい MAA を他のフォルダにコピーし
|
||||
<system:String x:Key="BadModules.ResetSuccess">ハードウェアレンダリングモードに戻しました。変更を適用するには MAA を再起動する必要があります。今すぐ再起動しますか?</system:String>
|
||||
<!-- !BadModules -->
|
||||
|
||||
<!-- EmulatorPathSelection -->
|
||||
<!-- ItemSelection -->
|
||||
<system:String x:Key="SelectItem">項目を選択</system:String>
|
||||
<system:String x:Key="SelectEmulatorPath">エミュレータのパスを選択</system:String>
|
||||
<system:String x:Key="SelectEmulator">エミュレータを選択</system:String>
|
||||
<system:String x:Key="SelectConnectionAddress">接続アドレスを選択</system:String>
|
||||
<system:String x:Key="MultipleEmulatorsDetected">複数のエミュレータのインストールパスが検出されました。使用するパスを選択してください:</system:String>
|
||||
<system:String x:Key="MultipleEmulatorsDetectedForConnection">複数のエミュレータが検出されました。接続するエミュレータを選択してください:</system:String>
|
||||
<system:String x:Key="MultipleAddressesDetected">複数の接続アドレスが検出されました。使用するアドレスを選択してください:</system:String>
|
||||
<system:String x:Key="PleaseSelectPath">パスを選択してください</system:String>
|
||||
<!-- !EmulatorPathSelection -->
|
||||
<system:String x:Key="PleaseSelectItem">項目を選択してください</system:String>
|
||||
<system:String x:Key="EmulatorSelectionCancelled">エミュレータの選択がキャンセルされました</system:String>
|
||||
<!-- !ItemSelection -->
|
||||
</ResourceDictionary>
|
||||
|
||||
@@ -1845,9 +1845,16 @@ MAA를 독립된 새 폴더에 압축 해제하거나, MAA에 속하지 않는 D
|
||||
<system:String x:Key="BadModules.ResetSuccess">하드웨어 렌더링 모드로 복원되었습니다. 변경 사항을 적용하려면 MAA를 다시 시작해야 합니다. 지금 다시 시작하시겠습니까?</system:String>
|
||||
<!-- !BadModules -->
|
||||
|
||||
<!-- EmulatorPathSelection -->
|
||||
<!-- ItemSelection -->
|
||||
<system:String x:Key="SelectItem">항목 선택</system:String>
|
||||
<system:String x:Key="SelectEmulatorPath">에뮬레이터 경로 선택</system:String>
|
||||
<system:String x:Key="SelectEmulator">에뮬레이터 선택</system:String>
|
||||
<system:String x:Key="SelectConnectionAddress">연결 주소 선택</system:String>
|
||||
<system:String x:Key="MultipleEmulatorsDetected">여러 에뮬레이터 설치 경로가 감지되었습니다. 사용할 경로를 선택하세요:</system:String>
|
||||
<system:String x:Key="MultipleEmulatorsDetectedForConnection">여러 에뮬레이터가 감지되었습니다. 연결할 에뮬레이터를 선택하세요:</system:String>
|
||||
<system:String x:Key="MultipleAddressesDetected">여러 연결 주소가 감지되었습니다. 사용할 주소를 선택하세요:</system:String>
|
||||
<system:String x:Key="PleaseSelectPath">경로를 선택하세요</system:String>
|
||||
<!-- !EmulatorPathSelection -->
|
||||
<system:String x:Key="PleaseSelectItem">항목을 선택하세요</system:String>
|
||||
<system:String x:Key="EmulatorSelectionCancelled">에뮬레이터 선택이 취소되었습니다</system:String>
|
||||
<!-- !ItemSelection -->
|
||||
</ResourceDictionary>
|
||||
|
||||
@@ -1844,9 +1844,16 @@ DEBUG 目录下保存的图片有数量限制,超出后会自动清理旧图
|
||||
<system:String x:Key="BadModules.ResetSuccess">已重置为硬件渲染模式。需要重启 MAA 后生效。是否立即重启?</system:String>
|
||||
<!-- !BadModules -->
|
||||
|
||||
<!-- EmulatorPathSelection -->
|
||||
<!-- ItemSelection -->
|
||||
<system:String x:Key="SelectItem">选择项目</system:String>
|
||||
<system:String x:Key="SelectEmulatorPath">选择模拟器路径</system:String>
|
||||
<system:String x:Key="SelectEmulator">选择模拟器</system:String>
|
||||
<system:String x:Key="SelectConnectionAddress">选择连接地址</system:String>
|
||||
<system:String x:Key="MultipleEmulatorsDetected">检测到多个模拟器安装路径,请选择您要使用的路径:</system:String>
|
||||
<system:String x:Key="MultipleEmulatorsDetectedForConnection">检测到多个模拟器,请选择您要连接的模拟器:</system:String>
|
||||
<system:String x:Key="MultipleAddressesDetected">检测到多个连接地址,请选择您要使用的地址:</system:String>
|
||||
<system:String x:Key="PleaseSelectPath">请选择一个路径</system:String>
|
||||
<!-- !EmulatorPathSelection -->
|
||||
<system:String x:Key="PleaseSelectItem">请选择一项</system:String>
|
||||
<system:String x:Key="EmulatorSelectionCancelled">已取消选择模拟器</system:String>
|
||||
<!-- !ItemSelection -->
|
||||
</ResourceDictionary>
|
||||
|
||||
@@ -1844,9 +1844,16 @@ DEBUG 目錄下儲存的圖片有數量限制,超出後會自動清理舊圖
|
||||
<system:String x:Key="BadModules.ResetSuccess">已重置為硬體渲染模式。需要重新啟動 MAA 後生效。是否立即重新啟動?</system:String>
|
||||
<!-- !BadModules -->
|
||||
|
||||
<!-- EmulatorPathSelection -->
|
||||
<!-- ItemSelection -->
|
||||
<system:String x:Key="SelectItem">選擇項目</system:String>
|
||||
<system:String x:Key="SelectEmulatorPath">選擇模擬器路徑</system:String>
|
||||
<system:String x:Key="SelectEmulator">選擇模擬器</system:String>
|
||||
<system:String x:Key="SelectConnectionAddress">選擇連線地址</system:String>
|
||||
<system:String x:Key="MultipleEmulatorsDetected">偵測到多個模擬器安裝路徑,請選擇您要使用的路徑:</system:String>
|
||||
<system:String x:Key="MultipleEmulatorsDetectedForConnection">偵測到多個模擬器,請選擇您要連線的模擬器:</system:String>
|
||||
<system:String x:Key="MultipleAddressesDetected">偵測到多個連線地址,請選擇您要使用的地址:</system:String>
|
||||
<system:String x:Key="PleaseSelectPath">請選擇路徑</system:String>
|
||||
<!-- !EmulatorPathSelection -->
|
||||
<system:String x:Key="PleaseSelectItem">請選擇一項</system:String>
|
||||
<system:String x:Key="EmulatorSelectionCancelled">已取消選擇模擬器</system:String>
|
||||
<!-- !ItemSelection -->
|
||||
</ResourceDictionary>
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
// <copyright file="EmulatorPathSelectionDialogViewModel.cs" company="MaaAssistantArknights">
|
||||
// Part of the MaaWpfGui project, maintained by the MaaAssistantArknights team (Maa Team)
|
||||
// Copyright (C) 2021-2025 MaaAssistantArknights Contributors
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License v3.0 only as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY
|
||||
// </copyright>
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Stylet;
|
||||
|
||||
namespace MaaWpfGui.ViewModels.Dialogs;
|
||||
|
||||
/// <summary>
|
||||
/// ViewModel for EmulatorPathSelectionDialogView
|
||||
/// </summary>
|
||||
public class EmulatorPathSelectionDialogViewModel : PropertyChangedBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EmulatorPathSelectionDialogViewModel"/> class.
|
||||
/// </summary>
|
||||
/// <param name="paths">可选路径列表</param>
|
||||
public EmulatorPathSelectionDialogViewModel(List<string> paths)
|
||||
{
|
||||
Paths = paths;
|
||||
if (paths.Count > 0)
|
||||
{
|
||||
SelectedPath = paths[0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of paths.
|
||||
/// </summary>
|
||||
public List<string> Paths { get; }
|
||||
|
||||
private string? _selectedPath;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected path.
|
||||
/// </summary>
|
||||
public string? SelectedPath
|
||||
{
|
||||
get => _selectedPath;
|
||||
set => SetAndNotify(ref _selectedPath, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// <copyright file="ItemSelectionDialogViewModel.cs" company="MaaAssistantArknights">
|
||||
// Part of the MaaWpfGui project, maintained by the MaaAssistantArknights team (Maa Team)
|
||||
// Copyright (C) 2021-2025 MaaAssistantArknights Contributors
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License v3.0 only as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY
|
||||
// </copyright>
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Stylet;
|
||||
|
||||
namespace MaaWpfGui.ViewModels.Dialogs;
|
||||
|
||||
/// <summary>
|
||||
/// ViewModel for ItemSelectionDialogView
|
||||
/// </summary>
|
||||
public class ItemSelectionDialogViewModel : PropertyChangedBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ItemSelectionDialogViewModel"/> class.
|
||||
/// </summary>
|
||||
/// <param name="availableItems">可选项</param>
|
||||
/// <param name="windowTitle">窗口标题</param>
|
||||
/// <param name="promptMessage">提示信息</param>
|
||||
public ItemSelectionDialogViewModel(IEnumerable<string> availableItems, string? windowTitle = null, string? promptMessage = null)
|
||||
{
|
||||
var itemsList = availableItems.ToList();
|
||||
Items = itemsList;
|
||||
WindowTitle = windowTitle ?? Helper.LocalizationHelper.GetString("SelectItem");
|
||||
PromptMessage = promptMessage ?? Helper.LocalizationHelper.GetString("PleaseSelectItem");
|
||||
if (itemsList.Count > 0)
|
||||
{
|
||||
SelectedItem = itemsList.First();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the window title.
|
||||
/// </summary>
|
||||
public string WindowTitle { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the prompt message.
|
||||
/// </summary>
|
||||
public string PromptMessage { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of items.
|
||||
/// </summary>
|
||||
public List<string> Items { get; }
|
||||
|
||||
private string? _selectedItem;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected item.
|
||||
/// </summary>
|
||||
public string? SelectedItem
|
||||
{
|
||||
get => _selectedItem;
|
||||
set => SetAndNotify(ref _selectedItem, value);
|
||||
}
|
||||
}
|
||||
@@ -357,13 +357,13 @@ public class ConnectSettingsUserControlModel : PropertyChangedBase
|
||||
return;
|
||||
}
|
||||
|
||||
// 多个路径,弹出选择框
|
||||
var selectionWindow = new Views.Dialogs.EmulatorPathSelectionDialogView(detectedPaths) {
|
||||
Owner = Application.Current.MainWindow,
|
||||
};
|
||||
if (selectionWindow.ShowDialog() == true && !string.IsNullOrEmpty(selectionWindow.SelectedPath))
|
||||
var selectedPath = ShowItemSelectionDialog(
|
||||
detectedPaths,
|
||||
LocalizationHelper.GetString("SelectEmulatorPath"),
|
||||
LocalizationHelper.GetString("MultipleEmulatorsDetected"));
|
||||
if (!string.IsNullOrEmpty(selectedPath))
|
||||
{
|
||||
EmulatorPath = selectionWindow.SelectedPath;
|
||||
EmulatorPath = selectedPath;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -373,7 +373,7 @@ public class ConnectSettingsUserControlModel : PropertyChangedBase
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly string _configuredPath = ConfigurationHelper.GetValue(ConfigurationKeys.MuMu12EmulatorPath, @"C:\Program Files\Netease\MuMuPlayer-12.0");
|
||||
private static readonly string _configuredPath = ConfigurationHelper.GetValue(ConfigurationKeys.MuMu12EmulatorPath, string.Empty);
|
||||
private string _emulatorPath = Directory.Exists(_configuredPath) ? _configuredPath : string.Empty;
|
||||
|
||||
/// <summary>
|
||||
@@ -557,11 +557,13 @@ public class ConnectSettingsUserControlModel : PropertyChangedBase
|
||||
return;
|
||||
}
|
||||
|
||||
// 多个路径,弹出选择框
|
||||
var selectionWindow = new Views.Dialogs.EmulatorPathSelectionDialogView(detectedPaths);
|
||||
if (selectionWindow.ShowDialog() == true && !string.IsNullOrEmpty(selectionWindow.SelectedPath))
|
||||
var selectedPath = ShowItemSelectionDialog(
|
||||
detectedPaths,
|
||||
LocalizationHelper.GetString("SelectEmulatorPath"),
|
||||
LocalizationHelper.GetString("MultipleEmulatorsDetected"));
|
||||
if (!string.IsNullOrEmpty(selectedPath))
|
||||
{
|
||||
EmulatorPath = selectionWindow.SelectedPath;
|
||||
EmulatorPath = selectedPath;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -571,7 +573,7 @@ public class ConnectSettingsUserControlModel : PropertyChangedBase
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly string _configuredPath = ConfigurationHelper.GetValue(ConfigurationKeys.LdPlayerEmulatorPath, @"C:\leidian\LDPlayer9");
|
||||
private static readonly string _configuredPath = ConfigurationHelper.GetValue(ConfigurationKeys.LdPlayerEmulatorPath, string.Empty);
|
||||
private string _emulatorPath = Directory.Exists(_configuredPath) ? _configuredPath : string.Empty;
|
||||
|
||||
/// <summary>
|
||||
@@ -845,6 +847,31 @@ public class ConnectSettingsUserControlModel : PropertyChangedBase
|
||||
|
||||
private const string BluestacksNxtValueName = "UserDefinedDir";
|
||||
|
||||
private static string? ShowItemSelectionDialog(IEnumerable<string> items, string windowTitle, string promptMessage)
|
||||
{
|
||||
string? ShowDialogCore()
|
||||
{
|
||||
var selectionWindow = new Views.Dialogs.ItemSelectionDialogView(items, windowTitle, promptMessage)
|
||||
{
|
||||
Owner = Application.Current.MainWindow,
|
||||
};
|
||||
|
||||
return selectionWindow.ShowDialog() == true && !string.IsNullOrEmpty(selectionWindow.SelectedItem)
|
||||
? selectionWindow.SelectedItem
|
||||
: null;
|
||||
}
|
||||
|
||||
var application = Application.Current;
|
||||
if (application?.Dispatcher == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return application.Dispatcher.CheckAccess()
|
||||
? ShowDialogCore()
|
||||
: application.Dispatcher.Invoke(ShowDialogCore);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes ADB config.
|
||||
/// </summary>
|
||||
@@ -853,7 +880,8 @@ public class ConnectSettingsUserControlModel : PropertyChangedBase
|
||||
public bool DetectAdbConfig(ref string error)
|
||||
{
|
||||
var adapter = new WinAdapter();
|
||||
List<string> emulators;
|
||||
List<WinAdapter.DetectedEmulatorInfo> emulators;
|
||||
WinAdapter.DetectedEmulatorInfo? selectedEmulator = null;
|
||||
try
|
||||
{
|
||||
emulators = adapter.RefreshEmulatorsInfo();
|
||||
@@ -872,12 +900,30 @@ public class ConnectSettingsUserControlModel : PropertyChangedBase
|
||||
return false;
|
||||
|
||||
case > 1:
|
||||
error = LocalizationHelper.GetString("EmulatorTooMany");
|
||||
{
|
||||
var selectedEmulatorDisplayText = ShowItemSelectionDialog(
|
||||
[.. emulators.Select(emulator => emulator.SelectionDisplayText)],
|
||||
LocalizationHelper.GetString("SelectEmulator"),
|
||||
LocalizationHelper.GetString("MultipleEmulatorsDetectedForConnection"));
|
||||
|
||||
if (string.IsNullOrEmpty(selectedEmulatorDisplayText))
|
||||
{
|
||||
error = LocalizationHelper.GetString("EmulatorSelectionCancelled");
|
||||
return false;
|
||||
}
|
||||
|
||||
selectedEmulator = emulators.First(emulator => emulator.SelectionDisplayText == selectedEmulatorDisplayText);
|
||||
ConnectConfig = selectedEmulator.EmulatorName;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
selectedEmulator = emulators.First();
|
||||
ConnectConfig = selectedEmulator.EmulatorName;
|
||||
break;
|
||||
}
|
||||
|
||||
ConnectConfig = emulators.First();
|
||||
AdbPath = adapter.GetAdbPathByEmulatorName(ConnectConfig) ?? AdbPath;
|
||||
AdbPath = selectedEmulator?.AdbPath ?? AdbPath;
|
||||
if (string.IsNullOrEmpty(AdbPath))
|
||||
{
|
||||
error = LocalizationHelper.GetString("AdbException");
|
||||
@@ -898,10 +944,31 @@ public class ConnectSettingsUserControlModel : PropertyChangedBase
|
||||
|
||||
case > 1:
|
||||
{
|
||||
foreach (var address in addresses.Where(address => address != "emulator-5554" && address != "1234567890ABCDEF"))
|
||||
// 过滤掉默认地址
|
||||
var filteredAddresses = addresses
|
||||
.Where(address => address != "1234567890ABCDEF")
|
||||
.ToList();
|
||||
|
||||
if (filteredAddresses.Count == 1)
|
||||
{
|
||||
ConnectAddress = address;
|
||||
break;
|
||||
ConnectAddress = filteredAddresses.First();
|
||||
}
|
||||
else if (filteredAddresses.Count > 1)
|
||||
{
|
||||
var selectedAddress = ShowItemSelectionDialog(
|
||||
filteredAddresses,
|
||||
LocalizationHelper.GetString("SelectConnectionAddress"),
|
||||
LocalizationHelper.GetString("MultipleAddressesDetected"));
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedAddress))
|
||||
{
|
||||
ConnectAddress = selectedAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = LocalizationHelper.GetString("EmulatorSelectionCancelled");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<hc:Window
|
||||
x:Class="MaaWpfGui.Views.Dialogs.EmulatorPathSelectionDialogView"
|
||||
x:Class="MaaWpfGui.Views.Dialogs.ItemSelectionDialogView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||
Title="{DynamicResource SelectEmulatorPath}"
|
||||
Title="{Binding WindowTitle}"
|
||||
Width="600"
|
||||
Height="400"
|
||||
Background="{DynamicResource RegionBrush}"
|
||||
@@ -20,14 +20,14 @@
|
||||
Grid.Row="0"
|
||||
Margin="0,0,0,15"
|
||||
FontSize="14"
|
||||
Text="{DynamicResource MultipleEmulatorsDetected}"
|
||||
Text="{Binding PromptMessage}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<ListBox
|
||||
Grid.Row="1"
|
||||
Margin="0,0,0,15"
|
||||
ItemsSource="{Binding Paths}"
|
||||
SelectedItem="{Binding SelectedPath}">
|
||||
ItemsSource="{Binding Items}"
|
||||
SelectedItem="{Binding SelectedItem}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding}" TextWrapping="Wrap" />
|
||||
@@ -1,4 +1,4 @@
|
||||
// <copyright file="EmulatorPathSelectionDialogView.xaml.cs" company="MaaAssistantArknights">
|
||||
// <copyright file="ItemSelectionDialogView.xaml.cs" company="MaaAssistantArknights">
|
||||
// Part of the MaaWpfGui project, maintained by the MaaAssistantArknights team (Maa Team)
|
||||
// Copyright (C) 2021-2025 MaaAssistantArknights Contributors
|
||||
//
|
||||
@@ -20,28 +20,30 @@ using MaaWpfGui.ViewModels.Dialogs;
|
||||
namespace MaaWpfGui.Views.Dialogs;
|
||||
|
||||
/// <summary>
|
||||
/// EmulatorPathSelectionDialogView.xaml 的交互逻辑
|
||||
/// ItemSelectionDialogView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class EmulatorPathSelectionDialogView
|
||||
public partial class ItemSelectionDialogView
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EmulatorPathSelectionDialogView"/> class.
|
||||
/// Initializes a new instance of the <see cref="ItemSelectionDialogView"/> class.
|
||||
/// </summary>
|
||||
/// <param name="paths">可选路径列表</param>
|
||||
public EmulatorPathSelectionDialogView(List<string> paths)
|
||||
/// <param name="availableItems">可选项</param>
|
||||
/// <param name="windowTitle">窗口标题(可选)</param>
|
||||
/// <param name="promptMessage">提示信息(可选)</param>
|
||||
public ItemSelectionDialogView(IEnumerable<string> availableItems, string? windowTitle = null, string? promptMessage = null)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = new EmulatorPathSelectionDialogViewModel(paths);
|
||||
DataContext = new ItemSelectionDialogViewModel(availableItems, windowTitle, promptMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the selected path.
|
||||
/// Gets the selected item.
|
||||
/// </summary>
|
||||
public string? SelectedPath => (DataContext as EmulatorPathSelectionDialogViewModel)?.SelectedPath;
|
||||
public string? SelectedItem => (DataContext as ItemSelectionDialogViewModel)?.SelectedItem;
|
||||
|
||||
private void OnConfirmClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(SelectedPath))
|
||||
if (!string.IsNullOrEmpty(SelectedItem))
|
||||
{
|
||||
DialogResult = true;
|
||||
Close();
|
||||
@@ -49,7 +51,7 @@ public partial class EmulatorPathSelectionDialogView
|
||||
else
|
||||
{
|
||||
MessageBox.Show(
|
||||
Helper.LocalizationHelper.GetString("PleaseSelectPath"),
|
||||
Helper.LocalizationHelper.GetString("PleaseSelectItem"),
|
||||
Helper.LocalizationHelper.GetString("Tip"),
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Warning);
|
||||
Reference in New Issue
Block a user