Fix #13113: add default frame rate setting to options - #13281
Conversation
93ac231 to
49357e0
Compare
|
AUDIT 13281 (issue #13113): PASS-WITH-WARNINGS -> follow-up committed (49357e0)
|
|
/copilot-review |
49357e0 to
deb99c6
Compare
|
AUDIT #13281 (issue #13113): FAIL on first pass → FIXED in deb99c6
|
|
/copilot-review |
deb99c6 to
4cc5fe6
Compare
|
FINAL AUDIT #13281 (issue #13113) — FAIL → FIXED in 4cc5fe6
|
niksedk
left a comment
There was a problem hiding this comment.
Request changes
Restoring the lost SE4 control is the right call and the Options wiring looks fine. Three things.
The libse bridge claim in Follow-up 2 is backwards
at startup libse's own load syncs
CurrentFrameRate = DefaultFrameRate(GeneralSettings.cs:63) after the DefaultFrameRate bridge (line 622), so the default still applies
GeneralSettings.cs:60-63 is the constructor:
public GeneralSettings()
{
DefaultFrameRate = 23.976;
CurrentFrameRate = DefaultFrameRate;It runs when Configuration.Settings is first constructed, which cannot be after UpdateLibSeSettings() — that method dereferences Configuration.Settings.General to do the bridging, so the ctor has already run by then. And even in the ordering the note assumes, the ctor seeds CurrentFrameRate from libse's own hard-coded 23.976, not from the user's value.
Net effect: with CurrentFrameRate removed from the bridge and nothing else writing it at startup, Configuration.Settings.General.CurrentFrameRate stays 23.976 no matter what the user picks. The libse consumers the PR itself names — TimedTextImscRosetta, TimeCode frame formatting — therefore ignore the new setting until a video is opened or the toolbar combo is touched. That is exactly the no-video-loaded case the reporter described.
The concern that motivated removing the line (a stale UI value clobbering the parser's rate on SaveSettings) is legitimate. The fix is to seed libse's CurrentFrameRate once at load rather than to stop bridging it at all — e.g. set it inside LoadSettings next to the existing UI-side seed, and leave SaveSettings alone.
The setting needs a restart to do anything
SettingsViewModel.SaveSettings writes general.DefaultFrameRate but not general.CurrentFrameRate, and Se.LoadSettings only runs at startup. So the user changes the option, closes Options, and nothing happens until they restart — which the manual verification path confirms (step 4 is "Restart SE"). Please also apply it to the live CurrentFrameRate on save when no video is loaded, or the setting looks broken on first use.
Don't hand-edit English.json
src/ui/Assets/Languages/English.json is generated from the Language*.cs classes — the class is the source of truth. LanguageSettings.cs is edited correctly here; the English.json hunk should be dropped and the file regenerated.
Minor
The toolbar combo reads Se.Settings.General.CurrentFrameRate once in the MainViewModel constructor, so changing the option mid-session leaves the toolbar showing the old value even after the underlying setting changes. Consistent with the restart-required behaviour above, and it would be fixed by the same change.
4cc5fe6 to
887a210
Compare
|
Fixed in 887a210. You were right about the constructor order. The final behavior is now split clearly:\n\n- On startup, LoadSettings sets both UI and libse current frame rate from the user's default.\n- Later SaveSettings calls do not overwrite a rate read from a video.\n- Changing the option with no video loaded applies at once and updates the toolbar.\n- If a video is loaded, its rate stays unchanged.\n- The generated English.json hunk was removed.\n\nReal checks: clean UI build EXIT:0; focused startup/save probe 2/2 PASS (startup default 25 reaches both stores; parser 29.97 survives a later settings save). One commit, Ironship. |
|
FINAL AUDIT #13281 for issue #13113: PASS\n\nFresh head: 887a210; one Ironship commit; CI success. The final implementation now has explicit ownership of the live rate:\n- startup seeds UI and libse once from DefaultFrameRate;\n- Options updates UI/libse immediately only when no video is loaded and refreshes the toolbar;\n- video-open and toolbar paths remain the writers for video/session-derived rates;\n- UpdateLibSeSettings bridges DefaultFrameRate only, so later SaveSettings cannot clobber a parser-derived CurrentFrameRate.\n\nThe previously reproduced 29.97 -> 24 regression path is closed, the no-video startup path is covered, the generated English.json change is gone, and no duplicate/dead writer remains. Verification: clean UI build EXIT:0; startup/save focused probe 2/2 PASS; current CI success. |
|
/copilot-review |
887a210 to
cded430
Compare
|
Rebased the single Ironship commit onto current main (e44a388). The only conflict was the BatchConverter frame-rate fallback comment: the upstream fixed/video/project-rate selection remains intact, and the final invalid-rate fallback now correctly refers to the restored Default frame rate option. No behavior was dropped. Fresh head: cded430. Verification: clean non-incremental UI build EXIT:0; BatchConverterBeautifyTimeCodesTests 3/3 PASS; full UITests 1483 passed, 0 failed, 1 skipped; current GitHub CI PASS. |
niksedk
left a comment
There was a problem hiding this comment.
Comment — the code is right now; the remaining question is product, not code
All three of my earlier points are fixed, and the libse one is fixed the right way:
- The startup seed is outside
UpdateLibSeSettings.Configuration.Settings.General.CurrentFrameRateis now set once inLoadSettingsafter the bridge call, with a comment saying why it must not live inUpdateLibSeSettings(whichSaveSettingsalso calls). That resolves the contradiction in the previous revision, where libse would have kept 23.976 regardless of the setting while the note claimed the constructor ran afterwards. - The setting applies without a restart.
SaveSettingsnow writesgeneral.CurrentFrameRate,Configuration.Settings.General.CurrentFrameRateand the toolbar'sSelectedFrameRatewhen_mainViewModel is { IsVideoLoaded: false }— correctly gated so it cannot stomp a rate the parser derived from an open video, and null-safe via the pattern match. English.jsonis no longer hand-edited; onlyLanguageSettings.cs.
The decision I would not make for you
Settings.General.CurrentFrameRate = Settings.General.DefaultFrameRate;in LoadSettings means the frame rate a user picks from the toolbar is no longer remembered across restarts — the Options value always wins at startup. #13113 asked for either a configurable default or remembering the last used rate; this implements the first and deliberately removes the second. That is defensible and the PR is honest about it, but it is a behaviour change for every existing user, not just the reporter, and it is not something the diff can justify on its own.
Smaller
- No test. An earlier revision had a probe that reproduced the
SaveSettingsclobbering bug — exactly the regression this PR has already had once.Se.LoadSettingsseeding libse, andSaveSettingsnot overwriting a video-derived rate, are both plain state checks against a temp settings file with no UI involved. - The combo is not editable, so a rate like 23.98 can only appear if it is already in
Settings.json.FrameRates.Insert(0, …)handles displaying such a value but there is no way to enter one. Fine if intentional, worth a line in the description if so.
cded430 to
f7cb35c
Compare
|
Addressed in f7cb35c — both remaining points: 1. Tests are now committed (
Both are RED on the pre-fix behavior (stale value survives load / save overwrites 29.97) and GREEN on the current head. 2/2 PASS; neighboring continuation-style round-trip tests 4/4 PASS. 2. Non-editable combo — deliberate; documented in the PR description: a rate outside the presets (e.g. 23.98) can only appear if already present in Verification: clean non-incremental UI build EXIT:0, fresh GitHub CI PASS on the new SHA. |
Problem
Fixes #13113 — on macOS (and other platforms) SubtitleEdit 5.x always opens files at the default 23.976 fps and there is no way to change the default frame rate in the UI.
The setting value exists (
Se.Settings.General.DefaultFrameRate,src/ui/Logic/Config/SeGeneral.cs:40, default 23.976) but no UI control reads or writes it in SE 5.x — a comment insrc/ui/Features/Tools/BatchConvert/BatchConverter.cs:2112confirms: "nothing in the UI ever assigns it". SE 4.0.16 had a "Default frame rate" combo box in Options (src/ui/Forms/Options/Settings.Designer.csin tag 4.0.16, savinggs.DefaultFrameRate = outFrameRate); the control was lost in the 5.x rewrite.Fix
Restore the missing UI control: add a "Default frame rate" combo box to Options → General (next to "Use frame mode"), wired to
Se.Settings.General.DefaultFrameRate:src/ui/Features/Options/Settings/SettingsPage.cs— newSettingsItemwith aComboBoxbound toFrameRates/SelectedDefaultFrameRate(same pattern as the existing DefaultEncoding combo).src/ui/Features/Options/Settings/SettingsViewModel.cs—FrameRateslist (23.976/24/25/29.97/30/50/59.94/60/120), load of the current value (inserted into the list when it is not one of the presets), and save back togeneral.DefaultFrameRate.src/ui/Logic/Config/Se.cs—LoadSettings()re-derives the UI-sideCurrentFrameRate = DefaultFrameRate, bridges the default into libse, and then seeds libse's liveCurrentFrameRateonce at startup.SaveSettings()deliberately does not copy the UI-side current rate, so later settings saves cannot overwrite a frame rate supplied by a video parser.src/ui/Logic/Config/Language/Options/LanguageSettings.cs— "Default frame rate" resource string (the generatedEnglish.jsonfile is not hand-edited).CurrentFrameRatesemantics: at startup it now comes from the configurable default; opening a video still overrides it with the video's actual frame rate (MainViewModel.cs:19224), and the toolbar combo still overrides it for the session.Verification
dotnet build src/ui/UI.csproj -v q -nologo— EXIT:0, 0 warnings, 0 errors (build.log attached in run)tests/UI/Logic/Config/FrameRateSettingsTests.cs):LoadSettings_SeedsCurrentFrameRateFromDefault— a persisted stale 23.976 current rate is replaced by the configured default (25) on load, in both the UI settings store and libse;SaveSettings_DoesNotOverwriteVideoDerivedFrameRate— a parser-provided 29.97 in libse survives a laterSaveSettings(temp).Notes
CurrentFrameRatesemantics, which is deliberately NOT done.Settings.json;FrameRates.Insert(0, …)displays such a value but there is no way to type a custom one. Deliberate, matching the same pattern as the other frame-rate combos in the app.GetMediaInformation(MainViewModel.cs:19224) is only hit when a video is loaded but its frame rate cannot be read; left untouched to keepCurrentFrameRatesemantics stable.Follow-up (audit-driven, commit deb99c6)
Independent audit found the setting was persisted but never applied at startup:
Settings.jsonstorescurrentFrameRate, and it was restored over the constructor'sCurrentFrameRate = DefaultFrameRateon every load. Fixed:Se.cs— after settings load,CurrentFrameRateis re-seeded fromDefaultFrameRate(the explicit setting now wins at startup; opening a video still overrides it with the video's real frame rate, and the toolbar combo still overrides it for the session).MainViewModel.cs— the toolbar frame-rate combo now shows the configured default instead of a hardcoded 23.976 when no video is loaded (custom values are added to the combo list, same pattern as the Options combo).BatchConverter.cs— comment updated (it claimed no UI ever assignsDefaultFrameRate; that is no longer true).Deliberate behavior change: the last-used frame rate is no longer restored across restarts; the "Default frame rate" setting is authoritative at startup (the issue asked for exactly this).
Follow-up 2 + maintainer review (final commit 887a210)
The final deep audit found that copying
CurrentFrameRateinsideUpdateLibSeSettings()made everySe.SaveSettings()overwrite a parser-provided rate (for example 29.97) with stale UI session state (for example 24). The first follow-up removed that copy, but maintainer review correctly found that libse then stayed at its constructor default (23.976) at startup.Final split of responsibilities:
LoadSettings()seeds both the UI-side and libse live current rate from the user's configured default exactly once at startup.UpdateLibSeSettings()bridgesDefaultFrameRate, but does not overwrite the live current rate during later settings saves.English.jsonhunk was removed;LanguageSettings.csremains the source of truth.Verification on 887a210 (real runs):
dotnet build src/ui/UI.csproj --no-incremental— EXIT:0;SaveSettings(temp).