{"owner":"qarmin","repo":"czkawka","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md"],"skills":{"AGENTS.md":"# Czkawka – Codebase Guide\n\n## Language\n\nAll code, comments, commit messages, and documentation must be written in **English**.\n\n---\n\n## Rust Style\n\nApplies to every Rust crate in the workspace (`czkawka_core`, `czkawka_cli`, `czkawka_gui`,\n`krokiet`, `cedinia`). Program-specific deviations or elaborations live in that program's own\n`AGENTS.md`.\n\n**Formatting & lints**\n- Format with `cargo +nightly fmt`, then `cargo fmt` for stable compatibility\n  (`.rustfmt.toml`: `max_width = 120`, granular import grouping `group_imports = \"StdExternalCrate\"`).\n- Code must compile without clippy warnings. Suppress a lint locally only with a comment\n  explaining why.\n\n**Errors & panics**\n- Prefer `?`, `ok_or_else`, `map_err` over panic-based flows.\n- `unwrap()` only in tests.\n- `expect()` in production only when BOTH hold: there is no correct recovery path, and\n  continuing would likely hide a serious bug - always with a precise, actionable message. This\n  is visible throughout Krokiet/Cedinia callback code: a Slint weak reference is upgraded with\n  `expect()` because if the window is already gone there is nothing meaningful to do except crash.\n- Never silently swallow errors with `let _ = ...` unless the failure is genuinely irrelevant.\n- Model domain errors with explicit types (`thiserror`/enums), not raw strings.\n- Wrap I/O errors with context (e.g. file path) instead of letting std's bare \"Permission\n  denied\" propagate - without the path it's hard to find the source.\n- Don't ignore `Result`; handle it explicitly.\n\n**Code shape**\n- Keep functions focused; once one grows past ~30-50 lines, extract its logical steps into\n  separate, well-named functions. Never carve a long function into sections with comment\n  headers or bare `{ ... }` scope blocks - a `// validate input` comment over a block is the\n  signal to pull it out into `validate_input(...)`, not to fence it off.\n- Name things by intent, not by container/type (`user_count`, not `vec_users_len`).\n- Make invalid states unrepresentable: enums over strings, `Option<T>` over sentinel values\n  (`-1`, empty string).\n- Prefer iterators and collection methods over manual index-based loops.\n- Prefer `#[derive(...)]` over manual impls when behavior is standard.\n- Avoid unnecessary copies and allocations; prefer references and `Cow` where it helps.\n- Prefer external crates over reimplementing them.\n\n**Comments**\nKeep comments short and minimal - a single terse line, not a paragraph. Code should be\nself-documenting through clear naming. Add a comment only when the _why_ is not easily inferred\nfrom reading the code - algorithmic choices, non-obvious constraints, workarounds for external\nlibrary bugs, etc. Do not restate what the code already says. Never use the `—`/`–` dash\ncharacters in code, comments, or commit messages - plain `-` only (ASCII box-drawing diagrams are\nthe only exception).\n\nException: `czkawka_core` is a library - every frontend in this workspace depends on it, and so do\nexternal consumers who only read its public API, not its internals. Its `pub fn`/`pub struct`\nsurface warrants more explanation than the rest of the workspace; see `czkawka_core/AGENTS.md`.\n\n**Tests, fuzzers, benchmarks**\n- Cover as much code as possible with tests; keep them readable with explicit `assert_eq!` and\n  input data close to the assertions.\n- Add fuzzers/examples/benchmarks where it helps show usage, find bugs, or measure the\n  performance impact of a change.\n\n**`unsafe`**\nAvoid whenever possible. Every `unsafe` block documents its invariants and why the safety\nrequirements hold (see cedinia's `#[unsafe(no_mangle)] android_main`).\n\n**Files & logging**\n- Keep source files at or below 500 lines; split large files into modules.\n- Always log via `log` (`handsome_logger`); reach for `tracing` only if actually needed.\n\n**Auto-vectorization**\nLLVM vectorizes a loop when it can prove: no loop-carried dependency, no aliasing, no bounds\nchecks, and a favorable cost model.\n- Enable it: `.iter()`/`.iter_mut()` + `.zip()` instead of index loops (drops bounds checks);\n  `.chunks_exact(N)`/`.chunks_exact_mut(N)` + `.remainder()` for aligned SIMD chunk processing;\n  `(&[T], &mut [T])` over `(&mut [T], &mut [T])` so LLVM can assume no aliasing; keep the loop\n  body uniform (no per-element `if`/`match`, no early returns); use a reduction (`.sum()`/\n  `.fold()`) instead of a running accumulator that depends on its own previous value.\n- Kills it: `slice[i]` index loops, value-based `continue` inside an element loop, mutable\n  state shared across iterations.\n- Verify: inspect asm on godbolt.org for `vmulps`/`vpaddb`/`vpsubusb` vs scalar `mulss`/`movss`;\n  measure the delta with `RUSTFLAGS=\"-C opt-level=3 -C no-vectorize-loops -C no-vectorize-slp\"`;\n  build with `RUSTFLAGS=\"-C target-cpu=native\"` to unlock AVX2/AVX-512 on the host CPU.\n- When LLVM won't vectorize, reach for explicit SIMD: `std::arch` (stable, arch-specific),\n  `std::simd`/`portable_simd` (nightly, portable), or the stable `wide`/`pulp` crates.\n\n**Performance micro-hints**\n- Pre-allocate with `Vec::with_capacity(n)` / `HashMap::with_capacity(n)` when the count is\n  roughly known - avoids the realloc ladder.\n- Reuse buffers across calls (`buf.clear()`) instead of reallocating.\n- For almost-always-short collections, consider `SmallVec`/`ArrayVec` (stack-allocated until\n  they spill).\n- Use the smallest enum discriminant that fits (`#[repr(u8)]`/`#[repr(u16)]`) for tighter\n  packing and better cache density.\n- Wrap Criterion bench inputs/outputs in `std::hint::black_box(...)` to stop dead-code\n  elimination from invalidating the measurement.\n\n---\n\n## Project Goals\n\nTwo properties are non-negotiable across every sub-project:\n\n1. **Performance first** – scanning and file operations must be fast. Parallelism via `rayon`,\n   efficient algorithms (e.g. perceptual hashing, blake3), and careful memory use are the norm.\n   Avoid unnecessary allocations or copies in hot paths.\n\n2. **Minimal non-Rust dependencies** – every additional C/C++ library (or any other non-Rust\n   language) makes cross-compilation harder, narrows the set of supported targets, and increases\n   build complexity for contributors. Prefer pure-Rust crates. If a native library is truly\n   necessary (e.g. `libheif`, `libraw`), gate it behind an optional Cargo feature so the default\n   build stays fully Rust.\n\n---\n\n## `just fix` – baseline quality gate\n\nRunning `just fix` must pass before any merge request. It runs, in order:\n\n1. Repo-wide auto-fix of `—`/`–`/`―` dash characters back to plain `-` (`.rs`, `.slint`, `.md`,\n   `.ftl`; `AGENTS.md` and `justfile` themselves are excluded) – the enforcement behind the\n   \"never use em/en dash\" style rule above.\n2. `uv run ruff format --line-length 120` – Python code formatting.\n3. `uv run mypy misc --strict` – static type checking for all scripts in `misc/`.\n4. `bash misc/run_checks.sh` – project-specific checks:\n   - `delete_unused_krokiet_slint_imports.py` for krokiet and cedinia\n   - `find_unused_fluent_translations.py` for all four projects\n   - `find_unused_slint_translations.py` for krokiet and cedinia\n   - `find_unused_callbacks.py` for krokiet and cedinia\n   - `find_unused_settings_properties.py` for krokiet and cedinia\n5. `cargo +nightly fmt` – Rust formatting.\n6. `cargo clippy --fix --all-features --all-targets` – Rust linting (single pass).\n7. `cargo +nightly fmt` + `cargo fmt` again – re-format whatever clippy's fixes touched.\n\nFor a clippy pass that also covers the `--no-default-features` build, run `just clip` separately\n(two passes: `--all-features` and `--no-default-features --features winit_software`).\n\nIf `just fix` produces any output on stderr or exits non-zero the code is not ready for review.\n\n---\n\n## Workspace Structure\n\n```\nczkawka/\n├── czkawka_core/   # Scanning logic – shared library used by all frontends\n├── czkawka_cli/    # Command-line interface\n├── czkawka_gui/    # Legacy GTK 4 GUI (maintenance mode only)\n├── krokiet/        # Primary desktop GUI – Slint-based\n├── cedinia/        # Android / mobile GUI – Slint-based\n└── misc/           # Scripts: AI translation, validation, benchmarks, CI helpers\n```\n\nCargo workspace resolver v3, minimum Rust 1.94.1, edition 2024 throughout.\n\n---\n\n## czkawka_core\n\nThe shared scanning engine. Every frontend depends on it; it has no UI dependency.\n\n**Key modules:**\n- `common/` – `CommonToolData` (settings, stop-flag, progress sender), `DirTraversal`, cache,\n  extension filtering, path helpers, progress types.\n- `tools/` – One sub-module per scanning tool:\n  `duplicate`, `empty_folder`, `empty_files`, `big_file`, `similar_images`, `similar_videos`,\n  `same_music`, `broken_files`, `bad_extensions`, `bad_names`, `invalid_symlinks`, `temporary`,\n  `exif_remover`, `video_optimizer`.\n- `localizer_core.rs` – Fluent translation loader for Rust-side messages.\n\nEach tool implements the `CommonData` trait (shared settings access) and `PrintResults` (CSV/JSON\nexport). The tool struct is constructed, configured, then its `find_*()` method is called in a\nworker thread. Progress is reported over a `crossbeam` channel; a stop `AtomicBool` is polled to\nsupport cancellation.\n\n---\n\n## krokiet\n\nThe primary desktop GUI. Built with [Slint](https://slint.dev/) (GPL-3.0). The UI is declared\nin `ui/*.slint`; Rust connects callbacks and drives the Slint model.\n\n**Build:** `slint_build` compiles `.slint` sources at build time; `slint::include_modules!()`\nexposes the generated types.\n\n**Entry point:** `src/main.rs`\n- Loads settings, creates `MainWindow`, wires up all callbacks, starts the event loop.\n\n**Callback pattern:**\n```rust\nlet weak = app.as_weak();\napp.global::<Callabler>().on_some_action(move || {\n    let app = weak.upgrade().expect(\"MainWindow dropped while callback is still live\");\n    // ...\n});\n```\nEach feature area lives in a dedicated `connect_*.rs` file (e.g. `connect_scan.rs`,\n`connect_compare.rs`, `connect_delete_button.rs`).\n\n**`SharedModels`** (`src/shared_models.rs`):\nAn `Arc<Mutex<SharedModels>>` holds the last scan result and parameters of scan of each tool. It is passed to every\n`connect_*` function that needs to access or mutate scan state from a background thread.\n\n**Model layer:**\n- The Slint UI is driven by `ModelRc<VecModel<SingleMainListModel>>`.\n- `SingleMainListModel` carries `val_str: [string]` and `val_int: [int]` vectors – a flat,\n  index-based row representation.\n- Column indices for each tool are defined as constants in `src/common.rs`\n  (`StrDataSimilarImages`, `StrDataDuplicates`, …).\n\n**Translation:** `flk!(\"key\")` / `flk!(\"key\", var = value)` macros defined in\n`src/localizer_krokiet.rs`. Language files in `i18n/<lang-code>/krokiet.ftl`.\n\n---\n\n## cedinia\n\nThe Android (and secondary desktop) GUI. Architecture mirrors Krokiet but adapts to mobile\nconstraints. Compiled as `cdylib` for Android (loaded via `android-activity`).\n\n**Entry points:**\n- Android: `#[unsafe(no_mangle)] fn android_main(android_app: AndroidApp)` in `src/lib.rs`\n- Desktop: `fn run_app()` in `src/app.rs`\n\n**Android-specific:**\n- File picker uses JNI to call into a Kotlin/Java helper embedded via `include_bytes!` (DEX).\n- Storage permissions requested at runtime; `AppState.storage_permission_granted` gates scanning.\n- System insets (`inset_top`, `inset_bottom`) plumbed through to Slint for edge-to-edge layout.\n- `android_logger` routes Rust log output to logcat.\n\n**Differences from Krokiet:**\n- Has `SimilarVideos` (audio-fingerprint matching only, via `rusty-chromaprint`), but not\n  `VideoOptimizer` - ffmpeg-based transcoding/crop-detection is not available on Android.\n- Touch-optimised UI (`cedinia/ui/`); momentum-scroll views, bottom sheets, FAB.\n- `flc!` macro (cedinia-specific) in `src/localizer_cedinia.rs`.\n- See `cedinia/AGENTS.md` (\"Differences from krokiet\") for the full comparison table.\n\n**Translation:** `flc!(\"key\")` macro; language files in `cedinia/i18n/<lang-code>/cedinia.ftl`.\n\n---\n\n## czkawka_cli\n\nThin wrapper around `czkawka_core`. Uses `clap` (derive API) for argument parsing and `indicatif`\nfor progress bars. No GUI code. Results printed via the tool's `PrintResults` trait.\n\n---\n\n## czkawka_gui\n\nLegacy GTK 4 GUI. **Maintenance mode only** – no new features are added. Bug-fixes that\nkeep it compatible with core API changes are accepted.\n\n---\n\n## misc/\n\n**Translation tooling** (`ai_translate/`):\n- `translate.py` – AI-powered batch translation into all supported languages.\n- `validate_translations.py` – Checks placeholder consistency across translations.\n  Pass `--fix` to automatically remove invalid entries.\n\n**Dead-code detection** (run by `run_checks.sh`, see `just fix` above):\n- `find_unused_fluent_translations.py` / `find_unused_slint_translations.py` – Unused\n  translation keys.\n- `find_unused_callbacks.py` – Slint callbacks never invoked from Rust.\n- `find_unused_settings_properties.py` – Settings struct fields never read by the UI.\n- `delete_unused_krokiet_slint_imports.py` – Removes dead `import` lines from `.slint` files.\n\n**Packaging / release:**\n- `gen_cedinia_licenses.py` – Generates `THIRD_PARTY_LICENSES.txt` from Cargo metadata.\n- `gen_android_icons.py` – Generates cedinia's Android adaptive-icon assets from an SVG logo.\n- `simplify_and_minify_svg.py` – Minifies SVG icons via Inkscape.\n- `pack_all_backends.sh` / `.ps1` – Bundles an all-backends krokiet binary with per-backend\n  launcher scripts into a release zip.\n- `flathub.sh` – Generates Flatpak cargo-sources metadata for the Flathub manifest.\n- `add_icon_exe/` – Cargo helper crate that embeds the `.ico` into Windows binaries at build time.\n- `docker/` – `Dockerfile` for containerized builds.\n- `nix/` – Nix flake (`flake.nix`, `packages.nix`) for Nix-based builds.\n- `install_scripts/` – `install_linux.sh`, `install_macos.sh`, `install_windows.bat` end-user\n  installers.\n\n**Dev utilities:**\n- `remove_comments.py` – Strips comments from source files (one-off cleanup tool).\n- `compare_files.sh` – Diffs MD5 hashes of CI build artifacts across runs to check determinism.\n- `run_checks.sh` – Runs all the dead-code detection scripts above; invoked by `just fix`.\n\n**Benchmarks** (standalone Cargo crates):\n- `test_image_perf/`, `test_read_perf/` – Microbenchmarks for image hashing / file reading.\n- `test_compilation_speed_size/` – Tracks build time and binary size across changes.\n\n---\n\n## i18n\n\nAll user-visible strings use [Fluent](https://projectfluent.org/) (`.ftl` files).\n\n| Project      | Macro  | File pattern                                |\n|--------------|--------|---------------------------------------------|\n| krokiet      | `flk!` | `krokiet/i18n/<lang>/krokiet.ftl`           |\n| cedinia      | `flc!` | `cedinia/i18n/<lang>/cedinia.ftl`           |\n| czkawka_core | `flc!` | `czkawka_core/i18n/<lang>/czkawka_core.ftl` |\n| czkawka_gui  | `flg!` | `czkawka_gui/i18n/<lang>/czkawka_gui.ftl`   |\n\nEnglish is the source/fallback language. All other locales are AI-translated and then validated.\n\n**Important:** Only edit the English `.ftl` files (`i18n/en/`) directly in this repository.\nAll other language files are managed through [Crowdin](https://crowdin.com/) and will be\n**overwritten** when translations are pulled from Crowdin. Any manual edits to non-English\n`.ftl` files in the repo will be lost on the next `just unpack_translations` run.\n\n---\n\n## Slint UI conventions\n\n- **Hidden Text elements for width measurement** – where a layout element must adapt its width to\n  translated label text, add off-screen `Text` instances (`x: -10000px; y: -10000px; height: 0`)\n  and compute `preferred-width` at runtime (see `LeftSidePanel`, `CompareInfoBar`).\n- **Enums over strings** – UI state that takes a fixed set of values should use a Slint `enum`,\n  not a `string` (e.g. `ConfirmPopupAction`, `ActiveTool`, `ScanState`).\n- **Global state** – Application-wide state lives in Slint `global` blocks (`GuiState`,\n  `AppState`, `Settings`, `Translations`, …). Rust reads/writes via `app.global::<GlobalName>()`.\n\n---\n\n## Build profiles (Cargo.toml)\n\n| Profile        | Purpose                                                              |\n|----------------|----------------------------------------------------------------------|\n| `release`      | Standard release                                                     |\n| `fast_release` | Incremental, stripped – fast iteration                               |\n| `rdebug`       | Release + full debug symbols (profiling)                             |\n| `fastest`      | Max opt, LTO, panic=abort – mostly benchmarks/poc how fast it can be |\n| `fastci`       | Small binary, fast CI builds                                         |\n\n---\n\n## justfile quick reference\n\n```\njust run krokiet          # debug run\njust runr krokiet         # fast_release run\njust fix                  # format + clippy + Python checks\njust translate            # AI-translate all projects\njust validate_translations [--fix]\njust pack_translations    # create i18n_translations.zip for Crowdin\njust unpack_translations <path>\njust android              # build + install + launch on device\njust androidr             # release variant\n```\n"},"files":{"AGENTS.md":"# Czkawka – Codebase Guide\n\n## Language\n\nAll code, comments, commit messages, and documentation must be written in **English**.\n\n---\n\n## Rust Style\n\nApplies to every Rust crate in the workspace (`czkawka_core`, `czkawka_cli`, `czkawka_gui`,\n`krokiet`, `cedinia`). Program-specific deviations or elaborations live in that program's own\n`AGENTS.md`.\n\n**Formatting & lints**\n- Format with `cargo +nightly fmt`, then `cargo fmt` for stable compatibility\n  (`.rustfmt.toml`: `max_width = 120`, granular import grouping `group_imports = \"StdExternalCrate\"`).\n- Code must compile without clippy warnings. Suppress a lint locally only with a comment\n  explaining why.\n\n**Errors & panics**\n- Prefer `?`, `ok_or_else`, `map_err` over panic-based flows.\n- `unwrap()` only in tests.\n- `expect()` in production only when BOTH hold: there is no correct recovery path, and\n  continuing would likely hide a serious bug - always with a precise, actionable message. This\n  is visible throughout Krokiet/Cedinia callback code: a Slint weak reference is upgraded with\n  `expect()` because if the window is already gone there is nothing meaningful to do except crash.\n- Never silently swallow errors with `let _ = ...` unless the failure is genuinely irrelevant.\n- Model domain errors with explicit types (`thiserror`/enums), not raw strings.\n- Wrap I/O errors with context (e.g. file path) instead of letting std's bare \"Permission\n  denied\" propagate - without the path it's hard to find the source.\n- Don't ignore `Result`; handle it explicitly.\n\n**Code shape**\n- Keep functions focused; once one grows past ~30-50 lines, extract its logical steps into\n  separate, well-named functions. Never carve a long function into sections with comment\n  headers or bare `{ ... }` scope blocks - a `// validate input` comment over a block is the\n  signal to pull it out into `validate_input(...)`, not to fence it off.\n- Name things by intent, not by container/type (`user_count`, not `vec_users_len`).\n- Make invalid states unrepresentable: enums over strings, `Option<T>` over sentinel values\n  (`-1`, empty string).\n- Prefer iterators and collection methods over manual index-based loops.\n- Prefer `#[derive(...)]` over manual impls when behavior is standard.\n- Avoid unnecessary copies and allocations; prefer references and `Cow` where it helps.\n- Prefer external crates over reimplementing them.\n\n**Comments**\nKeep comments short and minimal - a single terse line, not a paragraph. Code should be\nself-documenting through clear naming. Add a comment only when the _why_ is not easily inferred\nfrom reading the code - algorithmic choices, non-obvious constraints, workarounds for external\nlibrary bugs, etc. Do not restate what the code already says. Never use the `—`/`–` dash\ncharacters in code, comments, or commit messages - plain `-` only (ASCII box-drawing diagrams are\nthe only exception).\n\nException: `czkawka_core` is a library - every frontend in this workspace depends on it, and so do\nexternal consumers who only read its public API, not its internals. Its `pub fn`/`pub struct`\nsurface warrants more explanation than the rest of the workspace; see `czkawka_core/AGENTS.md`.\n\n**Tests, fuzzers, benchmarks**\n- Cover as much code as possible with tests; keep them readable with explicit `assert_eq!` and\n  input data close to the assertions.\n- Add fuzzers/examples/benchmarks where it helps show usage, find bugs, or measure the\n  performance impact of a change.\n\n**`unsafe`**\nAvoid whenever possible. Every `unsafe` block documents its invariants and why the safety\nrequirements hold (see cedinia's `#[unsafe(no_mangle)] android_main`).\n\n**Files & logging**\n- Keep source files at or below 500 lines; split large files into modules.\n- Always log via `log` (`handsome_logger`); reach for `tracing` only if actually needed.\n\n**Auto-vectorization**\nLLVM vectorizes a loop when it can prove: no loop-carried dependency, no aliasing, no bounds\nchecks, and a favorable cost model.\n- Enable it: `.iter()`/`.iter_mut()` + `.zip()` instead of index loops (drops bounds checks);\n  `.chunks_exact(N)`/`.chunks_exact_mut(N)` + `.remainder()` for aligned SIMD chunk processing;\n  `(&[T], &mut [T])` over `(&mut [T], &mut [T])` so LLVM can assume no aliasing; keep the loop\n  body uniform (no per-element `if`/`match`, no early returns); use a reduction (`.sum()`/\n  `.fold()`) instead of a running accumulator that depends on its own previous value.\n- Kills it: `slice[i]` index loops, value-based `continue` inside an element loop, mutable\n  state shared across iterations.\n- Verify: inspect asm on godbolt.org for `vmulps`/`vpaddb`/`vpsubusb` vs scalar `mulss`/`movss`;\n  measure the delta with `RUSTFLAGS=\"-C opt-level=3 -C no-vectorize-loops -C no-vectorize-slp\"`;\n  build with `RUSTFLAGS=\"-C target-cpu=native\"` to unlock AVX2/AVX-512 on the host CPU.\n- When LLVM won't vectorize, reach for explicit SIMD: `std::arch` (stable, arch-specific),\n  `std::simd`/`portable_simd` (nightly, portable), or the stable `wide`/`pulp` crates.\n\n**Performance micro-hints**\n- Pre-allocate with `Vec::with_capacity(n)` / `HashMap::with_capacity(n)` when the count is\n  roughly known - avoids the realloc ladder.\n- Reuse buffers across calls (`buf.clear()`) instead of reallocating.\n- For almost-always-short collections, consider `SmallVec`/`ArrayVec` (stack-allocated until\n  they spill).\n- Use the smallest enum discriminant that fits (`#[repr(u8)]`/`#[repr(u16)]`) for tighter\n  packing and better cache density.\n- Wrap Criterion bench inputs/outputs in `std::hint::black_box(...)` to stop dead-code\n  elimination from invalidating the measurement.\n\n---\n\n## Project Goals\n\nTwo properties are non-negotiable across every sub-project:\n\n1. **Performance first** – scanning and file operations must be fast. Parallelism via `rayon`,\n   efficient algorithms (e.g. perceptual hashing, blake3), and careful memory use are the norm.\n   Avoid unnecessary allocations or copies in hot paths.\n\n2. **Minimal non-Rust dependencies** – every additional C/C++ library (or any other non-Rust\n   language) makes cross-compilation harder, narrows the set of supported targets, and increases\n   build complexity for contributors. Prefer pure-Rust crates. If a native library is truly\n   necessary (e.g. `libheif`, `libraw`), gate it behind an optional Cargo feature so the default\n   build stays fully Rust.\n\n---\n\n## `just fix` – baseline quality gate\n\nRunning `just fix` must pass before any merge request. It runs, in order:\n\n1. Repo-wide auto-fix of `—`/`–`/`―` dash characters back to plain `-` (`.rs`, `.slint`, `.md`,\n   `.ftl`; `AGENTS.md` and `justfile` themselves are excluded) – the enforcement behind the\n   \"never use em/en dash\" style rule above.\n2. `uv run ruff format --line-length 120` – Python code formatting.\n3. `uv run mypy misc --strict` – static type checking for all scripts in `misc/`.\n4. `bash misc/run_checks.sh` – project-specific checks:\n   - `delete_unused_krokiet_slint_imports.py` for krokiet and cedinia\n   - `find_unused_fluent_translations.py` for all four projects\n   - `find_unused_slint_translations.py` for krokiet and cedinia\n   - `find_unused_callbacks.py` for krokiet and cedinia\n   - `find_unused_settings_properties.py` for krokiet and cedinia\n5. `cargo +nightly fmt` – Rust formatting.\n6. `cargo clippy --fix --all-features --all-targets` – Rust linting (single pass).\n7. `cargo +nightly fmt` + `cargo fmt` again – re-format whatever clippy's fixes touched.\n\nFor a clippy pass that also covers the `--no-default-features` build, run `just clip` separately\n(two passes: `--all-features` and `--no-default-features --features winit_software`).\n\nIf `just fix` produces any output on stderr or exits non-zero the code is not ready for review.\n\n---\n\n## Workspace Structure\n\n```\nczkawka/\n├── czkawka_core/   # Scanning logic – shared library used by all frontends\n├── czkawka_cli/    # Command-line interface\n├── czkawka_gui/    # Legacy GTK 4 GUI (maintenance mode only)\n├── krokiet/        # Primary desktop GUI – Slint-based\n├── cedinia/        # Android / mobile GUI – Slint-based\n└── misc/           # Scripts: AI translation, validation, benchmarks, CI helpers\n```\n\nCargo workspace resolver v3, minimum Rust 1.94.1, edition 2024 throughout.\n\n---\n\n## czkawka_core\n\nThe shared scanning engine. Every frontend depends on it; it has no UI dependency.\n\n**Key modules:**\n- `common/` – `CommonToolData` (settings, stop-flag, progress sender), `DirTraversal`, cache,\n  extension filtering, path helpers, progress types.\n- `tools/` – One sub-module per scanning tool:\n  `duplicate`, `empty_folder`, `empty_files`, `big_file`, `similar_images`, `similar_videos`,\n  `same_music`, `broken_files`, `bad_extensions`, `bad_names`, `invalid_symlinks`, `temporary`,\n  `exif_remover`, `video_optimizer`.\n- `localizer_core.rs` – Fluent translation loader for Rust-side messages.\n\nEach tool implements the `CommonData` trait (shared settings access) and `PrintResults` (CSV/JSON\nexport). The tool struct is constructed, configured, then its `find_*()` method is called in a\nworker thread. Progress is reported over a `crossbeam` channel; a stop `AtomicBool` is polled to\nsupport cancellation.\n\n---\n\n## krokiet\n\nThe primary desktop GUI. Built with [Slint](https://slint.dev/) (GPL-3.0). The UI is declared\nin `ui/*.slint`; Rust connects callbacks and drives the Slint model.\n\n**Build:** `slint_build` compiles `.slint` sources at build time; `slint::include_modules!()`\nexposes the generated types.\n\n**Entry point:** `src/main.rs`\n- Loads settings, creates `MainWindow`, wires up all callbacks, starts the event loop.\n\n**Callback pattern:**\n```rust\nlet weak = app.as_weak();\napp.global::<Callabler>().on_some_action(move || {\n    let app = weak.upgrade().expect(\"MainWindow dropped while callback is still live\");\n    // ...\n});\n```\nEach feature area lives in a dedicated `connect_*.rs` file (e.g. `connect_scan.rs`,\n`connect_compare.rs`, `connect_delete_button.rs`).\n\n**`SharedModels`** (`src/shared_models.rs`):\nAn `Arc<Mutex<SharedModels>>` holds the last scan result and parameters of scan of each tool. It is passed to every\n`connect_*` function that needs to access or mutate scan state from a background thread.\n\n**Model layer:**\n- The Slint UI is driven by `ModelRc<VecModel<SingleMainListModel>>`.\n- `SingleMainListModel` carries `val_str: [string]` and `val_int: [int]` vectors – a flat,\n  index-based row representation.\n- Column indices for each tool are defined as constants in `src/common.rs`\n  (`StrDataSimilarImages`, `StrDataDuplicates`, …).\n\n**Translation:** `flk!(\"key\")` / `flk!(\"key\", var = value)` macros defined in\n`src/localizer_krokiet.rs`. Language files in `i18n/<lang-code>/krokiet.ftl`.\n\n---\n\n## cedinia\n\nThe Android (and secondary desktop) GUI. Architecture mirrors Krokiet but adapts to mobile\nconstraints. Compiled as `cdylib` for Android (loaded via `android-activity`).\n\n**Entry points:**\n- Android: `#[unsafe(no_mangle)] fn android_main(android_app: AndroidApp)` in `src/lib.rs`\n- Desktop: `fn run_app()` in `src/app.rs`\n\n**Android-specific:**\n- File picker uses JNI to call into a Kotlin/Java helper embedded via `include_bytes!` (DEX).\n- Storage permissions requested at runtime; `AppState.storage_permission_granted` gates scanning.\n- System insets (`inset_top`, `inset_bottom`) plumbed through to Slint for edge-to-edge layout.\n- `android_logger` routes Rust log output to logcat.\n\n**Differences from Krokiet:**\n- Has `SimilarVideos` (audio-fingerprint matching only, via `rusty-chromaprint`), but not\n  `VideoOptimizer` - ffmpeg-based transcoding/crop-detection is not available on Android.\n- Touch-optimised UI (`cedinia/ui/`); momentum-scroll views, bottom sheets, FAB.\n- `flc!` macro (cedinia-specific) in `src/localizer_cedinia.rs`.\n- See `cedinia/AGENTS.md` (\"Differences from krokiet\") for the full comparison table.\n\n**Translation:** `flc!(\"key\")` macro; language files in `cedinia/i18n/<lang-code>/cedinia.ftl`.\n\n---\n\n## czkawka_cli\n\nThin wrapper around `czkawka_core`. Uses `clap` (derive API) for argument parsing and `indicatif`\nfor progress bars. No GUI code. Results printed via the tool's `PrintResults` trait.\n\n---\n\n## czkawka_gui\n\nLegacy GTK 4 GUI. **Maintenance mode only** – no new features are added. Bug-fixes that\nkeep it compatible with core API changes are accepted.\n\n---\n\n## misc/\n\n**Translation tooling** (`ai_translate/`):\n- `translate.py` – AI-powered batch translation into all supported languages.\n- `validate_translations.py` – Checks placeholder consistency across translations.\n  Pass `--fix` to automatically remove invalid entries.\n\n**Dead-code detection** (run by `run_checks.sh`, see `just fix` above):\n- `find_unused_fluent_translations.py` / `find_unused_slint_translations.py` – Unused\n  translation keys.\n- `find_unused_callbacks.py` – Slint callbacks never invoked from Rust.\n- `find_unused_settings_properties.py` – Settings struct fields never read by the UI.\n- `delete_unused_krokiet_slint_imports.py` – Removes dead `import` lines from `.slint` files.\n\n**Packaging / release:**\n- `gen_cedinia_licenses.py` – Generates `THIRD_PARTY_LICENSES.txt` from Cargo metadata.\n- `gen_android_icons.py` – Generates cedinia's Android adaptive-icon assets from an SVG logo.\n- `simplify_and_minify_svg.py` – Minifies SVG icons via Inkscape.\n- `pack_all_backends.sh` / `.ps1` – Bundles an all-backends krokiet binary with per-backend\n  launcher scripts into a release zip.\n- `flathub.sh` – Generates Flatpak cargo-sources metadata for the Flathub manifest.\n- `add_icon_exe/` – Cargo helper crate that embeds the `.ico` into Windows binaries at build time.\n- `docker/` – `Dockerfile` for containerized builds.\n- `nix/` – Nix flake (`flake.nix`, `packages.nix`) for Nix-based builds.\n- `install_scripts/` – `install_linux.sh`, `install_macos.sh`, `install_windows.bat` end-user\n  installers.\n\n**Dev utilities:**\n- `remove_comments.py` – Strips comments from source files (one-off cleanup tool).\n- `compare_files.sh` – Diffs MD5 hashes of CI build artifacts across runs to check determinism.\n- `run_checks.sh` – Runs all the dead-code detection scripts above; invoked by `just fix`.\n\n**Benchmarks** (standalone Cargo crates):\n- `test_image_perf/`, `test_read_perf/` – Microbenchmarks for image hashing / file reading.\n- `test_compilation_speed_size/` – Tracks build time and binary size across changes.\n\n---\n\n## i18n\n\nAll user-visible strings use [Fluent](https://projectfluent.org/) (`.ftl` files).\n\n| Project      | Macro  | File pattern                                |\n|--------------|--------|---------------------------------------------|\n| krokiet      | `flk!` | `krokiet/i18n/<lang>/krokiet.ftl`           |\n| cedinia      | `flc!` | `cedinia/i18n/<lang>/cedinia.ftl`           |\n| czkawka_core | `flc!` | `czkawka_core/i18n/<lang>/czkawka_core.ftl` |\n| czkawka_gui  | `flg!` | `czkawka_gui/i18n/<lang>/czkawka_gui.ftl`   |\n\nEnglish is the source/fallback language. All other locales are AI-translated and then validated.\n\n**Important:** Only edit the English `.ftl` files (`i18n/en/`) directly in this repository.\nAll other language files are managed through [Crowdin](https://crowdin.com/) and will be\n**overwritten** when translations are pulled from Crowdin. Any manual edits to non-English\n`.ftl` files in the repo will be lost on the next `just unpack_translations` run.\n\n---\n\n## Slint UI conventions\n\n- **Hidden Text elements for width measurement** – where a layout element must adapt its width to\n  translated label text, add off-screen `Text` instances (`x: -10000px; y: -10000px; height: 0`)\n  and compute `preferred-width` at runtime (see `LeftSidePanel`, `CompareInfoBar`).\n- **Enums over strings** – UI state that takes a fixed set of values should use a Slint `enum`,\n  not a `string` (e.g. `ConfirmPopupAction`, `ActiveTool`, `ScanState`).\n- **Global state** – Application-wide state lives in Slint `global` blocks (`GuiState`,\n  `AppState`, `Settings`, `Translations`, …). Rust reads/writes via `app.global::<GlobalName>()`.\n\n---\n\n## Build profiles (Cargo.toml)\n\n| Profile        | Purpose                                                              |\n|----------------|----------------------------------------------------------------------|\n| `release`      | Standard release                                                     |\n| `fast_release` | Incremental, stripped – fast iteration                               |\n| `rdebug`       | Release + full debug symbols (profiling)                             |\n| `fastest`      | Max opt, LTO, panic=abort – mostly benchmarks/poc how fast it can be |\n| `fastci`       | Small binary, fast CI builds                                         |\n\n---\n\n## justfile quick reference\n\n```\njust run krokiet          # debug run\njust runr krokiet         # fast_release run\njust fix                  # format + clippy + Python checks\njust translate            # AI-translate all projects\njust validate_translations [--fix]\njust pack_translations    # create i18n_translations.zip for Crowdin\njust unpack_translations <path>\njust android              # build + install + launch on device\njust androidr             # release variant\n```\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","title":"AGENTS.md","content":"# Czkawka – Codebase Guide\n\n## Language\n\nAll code, comments, commit messages, and documentation must be written in **English**.\n\n---\n\n## Rust Style\n\nApplies to every Rust crate in the workspace (`czkawka_core`, `czkawka_cli`, `czkawka_gui`,\n`krokiet`, `cedinia`). Program-specific deviations or elaborations live in that program's own\n`AGENTS.md`.\n\n**Formatting & lints**\n- Format with `cargo +nightly fmt`, then `cargo fmt` for stable compatibility\n  (`.rustfmt.toml`: `max_width = 120`, granular import grouping `group_imports = \"StdExternalCrate\"`).\n- Code must compile without clippy warnings. Suppress a lint locally only with a comment\n  explaining why.\n\n**Errors & panics**\n- Prefer `?`, `ok_or_else`, `map_err` over panic-based flows.\n- `unwrap()` only in tests.\n- `expect()` in production only when BOTH hold: there is no correct recovery path, and\n  continuing would likely hide a serious bug - always with a precise, actionable message. This\n  is visible throughout Krokiet/Cedinia callback code: a Slint weak reference is upgraded with\n  `expect()` because if the window is already gone there is nothing meaningful to do except crash.\n- Never silently swallow errors with `let _ = ...` unless the failure is genuinely irrelevant.\n- Model domain errors with explicit types (`thiserror`/enums), not raw strings.\n- Wrap I/O errors with context (e.g. file path) instead of letting std's bare \"Permission\n  denied\" propagate - without the path it's hard to find the source.\n- Don't ignore `Result`; handle it explicitly.\n\n**Code shape**\n- Keep functions focused; once one grows past ~30-50 lines, extract its logical steps into\n  separate, well-named functions. Never carve a long function into sections with comment\n  headers or bare `{ ... }` scope blocks - a `// validate input` comment over a block is the\n  signal to pull it out into `validate_input(...)`, not to fence it off.\n- Name things by intent, not by container/type (`user_count`, not `vec_users_len`).\n- Make invalid states unrepresentable: enums over strings, `Option<T>` over sentinel values\n  (`-1`, empty string).\n- Prefer iterators and collection methods over manual index-based loops.\n- Prefer `#[derive(...)]` over manual impls when behavior is standard.\n- Avoid unnecessary copies and allocations; prefer references and `Cow` where it helps.\n- Prefer external crates over reimplementing them.\n\n**Comments**\nKeep comments short and minimal - a single terse line, not a paragraph. Code should be\nself-documenting through clear naming. Add a comment only when the _why_ is not easily inferred\nfrom reading the code - algorithmic choices, non-obvious constraints, workarounds for external\nlibrary bugs, etc. Do not restate what the code already says. Never use the `—`/`–` dash\ncharacters in code, comments, or commit messages - plain `-` only (ASCII box-drawing diagrams are\nthe only exception).\n\nException: `czkawka_core` is a library - every frontend in this workspace depends on it, and so do\nexternal consumers who only read its public API, not its internals. Its `pub fn`/`pub struct`\nsurface warrants more explanation than the rest of the workspace; see `czkawka_core/AGENTS.md`.\n\n**Tests, fuzzers, benchmarks**\n- Cover as much code as possible with tests; keep them readable with explicit `assert_eq!` and\n  input data close to the assertions.\n- Add fuzzers/examples/benchmarks where it helps show usage, find bugs, or measure the\n  performance impact of a change.\n\n**`unsafe`**\nAvoid whenever possible. Every `unsafe` block documents its invariants and why the safety\nrequirements hold (see cedinia's `#[unsafe(no_mangle)] android_main`).\n\n**Files & logging**\n- Keep source files at or below 500 lines; split large files into modules.\n- Always log via `log` (`handsome_logger`); reach for `tracing` only if actually needed.\n\n**Auto-vectorization**\nLLVM vectorizes a loop when it can prove: no loop-carried dependency, no aliasing, no bounds\nchecks, and a favorable cost model.\n- Enable it: `.iter()`/`.iter_mut()` + `.zip()` instead of index loops (drops bounds checks);\n  `.chunks_exact(N)`/`.chunks_exact_mut(N)` + `.remainder()` for aligned SIMD chunk processing;\n  `(&[T], &mut [T])` over `(&mut [T], &mut [T])` so LLVM can assume no aliasing; keep the loop\n  body uniform (no per-element `if`/`match`, no early returns); use a reduction (`.sum()`/\n  `.fold()`) instead of a running accumulator that depends on its own previous value.\n- Kills it: `slice[i]` index loops, value-based `continue` inside an element loop, mutable\n  state shared across iterations.\n- Verify: inspect asm on godbolt.org for `vmulps`/`vpaddb`/`vpsubusb` vs scalar `mulss`/`movss`;\n  measure the delta with `RUSTFLAGS=\"-C opt-level=3 -C no-vectorize-loops -C no-vectorize-slp\"`;\n  build with `RUSTFLAGS=\"-C target-cpu=native\"` to unlock AVX2/AVX-512 on the host CPU.\n- When LLVM won't vectorize, reach for explicit SIMD: `std::arch` (stable, arch-specific),\n  `std::simd`/`portable_simd` (nightly, portable), or the stable `wide`/`pulp` crates.\n\n**Performance micro-hints**\n- Pre-allocate with `Vec::with_capacity(n)` / `HashMap::with_capacity(n)` when the count is\n  roughly known - avoids the realloc ladder.\n- Reuse buffers across calls (`buf.clear()`) instead of reallocating.\n- For almost-always-short collections, consider `SmallVec`/`ArrayVec` (stack-allocated until\n  they spill).\n- Use the smallest enum discriminant that fits (`#[repr(u8)]`/`#[repr(u16)]`) for tighter\n  packing and better cache density.\n- Wrap Criterion bench inputs/outputs in `std::hint::black_box(...)` to stop dead-code\n  elimination from invalidating the measurement.\n\n---\n\n## Project Goals\n\nTwo properties are non-negotiable across every sub-project:\n\n1. **Performance first** – scanning and file operations must be fast. Parallelism via `rayon`,\n   efficient algorithms (e.g. perceptual hashing, blake3), and careful memory use are the norm.\n   Avoid unnecessary allocations or copies in hot paths.\n\n2. **Minimal non-Rust dependencies** – every additional C/C++ library (or any other non-Rust\n   language) makes cross-compilation harder, narrows the set of supported targets, and increases\n   build complexity for contributors. Prefer pure-Rust crates. If a native library is truly\n   necessary (e.g. `libheif`, `libraw`), gate it behind an optional Cargo feature so the default\n   build stays fully Rust.\n\n---\n\n## `just fix` – baseline quality gate\n\nRunning `just fix` must pass before any merge request. It runs, in order:\n\n1. Repo-wide auto-fix of `—`/`–`/`―` dash characters back to plain `-` (`.rs`, `.slint`, `.md`,\n   `.ftl`; `AGENTS.md` and `justfile` themselves are excluded) – the enforcement behind the\n   \"never use em/en dash\" style rule above.\n2. `uv run ruff format --line-length 120` – Python code formatting.\n3. `uv run mypy misc --strict` – static type checking for all scripts in `misc/`.\n4. `bash misc/run_checks.sh` – project-specific checks:\n   - `delete_unused_krokiet_slint_imports.py` for krokiet and cedinia\n   - `find_unused_fluent_translations.py` for all four projects\n   - `find_unused_slint_translations.py` for krokiet and cedinia\n   - `find_unused_callbacks.py` for krokiet and cedinia\n   - `find_unused_settings_properties.py` for krokiet and cedinia\n5. `cargo +nightly fmt` – Rust formatting.\n6. `cargo clippy --fix --all-features --all-targets` – Rust linting (single pass).\n7. `cargo +nightly fmt` + `cargo fmt` again – re-format whatever clippy's fixes touched.\n\nFor a clippy pass that also covers the `--no-default-features` build, run `just clip` separately\n(two passes: `--all-features` and `--no-default-features --features winit_software`).\n\nIf `just fix` produces any output on stderr or exits non-zero the code is not ready for review.\n\n---\n\n## Workspace Structure\n\n```\nczkawka/\n├── czkawka_core/   # Scanning logic – shared library used by all frontends\n├── czkawka_cli/    # Command-line interface\n├── czkawka_gui/    # Legacy GTK 4 GUI (maintenance mode only)\n├── krokiet/        # Primary desktop GUI – Slint-based\n├── cedinia/        # Android / mobile GUI – Slint-based\n└── misc/           # Scripts: AI translation, validation, benchmarks, CI helpers\n```\n\nCargo workspace resolver v3, minimum Rust 1.94.1, edition 2024 throughout.\n\n---\n\n## czkawka_core\n\nThe shared scanning engine. Every frontend depends on it; it has no UI dependency.\n\n**Key modules:**\n- `common/` – `CommonToolData` (settings, stop-flag, progress sender), `DirTraversal`, cache,\n  extension filtering, path helpers, progress types.\n- `tools/` – One sub-module per scanning tool:\n  `duplicate`, `empty_folder`, `empty_files`, `big_file`, `similar_images`, `similar_videos`,\n  `same_music`, `broken_files`, `bad_extensions`, `bad_names`, `invalid_symlinks`, `temporary`,\n  `exif_remover`, `video_optimizer`.\n- `localizer_core.rs` – Fluent translation loader for Rust-side messages.\n\nEach tool implements the `CommonData` trait (shared settings access) and `PrintResults` (CSV/JSON\nexport). The tool struct is constructed, configured, then its `find_*()` method is called in a\nworker thread. Progress is reported over a `crossbeam` channel; a stop `AtomicBool` is polled to\nsupport cancellation.\n\n---\n\n## krokiet\n\nThe primary desktop GUI. Built with [Slint](https://slint.dev/) (GPL-3.0). The UI is declared\nin `ui/*.slint`; Rust connects callbacks and drives the Slint model.\n\n**Build:** `slint_build` compiles `.slint` sources at build time; `slint::include_modules!()`\nexposes the generated types.\n\n**Entry point:** `src/main.rs`\n- Loads settings, creates `MainWindow`, wires up all callbacks, starts the event loop.\n\n**Callback pattern:**\n```rust\nlet weak = app.as_weak();\napp.global::<Callabler>().on_some_action(move || {\n    let app = weak.upgrade().expect(\"MainWindow dropped while callback is still live\");\n    // ...\n});\n```\nEach feature area lives in a dedicated `connect_*.rs` file (e.g. `connect_scan.rs`,\n`connect_compare.rs`, `connect_delete_button.rs`).\n\n**`SharedModels`** (`src/shared_models.rs`):\nAn `Arc<Mutex<SharedModels>>` holds the last scan result and parameters of scan of each tool. It is passed to every\n`connect_*` function that needs to access or mutate scan state from a background thread.\n\n**Model layer:**\n- The Slint UI is driven by `ModelRc<VecModel<SingleMainListModel>>`.\n- `SingleMainListModel` carries `val_str: [string]` and `val_int: [int]` vectors – a flat,\n  index-based row representation.\n- Column indices for each tool are defined as constants in `src/common.rs`\n  (`StrDataSimilarImages`, `StrDataDuplicates`, …).\n\n**Translation:** `flk!(\"key\")` / `flk!(\"key\", var = value)` macros defined in\n`src/localizer_krokiet.rs`. Language files in `i18n/<lang-code>/krokiet.ftl`.\n\n---\n\n## cedinia\n\nThe Android (and secondary desktop) GUI. Architecture mirrors Krokiet but adapts to mobile\nconstraints. Compiled as `cdylib` for Android (loaded via `android-activity`).\n\n**Entry points:**\n- Android: `#[unsafe(no_mangle)] fn android_main(android_app: AndroidApp)` in `src/lib.rs`\n- Desktop: `fn run_app()` in `src/app.rs`\n\n**Android-specific:**\n- File picker uses JNI to call into a Kotlin/Java helper embedded via `include_bytes!` (DEX).\n- Storage permissions requested at runtime; `AppState.storage_permission_granted` gates scanning.\n- System insets (`inset_top`, `inset_bottom`) plumbed through to Slint for edge-to-edge layout.\n- `android_logger` routes Rust log output to logcat.\n\n**Differences from Krokiet:**\n- Has `SimilarVideos` (audio-fingerprint matching only, via `rusty-chromaprint`), but not\n  `VideoOptimizer` - ffmpeg-based transcoding/crop-detection is not available on Android.\n- Touch-optimised UI (`cedinia/ui/`); momentum-scroll views, bottom sheets, FAB.\n- `flc!` macro (cedinia-specific) in `src/localizer_cedinia.rs`.\n- See `cedinia/AGENTS.md` (\"Differences from krokiet\") for the full comparison table.\n\n**Translation:** `flc!(\"key\")` macro; language files in `cedinia/i18n/<lang-code>/cedinia.ftl`.\n\n---\n\n## czkawka_cli\n\nThin wrapper around `czkawka_core`. Uses `clap` (derive API) for argument parsing and `indicatif`\nfor progress bars. No GUI code. Results printed via the tool's `PrintResults` trait.\n\n---\n\n## czkawka_gui\n\nLegacy GTK 4 GUI. **Maintenance mode only** – no new features are added. Bug-fixes that\nkeep it compatible with core API changes are accepted.\n\n---\n\n## misc/\n\n**Translation tooling** (`ai_translate/`):\n- `translate.py` – AI-powered batch translation into all supported languages.\n- `validate_translations.py` – Checks placeholder consistency across translations.\n  Pass `--fix` to automatically remove invalid entries.\n\n**Dead-code detection** (run by `run_checks.sh`, see `just fix` above):\n- `find_unused_fluent_translations.py` / `find_unused_slint_translations.py` – Unused\n  translation keys.\n- `find_unused_callbacks.py` – Slint callbacks never invoked from Rust.\n- `find_unused_settings_properties.py` – Settings struct fields never read by the UI.\n- `delete_unused_krokiet_slint_imports.py` – Removes dead `import` lines from `.slint` files.\n\n**Packaging / release:**\n- `gen_cedinia_licenses.py` – Generates `THIRD_PARTY_LICENSES.txt` from Cargo metadata.\n- `gen_android_icons.py` – Generates cedinia's Android adaptive-icon assets from an SVG logo.\n- `simplify_and_minify_svg.py` – Minifies SVG icons via Inkscape.\n- `pack_all_backends.sh` / `.ps1` – Bundles an all-backends krokiet binary with per-backend\n  launcher scripts into a release zip.\n- `flathub.sh` – Generates Flatpak cargo-sources metadata for the Flathub manifest.\n- `add_icon_exe/` – Cargo helper crate that embeds the `.ico` into Windows binaries at build time.\n- `docker/` – `Dockerfile` for containerized builds.\n- `nix/` – Nix flake (`flake.nix`, `packages.nix`) for Nix-based builds.\n- `install_scripts/` – `install_linux.sh`, `install_macos.sh`, `install_windows.bat` end-user\n  installers.\n\n**Dev utilities:**\n- `remove_comments.py` – Strips comments from source files (one-off cleanup tool).\n- `compare_files.sh` – Diffs MD5 hashes of CI build artifacts across runs to check determinism.\n- `run_checks.sh` – Runs all the dead-code detection scripts above; invoked by `just fix`.\n\n**Benchmarks** (standalone Cargo crates):\n- `test_image_perf/`, `test_read_perf/` – Microbenchmarks for image hashing / file reading.\n- `test_compilation_speed_size/` – Tracks build time and binary size across changes.\n\n---\n\n## i18n\n\nAll user-visible strings use [Fluent](https://projectfluent.org/) (`.ftl` files).\n\n| Project      | Macro  | File pattern                                |\n|--------------|--------|---------------------------------------------|\n| krokiet      | `flk!` | `krokiet/i18n/<lang>/krokiet.ftl`           |\n| cedinia      | `flc!` | `cedinia/i18n/<lang>/cedinia.ftl`           |\n| czkawka_core | `flc!` | `czkawka_core/i18n/<lang>/czkawka_core.ftl` |\n| czkawka_gui  | `flg!` | `czkawka_gui/i18n/<lang>/czkawka_gui.ftl`   |\n\nEnglish is the source/fallback language. All other locales are AI-translated and then validated.\n\n**Important:** Only edit the English `.ftl` files (`i18n/en/`) directly in this repository.\nAll other language files are managed through [Crowdin](https://crowdin.com/) and will be\n**overwritten** when translations are pulled from Crowdin. Any manual edits to non-English\n`.ftl` files in the repo will be lost on the next `just unpack_translations` run.\n\n---\n\n## Slint UI conventions\n\n- **Hidden Text elements for width measurement** – where a layout element must adapt its width to\n  translated label text, add off-screen `Text` instances (`x: -10000px; y: -10000px; height: 0`)\n  and compute `preferred-width` at runtime (see `LeftSidePanel`, `CompareInfoBar`).\n- **Enums over strings** – UI state that takes a fixed set of values should use a Slint `enum`,\n  not a `string` (e.g. `ConfirmPopupAction`, `ActiveTool`, `ScanState`).\n- **Global state** – Application-wide state lives in Slint `global` blocks (`GuiState`,\n  `AppState`, `Settings`, `Translations`, …). Rust reads/writes via `app.global::<GlobalName>()`.\n\n---\n\n## Build profiles (Cargo.toml)\n\n| Profile        | Purpose                                                              |\n|----------------|----------------------------------------------------------------------|\n| `release`      | Standard release                                                     |\n| `fast_release` | Incremental, stripped – fast iteration                               |\n| `rdebug`       | Release + full debug symbols (profiling)                             |\n| `fastest`      | Max opt, LTO, panic=abort – mostly benchmarks/poc how fast it can be |\n| `fastci`       | Small binary, fast CI builds                                         |\n\n---\n\n## justfile quick reference\n\n```\njust run krokiet          # debug run\njust runr krokiet         # fast_release run\njust fix                  # format + clippy + Python checks\njust translate            # AI-translate all projects\njust validate_translations [--fix]\njust pack_translations    # create i18n_translations.zip for Crowdin\njust unpack_translations <path>\njust android              # build + install + launch on device\njust androidr             # release variant\n```\n","category":"root","tokens":4285}]}