Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .agent/DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

3 changes: 2 additions & 1 deletion OpenUtauMobile/App.axaml.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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 _);
Expand Down
28 changes: 26 additions & 2 deletions OpenUtauMobile/Assets/Lang/Strings.en.resx
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,12 @@
<data name="DependencyManager.Title" xml:space="preserve">
<value>Dependency Management</value>
</data>
<data name="LoadingPopup.Title" xml:space="preserve">
<value>Please wait</value>
</data>
<data name="LoadingPopup.DefaultMessage" xml:space="preserve">
<value>Working in the background…</value>
</data>
<data name="DependencyManager.Refresh" xml:space="preserve">
<value>Refresh List</value>
</data>
Expand Down Expand Up @@ -882,8 +888,26 @@
<data name="DependencyManager.Toast.InstalledListFailed" xml:space="preserve">
<value>Failed to load installed list: {0}</value>
</data>
<data name="DependencyManager.Toast.InstallFromFileNotImpl" xml:space="preserve">
<value>Install from file not implemented yet</value>
<data name="DependencyManager.FilePicker.SelectPackage" xml:space="preserve">
<value>Select dependency package</value>
</data>
<data name="DependencyManager.Loading.InstallFromFile" xml:space="preserve">
<value>Installing the dependency package…</value>
</data>
<data name="DependencyManager.Toast.InstallFromFileSuccess" xml:space="preserve">
<value>Installed dependency package "{0}"</value>
</data>
<data name="DependencyManager.Error.InvalidPackage" xml:space="preserve">
<value>The selected file is not a valid dependency package or is damaged.</value>
</data>
<data name="DependencyManager.Error.AccessDenied" xml:space="preserve">
<value>Unable to read the package or write to dependency storage. Check storage permissions.</value>
</data>
<data name="DependencyManager.Error.FileUnavailable" xml:space="preserve">
<value>The selected package is no longer available. Choose the file again.</value>
</data>
<data name="DependencyManager.Error.Storage" xml:space="preserve">
<value>Unable to install the package. Check available storage space and whether the file is in use.</value>
</data>
<data name="DependencyManager.Toast.Uninstalled" xml:space="preserve">
<value>Uninstalled {0}</value>
Expand Down
28 changes: 26 additions & 2 deletions OpenUtauMobile/Assets/Lang/Strings.ja.resx
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,12 @@
<data name="DependencyManager.Title" xml:space="preserve">
<value>依存関係管理</value>
</data>
<data name="LoadingPopup.Title" xml:space="preserve">
<value>しばらくお待ちください</value>
</data>
<data name="LoadingPopup.DefaultMessage" xml:space="preserve">
<value>バックグラウンド処理を実行しています…</value>
</data>
<data name="DependencyManager.Refresh" xml:space="preserve">
<value>リストを更新</value>
</data>
Expand Down Expand Up @@ -879,8 +885,26 @@
<data name="DependencyManager.Toast.InstalledListFailed" xml:space="preserve">
<value>インストール済みリストの読み込みに失敗: {0}</value>
</data>
<data name="DependencyManager.Toast.InstallFromFileNotImpl" xml:space="preserve">
<value>ファイルからのインストールは未実装です</value>
<data name="DependencyManager.FilePicker.SelectPackage" xml:space="preserve">
<value>依存関係パッケージを選択</value>
</data>
<data name="DependencyManager.Loading.InstallFromFile" xml:space="preserve">
<value>依存関係パッケージをインストールしています…</value>
</data>
<data name="DependencyManager.Toast.InstallFromFileSuccess" xml:space="preserve">
<value>依存関係パッケージ「{0}」をインストールしました</value>
</data>
<data name="DependencyManager.Error.InvalidPackage" xml:space="preserve">
<value>選択したファイルは有効な依存関係パッケージではないか、破損しています。</value>
</data>
<data name="DependencyManager.Error.AccessDenied" xml:space="preserve">
<value>パッケージの読み込みまたは依存関係ストレージへの書き込みができません。ストレージ権限を確認してください。</value>
</data>
<data name="DependencyManager.Error.FileUnavailable" xml:space="preserve">
<value>選択したパッケージは利用できなくなりました。ファイルを再度選択してください。</value>
</data>
<data name="DependencyManager.Error.Storage" xml:space="preserve">
<value>パッケージをインストールできません。空き容量とファイルが使用中でないか確認してください。</value>
</data>
<data name="DependencyManager.Toast.Uninstalled" xml:space="preserve">
<value>{0} をアンインストールしました</value>
Expand Down
28 changes: 26 additions & 2 deletions OpenUtauMobile/Assets/Lang/Strings.ru.resx
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,12 @@
<data name="DependencyManager.Title" xml:space="preserve">
<value>Управление зависимостями</value>
</data>
<data name="LoadingPopup.Title" xml:space="preserve">
<value>Пожалуйста, подождите</value>
</data>
<data name="LoadingPopup.DefaultMessage" xml:space="preserve">
<value>Выполняется фоновая операция…</value>
</data>
<data name="DependencyManager.Refresh" xml:space="preserve">
<value>Обновить список</value>
</data>
Expand Down Expand Up @@ -864,8 +870,26 @@
<data name="DependencyManager.Toast.InstalledListFailed" xml:space="preserve">
<value>Не удалось загрузить список установленных: {0}</value>
</data>
<data name="DependencyManager.Toast.InstallFromFileNotImpl" xml:space="preserve">
<value>Установка из файла ещё не реализована</value>
<data name="DependencyManager.FilePicker.SelectPackage" xml:space="preserve">
<value>Выберите пакет зависимостей</value>
</data>
<data name="DependencyManager.Loading.InstallFromFile" xml:space="preserve">
<value>Установка пакета зависимостей…</value>
</data>
<data name="DependencyManager.Toast.InstallFromFileSuccess" xml:space="preserve">
<value>Пакет зависимостей «{0}» установлен</value>
</data>
<data name="DependencyManager.Error.InvalidPackage" xml:space="preserve">
<value>Выбранный файл не является допустимым пакетом зависимостей или повреждён.</value>
</data>
<data name="DependencyManager.Error.AccessDenied" xml:space="preserve">
<value>Не удалось прочитать пакет или записать данные зависимостей. Проверьте разрешения хранилища.</value>
</data>
<data name="DependencyManager.Error.FileUnavailable" xml:space="preserve">
<value>Выбранный пакет больше недоступен. Выберите файл ещё раз.</value>
</data>
<data name="DependencyManager.Error.Storage" xml:space="preserve">
<value>Не удалось установить пакет. Проверьте свободное место и не используется ли файл.</value>
</data>
<data name="DependencyManager.Toast.Uninstalled" xml:space="preserve">
<value>Удалено: {0}</value>
Expand Down
28 changes: 26 additions & 2 deletions OpenUtauMobile/Assets/Lang/Strings.uk.resx
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,12 @@
<data name="DependencyManager.Title" xml:space="preserve">
<value>Керування залежностями</value>
</data>
<data name="LoadingPopup.Title" xml:space="preserve">
<value>Будь ласка, зачекайте</value>
</data>
<data name="LoadingPopup.DefaultMessage" xml:space="preserve">
<value>Виконується фонова операція…</value>
</data>
<data name="DependencyManager.Refresh" xml:space="preserve">
<value>Оновити список</value>
</data>
Expand Down Expand Up @@ -864,8 +870,26 @@
<data name="DependencyManager.Toast.InstalledListFailed" xml:space="preserve">
<value>Не вдалося завантажити список встановлених: {0}</value>
</data>
<data name="DependencyManager.Toast.InstallFromFileNotImpl" xml:space="preserve">
<value>Встановлення з файла ще не реалізовано</value>
<data name="DependencyManager.FilePicker.SelectPackage" xml:space="preserve">
<value>Виберіть пакет залежностей</value>
</data>
<data name="DependencyManager.Loading.InstallFromFile" xml:space="preserve">
<value>Встановлення пакета залежностей…</value>
</data>
<data name="DependencyManager.Toast.InstallFromFileSuccess" xml:space="preserve">
<value>Пакет залежностей «{0}» встановлено</value>
</data>
<data name="DependencyManager.Error.InvalidPackage" xml:space="preserve">
<value>Вибраний файл не є припустимим пакетом залежностей або пошкоджений.</value>
</data>
<data name="DependencyManager.Error.AccessDenied" xml:space="preserve">
<value>Не вдалося прочитати пакет або записати дані залежностей. Перевірте дозволи сховища.</value>
</data>
<data name="DependencyManager.Error.FileUnavailable" xml:space="preserve">
<value>Вибраний пакет більше недоступний. Виберіть файл ще раз.</value>
</data>
<data name="DependencyManager.Error.Storage" xml:space="preserve">
<value>Не вдалося встановити пакет. Перевірте вільне місце та чи не використовується файл.</value>
</data>
<data name="DependencyManager.Toast.Uninstalled" xml:space="preserve">
<value>Видалено {0}</value>
Expand Down
28 changes: 26 additions & 2 deletions OpenUtauMobile/Assets/Lang/Strings.zh-Hans.resx
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,12 @@
<data name="DependencyManager.Title" xml:space="preserve">
<value>依赖项管理</value>
</data>
<data name="LoadingPopup.Title" xml:space="preserve">
<value>请稍候</value>
</data>
<data name="LoadingPopup.DefaultMessage" xml:space="preserve">
<value>正在进行后台操作…</value>
</data>
<data name="DependencyManager.Refresh" xml:space="preserve">
<value>刷新列表</value>
</data>
Expand Down Expand Up @@ -882,8 +888,26 @@
<data name="DependencyManager.Toast.InstalledListFailed" xml:space="preserve">
<value>加载已安装列表失败: {0}</value>
</data>
<data name="DependencyManager.Toast.InstallFromFileNotImpl" xml:space="preserve">
<value>从文件安装功能待实现</value>
<data name="DependencyManager.FilePicker.SelectPackage" xml:space="preserve">
<value>选择依赖包</value>
</data>
<data name="DependencyManager.Loading.InstallFromFile" xml:space="preserve">
<value>正在安装依赖包…</value>
</data>
<data name="DependencyManager.Toast.InstallFromFileSuccess" xml:space="preserve">
<value>已安装依赖包“{0}”</value>
</data>
<data name="DependencyManager.Error.InvalidPackage" xml:space="preserve">
<value>所选文件不是有效的依赖包,或文件已损坏。</value>
</data>
<data name="DependencyManager.Error.AccessDenied" xml:space="preserve">
<value>无法读取依赖包或写入依赖项存储,请检查存储权限。</value>
</data>
<data name="DependencyManager.Error.FileUnavailable" xml:space="preserve">
<value>所选依赖包已不可用,请重新选择文件。</value>
</data>
<data name="DependencyManager.Error.Storage" xml:space="preserve">
<value>无法安装依赖包,请检查可用存储空间以及文件是否被占用。</value>
</data>
<data name="DependencyManager.Toast.Uninstalled" xml:space="preserve">
<value>已卸载 {0}</value>
Expand Down
41 changes: 41 additions & 0 deletions OpenUtauMobile/Controls/LoadingPopup.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:OpenUtauMobile.ViewModels"
xmlns:theme="clr-namespace:OpenUtauMobile.Themes.OpenUtauMobile.Runtime"
mc:Ignorable="d"
x:Class="OpenUtauMobile.Controls.LoadingPopup"
x:DataType="vm:LoadingPopupViewModel"
d:DataContext="{d:DesignInstance Type=vm:LoadingPopupViewModel, IsDesignTimeCreatable=False}"
Classes="PopupDialogRoot">

<Border Classes="PopupDialogSurface">
<DockPanel>
<Border Classes="PopupTitleBar"
DockPanel.Dock="Top">
<TextBlock Text="{DynamicResource LoadingPopup.Title}"
Classes="PopupTitle" />
</Border>

<StackPanel Margin="{x:Static theme:ThemeSemLayoutTokens.InsetCardComfortable}"
Spacing="{x:Static theme:ThemeSemLayoutTokens.SpaceMD}">
<TextBlock Text="{Binding Message}"
FontSize="{x:Static theme:ThemeSemTypographyTokens.BodyMSize}"
Foreground="{DynamicResource Sem.Color.OnSurface}"
TextWrapping="Wrap"
TextAlignment="Center" />

<ProgressBar Value="{Binding Progress}"
IsIndeterminate="{Binding IsIndeterminate}"
HorizontalAlignment="Stretch" />

<TextBlock Text="{Binding ProgressText}"
IsVisible="{Binding IsIndeterminate, Converter={x:Static BoolConverters.Not}}"
FontSize="{x:Static theme:ThemeSemTypographyTokens.LabelMSize}"
Foreground="{DynamicResource Sem.Color.Primary}"
HorizontalAlignment="Center" />
</StackPanel>
</DockPanel>
</Border>
</UserControl>
11 changes: 11 additions & 0 deletions OpenUtauMobile/Controls/LoadingPopup.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace OpenUtauMobile.Controls;

public partial class LoadingPopup : PopupDialogControl
{
protected override PopupDialogWidthPreset WidthPreset => PopupDialogWidthPreset.Compact;

public LoadingPopup()
{
InitializeComponent();
}
}
Loading