From 9571ead6ce865a70184d1018fcc0e29939bc6556 Mon Sep 17 00:00:00 2001 From: niksedk Date: Wed, 8 Jul 2026 07:21:21 +0200 Subject: [PATCH] Point sync via other: restore Apply and Find text buttons (#12262) The Avalonia "Point sync via another subtitle..." dialog was missing the Apply button and the two "Find text..." buttons present in SE 4. - Apply re-previews the synced timings in the left grid without closing, recomputing from the original timings so repeated clicks don't stack. - OK now also syncs from the original snapshot, avoiding a double-apply after Apply was used. - Find text opens the shared FindTextWindow for the main and the other subtitle and selects the matching line (reuses the VisualSync pattern). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../PointSyncViaOtherViewModel.cs | 61 ++++++++++++++++++- .../PointSyncViaOtherWindow.cs | 34 ++++++++++- 2 files changed, 91 insertions(+), 4 deletions(-) diff --git a/src/ui/Features/Sync/PointSyncViaOther/PointSyncViaOtherViewModel.cs b/src/ui/Features/Sync/PointSyncViaOther/PointSyncViaOtherViewModel.cs index c17c55021d0..b4d4f1b8b9d 100644 --- a/src/ui/Features/Sync/PointSyncViaOther/PointSyncViaOtherViewModel.cs +++ b/src/ui/Features/Sync/PointSyncViaOther/PointSyncViaOtherViewModel.cs @@ -7,6 +7,7 @@ using Nikse.SubtitleEdit.Core.SubtitleFormats; using Nikse.SubtitleEdit.Features.Main; using Nikse.SubtitleEdit.Features.Shared; +using Nikse.SubtitleEdit.Features.Shared.FindText; using Nikse.SubtitleEdit.Logic; using Nikse.SubtitleEdit.Logic.Config; using Nikse.SubtitleEdit.Logic.Media; @@ -40,6 +41,7 @@ public partial class PointSyncViaOtherViewModel : ObservableObject private readonly IWindowService _windowService; private string _videoFileName; + private List _originalSubtitles; public PointSyncViaOtherViewModel(IFileHelper fileHelper, IWindowService windowService) { @@ -53,12 +55,14 @@ public PointSyncViaOtherViewModel(IFileHelper fileHelper, IWindowService windowS FileNameOther = string.Empty; _videoFileName = string.Empty; SyncedSubtitles = new List(); + _originalSubtitles = new List(); } public void Initialize(List subtitles, string videoFileName, string fileName) { Subtitles.Clear(); Subtitles.AddRange(subtitles); + _originalSubtitles = subtitles.Select(s => new SubtitleLineViewModel(s)).ToList(); FileName = fileName; _videoFileName = videoFileName; @@ -152,10 +156,65 @@ private void DeleteSelectedPointSync() IsOkEnabled = SyncPoints.Count > 0; } + [RelayCommand] + private void Apply() + { + if (SyncPoints.Count == 0) + { + return; + } + + // Re-preview from the original timings so repeated Apply clicks don't stack. + var synced = PointSyncer.PointSync(_originalSubtitles, SyncPoints.ToList()); + for (var i = 0; i < Subtitles.Count && i < synced.Count; i++) + { + Subtitles[i].StartTime = synced[i].StartTime; + Subtitles[i].EndTime = synced[i].EndTime; + } + } + + [RelayCommand] + private async Task FindTextLeft() + { + if (Window == null) + { + return; + } + + var result = await _windowService.ShowDialogAsync(Window, vm => + { + vm.Initialize(Subtitles.ToList(), string.Format(Se.Language.General.FindTextX, FileName)); + }); + + if (result.OkPressed && result.SelectedSubtitle != null) + { + SelectedSubtitle = result.SelectedSubtitle; + } + } + + [RelayCommand] + private async Task FindTextOther() + { + if (Window == null || Othersubtitles.Count == 0) + { + return; + } + + var result = await _windowService.ShowDialogAsync(Window, vm => + { + vm.Initialize(Othersubtitles.ToList(), string.Format(Se.Language.General.FindTextX, FileNameOther)); + }); + + if (result.OkPressed && result.SelectedSubtitle != null) + { + SelectedOtherSubtitle = result.SelectedSubtitle; + } + } + [RelayCommand] private void Ok() { - SyncedSubtitles = PointSyncer.PointSync(Subtitles.ToList(), SyncPoints.ToList()); + SyncedSubtitles = PointSyncer.PointSync(_originalSubtitles, SyncPoints.ToList()); OkPressed = true; Close(); } diff --git a/src/ui/Features/Sync/PointSyncViaOther/PointSyncViaOtherWindow.cs b/src/ui/Features/Sync/PointSyncViaOther/PointSyncViaOtherWindow.cs index 2ae11df5f6e..6cebe819b9f 100644 --- a/src/ui/Features/Sync/PointSyncViaOther/PointSyncViaOtherWindow.cs +++ b/src/ui/Features/Sync/PointSyncViaOther/PointSyncViaOtherWindow.cs @@ -28,9 +28,10 @@ public PointSyncViaOtherWindow(PointSyncViaOtherViewModel vm) var controlView = MakeControlView(vm); var subtitleOtherView = MakeSubtitleOtherView(vm); + var buttonApply = UiUtil.MakeButton(Se.Language.General.Apply, vm.ApplyCommand).WithBindIsEnabled(nameof(vm.IsOkEnabled)); var buttonOk = UiUtil.MakeButtonOk(vm.OkCommand).WithBindIsEnabled(nameof(vm.IsOkEnabled)); var buttonCancel = UiUtil.MakeButtonCancel(vm.CancelCommand); - var panelButtons = UiUtil.MakeButtonBar(buttonOk, buttonCancel); + var panelButtons = UiUtil.MakeButtonBar(buttonApply, buttonOk, buttonCancel); var grid = new Grid { @@ -141,6 +142,19 @@ private static Grid MakeSubtitleView(PointSyncViaOtherViewModel vm) }; var labelFileName = UiUtil.MakeLabel(string.Empty).WithBindText(vm, nameof(vm.FileName)); + labelFileName.VerticalAlignment = VerticalAlignment.Center; + var buttonFindText = UiUtil.MakeButton(Se.Language.Sync.FindText, vm.FindTextLeftCommand); + buttonFindText.HorizontalAlignment = HorizontalAlignment.Right; + var panelHeader = new Grid + { + ColumnDefinitions = + { + new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }, + new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) }, + }, + }; + panelHeader.Add(labelFileName, 0, 0); + panelHeader.Add(buttonFindText, 0, 1); var fullTimeConverter = new TimeSpanToDisplayFullConverter(); var shortTimeConverter = new TimeSpanToDisplayShortConverter(); @@ -184,7 +198,7 @@ private static Grid MakeSubtitleView(PointSyncViaOtherViewModel vm) }; dataGrid.Bind(DataGrid.SelectedItemProperty, new Binding(nameof(vm.SelectedSubtitle))); - grid.Add(labelFileName, 0); + grid.Add(panelHeader, 0); grid.Add(UiUtil.MakeBorderForControlNoPadding(dataGrid), 1); return grid; @@ -209,11 +223,25 @@ private static Grid MakeSubtitleOtherView(PointSyncViaOtherViewModel vm) var buttonBrowseOther = UiUtil.MakeButtonBrowse(vm.BrowseOtherCommand); var labelOtherFileName = UiUtil.MakeLabel(string.Empty).WithBindText(vm, nameof(vm.FileNameOther)); + labelOtherFileName.VerticalAlignment = VerticalAlignment.Center; var panelOtherBrowse = new StackPanel { Orientation = Orientation.Horizontal, + VerticalAlignment = VerticalAlignment.Center, Children = { buttonBrowseOther, labelOtherFileName }, }; + var buttonFindTextOther = UiUtil.MakeButton(Se.Language.Sync.FindText, vm.FindTextOtherCommand); + buttonFindTextOther.HorizontalAlignment = HorizontalAlignment.Right; + var panelOtherHeader = new Grid + { + ColumnDefinitions = + { + new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }, + new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) }, + }, + }; + panelOtherHeader.Add(panelOtherBrowse, 0, 0); + panelOtherHeader.Add(buttonFindTextOther, 0, 1); var fullTimeConverter = new TimeSpanToDisplayFullConverter(); var shortTimeConverter = new TimeSpanToDisplayShortConverter(); @@ -257,7 +285,7 @@ private static Grid MakeSubtitleOtherView(PointSyncViaOtherViewModel vm) }; dataGridSubtitle.Bind(DataGrid.SelectedItemProperty, new Binding(nameof(vm.SelectedOtherSubtitle))); - grid.Add(panelOtherBrowse, 0); + grid.Add(panelOtherHeader, 0); grid.Add(UiUtil.MakeBorderForControlNoPadding(dataGridSubtitle), 1); return grid;