| name | app-guide |
| description | Application overview for frename. Use when: orienting to the project for the first time, deciding which crate or module to touch, understanding what the app does end-to-end, looking up where a concept lives (tags, files, ordering, colors), or understanding keyboard shortcuts and the tag/file lifecycle.
|
| disable-model-invocation | false |
Application Overview — frename
WHEN to use this skill
- Orienting to the project for the first time
- Deciding which crate or module to touch for a given change
- Understanding what the app does end-to-end
- Looking up where a concept lives (tags, files, ordering, colors, sessions)
- Understanding keyboard shortcuts or the tag/file lifecycle
What the app does
frename is a Windows desktop app for renaming video and image files using a tag-based system.
File name format: tag1.tag2.name.ext
The user opens a folder, browses video files, assigns tags by clicking checkboxes, optionally reorders tags by dragging chips in the rename panel, and the file is renamed when they move to the next file.
Cargo workspace
C:\Work\my\frename\
Cargo.toml workspace manifest
crates\frename-core\ library: pure business logic (no iced)
src\ binary: UI (iced 0.14, gstreamer video)
frename-core dependencies
rusqlite (SQLite, bundled), tokio (async file scan), uuid, indexmap, log
frename (binary) dependencies
iced 0.14, iced_video_player (GStreamer), frename-core
Source map
frename-core (crates/frename-core/src/)
| Path | What lives here |
|---|
lib.rs | All public exports |
db/traits.rs | AppStateStore, StoredTagStore, Initializable traits |
db/app_database.rs | AppDatabase — SQLite implementation |
db/fake_app_storage.rs | FakeAppStorage — in-memory test double |
db/migrations.rs | Schema creation (3 tables) |
ordered/collection.rs | OrderedCollection<K,V> — ordered dict with rebalance |
tags/tag_list.rs | TagList<S> — all tag state and operations |
tags/tag.rs | Tag, TagId structs |
tags/file_snapshot.rs | FileSnapshot — checked tags + name + ext |
tags/file_tagger.rs | FileTagger::parse, SaveAndReparse — file name ↔ snapshot |
tags/stored_tag.rs | StoredTag, TagColorMapping |
file.rs | File — path + metadata + snapshot |
directory.rs | Directory<S> — folder with sorted file list + selection |
folder_file.rs | FolderAndFile — session: folder path + optional file path |
frename binary (src/)
| Path | What lives here |
|---|
main.rs | Logging init, GStreamer check, iced::application |
app/ | FrenameApp root: routes messages, global subscription |
features/folder_workspace/ | Main coordinator: directory, file workspace, layout |
features/file_workspace/ | Current file + TagList + tag operations |
features/tag_panel/ | Tag selection grid: cursor, bounds, scroll state |
features/tag_grid/ | Tag grid view (used when panel is wide enough) |
features/file_name_panel/ | Rename chips panel: drag, trash zone, name line |
features/folder/ | File list panel: selection messages |
features/folder_controls/ | Folder navigation controls |
features/video_player/ | GStreamer video playback state |
features/video_controls/ | Progress bar, play/pause |
features/drag_drop/ | OS file drag-drop → OpenFile(path) |
widgets/ | 5 reusable widgets (search_bar, tag_chip, splitter, etc.) |
theme.rs | Color constants + style functions |
tag_colors.rs | 16-color tag palette |
Key concepts
Tags
- Stored tag: persisted in DB with a UUID, sort_order, and color (by tag name)
- Snapshot-only tag: exists in the current file name but not in DB; shown as unsaved (○ button to save)
- Checked tag: applied to the current file; appears in the rename panel as a chip
- Unchecked tag: in the tag panel but not applied to this file
Tag ordering (two independent orders)
display_tag_ids — display order in the tag panel; set at file-open, never reordered; used for persistence
selected_tag_ids — order of chips in the file name panel; reorderable via drag; determines file name tag order
File lifecycle
ScanFolder → async scan → FolderLoaded → FileOpened → user edits tags → switch file → FileUpdated (disk rename)
Tags are never written to disk while editing. The rename happens only when the user moves to another file (or the app closes). Video must unload before rename on Windows (GStreamer holds a file handle).
Session persistence
Last opened folder + file stored in folder_history SQLite table. Restored on startup via LoadLastSession.
Keyboard shortcuts
| Key | Action |
|---|
Space | Toggle the selected tag (strips trailing space from filter first) |
Escape | Clear the search filter |
← / → / ↑ / ↓ | Move tag grid cursor (wraps at edges) |
PageUp / PageDown | Previous / next file |
Delete | Remove the selected tag from DB and UI |
Enter | Save the selected unsaved tag to DB |
| Any char / Backspace | Focus search bar and emulate the key into the filter |
Tag colors
tag_colors::TagColors::PALETTE — 16 fixed colors (grays, blues, greens, ambers, etc.).
TagColors::color(index: u8) -> Color — wraps index modulo 16.
Color is assigned randomly when a tag is saved for the first time (random_color_index() in core).
Colors are stored by tag name in tag_color_mapping table, so they survive renames if done via save_tag.
Startup sequence
main() → init logging + check GStreamer
iced::application(FrenameApp::new)
→ FrenameApp::new() → FolderWorkspace::new()
→ WindowReady event → LoadLastSession
→ LoadLastSession → AppStateStore::get_last_session() → ScanFolder(session)
→ ScanFolder → async Directory::open() → FolderLoaded { directory, target_file }
→ FolderLoaded → select target file → FileOpened(file)
→ FileOpened → FileWorkspace::set_file(file) → TagList::new(store, snapshot)
→ video_player.load_video(path)
Common patterns
Open a folder/file from outside: emit Message::FolderWorkspace(OpenFile(path)) or drop a file on the window (handled by drag_drop feature).
The LoggingAppStateStore<AppDatabase> wrapper: used in production to log all store operations. Passed to Directory::open(). The underlying AppDatabase is used directly in FileWorkspace.
Generic type resolution: FolderWorkspace uses type Directory = frename_core::Directory<LoggingAppStateStore<AppDatabase>>. All generics are pinned at this level; the rest of the UI is concrete.