feat(playground): save & load decks from the filesystem#89
Open
tilucasoli wants to merge 4 commits into
Open
Conversation
Give the playground editor a real .md file behind it, backed by continuous auto-save, so edits survive refresh/relaunch. - DeckFileStore: storage interface + native (dart:io + path_provider + file_picker) impl and web stub, via conditional export (mirrors the AssetCacheStore pattern). AppSettingsStore persists the last-opened path. - DeckFileController: debounced auto-save, file watching with self-write filtering (content hash), external-wins auto-reload, delete/move -> unbind + warn (keeps in-memory content), and new/open/launch flows (reopen last file, fall back to a seeded default in ~/Documents/SuperDeck/). - Editor integration: TextEditorController gains an onMarkdownChanged sink; reloads drive the existing MarkdownEditor.replaceMarkdown port. New EditorBootstrap awaits initialize() and seeds the editor with the file. - UI: editor header (filename + New/Open + unbound warning), new-deck dialog with collision re-prompt, and Cmd+N / Cmd+O shortcuts. - Store/settings are injected via AppProviders so tests use in-memory fakes. Desktop-only; the storage interface leaves room for a web impl later. Tests: DeckFileController logic + native store I/O. Closes #88. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Visit the preview URL for this PR (updated for commit 5205063): https://superdeck-dev--pr89-tilucasoli-save-load-7n0gtvwj.web.app (expires Fri, 07 Aug 2026 13:41:51 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: bd68fc230762285849207e7e120aaf87cd4ca2f9 |
- Cancel the pending debounce before the unchanged-content early return so a revert-to-saved within the debounce window no longer writes stale content. - Replace the 8-char hash self-write filter with a direct content comparison, removing a collision path that could drop a genuine external edit and the full-document hash recomputed on every keystroke. - Advance the synced marker only after a successful write, so a failed auto-save no longer desyncs the self-write filter. - Guard pickDeckFile against an empty/odd picker result instead of letting `.single` throw a StateError that escapes openDeck's catch. - Add the user-selected files entitlement so the sandboxed macOS app can open the native file picker. - Add regression tests for the revert-in-debounce and failed-write cases. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- New/Open are both ghost buttons, grouped and left-aligned in the bar. - The filename bar now sits on top of the TextEditor pane instead of spanning the full width above the sidebars. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the filename + New/Open bar into the TextEditor's HeroCard, above the SuperEditor, so it sits directly on top of the editing surface. The bar keeps the filename on the left and the ghost New/Open actions on the right. Drop the now-unused header from EditorPage and its resize-handle offsets. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #88.
Gives the playground editor a real
.mdfile behind it, backed by continuous auto-save, so edits survive refresh/relaunch. A deck is now a file the user owns, living in~/Documents/SuperDeck/. Desktop-only (macOS); the storage interface leaves room for a web impl later.What's included
Storage layer (
playground/lib/core/data/data_sources/) — mirrors the existingAssetCacheStoreinterface + conditional-import native-impl pattern:DeckFileStore(_base/_io/_stub+ conditional export):read/write/createDeck/exists/pickDeckFile/watch/decksDirectoryPath. Native impl usesdart:io+path_provider+file_picker; watching reuses core'sFileWatcher. Web stub throws.AppSettingsStore: persists the single last-opened path as JSON in the app-support dir (no newshared_preferencesdependency).Binding controller —
features/editor/domain/stores/deck_file_controller.dart(ChangeNotifier):generateValueHash) so auto-save doesn't loop.new/open/initialize(reopen last file, fall back to a seeded default deck).Editor integration —
TextEditorControllergains anonMarkdownChangedsink (from its existing single chokepoint); reloads drive the existingMarkdownEditor.replaceMarkdownport. NewEditorBootstrapawaitsinitialize()before mounting, seeding the editor with the loaded content. Store/settings are injected viaAppProvidersso tests supply in-memory fakes.UI — editor header (filename + New/Open + unbound warning banner), new-deck dialog with collision re-prompt, and ⌘N / ⌘O shortcuts.
Acceptance criteria
.md(debounced); no manual save action.New(⌘N) prompts for a name, creates<name>.md, seeds a one-slide starter, rebinds; collisions re-prompt.Open(⌘O) opens a.mdfrom anywhere and rebinds.Impacted packages
packages/playgroundonly. Addspath_provider+file_pickerdeps (and two test-only platform-interface deps).GeneratedPluginRegistrant.swiftupdated to registerfile_pickeron macOS.Verification
fvm flutter analyze— clean.fvm flutter test— 114 tests pass, incl. 13 controller-logic tests (debounce, self-write filtering, external reload without looping, delete→unbind, new/open, collision) and 6 native-store I/O tests.fvm flutter build macos --debug— succeeds.🤖 Generated with Claude Code