diff --git a/.agent/DECISIONS.md b/.agent/DECISIONS.md
index c7c1f51..a45b40b 100644
--- a/.agent/DECISIONS.md
+++ b/.agent/DECISIONS.md
@@ -84,3 +84,27 @@ Record meaningful technical decisions here. Use one entry per decision.
- Alternatives considered: Launch the system Storage Access Framework picker; request permissions through an application context.
- Impacted areas: Android 10 and earlier storage permission checks, runtime permission requests, and raw external-storage access.
+- Date: 2026-07-25
+- Decision: Give the dependency manager a page-scoped MD3 component token set and render its tabs with a compact custom state-layer template.
+- Rationale: The default desktop tab indicator, unconstrained count badges, and filled hover treatment produced inconsistent geometry and excessive contrast. Page-scoped tokens keep responsive spacing, badge shape, state opacity, and the short pill indicator consistent across generated color themes.
+- Alternatives considered: Modify the global Avalonia TabItem theme; continue using per-control literal values.
+- Impacted areas: Dependency manager layout and styles; shared static theme tokens.
+
+- Date: 2026-07-27
+- Decision: Supersede the dependency-manager-specific tab header template with a global MD3 secondary TabItem style.
+- Rationale: Secondary tabs are a shared component pattern. A global style gives every TabItem the same 48dp container, Title Small label, state layer, semantic colors, and full-width 2dp active indicator while allowing each view to supply arbitrary header content.
+- Alternatives considered: Keep the dependency manager's page-scoped short pill indicator; duplicate the secondary-tab template in each view.
+- Impacted areas: Global OpenUtau Mobile TabItem headers; dependency manager tab header markup and tokens.
+
+- Date: 2026-07-29
+- Decision: Implement dependency installation from local files entirely in the Mobile layer without modifying the upstream-derived Core package manager.
+- Rationale: The existing Core API already supports file installation, while keeping this feature's UI state and error presentation outside Core avoids increasing the cost of future upstream synchronization.
+- Alternatives considered: Add transactional extraction, package metadata results, or typed installation errors to `OpenUtau.Core`; duplicate package parsing in a Mobile adapter.
+- Impacted areas: Dependency manager ViewModel, view state, and localization resources. Core installation behavior remains unchanged.
+
+- Date: 2026-07-29
+- Decision: Run non-cancellable background UI operations through a reusable LoadingPopup service with determinate and indeterminate progress modes.
+- Rationale: Centralizing first-frame yielding, UI-thread progress updates, and guaranteed dialog closure prevents operation-specific loading overlays from racing with completion or subsequent error dialogs.
+- Alternatives considered: Keep page-local busy indicators; open and close DialogHost directly in each ViewModel; add loading notifications to the upstream-derived Core.
+- Impacted areas: Shared popup controls and services; dependency installation now uses the indeterminate loading mode.
+
diff --git a/OpenUtauMobile/App.axaml.cs b/OpenUtauMobile/App.axaml.cs
index a51b27b..41fe07d 100644
--- a/OpenUtauMobile/App.axaml.cs
+++ b/OpenUtauMobile/App.axaml.cs
@@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
+using Avalonia.Media;
using Avalonia.Styling;
using OpenUtau.Core.Util;
using OpenUtauMobile.Helpers;
@@ -31,7 +32,7 @@ public override void OnFrameworkInitializationCompleted()
// Initialize runtime theme resources before creating UI.
ThemeManagerV2.Initialize();
- var seed = ThemeSeedResolver.ResolveSeed(
+ Color seed = ThemeSeedResolver.ResolveSeed(
ServiceHub.SystemAccentColorProvider,
out _,
out _);
diff --git a/OpenUtauMobile/Assets/Lang/Strings.en.resx b/OpenUtauMobile/Assets/Lang/Strings.en.resx
index 72e59c1..4cc4283 100644
--- a/OpenUtauMobile/Assets/Lang/Strings.en.resx
+++ b/OpenUtauMobile/Assets/Lang/Strings.en.resx
@@ -837,6 +837,12 @@
Dependency Management
+
+ Please wait
+
+
+ Working in the background…
+
Refresh List
@@ -882,8 +888,26 @@
Failed to load installed list: {0}
-
- Install from file not implemented yet
+
+ Select dependency package
+
+
+ Installing the dependency package…
+
+
+ Installed dependency package "{0}"
+
+
+ The selected file is not a valid dependency package or is damaged.
+
+
+ Unable to read the package or write to dependency storage. Check storage permissions.
+
+
+ The selected package is no longer available. Choose the file again.
+
+
+ Unable to install the package. Check available storage space and whether the file is in use.
Uninstalled {0}
diff --git a/OpenUtauMobile/Assets/Lang/Strings.ja.resx b/OpenUtauMobile/Assets/Lang/Strings.ja.resx
index 611000e..c6584d8 100644
--- a/OpenUtauMobile/Assets/Lang/Strings.ja.resx
+++ b/OpenUtauMobile/Assets/Lang/Strings.ja.resx
@@ -834,6 +834,12 @@
依存関係管理
+
+ しばらくお待ちください
+
+
+ バックグラウンド処理を実行しています…
+
リストを更新
@@ -879,8 +885,26 @@
インストール済みリストの読み込みに失敗: {0}
-
- ファイルからのインストールは未実装です
+
+ 依存関係パッケージを選択
+
+
+ 依存関係パッケージをインストールしています…
+
+
+ 依存関係パッケージ「{0}」をインストールしました
+
+
+ 選択したファイルは有効な依存関係パッケージではないか、破損しています。
+
+
+ パッケージの読み込みまたは依存関係ストレージへの書き込みができません。ストレージ権限を確認してください。
+
+
+ 選択したパッケージは利用できなくなりました。ファイルを再度選択してください。
+
+
+ パッケージをインストールできません。空き容量とファイルが使用中でないか確認してください。
{0} をアンインストールしました
diff --git a/OpenUtauMobile/Assets/Lang/Strings.ru.resx b/OpenUtauMobile/Assets/Lang/Strings.ru.resx
index 7ef7e65..d23c81a 100644
--- a/OpenUtauMobile/Assets/Lang/Strings.ru.resx
+++ b/OpenUtauMobile/Assets/Lang/Strings.ru.resx
@@ -819,6 +819,12 @@
Управление зависимостями
+
+ Пожалуйста, подождите
+
+
+ Выполняется фоновая операция…
+
Обновить список
@@ -864,8 +870,26 @@
Не удалось загрузить список установленных: {0}
-
- Установка из файла ещё не реализована
+
+ Выберите пакет зависимостей
+
+
+ Установка пакета зависимостей…
+
+
+ Пакет зависимостей «{0}» установлен
+
+
+ Выбранный файл не является допустимым пакетом зависимостей или повреждён.
+
+
+ Не удалось прочитать пакет или записать данные зависимостей. Проверьте разрешения хранилища.
+
+
+ Выбранный пакет больше недоступен. Выберите файл ещё раз.
+
+
+ Не удалось установить пакет. Проверьте свободное место и не используется ли файл.
Удалено: {0}
diff --git a/OpenUtauMobile/Assets/Lang/Strings.uk.resx b/OpenUtauMobile/Assets/Lang/Strings.uk.resx
index 61b3171..2a22562 100644
--- a/OpenUtauMobile/Assets/Lang/Strings.uk.resx
+++ b/OpenUtauMobile/Assets/Lang/Strings.uk.resx
@@ -819,6 +819,12 @@
Керування залежностями
+
+ Будь ласка, зачекайте
+
+
+ Виконується фонова операція…
+
Оновити список
@@ -864,8 +870,26 @@
Не вдалося завантажити список встановлених: {0}
-
- Встановлення з файла ще не реалізовано
+
+ Виберіть пакет залежностей
+
+
+ Встановлення пакета залежностей…
+
+
+ Пакет залежностей «{0}» встановлено
+
+
+ Вибраний файл не є припустимим пакетом залежностей або пошкоджений.
+
+
+ Не вдалося прочитати пакет або записати дані залежностей. Перевірте дозволи сховища.
+
+
+ Вибраний пакет більше недоступний. Виберіть файл ще раз.
+
+
+ Не вдалося встановити пакет. Перевірте вільне місце та чи не використовується файл.
Видалено {0}
diff --git a/OpenUtauMobile/Assets/Lang/Strings.zh-Hans.resx b/OpenUtauMobile/Assets/Lang/Strings.zh-Hans.resx
index e019fd2..5a4052f 100644
--- a/OpenUtauMobile/Assets/Lang/Strings.zh-Hans.resx
+++ b/OpenUtauMobile/Assets/Lang/Strings.zh-Hans.resx
@@ -837,6 +837,12 @@
依赖项管理
+
+ 请稍候
+
+
+ 正在进行后台操作…
+
刷新列表
@@ -882,8 +888,26 @@
加载已安装列表失败: {0}
-
- 从文件安装功能待实现
+
+ 选择依赖包
+
+
+ 正在安装依赖包…
+
+
+ 已安装依赖包“{0}”
+
+
+ 所选文件不是有效的依赖包,或文件已损坏。
+
+
+ 无法读取依赖包或写入依赖项存储,请检查存储权限。
+
+
+ 所选依赖包已不可用,请重新选择文件。
+
+
+ 无法安装依赖包,请检查可用存储空间以及文件是否被占用。
已卸载 {0}
diff --git a/OpenUtauMobile/Controls/LoadingPopup.axaml b/OpenUtauMobile/Controls/LoadingPopup.axaml
new file mode 100644
index 0000000..e5dbd11
--- /dev/null
+++ b/OpenUtauMobile/Controls/LoadingPopup.axaml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OpenUtauMobile/Controls/LoadingPopup.axaml.cs b/OpenUtauMobile/Controls/LoadingPopup.axaml.cs
new file mode 100644
index 0000000..be4f9e4
--- /dev/null
+++ b/OpenUtauMobile/Controls/LoadingPopup.axaml.cs
@@ -0,0 +1,11 @@
+namespace OpenUtauMobile.Controls;
+
+public partial class LoadingPopup : PopupDialogControl
+{
+ protected override PopupDialogWidthPreset WidthPreset => PopupDialogWidthPreset.Compact;
+
+ public LoadingPopup()
+ {
+ InitializeComponent();
+ }
+}
diff --git a/OpenUtauMobile/Services/LoadingPopupService.cs b/OpenUtauMobile/Services/LoadingPopupService.cs
new file mode 100644
index 0000000..3047625
--- /dev/null
+++ b/OpenUtauMobile/Services/LoadingPopupService.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Threading.Tasks;
+using Avalonia.Threading;
+using OpenUtauMobile.Controls;
+using OpenUtauMobile.ViewModels;
+
+namespace OpenUtauMobile.Services;
+
+///
+/// 在通用加载弹窗中运行后台操作
+///
+///
+/// 适用于安装、导入、导出等需要阻止用户继续操作,且通常无法立即完成的后台任务。
+/// 短暂操作或不阻塞交互的状态提示应优先使用 Toast 或页面内加载状态。
+///
+/// 无法获取进度时调用 ;
+/// 可获取 0–100 进度时调用带初始进度的重载,并通过
+/// 持续更新进度和说明。
+///
+/// Service 会先显示弹窗,再运行任务,并在任务成功或抛出异常时关闭弹窗。
+/// 异常会在弹窗完全关闭后继续向调用方传播,因此成功提示和错误弹窗应由调用方在
+/// await RunAsync(...) 之后处理。调用方不应自行关闭 LoadingPopup。
+///
+///
+///
+/// await LoadingPopupService.RunAsync(message, _ => InstallAsync());
+///
+/// await LoadingPopupService.RunAsync(message, 0d, async loading =>
+/// {
+/// loading.UpdateProgress(50d, nextMessage);
+/// await ExportAsync();
+/// });
+///
+///
+public static class LoadingPopupService
+{
+ /// 使用无确定进度的加载弹窗运行后台操作
+ public static async Task RunAsync(
+ string message,
+ Func operation)
+ {
+ LoadingPopupViewModel viewModel = new(message);
+ await RunAsync(viewModel, operation);
+ }
+
+ /// 使用确定进度的加载弹窗运行后台操作
+ public static async Task RunAsync(
+ string message,
+ double initialProgress,
+ Func operation)
+ {
+ LoadingPopupViewModel viewModel = new(message, initialProgress);
+ await RunAsync(viewModel, operation);
+ }
+
+ private static async Task RunAsync(
+ LoadingPopupViewModel viewModel,
+ Func operation)
+ {
+ ArgumentNullException.ThrowIfNull(operation);
+
+ Task