Skip to content

feat(ui): add a settings window - #25

Merged
CoderDayton merged 30 commits into
mainfrom
feat/settings-ui
Oct 17, 2026
Merged

CoderDayton merged 30 commits into
mainfrom
feat/settings-ui

Conversation

@CoderDayton

Copy link
Copy Markdown
Owner

Adds a settings window, so config.yaml and fflags.json can be changed without editing them by hand.

What it does

  • Opens from the app menu (right-click Nightcap, then Settings) or with mocktail --settings. The Flatpak uses flatpak run io.github.CoderDayton.nightcap --settings.
  • Has a row for every config.yaml setting, grouped into Graphics, Input, Performance, Audio, Network, Discord, Fleasion and Advanced pages. Advanced includes an editor for fflags.json.
  • Saves each change at once and keeps the file's comments and layout. It refuses a value Nightcap would not start with, and Undo takes back the last change.
  • Gives a reset button to any row that differs from its default. Rows a switched-off block makes useless are greyed out.
  • If Nightcap is running, offers to restart it with the same arguments, environment and folder. Restart is off in the Flatpak, where the window cannot reach the game.
  • The loading window and the crash dialog now use Nightcap's app id, so docks show them under Nightcap's icon.

Testing

  • ctest: 1688 of 1688 pass in a Debug build.
  • Release build set up like CI, under xvfb-run: 1685 of 1685 pass. The 3 GlesTextOverlayRenderingTest tests crash under xvfb on my NVIDIA machine, pass on a real display, and this branch does not touch them.
  • The CI contract checks pass: shell syntax, JSON, and the four packaging contract tests.
  • Checked by hand: every page on Broadway, Restart Now on a native install, and the settings window in a locally built Flatpak.

make flatpak-build and --no-install build without installing. The packaging test no longer finds a flatpak-builder installed on the host.
Sets and unsets one key by editing only its bytes. Each result is parsed again and refused if any other setting changed.
A save is refused when the loader rejects the new text or the file changed on disk since it was read.
Rows without a working control yet are shown grayed out.
Text rows save on Enter and have a button that restores the default.
The editor saves only text that the FFlag loader accepts.
The switch writes touch into the device block, since the loader refuses input.touch_enabled beside a device key.

The editor asks before dropping unsaved text, keeps undo from clearing the file's text, puts the cursor on a JSON fault, names the flag at fault, refuses a flag listed twice, and does not open a file that is not UTF-8 or is over the 64 KiB read limit.
The names come from SDL, which is what Nightcap picks a device by.
Undo puts config.yaml back as it was before the last saved change, and refuses when the file was edited by hand since.
- Add rows for the device, window, proxy, Fleasion, update, runtime and
  device identity keys, so every config.yaml setting has one.
- Offer to restart a running Nightcap after a change, with the options and
  environment it was started with. Off in Flatpak.
- Show a reset button and per-page counts for settings changed from their
  defaults, with a tighter sidebar and a full-width notice bar.
- Grey out rows a switched-off block or the system proxy leaves without
  effect.
- Show "Off" for a memory limit of 0.
- Explain the Discord placeholders, the application ID, the CA bundle and
  the Roblox library under their group titles.
- Merge the one-row mouse and touch groups, drop the repeated Fleasion
  heading, and hide the pencil on rows with a file picker.
- Remove the changed chip and the sidebar counts.
- Show a row's reset button whenever it differs from its default.
- Write an empty mapping when a change leaves config.yaml without keys,
  so resetting the last setting no longer fails to load.
- Grey out the proxy port while Fleasion routes through the hosts file.
- Explain the empty Fleasion CA certificate under a Connection heading.
- Say that both download sources pick the same sources for now.
- Restart keeps Nightcap running when its launch cannot be read, starts the
  new one in the old one's folder, resets ignored signals, and waits 2 minutes.
- Number rows save once stepping stops; other saves, Undo, Restart and close flush it.
- Cache config values per document text and scan audio devices once.
- Restart closes the exact instance it read, reports an unreachable one
  accurately, and still starts when the old folder is gone.
- Save a stepped value without refreshing rows; route every file change
  through EditDocument and cancel the timer on destroy.
- Share the app id constant, return cached config values by reference, and
  fix Release-only warnings.
@CoderDayton
CoderDayton merged commit f655a75 into main Oct 17, 2026
6 checks passed
@CoderDayton
CoderDayton deleted the feat/settings-ui branch October 17, 2026 01:52
randomstuffhere1 added a commit to randomstuffhere1/nightcap-enhanced that referenced this pull request Oct 17, 2026
Our settings window was an independent implementation that wrote a
config.ui.yaml sidecar next to config.yaml and covered 25 curated keys.
coderdayton/nightcap's window (CoderDayton#25) is the same kind of separate
mocktail_settings binary but edits config.yaml in place, keeps comments,
covers every key, and adds an fflags.json editor, audio-device pickers,
the config folder, per-row reset and a restart of a running instance.

Replace ours with theirs and remove the sidecar machinery it made
redundant: ui_config_overrides.{cc,h}, sibling_executable.{cc,h}, the
config.ui.yaml merge in LoadRuntimeConfig, the separate
nightcap-settings.desktop entry and their tests. config.yaml is now the
only file the window touches.

Port our fork's own settings back in as rows on theirs' model:
graphics.quality, graphics.pipeline_cache, performance.texture_memory_mb,
performance.small_texture_upscale, audio.buffer_samples,
window.close_on_leave and integrations.server_location_indicator, plus
angle-swiftshader on the backend choice. compatibility.desktop_playability
is already folded into theirs' device preset, so it needs no row.

Also drop our early-return on --settings so theirs' "used on its own"
validation applies.

Verified: mocktail, mocktail_settings and every test target build;
settings_model/runtime_config_editor/runtime_config_store/
settings_launcher/command_line/runtime_config_file/failure_dialog/
single_instance_lock/client_settings_service/native_update and the
packaging contract scripts pass. RunningInstanceTest's
StartDetachedDoesNotPassOnIgnoredSignals fails only because this host's
/bin/sh is bash, which ignores SIGQUIT for script files; upstream CI runs
dash, where it passes.
randomstuffhere1 added a commit to randomstuffhere1/nightcap-enhanced that referenced this pull request Oct 17, 2026
Adopt upstream's settings window (CoderDayton#25) and retire ours. Our window wrote a
config.ui.yaml sidecar and covered 25 curated keys; upstream's edits
config.yaml in place, keeps comments and layout, covers every setting, and
adds an fflags.json editor, audio-device pickers, the config folder,
per-row reset, and a restart of a running instance with its own options
and environment.

Remove what the sidecar made redundant: ui_config_overrides.{cc,h},
sibling_executable.{cc,h}, the config.ui.yaml merge in LoadRuntimeConfig,
the separate nightcap-settings.desktop entry and their tests. config.yaml
is now the only file the window touches.

Port our fork's own settings back in as rows on upstream's model:
graphics.quality, graphics.pipeline_cache, performance.texture_memory_mb,
performance.small_texture_upscale, audio.buffer_samples,
window.close_on_leave and integrations.server_location_indicator, plus
angle-swiftshader on the backend choice. compatibility.desktop_playability
is already folded into upstream's device preset, so it needs no row.

Also drop our early-return on --settings so upstream's "used on its own"
validation applies.

Verified: every target builds; settings_model/runtime_config_editor/
runtime_config_store/settings_launcher/command_line/runtime_config_file/
failure_dialog/single_instance_lock/client_settings_service/native_update
and the packaging contract scripts pass. RunningInstanceTest's
StartDetachedDoesNotPassOnIgnoredSignals fails only because this host's
/bin/sh is bash, which ignores SIGQUIT for script files; upstream CI runs
dash, where it passes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant