Merge pull request #11 from vnidrop/docs/agents-md

docs: AGENTS.md guides and multi-platform app icons
This commit is contained in:
Hammed Abass
2026-07-13 00:52:58 +02:00
committed by GitHub
67 changed files with 1021 additions and 240 deletions

3
.gitignore vendored
View File

@@ -19,3 +19,6 @@ captures
node_modules/ node_modules/
target/ target/
.junie .junie
# Local design export scratch
output/

308
AGENTS.md Normal file
View File

@@ -0,0 +1,308 @@
# AGENTS.md
Operational instructions for coding agents working in this repository.
Humans: see `README.md` for product overview and run configs.
Agents: read this file (and the nearest nested `AGENTS.md`) before editing.
Nested guides take precedence when editing under those trees:
- [`crates/vnidrop/AGENTS.md`](crates/vnidrop/AGENTS.md) — Rust core
- [`shared/AGENTS.md`](shared/AGENTS.md) — Compose Multiplatform UI / KMP
---
## Project overview
VniDrop is a cross-platform **local P2P file transfer** app (Android, iOS, Desktop).
| Layer | Path | Responsibility |
|-------|------|----------------|
| Rust core | `crates/vnidrop/` | Iroh endpoint, blobs, SQLite, tickets, approval, streaming |
| Shared KMP | `shared/` | Compose UI, ViewModels, expect/actual platform bridges |
| Hosts | `androidApp/`, `iosApp/`, `desktopApp/` | Thin app shells |
**Invariant:** UI/platform opens files and handles pickers; **Rust streams bytes**.
Do not design features that move transfer payloads through Kotlin heap by default.
Domain docs (reference, do not paste into PRs):
- [`crates/vnidrop/CORE_FLOW.md`](crates/vnidrop/CORE_FLOW.md)
- [`crates/vnidrop/tests/README.md`](crates/vnidrop/tests/README.md)
---
## Absolute rules
1. Prefer PRs into `master`. Do not merge to `master` locally unless the user asks.
2. Do not `git push`, force-push, or open a PR unless the user asks.
3. If `commit.gpgsign` is enabled, create **signed** commits only. If signing fails
(empty `ssh-add -l`), stop and tell the user to unlock the key. Never switch to
unsigned commits to “unblock” yourself.
4. Change only files required for the task. No drive-by refactors, dependency bumps,
or repo-wide formatting.
5. Do not force architecture migrations (MVI, Hilt, Nav3, etc.) unless requested.
6. Never commit secrets, key material, or passphrases.
7. Destructive git (`reset --hard`, `push --force`, dropping DBs) only with explicit
user approval.
8. **Every bug fix includes a regression test** at the lowest layer that catches it.
9. After code changes, run the **relevant** checks in [Build and test](#build-and-test)
and fix failures before finishing.
---
## Build and test
Install prerequisites when missing: Rust stable + rustfmt + clippy, JDK 17,
Android NDK/SDK only if building Android, Xcode only for iOS.
### Rust core (`crates/vnidrop` or workspace root)
Run from the **repo root** (Cargo workspace):
```bash
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace --all-targets
```
Focused:
```bash
cargo test -p vnidrop
cargo test -p vnidrop --test output_sink
cargo test -p vnidrop --test transfer
cargo test -p vnidrop --test approval
cargo test -p vnidrop --test lifecycle
```
After finishing Rust edits, format:
```bash
cargo fmt --all
```
CI also runs `cargo doc --workspace --no-deps` with `RUSTDOCFLAGS=-D warnings`
(see `.github/workflows/rust-core.yml`). Run it before large Rust public-API changes.
### Shared KMP / Compose (`shared/`)
```bash
./gradlew :shared:jvmTest
./gradlew :shared:compileKotlinJvm
```
Other targets (slower / machine-dependent):
```bash
./gradlew :shared:testAndroidHostTest
./gradlew :shared:iosSimulatorArm64Test # macOS + Xcode
./gradlew :androidApp:assembleDebug
./gradlew :desktopApp:run
```
**Note:** `jvmTest` CI runs on **macOS** because Gobley host cargo is enabled for
the current Gobley host; Linux JVM cargo may be disabled in
`shared/build.gradle.kts`. Prefer macOS for local parity with CI.
### What to run before finishing
| You changed… | Minimum verification |
|--------------|----------------------|
| `crates/vnidrop/**` only | `cargo fmt`, `cargo clippy … -D warnings`, `cargo test -p vnidrop` |
| Cancel / export / sinks | Above + `cargo test -p vnidrop --test output_sink` |
| `shared/**` only | `./gradlew :shared:jvmTest` |
| Both | Rust suite + `:shared:jvmTest` |
| Docs only | No suite required; verify links/paths |
Do not kill long `cargo` / Gradle runs mid-flight unless they hang past several
minutes with no output; first builds are slow.
---
## Repository map (edit here)
### Rust runtime (keep split; do not re-merge into one file)
```
crates/vnidrop/src/runtime/
mod.rs # CoreInner, startup recovery, emit helpers
facade.rs # UniFFI VnidropCore + block_on
share.rs # import / share
receive.rs # receive, download, export, output sinks
lifecycle.rs # cancel, delete, status, access mode, shutdown
provider.rs # provider events, per-connection send progress
```
Other core modules: `filesystem.rs`, `repository.rs`, `approval.rs`,
`handshake.rs`, `ticket.rs`, `access_policy.rs`, `event_hub.rs`, `api.rs`.
### Shared app
```
shared/src/commonMain/kotlin/com/vnidrop/app/
core/ # CoreGateway, models, pickers interfaces
feature/send|receive|approvals|settings|app/
ui/theme|components|navigation|feedback|state/
androidMain|iosMain|jvmMain/ # expect/actual implementations
```
### Platform file rules (do not violate)
- Desktop / path-based iOS: paths; directory walk in Rust when `is_directory`.
- Android **share**: ParcelFileDescriptor **file** FDs only — never a directory FD.
Folder share expands SAF trees in Kotlin to per-file FDs + relative names.
- Android **receive** default: MediaStore Downloads sink; custom trees via SAF write.
- Receive publish: no-overwrite temp + hard link / exclusive rename
(see `CORE_FLOW.md`).
---
## Code style
### General
- Match surrounding code (naming, imports, error handling).
- Prefer small, reviewable diffs. Avoid files growing past ~800 LoC without
splitting when adding substantial logic.
- Do not add one-off helpers used only once if an inline block is clearer.
- Prefer exhaustive `when` / `match`; avoid wildcards that hide new cases.
### Comments (strict)
Comment **why**, invariants, and platform/concurrency traps only.
- Do comment: cancel-before-await ordering, SAF/FD limits, security-scoped
leases, “exactly one finish/abort after start_file”, durability rules.
- Do **not** comment: restating the next line, tutorial narration, section
banners that repeat the function name, pasted docs from this file.
### Rust
- Follow Clippy with `-D warnings` (CI fails otherwise).
- Do not hold `std::sync::MutexGuard` or other guards across `.await`.
- Prefer `Handle::block_on` via existing `VnidropCore::block_on` for concurrent
API entry; cancel signals active transfers **synchronously** before async work.
- Prefer private modules; export only what UniFFI / other crates need.
- New public traits/types: short docs when the role is non-obvious.
### Kotlin / Compose
For UI and presentation work, **load and follow** the in-repo skill:
```text
.codex/skills/compose-skill/SKILL.md
```
- Open at most one `references/*.md` file when the skills Quick Routing requires it.
- Do not invent a second Compose style guide.
- VniDrop uses **MVVM-style** ViewModels (`*State` + `StateFlow` + named methods),
not a forced MVI `onEvent` base — adapt, do not rewrite.
- Theme via `LocalVniDropColors` / `VniDropThemeTokens` only.
Brand primary (light): HSL `271, 91%, 65%``#A855F7`.
- Strings: CMP `Res.string.*` / composeResources — not Android `R` in `commonMain`.
- Verify multiplatform target support before adding AndroidX/Jetpack deps to
`commonMain`.
Details: [`shared/AGENTS.md`](shared/AGENTS.md).
---
## Testing instructions
- Prefer deterministic tests (gates, fixed sizes, public API fixtures).
- Avoid long sleeps; if polling is required: short interval + hard timeout +
clear assertion message.
- Rust integration tests use **public** UniFFI API + `tests/support/` only.
- Failure paths: assert durable status and/or events when applicable, not only
the error string.
- Do not add tests for pure static constants.
- Do not add negative tests for code you deleted.
- Prefer comparing whole objects when equality is meaningful.
Layout:
| Layer | Location |
|-------|----------|
| Rust unit / private | `crates/vnidrop/src/tests/` |
| Rust integration | `crates/vnidrop/tests/` |
| Shared logic | `shared/src/commonTest/` |
| Shared Compose/JVM | `shared/src/jvmTest/` |
---
## Git and PR instructions
### Branches
Name the change, not a roadmap step:
- Good: `feat/folder-share`, `fix/cancel-export-hang`, `docs/agents-md`
- Bad: `feat/step3-remaining`, `wip`, `temp`
After a PR merges: delete the feature branch **locally and on `origin`**, then
branch from updated `master`.
### Commits
- Style in history: `feat(scope):`, `fix(scope):`, `refactor(scope):`, `docs:`, `ci:`.
- Subject = outcome; body only when needed.
- Signed when repo requires it.
### Pull requests
- Title matches the main change.
- Summary: short bullets of what/why.
- **Test plan must be executable for this PR**:
- exact commands, and/or
- 12 concrete scenarios that would catch a regression.
- No filler plans (“everything works”, “CI green”) without commands or scenarios.
---
## Security considerations
- Treat tickets and endpoint IDs as sensitive enough not to log full blobs in
production paths.
- Do not weaken approval/access checks for convenience.
- Do not store secrets in the repo; app data dirs and key files stay out of git.
- Be careful with file publish races (no-clobber rename/link policy exists for a reason).
---
## Common tasks → start files
| Task | Start here |
|------|------------|
| Share / multi-file / folders | `runtime/share.rs`, `filesystem.rs`, platform `FileSystemService.*` |
| Receive / export / sinks | `runtime/receive.rs` |
| Cancel / delete / stop share | `runtime/lifecycle.rs`, `facade.rs` |
| Per-receiver send progress | `runtime/provider.rs`, `ui/state/AppUiModels.kt` |
| Approvals | `feature/approvals/`, `approval.rs` |
| QR / NFC invitations | `TransferShareActions.*`, `ReceiveInvitationActions.*` |
| Theme / brand | `ui/theme/VniDropTheme.kt` |
| Compose skill | `.codex/skills/compose-skill/SKILL.md` |
---
## Anti-patterns (never)
- Streaming multi-MB transfer data through Kotlin as the primary design
- Passing Android **directory** FDs into Rust
- Nested exclusive `Runtime::block_on` that deadlocks cancel during receive
- Holding locks across `.await`
- Rebuilding a monolithic `runtime.rs`
- Flaky multi-minute sleeps in tests
- Unsigned commits when signing is required
- Force-push or secret commits without explicit user direction
---
## Implementation checklist
1. Read this file + nearest nested `AGENTS.md`.
2. For Compose/UI: load `compose-skill`.
3. Smallest correct change; tests for bugs/behavior changes.
4. Run relevant build/test commands; fix failures.
5. Sparse comments only where non-obvious.
6. Commit (signed) / push / PR only as the user requests.
7. Summarize what changed and what you ran.

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -1,31 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt" xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp" android:width="108dp"
android:height="108dp" android:height="108dp"
android:viewportWidth="108" android:viewportWidth="108"
android:viewportHeight="108"> android:viewportHeight="108">
<group
android:scaleX="0.26"
android:scaleY="0.26"
android:translateX="18.02"
android:translateY="15.84">
<path <path
android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z"> android:fillType="evenOdd"
android:pathData="M69.70,55.35L95.12,55.35C102.09,55.35 107.42,61.09 107.42,68.06L107.42,159.49C107.42,167.69 103.73,173.43 103.73,179.99C103.73,199.67 119.72,215.25 141.04,215.25C162.36,215.25 177.53,199.67 177.53,179.99C177.53,173.43 174.66,167.69 174.66,159.49L174.66,68.06C174.66,61.09 179.99,55.35 186.96,55.35L205.82,55.35C214.84,55.35 222.22,62.73 222.22,71.75L222.22,159.49C222.22,202.95 186.55,238.21 141.04,238.21C95.53,238.21 59.04,202.95 59.04,159.49L59.04,111.93L65.60,111.93L65.60,94.71C59.45,94.71 54.53,92.66 54.53,88.56L54.53,79.95C54.53,76.26 57.40,73.39 61.09,73.39L69.70,73.39ZM74.62,78.31C73.39,78.31 72.57,79.54 72.57,80.77L72.57,87.33C72.57,88.97 73.80,89.79 75.44,89.79L81.18,89.79C82.82,89.79 83.64,88.56 83.64,86.92L83.64,81.18C83.64,79.54 82.41,78.31 80.77,78.31Z">
<aapt:attr name="android:fillColor"> <aapt:attr name="android:fillColor">
<gradient <gradient android:startX="59" android:startY="55" android:endX="222" android:endY="238" android:type="linear">
android:endX="85.84757" <item android:color="#FFA855F7" android:offset="0" />
android:endY="92.4963" <item android:color="#FF9D4DF4" android:offset="0.48" />
android:startX="42.9492" <item android:color="#FF7C2AEF" android:offset="1" />
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0"/>
<item
android:color="#00000000"
android:offset="1.0"/>
</gradient> </gradient>
</aapt:attr> </aapt:attr>
</path> </path>
<path <path android:pathData="M140.63,126.28C134.48,134.48 121.36,150.88 115.62,162.77C108.24,177.53 111.52,193.11 122.18,201.31C132.43,207.87 148.01,207.87 158.67,200.90C168.92,193.52 172.20,177.53 165.64,162.77C159.90,150.88 147.19,134.48 140.63,126.28Z">
android:fillColor="#FFFFFF" <aapt:attr name="android:fillColor">
android:fillType="nonZero" <gradient android:startX="116" android:startY="126" android:endX="166" android:endY="208" android:type="linear">
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z" <item android:color="#FFA855F7" android:offset="0" />
android:strokeWidth="1" <item android:color="#FF9D4DF4" android:offset="0.48" />
android:strokeColor="#00000000"/> <item android:color="#FF7C2AEF" android:offset="1" />
</gradient>
</aapt:attr>
</path>
<path android:fillColor="#FFD8B4FE" android:pathData="M181.22,55.76H205.82C214.88,55.76 222.22,63.10 222.22,72.16V95.53Z" />
</group>
</vector> </vector>

View File

@@ -5,166 +5,6 @@
android:viewportWidth="108" android:viewportWidth="108"
android:viewportHeight="108"> android:viewportHeight="108">
<path <path
android:fillColor="#3DDC84" android:fillColor="#07061E"
android:pathData="M0,0h108v108h-108z"/> android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
</vector> </vector>

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/> <background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/> <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon> </adaptive-icon>

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/> <background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/> <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon> </adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>

BIN
assets/1024x1024.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

26
assets/1024x1024.svg Normal file
View File

@@ -0,0 +1,26 @@
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="url(#paint0_linear_11_12)"/>
<path d="M520.4 431.72C495.8 464.52 443.32 530.12 420.36 577.68C390.84 636.72 403.96 699.04 446.6 731.84C487.6 758.08 549.92 758.08 592.56 730.2C633.56 700.68 646.68 636.72 620.44 577.68C597.48 530.12 546.64 464.52 520.4 431.72Z" fill="url(#paint1_linear_11_12)"/>
<mask id="mask0_11_12" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="176" y="148" width="671" height="732">
<path d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="white"/>
</mask>
<g mask="url(#mask0_11_12)">
<path d="M688 148H782C832 148 842 171.8 847.48 210V303.68L688 148Z" fill="url(#paint2_linear_11_12)"/>
</g>
<defs>
<linearGradient id="paint0_linear_11_12" x1="176" y1="148" x2="904.706" y2="816.252" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint1_linear_11_12" x1="404.439" y1="431.72" x2="707.314" y2="649.286" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint2_linear_11_12" x1="683.48" y1="144.6" x2="793.636" y2="306.833" gradientUnits="userSpaceOnUse">
<stop stop-color="#F2DDFF"/>
<stop offset="1" stop-color="#C084FC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

26
assets/108x108.svg Normal file
View File

@@ -0,0 +1,26 @@
<svg width="108" height="108" viewBox="0 0 108 108" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.9623 15.6094H35.6864C38.6269 15.6094 40.8755 18.0309 40.8755 20.9714V59.5434C40.8755 63.0028 39.3188 65.4244 39.3188 68.1919C39.3188 76.4944 46.0645 83.0672 55.0589 83.0672C64.0533 83.0672 70.4531 76.4944 70.4531 68.1919C70.4531 65.4244 69.2423 63.0028 69.2423 59.5434V20.9714C69.2423 18.0309 71.4909 15.6094 74.4314 15.6094H82.388C86.1933 15.6094 89.3067 18.7228 89.3067 22.5281V59.5434C89.3067 77.8781 74.2584 92.7534 55.0589 92.7534C35.8594 92.7534 20.4652 77.8781 20.4652 59.5434V39.4791H23.2327V32.2144C20.6381 32.2144 18.5625 31.3495 18.5625 29.6198V25.9875C18.5625 24.4308 19.7733 23.22 21.33 23.22H24.9623V15.6094ZM27.038 25.2956C26.5191 25.2956 26.1731 25.8145 26.1731 26.3334V29.1009C26.1731 29.7928 26.692 30.1388 27.3839 30.1388H29.8055C30.4973 30.1388 30.8433 29.6198 30.8433 28.928V26.5064C30.8433 25.8145 30.3244 25.2956 29.6325 25.2956H27.038Z" fill="url(#paint0_linear_11_12)"/>
<path d="M54.8859 45.533C52.2914 48.9923 46.7564 55.9111 44.3348 60.9272C41.2214 67.1541 42.6051 73.7269 47.1023 77.1862C51.4265 79.9537 57.9994 79.9537 62.4965 77.0133C66.8208 73.8998 68.2045 67.1541 65.437 60.9272C63.0155 55.9111 57.6534 48.9923 54.8859 45.533Z" fill="url(#paint1_linear_11_12)"/>
<mask id="mask0_11_12" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="18" y="15" width="72" height="78">
<path d="M24.9623 15.6094H35.6864C38.6269 15.6094 40.8755 18.0309 40.8755 20.9714V59.5434C40.8755 63.0028 39.3188 65.4244 39.3188 68.1919C39.3188 76.4944 46.0645 83.0672 55.0589 83.0672C64.0533 83.0672 70.4531 76.4944 70.4531 68.1919C70.4531 65.4244 69.2423 63.0028 69.2423 59.5434V20.9714C69.2423 18.0309 71.4909 15.6094 74.4314 15.6094H82.388C86.1933 15.6094 89.3067 18.7228 89.3067 22.5281V59.5434C89.3067 77.8781 74.2584 92.7534 55.0589 92.7534C35.8594 92.7534 20.4652 77.8781 20.4652 59.5434V39.4791H23.2327V32.2144C20.6381 32.2144 18.5625 31.3495 18.5625 29.6198V25.9875C18.5625 24.4308 19.7733 23.22 21.33 23.22H24.9623V15.6094ZM27.038 25.2956C26.5191 25.2956 26.1731 25.8145 26.1731 26.3334V29.1009C26.1731 29.7928 26.692 30.1388 27.3839 30.1388H29.8055C30.4973 30.1388 30.8433 29.6198 30.8433 28.928V26.5064C30.8433 25.8145 30.3244 25.2956 29.6325 25.2956H27.038Z" fill="white"/>
</mask>
<g mask="url(#mask0_11_12)">
<path d="M72.5625 15.6094H82.4766C87.75 15.6094 88.8047 18.1195 89.3827 22.1484V32.0288L72.5625 15.6094Z" fill="url(#paint2_linear_11_12)"/>
</g>
<defs>
<linearGradient id="paint0_linear_11_12" x1="18.5625" y1="15.6094" x2="95.4182" y2="86.0891" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint1_linear_11_12" x1="42.6557" y1="45.533" x2="74.5995" y2="68.4794" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint2_linear_11_12" x1="72.0858" y1="15.2508" x2="83.7038" y2="32.3613" gradientUnits="userSpaceOnUse">
<stop stop-color="#F2DDFF"/>
<stop offset="1" stop-color="#C084FC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
assets/android/app-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -0,0 +1,30 @@
<svg width="108" height="108" viewBox="0 0 108 108" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg x="21.6" y="21.6" width="64.8" height="64.8" viewBox="0 0 108 108">
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.9623 15.6094H35.6864C38.6269 15.6094 40.8755 18.0309 40.8755 20.9714V59.5434C40.8755 63.0028 39.3188 65.4244 39.3188 68.1919C39.3188 76.4944 46.0645 83.0672 55.0589 83.0672C64.0533 83.0672 70.4531 76.4944 70.4531 68.1919C70.4531 65.4244 69.2423 63.0028 69.2423 59.5434V20.9714C69.2423 18.0309 71.4909 15.6094 74.4314 15.6094H82.388C86.1933 15.6094 89.3067 18.7228 89.3067 22.5281V59.5434C89.3067 77.8781 74.2584 92.7534 55.0589 92.7534C35.8594 92.7534 20.4652 77.8781 20.4652 59.5434V39.4791H23.2327V32.2144C20.6381 32.2144 18.5625 31.3495 18.5625 29.6198V25.9875C18.5625 24.4308 19.7733 23.22 21.33 23.22H24.9623V15.6094ZM27.038 25.2956C26.5191 25.2956 26.1731 25.8145 26.1731 26.3334V29.1009C26.1731 29.7928 26.692 30.1388 27.3839 30.1388H29.8055C30.4973 30.1388 30.8433 29.6198 30.8433 28.928V26.5064C30.8433 25.8145 30.3244 25.2956 29.6325 25.2956H27.038Z" fill="url(#paint0_linear_11_12)"/>
<path d="M54.8859 45.533C52.2914 48.9923 46.7564 55.9111 44.3348 60.9272C41.2214 67.1541 42.6051 73.7269 47.1023 77.1862C51.4265 79.9537 57.9994 79.9537 62.4965 77.0133C66.8208 73.8998 68.2045 67.1541 65.437 60.9272C63.0155 55.9111 57.6534 48.9923 54.8859 45.533Z" fill="url(#paint1_linear_11_12)"/>
<mask id="mask0_11_12" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="18" y="15" width="72" height="78">
<path d="M24.9623 15.6094H35.6864C38.6269 15.6094 40.8755 18.0309 40.8755 20.9714V59.5434C40.8755 63.0028 39.3188 65.4244 39.3188 68.1919C39.3188 76.4944 46.0645 83.0672 55.0589 83.0672C64.0533 83.0672 70.4531 76.4944 70.4531 68.1919C70.4531 65.4244 69.2423 63.0028 69.2423 59.5434V20.9714C69.2423 18.0309 71.4909 15.6094 74.4314 15.6094H82.388C86.1933 15.6094 89.3067 18.7228 89.3067 22.5281V59.5434C89.3067 77.8781 74.2584 92.7534 55.0589 92.7534C35.8594 92.7534 20.4652 77.8781 20.4652 59.5434V39.4791H23.2327V32.2144C20.6381 32.2144 18.5625 31.3495 18.5625 29.6198V25.9875C18.5625 24.4308 19.7733 23.22 21.33 23.22H24.9623V15.6094ZM27.038 25.2956C26.5191 25.2956 26.1731 25.8145 26.1731 26.3334V29.1009C26.1731 29.7928 26.692 30.1388 27.3839 30.1388H29.8055C30.4973 30.1388 30.8433 29.6198 30.8433 28.928V26.5064C30.8433 25.8145 30.3244 25.2956 29.6325 25.2956H27.038Z" fill="white"/>
</mask>
<g mask="url(#mask0_11_12)">
<path d="M72.5625 15.6094H82.4766C87.75 15.6094 88.8047 18.1195 89.3827 22.1484V32.0288L72.5625 15.6094Z" fill="url(#paint2_linear_11_12)"/>
</g>
<defs>
<linearGradient id="paint0_linear_11_12" x1="18.5625" y1="15.6094" x2="95.4182" y2="86.0891" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint1_linear_11_12" x1="42.6557" y1="45.533" x2="74.5995" y2="68.4794" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint2_linear_11_12" x1="72.0858" y1="15.2508" x2="83.7038" y2="32.3613" gradientUnits="userSpaceOnUse">
<stop stop-color="#F2DDFF"/>
<stop offset="1" stop-color="#C084FC"/>
</linearGradient>
</defs>
</svg>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
assets/desktop/app-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@@ -0,0 +1,29 @@
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="40" y="40" width="944" height="944" rx="210" fill="#FFFFFF" stroke="#E9E7F0" stroke-width="8"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="url(#paint0_linear_11_12)"/>
<path d="M520.4 431.72C495.8 464.52 443.32 530.12 420.36 577.68C390.84 636.72 403.96 699.04 446.6 731.84C487.6 758.08 549.92 758.08 592.56 730.2C633.56 700.68 646.68 636.72 620.44 577.68C597.48 530.12 546.64 464.52 520.4 431.72Z" fill="url(#paint1_linear_11_12)"/>
<mask id="mask0_11_12" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="176" y="148" width="671" height="732">
<path d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="white"/>
</mask>
<g mask="url(#mask0_11_12)">
<path d="M688 148H782C832 148 842 171.8 847.48 210V303.68L688 148Z" fill="url(#paint2_linear_11_12)"/>
</g>
<defs>
<linearGradient id="paint0_linear_11_12" x1="176" y1="148" x2="904.706" y2="816.252" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint1_linear_11_12" x1="404.439" y1="431.72" x2="707.314" y2="649.286" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint2_linear_11_12" x1="683.48" y1="144.6" x2="793.636" y2="306.833" gradientUnits="userSpaceOnUse">
<stop stop-color="#F2DDFF"/>
<stop offset="1" stop-color="#C084FC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

View File

@@ -0,0 +1,26 @@
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="url(#paint0_linear_11_12)"/>
<path d="M520.4 431.72C495.8 464.52 443.32 530.12 420.36 577.68C390.84 636.72 403.96 699.04 446.6 731.84C487.6 758.08 549.92 758.08 592.56 730.2C633.56 700.68 646.68 636.72 620.44 577.68C597.48 530.12 546.64 464.52 520.4 431.72Z" fill="url(#paint1_linear_11_12)"/>
<mask id="mask0_11_12" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="176" y="148" width="671" height="732">
<path d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="white"/>
</mask>
<g mask="url(#mask0_11_12)">
<path d="M688 148H782C832 148 842 171.8 847.48 210V303.68L688 148Z" fill="url(#paint2_linear_11_12)"/>
</g>
<defs>
<linearGradient id="paint0_linear_11_12" x1="176" y1="148" x2="904.706" y2="816.252" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint1_linear_11_12" x1="404.439" y1="431.72" x2="707.314" y2="649.286" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint2_linear_11_12" x1="683.48" y1="144.6" x2="793.636" y2="306.833" gradientUnits="userSpaceOnUse">
<stop stop-color="#F2DDFF"/>
<stop offset="1" stop-color="#C084FC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
assets/ios/app-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

29
assets/ios/app-icon.svg Normal file
View File

@@ -0,0 +1,29 @@
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="1024" height="1024" fill="#FFFFFF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="url(#paint0_linear_11_12)"/>
<path d="M520.4 431.72C495.8 464.52 443.32 530.12 420.36 577.68C390.84 636.72 403.96 699.04 446.6 731.84C487.6 758.08 549.92 758.08 592.56 730.2C633.56 700.68 646.68 636.72 620.44 577.68C597.48 530.12 546.64 464.52 520.4 431.72Z" fill="url(#paint1_linear_11_12)"/>
<mask id="mask0_11_12" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="176" y="148" width="671" height="732">
<path d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="white"/>
</mask>
<g mask="url(#mask0_11_12)">
<path d="M688 148H782C832 148 842 171.8 847.48 210V303.68L688 148Z" fill="url(#paint2_linear_11_12)"/>
</g>
<defs>
<linearGradient id="paint0_linear_11_12" x1="176" y1="148" x2="904.706" y2="816.252" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint1_linear_11_12" x1="404.439" y1="431.72" x2="707.314" y2="649.286" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint2_linear_11_12" x1="683.48" y1="144.6" x2="793.636" y2="306.833" gradientUnits="userSpaceOnUse">
<stop stop-color="#F2DDFF"/>
<stop offset="1" stop-color="#C084FC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
assets/ios/foreground.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

26
assets/ios/foreground.svg Normal file
View File

@@ -0,0 +1,26 @@
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="url(#paint0_linear_11_12)"/>
<path d="M520.4 431.72C495.8 464.52 443.32 530.12 420.36 577.68C390.84 636.72 403.96 699.04 446.6 731.84C487.6 758.08 549.92 758.08 592.56 730.2C633.56 700.68 646.68 636.72 620.44 577.68C597.48 530.12 546.64 464.52 520.4 431.72Z" fill="url(#paint1_linear_11_12)"/>
<mask id="mask0_11_12" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="176" y="148" width="671" height="732">
<path d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="white"/>
</mask>
<g mask="url(#mask0_11_12)">
<path d="M688 148H782C832 148 842 171.8 847.48 210V303.68L688 148Z" fill="url(#paint2_linear_11_12)"/>
</g>
<defs>
<linearGradient id="paint0_linear_11_12" x1="176" y1="148" x2="904.706" y2="816.252" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint1_linear_11_12" x1="404.439" y1="431.72" x2="707.314" y2="649.286" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint2_linear_11_12" x1="683.48" y1="144.6" x2="793.636" y2="306.833" gradientUnits="userSpaceOnUse">
<stop stop-color="#F2DDFF"/>
<stop offset="1" stop-color="#C084FC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
assets/linux/app-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

29
assets/linux/app-icon.svg Normal file
View File

@@ -0,0 +1,29 @@
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="40" y="40" width="944" height="944" rx="210" fill="#FFFFFF" stroke="#E9E7F0" stroke-width="8"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="url(#paint0_linear_11_12)"/>
<path d="M520.4 431.72C495.8 464.52 443.32 530.12 420.36 577.68C390.84 636.72 403.96 699.04 446.6 731.84C487.6 758.08 549.92 758.08 592.56 730.2C633.56 700.68 646.68 636.72 620.44 577.68C597.48 530.12 546.64 464.52 520.4 431.72Z" fill="url(#paint1_linear_11_12)"/>
<mask id="mask0_11_12" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="176" y="148" width="671" height="732">
<path d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="white"/>
</mask>
<g mask="url(#mask0_11_12)">
<path d="M688 148H782C832 148 842 171.8 847.48 210V303.68L688 148Z" fill="url(#paint2_linear_11_12)"/>
</g>
<defs>
<linearGradient id="paint0_linear_11_12" x1="176" y1="148" x2="904.706" y2="816.252" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint1_linear_11_12" x1="404.439" y1="431.72" x2="707.314" y2="649.286" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint2_linear_11_12" x1="683.48" y1="144.6" x2="793.636" y2="306.833" gradientUnits="userSpaceOnUse">
<stop stop-color="#F2DDFF"/>
<stop offset="1" stop-color="#C084FC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
assets/linux/foreground.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

View File

@@ -0,0 +1,26 @@
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="url(#paint0_linear_11_12)"/>
<path d="M520.4 431.72C495.8 464.52 443.32 530.12 420.36 577.68C390.84 636.72 403.96 699.04 446.6 731.84C487.6 758.08 549.92 758.08 592.56 730.2C633.56 700.68 646.68 636.72 620.44 577.68C597.48 530.12 546.64 464.52 520.4 431.72Z" fill="url(#paint1_linear_11_12)"/>
<mask id="mask0_11_12" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="176" y="148" width="671" height="732">
<path d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="white"/>
</mask>
<g mask="url(#mask0_11_12)">
<path d="M688 148H782C832 148 842 171.8 847.48 210V303.68L688 148Z" fill="url(#paint2_linear_11_12)"/>
</g>
<defs>
<linearGradient id="paint0_linear_11_12" x1="176" y1="148" x2="904.706" y2="816.252" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint1_linear_11_12" x1="404.439" y1="431.72" x2="707.314" y2="649.286" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint2_linear_11_12" x1="683.48" y1="144.6" x2="793.636" y2="306.833" gradientUnits="userSpaceOnUse">
<stop stop-color="#F2DDFF"/>
<stop offset="1" stop-color="#C084FC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
assets/macos/app-icon.icns Normal file

Binary file not shown.

BIN
assets/macos/app-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

29
assets/macos/app-icon.svg Normal file
View File

@@ -0,0 +1,29 @@
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="40" y="40" width="944" height="944" rx="210" fill="#FFFFFF" stroke="#E9E7F0" stroke-width="8"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="url(#paint0_linear_11_12)"/>
<path d="M520.4 431.72C495.8 464.52 443.32 530.12 420.36 577.68C390.84 636.72 403.96 699.04 446.6 731.84C487.6 758.08 549.92 758.08 592.56 730.2C633.56 700.68 646.68 636.72 620.44 577.68C597.48 530.12 546.64 464.52 520.4 431.72Z" fill="url(#paint1_linear_11_12)"/>
<mask id="mask0_11_12" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="176" y="148" width="671" height="732">
<path d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="white"/>
</mask>
<g mask="url(#mask0_11_12)">
<path d="M688 148H782C832 148 842 171.8 847.48 210V303.68L688 148Z" fill="url(#paint2_linear_11_12)"/>
</g>
<defs>
<linearGradient id="paint0_linear_11_12" x1="176" y1="148" x2="904.706" y2="816.252" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint1_linear_11_12" x1="404.439" y1="431.72" x2="707.314" y2="649.286" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint2_linear_11_12" x1="683.48" y1="144.6" x2="793.636" y2="306.833" gradientUnits="userSpaceOnUse">
<stop stop-color="#F2DDFF"/>
<stop offset="1" stop-color="#C084FC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
assets/macos/foreground.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

View File

@@ -0,0 +1,26 @@
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="url(#paint0_linear_11_12)"/>
<path d="M520.4 431.72C495.8 464.52 443.32 530.12 420.36 577.68C390.84 636.72 403.96 699.04 446.6 731.84C487.6 758.08 549.92 758.08 592.56 730.2C633.56 700.68 646.68 636.72 620.44 577.68C597.48 530.12 546.64 464.52 520.4 431.72Z" fill="url(#paint1_linear_11_12)"/>
<mask id="mask0_11_12" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="176" y="148" width="671" height="732">
<path d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="white"/>
</mask>
<g mask="url(#mask0_11_12)">
<path d="M688 148H782C832 148 842 171.8 847.48 210V303.68L688 148Z" fill="url(#paint2_linear_11_12)"/>
</g>
<defs>
<linearGradient id="paint0_linear_11_12" x1="176" y1="148" x2="904.706" y2="816.252" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint1_linear_11_12" x1="404.439" y1="431.72" x2="707.314" y2="649.286" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint2_linear_11_12" x1="683.48" y1="144.6" x2="793.636" y2="306.833" gradientUnits="userSpaceOnUse">
<stop stop-color="#F2DDFF"/>
<stop offset="1" stop-color="#C084FC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
assets/windows/app-icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
assets/windows/app-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@@ -0,0 +1,29 @@
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="40" y="40" width="944" height="944" rx="210" fill="#FFFFFF" stroke="#E9E7F0" stroke-width="8"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="url(#paint0_linear_11_12)"/>
<path d="M520.4 431.72C495.8 464.52 443.32 530.12 420.36 577.68C390.84 636.72 403.96 699.04 446.6 731.84C487.6 758.08 549.92 758.08 592.56 730.2C633.56 700.68 646.68 636.72 620.44 577.68C597.48 530.12 546.64 464.52 520.4 431.72Z" fill="url(#paint1_linear_11_12)"/>
<mask id="mask0_11_12" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="176" y="148" width="671" height="732">
<path d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="white"/>
</mask>
<g mask="url(#mask0_11_12)">
<path d="M688 148H782C832 148 842 171.8 847.48 210V303.68L688 148Z" fill="url(#paint2_linear_11_12)"/>
</g>
<defs>
<linearGradient id="paint0_linear_11_12" x1="176" y1="148" x2="904.706" y2="816.252" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint1_linear_11_12" x1="404.439" y1="431.72" x2="707.314" y2="649.286" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint2_linear_11_12" x1="683.48" y1="144.6" x2="793.636" y2="306.833" gradientUnits="userSpaceOnUse">
<stop stop-color="#F2DDFF"/>
<stop offset="1" stop-color="#C084FC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

View File

@@ -0,0 +1,26 @@
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="url(#paint0_linear_11_12)"/>
<path d="M520.4 431.72C495.8 464.52 443.32 530.12 420.36 577.68C390.84 636.72 403.96 699.04 446.6 731.84C487.6 758.08 549.92 758.08 592.56 730.2C633.56 700.68 646.68 636.72 620.44 577.68C597.48 530.12 546.64 464.52 520.4 431.72Z" fill="url(#paint1_linear_11_12)"/>
<mask id="mask0_11_12" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="176" y="148" width="671" height="732">
<path d="M236.68 148H338.36C366.24 148 387.56 170.96 387.56 198.84V564.56C387.56 597.36 372.8 620.32 372.8 646.56C372.8 725.28 436.76 787.6 522.04 787.6C607.32 787.6 668 725.28 668 646.56C668 620.32 656.52 597.36 656.52 564.56V198.84C656.52 170.96 677.84 148 705.72 148H781.16C817.24 148 846.76 177.52 846.76 213.6V564.56C846.76 738.4 704.08 879.44 522.04 879.44C340 879.44 194.04 738.4 194.04 564.56V374.32H220.28V305.44C195.68 305.44 176 297.24 176 280.84V246.4C176 231.64 187.48 220.16 202.24 220.16H236.68V148ZM256.36 239.84C251.44 239.84 248.16 244.76 248.16 249.68V275.92C248.16 282.48 253.08 285.76 259.64 285.76H282.6C289.16 285.76 292.44 280.84 292.44 274.28V251.32C292.44 244.76 287.52 239.84 280.96 239.84H256.36Z" fill="white"/>
</mask>
<g mask="url(#mask0_11_12)">
<path d="M688 148H782C832 148 842 171.8 847.48 210V303.68L688 148Z" fill="url(#paint2_linear_11_12)"/>
</g>
<defs>
<linearGradient id="paint0_linear_11_12" x1="176" y1="148" x2="904.706" y2="816.252" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint1_linear_11_12" x1="404.439" y1="431.72" x2="707.314" y2="649.286" gradientUnits="userSpaceOnUse">
<stop stop-color="#A855F7"/>
<stop offset="0.48" stop-color="#9D4DF4"/>
<stop offset="1" stop-color="#7C2AEF"/>
</linearGradient>
<linearGradient id="paint2_linear_11_12" x1="683.48" y1="144.6" x2="793.636" y2="306.833" gradientUnits="userSpaceOnUse">
<stop stop-color="#F2DDFF"/>
<stop offset="1" stop-color="#C084FC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

128
crates/vnidrop/AGENTS.md Normal file
View File

@@ -0,0 +1,128 @@
# AGENTS.md — `crates/vnidrop` (Rust core)
Nearest guide when editing under `crates/vnidrop/`. Root [`AGENTS.md`](../../AGENTS.md)
still applies; this file wins for Rust-specific commands and conventions.
---
## Purpose
This crate is the transfer backend exposed to Kotlin via UniFFI (`VnidropCore`).
It owns Iroh, blobs, SQLite history, tickets, approval handshake, and file streaming.
Read [`CORE_FLOW.md`](CORE_FLOW.md) before changing send/receive/export/cancel.
---
## Commands (run from repo root)
Always prefer workspace commands so lockfile/fmt stay consistent:
```bash
cargo fmt --all
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test -p vnidrop
cargo test --workspace --all-targets
```
Focused integration suites:
```bash
cargo test -p vnidrop --test transfer
cargo test -p vnidrop --test approval
cargo test -p vnidrop --test lifecycle
cargo test -p vnidrop --test output_sink
```
Docs (CI uses `-D warnings`):
```bash
RUSTDOCFLAGS='-D warnings' cargo doc -p vnidrop --no-deps
```
Run `cargo fmt --all` after finishing Rust edits without asking.
---
## Module layout
```
src/
runtime/
mod.rs # CoreInner, startup recovery, emit helpers
facade.rs # UniFFI surface, block_on, cancel entry
share.rs # share / import
receive.rs # receive, download, export, OutputSinkFile
lifecycle.rs # cancel share, delete, status, access mode, shutdown
provider.rs # provider messages, per-peer transfer progress
filesystem.rs # collect sources, atomic publish, path rules
repository.rs # SQLite
approval.rs / handshake.rs / ticket.rs / access_policy.rs / event_hub.rs
api.rs # UniFFI records/enums
tests/ # crate-private unit tests
tests/ # public-API integration tests + support/
```
**Do not** reassemble a single huge `runtime.rs`. Prefer new focused modules if a
file approaches ~800 LoC of non-test code.
---
## Hard constraints
1. **Public API stability:** UniFFI surface changes break Kotlin. Prefer additive
changes; update shared Kotlin call sites in the same change when required.
2. **Streaming stays in Rust.** Platform passes paths or FDs; core does not pull
whole files into Kotlin.
3. **Android FDs are files only.** `SourceKind::FileDescriptor` with
`is_directory=true` must fail; directories are expanded on the platform side.
4. **Cancel:** signal active-transfer oneshot **synchronously** before async DB
work. Use existing `take_active_transfer` / facade cancel path. Do not reintroduce
nested exclusive `Runtime::block_on` deadlocks.
5. **No lock across await:** Clippy `await_holding_lock` fails CI.
6. **ReceiveOutputSink:** after successful `start_file`, exactly one of
`finish_file` or `abort_file` (see `OutputSinkFile` Drop).
7. **No-overwrite publish** for path receives (temp + hard link / exclusive rename).
8. Integration tests must use the **public** API + `tests/support/` only.
---
## Code style (Rust)
- Clippy clean with `-D warnings`.
- Prefer exhaustive `match`; avoid catch-all arms that hide new enum variants.
- Prefer comparing whole objects in tests when practical.
- Comment only non-obvious why (concurrency, durability, platform FS quirks).
- Do not add one-off private helpers used once if inline is clearer.
- Prefer private modules; export deliberately via `lib.rs` / UniFFI.
---
## Testing
- Unit / private: `src/tests/` (see crate `tests.rs` paths).
- Integration: `tests/*.rs` + `tests/support/mod.rs` (`TestNode`, `MemoryOutputSink`,
`CoreGuard`, etc.).
- Bug fixes need a regression test.
- Prefer gates/latches over multi-second sleeps (see output_sink cancel test).
- Failure tests: durable status and/or events when applicable.
- Recovery tests: shut down core, reopen same data dir.
Details: [`tests/README.md`](tests/README.md).
---
## PR / verify checklist for this crate
```bash
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test -p vnidrop
```
If you touched cancel, export, or sinks, also:
```bash
cargo test -p vnidrop --test output_sink
```

View File

@@ -25,6 +25,15 @@ compose.desktop {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "com.vnidrop.app" packageName = "com.vnidrop.app"
packageVersion = "1.0.0" packageVersion = "1.0.0"
macOS {
iconFile.set(project.file("../assets/macos/app-icon.icns"))
}
windows {
iconFile.set(project.file("../assets/windows/app-icon.ico"))
}
linux {
iconFile.set(project.file("../assets/linux/app-icon.png"))
}
fileAssociation( fileAssociation(
mimeType = "application/vnd.vnidrop.transfer", mimeType = "application/vnd.vnidrop.transfer",
extension = "vnd", extension = "vnd",

View File

@@ -1,36 +1,36 @@
{ {
"images": [ "images" : [
{ {
"filename": "app-icon-1024.png", "filename" : "app-icon.png",
"idiom": "universal", "idiom" : "universal",
"platform": "ios", "platform" : "ios",
"size": "1024x1024" "size" : "1024x1024"
}, },
{ {
"appearances": [ "appearances" : [
{ {
"appearance": "luminosity", "appearance" : "luminosity",
"value": "dark" "value" : "dark"
} }
], ],
"idiom": "universal", "idiom" : "universal",
"platform": "ios", "platform" : "ios",
"size": "1024x1024" "size" : "1024x1024"
}, },
{ {
"appearances": [ "appearances" : [
{ {
"appearance": "luminosity", "appearance" : "luminosity",
"value": "tinted" "value" : "tinted"
} }
], ],
"idiom": "universal", "idiom" : "universal",
"platform": "ios", "platform" : "ios",
"size": "1024x1024" "size" : "1024x1024"
} }
], ],
"info": { "info" : {
"author": "xcode", "author" : "xcode",
"version": 1 "version" : 1
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -1,6 +1,6 @@
{ {
"info": { "info" : {
"author": "xcode", "author" : "xcode",
"version": 1 "version" : 1
} }
} }

126
shared/AGENTS.md Normal file
View File

@@ -0,0 +1,126 @@
# AGENTS.md — `shared/` (Compose Multiplatform + KMP)
Nearest guide when editing under `shared/`. Root [`AGENTS.md`](../AGENTS.md)
still applies; this file wins for UI/KMP work.
---
## Purpose
`shared` is the multiplatform app layer: Compose UI, feature ViewModels, and
`expect`/`actual` bridges into Android, iOS, and desktop. Native transfer work
goes through UniFFI `VnidropCore` (see `crates/vnidrop`).
---
## Compose skill (required for UI work)
For screens, components, theme, navigation, resources, ViewModel↔UI wiring,
lists, animation, accessibility:
1. Load [`.codex/skills/compose-skill/SKILL.md`](../.codex/skills/compose-skill/SKILL.md).
2. Follow its workflow and defaults.
3. Open **at most one** file under `.codex/skills/compose-skill/references/` when
the skills Quick Routing table says you need deeper guidance.
4. Do **not** invent a parallel Compose style guide.
### Project policy (overrides generic skill defaults)
| Topic | Do this |
|-------|---------|
| Architecture | Keep **MVVM-style** ViewModels: immutable `*State`, `StateFlow`, **named methods**. Do not force MVI `onEvent` sealed hierarchies unless asked. |
| Structure | Feature packages under `com.vnidrop.app.feature.*`; thin route/wiring + screen/composables. |
| Theme | Only `LocalVniDropColors` / `VniDropThemeTokens` (`ui/theme/VniDropTheme.kt`). Brand primary light ≈ `#A855F7` (HSL 271, 91%, 65%). |
| Strings | CMP composeResources / `Res.string.*` — not Android `R` in `commonMain`. |
| DI | Follow existing `AppGraph` construction; no unprompted Hilt/Koin migration. |
| Platform | `androidMain` / `iosMain` / `jvmMain` for pickers, SAF, security-scoped URLs, NFC/QR. |
| Dependencies | Before adding Jetpack/AndroidX to `commonMain`, verify multiplatform artifacts for all targets. |
compose-skill “Existing Project Policy”: adapt to this repo; do not force-migrate.
---
## Commands
From repo root:
```bash
./gradlew :shared:jvmTest
./gradlew :shared:compileKotlinJvm
```
Optional:
```bash
./gradlew :shared:testAndroidHostTest
./gradlew :shared:iosSimulatorArm64Test
./gradlew :desktopApp:run
./gradlew :androidApp:assembleDebug
```
CI `:shared:jvmTest` runs on **macOS** (Gobley host cargo). Prefer macOS for
local parity.
When Kotlin changes touch UniFFI-generated APIs, rebuild/test with a full
`jvmTest` so Gobley/native pieces stay aligned.
---
## Layout
```
src/
commonMain/kotlin/com/vnidrop/app/
core/ # models, CoreGateway, FilePicker interfaces
feature/send|receive|approvals|settings|app/
ui/ # theme, components, navigation, feedback, state helpers
commonMain/composeResources/
androidMain|iosMain|jvmMain/
commonTest|jvmTest|...
```
### Platform file bridging (must preserve)
- **Android share:** open content URIs as FDs; expand **folder trees** to per-file
documents with relative `displayName` paths before calling Rust
(`FileSystemService.android.kt` / `expandShareDirectory`).
- **Android receive:** MediaStore Downloads sink and/or SAF tree write sink.
- **iOS:** keep security-scoped leases alive while Rust reads paths.
- **Desktop:** filesystem paths; directories may be marked `isDirectory` for Rust walk.
Never pass a directory as a single Android FD into `SourceKind.FILE_DESCRIPTOR`.
---
## Code style (Kotlin)
- Match existing feature style (imports, naming, state updates via `update { }`).
- Composables render state and invoke callbacks; no business rules in `@Composable`
bodies (network, share creation, ticket parse — ViewModel/core).
- Prefer stable list keys from domain IDs.
- Comments only for non-obvious platform or concurrency reasons.
- Do not hard-code brand colors; use theme tokens.
---
## Testing
- Logic: `src/commonTest/` (e.g. ViewModel fakes, `AppUiModels` progress helpers).
- Compose/JVM: `src/jvmTest/`.
- Add/adjust tests when changing state machines, progress aggregation, or
share/receive eligibility.
- Prefer fakes in `commonTest` support over real UniFFI in pure unit tests.
```bash
./gradlew :shared:jvmTest
```
---
## Anti-patterns
- Streaming transfer bytes through Kotlin as the main design
- Directory FDs on Android
- New DI framework “because best practice”
- Loading every compose-skill reference file for a small UI tweak
- Android `R.string` in `commonMain`