From c70153af5e76ef7d0e2fbf7c6b3365ef8800a719 Mon Sep 17 00:00:00 2001 From: MysticILD <173185810+MysticILD@users.noreply.github.com> Date: Sat, 16 May 2026 12:22:28 +0300 Subject: [PATCH 1/4] Add customizable Stop button behavior --- OpenUtau.Core/Util/Preferences.cs | 5 ++ OpenUtauMobile/Assets/Lang/Strings.en.resx | 15 ++++ OpenUtauMobile/Assets/Lang/Strings.ja.resx | 15 ++++ OpenUtauMobile/Assets/Lang/Strings.ru.resx | 15 ++++ OpenUtauMobile/Assets/Lang/Strings.uk.resx | 15 ++++ .../Assets/Lang/Strings.zh-Hans.resx | 15 ++++ OpenUtauMobile/ViewModels/EditorViewModel.cs | 76 ++++++++++++++++++- .../ViewModels/SettingsViewModel.cs | 52 +++++++++++++ OpenUtauMobile/Views/SettingsView.axaml | 26 +++++++ 9 files changed, 233 insertions(+), 1 deletion(-) diff --git a/OpenUtau.Core/Util/Preferences.cs b/OpenUtau.Core/Util/Preferences.cs index 704f53c..201dd6a 100644 --- a/OpenUtau.Core/Util/Preferences.cs +++ b/OpenUtau.Core/Util/Preferences.cs @@ -307,6 +307,11 @@ public class SerializablePreferences { /// 自动保存间隔,单位秒(仅在启用时生效)。 /// public int AutoSaveInterval = 120; + /// + /// Stop button behavior: 1 = StartTick -> SelectedPart -> 0 (default), + /// 2 = StartTick -> 0, 3 = Always 0. + /// + public int StopButtonBehavior = 1; #endregion } } diff --git a/OpenUtauMobile/Assets/Lang/Strings.en.resx b/OpenUtauMobile/Assets/Lang/Strings.en.resx index dcf5941..ccb6ee2 100644 --- a/OpenUtauMobile/Assets/Lang/Strings.en.resx +++ b/OpenUtauMobile/Assets/Lang/Strings.en.resx @@ -276,6 +276,21 @@ Smooth Scrolling + + Stop Button Behavior + + + Configure what happens when you press the stop button during and after playback. + + + Start Tick → Selected Part → 0 (Default) + + + Start Tick → 0 + + + Always Go to 0 + Render & Performance diff --git a/OpenUtauMobile/Assets/Lang/Strings.ja.resx b/OpenUtauMobile/Assets/Lang/Strings.ja.resx index 73abca1..eb06525 100644 --- a/OpenUtauMobile/Assets/Lang/Strings.ja.resx +++ b/OpenUtauMobile/Assets/Lang/Strings.ja.resx @@ -276,6 +276,21 @@ スムーズスクロール有効 + + 停止ボタンの動作 + + + 再生中および再生後に停止ボタンを押したときの動作を設定します。 + + + 開始位置 → 選択部分 → 0(デフォルト) + + + 開始位置 → 0 + + + 常に 0 に移動 + レンダーとパフォーマンス diff --git a/OpenUtauMobile/Assets/Lang/Strings.ru.resx b/OpenUtauMobile/Assets/Lang/Strings.ru.resx index 5395d71..e72197f 100644 --- a/OpenUtauMobile/Assets/Lang/Strings.ru.resx +++ b/OpenUtauMobile/Assets/Lang/Strings.ru.resx @@ -276,6 +276,21 @@ Плавная прокрутка + + Поведение кнопки Стоп + + + Настройка поведения кнопки остановки во время и после воспроизведения. + + + Начало → Выделенный фрагмент → 0 (По умолчанию) + + + Начало → 0 + + + Всегда к 0 + Рендеринг и производительность diff --git a/OpenUtauMobile/Assets/Lang/Strings.uk.resx b/OpenUtauMobile/Assets/Lang/Strings.uk.resx index e36f194..493d062 100644 --- a/OpenUtauMobile/Assets/Lang/Strings.uk.resx +++ b/OpenUtauMobile/Assets/Lang/Strings.uk.resx @@ -276,6 +276,21 @@ Плавне прокручування + + Поведінка кнопки Стоп + + + Налаштування поведінки кнопки зупинки під час та після відтворення. + + + Початок → Виділена партія → 0 (За замовчуванням) + + + Початок → 0 + + + Завжди до 0 + Рендеринг і продуктивність diff --git a/OpenUtauMobile/Assets/Lang/Strings.zh-Hans.resx b/OpenUtauMobile/Assets/Lang/Strings.zh-Hans.resx index 813ab8c..0d1c69f 100644 --- a/OpenUtauMobile/Assets/Lang/Strings.zh-Hans.resx +++ b/OpenUtauMobile/Assets/Lang/Strings.zh-Hans.resx @@ -276,6 +276,21 @@ 启用平滑自动翻页 + + 停止按钮行为 + + + 设置在播放期间和播放后按下停止按钮时的行为。 + + + 起始位置 → 选中部分 → 0(默认) + + + 起始位置 → 0 + + + 始终跳转到 0 + 渲染与性能 diff --git a/OpenUtauMobile/ViewModels/EditorViewModel.cs b/OpenUtauMobile/ViewModels/EditorViewModel.cs index 499756a..0eb6dc6 100644 --- a/OpenUtauMobile/ViewModels/EditorViewModel.cs +++ b/OpenUtauMobile/ViewModels/EditorViewModel.cs @@ -226,6 +226,8 @@ public class EditorViewModel : NavigateViewModelBase, ICmdSubscriber, IDisposabl // 最近一次来自回放流的等待标记(SetPlayPosTickNotification.waitingRendering) private bool _streamWaitingRender; + private int _stopSeekState; + // 随机数生成器 private Random Randomer { get; } = new(); @@ -254,13 +256,85 @@ public EditorViewModel(MainViewModel navigator, string path = "") : base(navigat { DocManager.Inst.ExecuteCmd(new SeekPlayPosTickNotification(PlaybackManager.Inst.StartTick, true)); } + + if (PlaybackManager.Inst.PlayingMaster || PlaybackManager.Inst.StartingToPlay) + { + _stopSeekState = 0; + } }).DisposeWith(_disposables); // 停止命令 StopCommand = ReactiveCommand.Create(() => { + bool wasPlaying = PlaybackManager.Inst.OutputActive || PlaybackManager.Inst.PlayingMaster; PlaybackManager.Inst.StopPlayback(); SyncPlaybackStateFromAuthority(); - DocManager.Inst.ExecuteCmd(new SeekPlayPosTickNotification(0)); + + int mode = Preferences.Default.StopButtonBehavior; + if (mode <= 0 || mode > 3) mode = 1; + + if (wasPlaying) + { + DocManager.Inst.ExecuteCmd(new SeekPlayPosTickNotification(PlaybackManager.Inst.StartTick)); + _stopSeekState = 1; + } + else + { + switch (mode) + { + case 2: + DocManager.Inst.ExecuteCmd(new SeekPlayPosTickNotification(0)); + _stopSeekState = 3; + break; + case 3: + DocManager.Inst.ExecuteCmd(new SeekPlayPosTickNotification(0)); + break; + default: + if (_stopSeekState <= 0) + { + int? selectedTick = null; + if (SelectedParts is { Count: > 0 } parts) + { + selectedTick = parts.Min(p => p.position); + } + + if (selectedTick.HasValue) + { + DocManager.Inst.ExecuteCmd(new SeekPlayPosTickNotification(selectedTick.Value)); + _stopSeekState = 2; + } + else + { + DocManager.Inst.ExecuteCmd(new SeekPlayPosTickNotification(0)); + _stopSeekState = 3; + } + } + else if (_stopSeekState == 1) + { + int? selectedTick = null; + if (SelectedParts is { Count: > 0 } parts) + { + selectedTick = parts.Min(p => p.position); + } + + if (selectedTick.HasValue) + { + DocManager.Inst.ExecuteCmd(new SeekPlayPosTickNotification(selectedTick.Value)); + _stopSeekState = 2; + } + else + { + DocManager.Inst.ExecuteCmd(new SeekPlayPosTickNotification(0)); + _stopSeekState = 3; + } + } + else + { + DocManager.Inst.ExecuteCmd(new SeekPlayPosTickNotification(0)); + _stopSeekState = 3; + } + break; + } + } }).DisposeWith(_disposables); // 工程信息编辑命令 EditBpmCommand = ReactiveCommand.CreateFromTask(EditBpmAsync); diff --git a/OpenUtauMobile/ViewModels/SettingsViewModel.cs b/OpenUtauMobile/ViewModels/SettingsViewModel.cs index 91d1935..9869ebd 100644 --- a/OpenUtauMobile/ViewModels/SettingsViewModel.cs +++ b/OpenUtauMobile/ViewModels/SettingsViewModel.cs @@ -81,6 +81,25 @@ public PianoKeyBehaviorOption(PianoKeyBehavior value, string displayName) } } +public enum StopButtonBehavior +{ + StartTickSelectedPartZero = 1, + StartTickZero = 2, + AlwaysZero = 3 +} + +public class StopButtonBehaviorOption +{ + public StopButtonBehavior Value { get; } + public string DisplayName { get; } + + public StopButtonBehaviorOption(StopButtonBehavior value, string displayName) + { + Value = value; + DisplayName = displayName; + } +} + /// 走带自动翻页行为选项(用于绑定到选择器)。 public class AutoScrollBehaviorOption { @@ -328,6 +347,20 @@ public class SettingsViewModel : NavigateViewModelBase, IDisposable [Reactive] public AutoScrollBehaviorOption? SelectedAutoScrollBehavior { get; set; } + // ── Edit & Behaviour: Stop Button ────────────────────────────── + /// List of available stop button actions. + public IReadOnlyList AvailableStopButtonBehaviors { get; } = + new List + { + new(StopButtonBehavior.StartTickSelectedPartZero, L.S("Settings.StopButton.StartTickSelectedPartZero")), + new(StopButtonBehavior.StartTickZero, L.S("Settings.StopButton.StartTickZero")), + new(StopButtonBehavior.AlwaysZero, L.S("Settings.StopButton.AlwaysZero")) + }; + + /// The currently selected behavior option for the Stop button. + [Reactive] + public StopButtonBehaviorOption? SelectedStopButtonBehavior { get; set; } + /// 回放刷新率(1-60)。 [Reactive] public int PlaybackRefreshRate { get; set; } @@ -551,6 +584,25 @@ await Task.Run(() => }) .DisposeWith(_disposables); + // Initializing Stop Button Behavior + int stopBehaviorVal = Preferences.Default.StopButtonBehavior; + StopButtonBehavior stopBehavior = stopBehaviorVal is >= 1 and <= 3 + ? (StopButtonBehavior)stopBehaviorVal + : StopButtonBehavior.StartTickSelectedPartZero; + SelectedStopButtonBehavior = AvailableStopButtonBehaviors.FirstOrDefault(b => b.Value == stopBehavior) + ?? AvailableStopButtonBehaviors[0]; + + // Monitor changes in the behavior of the Stop button and persist them to Preferences + this.WhenAnyValue(x => x.SelectedStopButtonBehavior) + .Skip(1) + .WhereNotNull() + .Subscribe(opt => + { + Preferences.Default.StopButtonBehavior = (int)opt.Value; + Preferences.Save(); + }) + .DisposeWith(_disposables); + // 编辑与行为:回放刷新率 / 立绘开关 / 撤销上限 PlaybackRefreshRate = Math.Clamp((int)Math.Round(Preferences.Default.PlaybackRefreshRate), 1, 60); ShowPortraitEnabled = Preferences.Default.ShowPortrait; diff --git a/OpenUtauMobile/Views/SettingsView.axaml b/OpenUtauMobile/Views/SettingsView.axaml index 85f8470..fd99bf6 100644 --- a/OpenUtauMobile/Views/SettingsView.axaml +++ b/OpenUtauMobile/Views/SettingsView.axaml @@ -468,6 +468,32 @@ + + + + + + + + + + + + + + + + + + + From 2e21f83c2fefdc659c74a904d3cdfb23a6d51dd8 Mon Sep 17 00:00:00 2001 From: MysticILD <173185810+MysticILD@users.noreply.github.com> Date: Sat, 16 May 2026 15:23:49 +0300 Subject: [PATCH 2/4] Update Settings layout --- OpenUtauMobile/Views/SettingsView.axaml | 554 ++++++++++-------------- 1 file changed, 221 insertions(+), 333 deletions(-) diff --git a/OpenUtauMobile/Views/SettingsView.axaml b/OpenUtauMobile/Views/SettingsView.axaml index fd99bf6..a5c2003 100644 --- a/OpenUtauMobile/Views/SettingsView.axaml +++ b/OpenUtauMobile/Views/SettingsView.axaml @@ -15,20 +15,13 @@ - - - - - - - -