mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-09-14 00:55:08 +00:00
Compare commits
49
Commits
0a4a0e60ff
...
513b21e9af
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
513b21e9af | ||
|
|
cba56f6304 | ||
|
|
bd1021c6f4 | ||
|
|
00379719c8 | ||
|
|
0c59d0ef2e | ||
|
|
3e9b629b8d | ||
|
|
032546f70b | ||
|
|
e2bbe41991 | ||
|
|
25e61542ba | ||
|
|
624e38ce34 | ||
|
|
b243184026 | ||
|
|
41113ca259 | ||
|
|
2b5ce62c6e | ||
|
|
5dcaa0bf5d | ||
|
|
2afe9b9221 | ||
|
|
1590fca9b7 | ||
|
|
afeb70b15b | ||
|
|
68a9f77337 | ||
|
|
153fd89f8d | ||
|
|
f9b11ef68b | ||
|
|
c8262d440b | ||
|
|
686975e322 | ||
|
|
5943dfe3d7 | ||
|
|
8e6cb1f7ac | ||
|
|
047eb197a4 | ||
|
|
795394c454 | ||
|
|
a2b0fd9405 | ||
|
|
9e380cf9dc | ||
|
|
0067db3608 | ||
|
|
08529c3a74 | ||
|
|
5f53568204 | ||
|
|
c33256a08e | ||
|
|
64e0ce4b3e | ||
|
|
6030d22aa9 | ||
|
|
d108ba0cc8 | ||
|
|
5142c88629 | ||
|
|
ae0b70728e | ||
|
|
add7bfe3ca | ||
|
|
b8135e76c4 | ||
|
|
4fa619d2a2 | ||
|
|
fe8580ca56 | ||
|
|
501c9a5b5a | ||
|
|
97b13b7c47 | ||
|
|
943e137d4e | ||
|
|
e076b1eaee | ||
|
|
88ae3d0f5a | ||
|
|
1093b3ce8a | ||
|
|
713b7d41f6 | ||
|
|
a87222c51f |
+43
-25
@@ -3,7 +3,7 @@
|
||||
## Project Overview
|
||||
|
||||
Amethyst is a Nostr Client for Android that was made for Android-only and has been slowly switching
|
||||
over to a Kotlin Multiplatform project. The main modules are: `quartz`, `commons`, `amethyst`,
|
||||
over to a Kotlin Multiplatform project. The main modules are: `quartz`, `commons`, `commonsUI`, `amethyst`,
|
||||
`desktopApp`, `cli`, plus the audio-rooms transport stack `quic` + `nestsClient`. Quartz should
|
||||
contain implementations of Nostr specifications and utilities to help implement them. Commons stores
|
||||
shared code between Amethyst Android (`amethyst`) and Amethyst Desktop (`desktopApp`). The Desktop
|
||||
@@ -48,11 +48,18 @@ amethyst/
|
||||
│ ├── androidMain/ # Android-specific (crypto, storage)
|
||||
│ ├── jvmMain/ # Desktop JVM-specific
|
||||
│ └── iosMain/ # iOS-specific
|
||||
├── commons/ # Shared UI components (convert to KMP)
|
||||
├── commons/ # Shared HEADLESS layer (models, state, ViewModels, relay client) — CLI-safe
|
||||
│ └── src/
|
||||
│ ├── commonMain/ # Shared composables, icons, state
|
||||
│ ├── androidMain/ # Android-specific UI utilities
|
||||
│ └── jvmMain/ # Desktop-specific UI utilities
|
||||
│ ├── commonMain/ # Domain models, state holders, ViewModels, services
|
||||
│ ├── jvmAndroid/ # JVM-bound services shared by Android + Desktop
|
||||
│ ├── androidMain/ # Android-specific actuals (Keystore, DataStore)
|
||||
│ └── jvmMain/ # Desktop-specific actuals (keyring, upload pipeline)
|
||||
├── commonsUI/ # Shared Compose UI on top of commons (composables, icons, theme, Coil, resources)
|
||||
│ └── src/
|
||||
│ ├── commonMain/ # Shared composables, icons, theme, composeResources (strings/fonts)
|
||||
│ ├── jvmAndroid/ # Markdown renderer, Coil OkHttp fetchers
|
||||
│ ├── androidMain/ # Android Coil bridge
|
||||
│ └── jvmMain/ # Desktop Coil bridge (+ skikoMain shared with iOS)
|
||||
├── quic/ # Pure-Kotlin QUIC v1 + HTTP/3 + WebTransport (audio-rooms transport)
|
||||
│ └── src/
|
||||
│ ├── commonMain/ # Protocol, frame/packet codecs, TLS state machine
|
||||
@@ -70,12 +77,20 @@ amethyst/
|
||||
|
||||
**Sharing Philosophy:**
|
||||
- `quartz/` = Nostr business logic, protocol, data (no UI)
|
||||
- `commons/` = Shared code for every front end (Android, Desktop, iOS, and the
|
||||
headless `cli`): domain models, state holders, ViewModels, the relay client,
|
||||
shared services, **and** the Compose UI that ≥1 GUI front end renders. The
|
||||
package taxonomy, the CLI-safe / UI boundary, and a "where does my code go?"
|
||||
guide are documented in **`commons/ARCHITECTURE.md`** — read it before adding
|
||||
a new package or dropping code into `commons`.
|
||||
- `commons/` = Shared **headless** code for every front end (Android, Desktop,
|
||||
iOS, and the headless `cli`): domain models, state holders, ViewModels, the
|
||||
relay client, shared services. It may use the Compose *runtime*
|
||||
(`@Stable`/`@Immutable`, snapshot state) but never Compose UI, Coil or
|
||||
Compose resources — the build enforces this: `commons` has no such deps.
|
||||
- `commonsUI/` = Shared **Compose UI** that ≥1 GUI front end renders
|
||||
(composables, `ui/theme`, icons, robohash, Coil fetchers, markdown, the
|
||||
`composeResources` strings/fonts and the generated `Res` class). Depends on
|
||||
`commons` (as `api`); `cli` never depends on it. Files keep their
|
||||
`com.vitorpamplona.amethyst.commons.*` packages — the split is a module
|
||||
boundary, not a package rename. The package taxonomy, the CLI-safe / UI
|
||||
boundary, and a "where does my code go?" guide are documented in
|
||||
**`commons/ARCHITECTURE.md`** (+ `commonsUI/ARCHITECTURE.md`) — read them
|
||||
before adding a new package or dropping code into either module.
|
||||
- `quic/` = Transport library (QUIC + HTTP/3 + WebTransport); reusable for any
|
||||
KMP project that needs MoQ. Has no Android-framework dependencies.
|
||||
- `nestsClient/` = MoQ + audio-rooms client; takes `:quic` as transport,
|
||||
@@ -88,7 +103,7 @@ amethyst/
|
||||
- `amethyst/` & `desktopApp/` = Platform-native layouts and navigation
|
||||
- `cli/` = Thin assembly layer over `quartz/` + `commons/` (no new logic
|
||||
allowed). May also depend on `:geode` (for `amy serve`, which embeds the
|
||||
standalone relay); never on `:amethyst` or `:desktopApp`.
|
||||
standalone relay); never on `:commonsUI`, `:amethyst` or `:desktopApp`.
|
||||
|
||||
**Plans per module:** design docs for new subsystems live in the owning
|
||||
module's `plans/YYYY-MM-DD-<slug>.md` (e.g. `cli/plans/`, `commons/plans/`).
|
||||
@@ -180,16 +195,19 @@ etc. instead of re-implementing them.
|
||||
|
||||
**Share vs keep platform-native:**
|
||||
|
||||
- **Share** → `quartz/commonMain/` (business logic, data models, protocol) and
|
||||
`commons/commonMain/` (major UI components, **ViewModels** under
|
||||
`viewmodels/`, icons). ViewModels are platform-agnostic state + logic
|
||||
(StateFlow/SharedFlow), so they belong in `commons`.
|
||||
- **Share** → `quartz/commonMain/` (business logic, data models, protocol),
|
||||
`commons/commonMain/` (**ViewModels** under `viewmodels/`, state holders,
|
||||
relay client, services — headless) and `commonsUI/commonMain/` (major UI
|
||||
components, icons, theme). ViewModels are platform-agnostic state + logic
|
||||
(StateFlow/SharedFlow), so they belong in `commons`; anything that imports
|
||||
`androidx.compose.ui`/`foundation`/`material3`, Coil, or `Res` belongs in
|
||||
`commonsUI`.
|
||||
- **Keep native** → screen composables/scaffolding (Desktop `Window` vs Android
|
||||
`Activity`), navigation (sidebar vs bottom nav), platform interactions
|
||||
(gestures, keyboard shortcuts), system integrations (notifications, file
|
||||
pickers).
|
||||
|
||||
When extracting a composable: move it to `commons/commonMain/` (see
|
||||
When extracting a composable: move it to `commonsUI/commonMain/` (see
|
||||
`/compose-expert`), add expect/actual for any platform behavior (see
|
||||
`/kotlin-multiplatform`), then point both Android and Desktop at the shared
|
||||
version. `quartz/` is protocol-only — no composables.
|
||||
@@ -216,7 +234,7 @@ version. `quartz/` is protocol-only — no composables.
|
||||
## Dependency Licensing
|
||||
|
||||
**MANDATORY whenever you introduce a new third-party dependency** — in *any*
|
||||
module (`quartz`, `commons`, `amethyst`, `desktopApp`, `cli`, `quic`,
|
||||
module (`quartz`, `commons`, `commonsUI`, `amethyst`, `desktopApp`, `cli`, `quic`,
|
||||
`nestsClient`, …), whether you add it to `gradle/libs.versions.toml` or to a
|
||||
module's `build.gradle.kts`: determine its license **before** wiring it in.
|
||||
Amethyst ships under the **MIT** license, so a copyleft dependency linked into a
|
||||
@@ -253,9 +271,9 @@ JVM). See `/kotlin-multiplatform` for the expect/actual and source-set patterns.
|
||||
## Icons
|
||||
|
||||
The Material Symbols font bundled at
|
||||
`commons/src/commonMain/composeResources/font/material_symbols_outlined.ttf`
|
||||
`commonsUI/src/commonMain/composeResources/font/material_symbols_outlined.ttf`
|
||||
is a **subset** that only contains the glyphs referenced from
|
||||
`commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/symbols/MaterialSymbols.kt`.
|
||||
`commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/symbols/MaterialSymbols.kt`.
|
||||
|
||||
**MANDATORY:** Whenever you add a new icon — i.e. introduce a
|
||||
`MaterialSymbol("\uXXXX")` codepoint that wasn't already referenced anywhere in
|
||||
@@ -274,21 +292,21 @@ regenerating.
|
||||
|
||||
### Amethyst's own icons are also a font
|
||||
|
||||
The icons in `commons/.../commons/icons/*.kt` (Like, Reply, Reposted, Zap, …) are
|
||||
The icons in `commonsUI/.../commons/icons/*.kt` (Like, Reply, Reposted, Zap, …) are
|
||||
**also** compiled into a font, `composeResources/font/amethyst_icons.ttf`, and drawn
|
||||
as glyphs via `AmethystIconGlyph`. Drawing an `ImageVector` rasterises its paths into
|
||||
a per-instance cached layer, so a feed re-rasterised the same glyph once per card;
|
||||
a glyph is a blit from the shared text atlas. Measured: frame P90 **-10.7%**,
|
||||
overrun P90 **-17.4%** on the feed scroll benchmark.
|
||||
|
||||
**MANDATORY:** whenever you add or change an icon under `commons/.../commons/icons/`,
|
||||
**MANDATORY:** whenever you add or change an icon under `commonsUI/.../commons/icons/`,
|
||||
regenerate the font *and* its codepoint table together:
|
||||
|
||||
```bash
|
||||
python3 tools/icon-font/build_icon_font.py \
|
||||
commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons \
|
||||
commons/src/commonMain/composeResources/font/amethyst_icons.ttf \
|
||||
commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/symbols/AmethystIcons.kt
|
||||
commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons \
|
||||
commonsUI/src/commonMain/composeResources/font/amethyst_icons.ttf \
|
||||
commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/symbols/AmethystIcons.kt
|
||||
```
|
||||
|
||||
Both outputs must be committed together: codepoints are assigned in filename order,
|
||||
|
||||
@@ -21,7 +21,7 @@ that has to catch it.
|
||||
Repair with:
|
||||
|
||||
python3 tools/strings-migrate/fix_escapes.py --no-unwrap-quotes \\
|
||||
commons/src/commonMain/composeResources
|
||||
commonsUI/src/commonMain/composeResources
|
||||
|
||||
`--no-unwrap-quotes` is mandatory on already-migrated files: escape conversion is
|
||||
idempotent, quote-unwrapping is not, and a second unwrap strips the real display
|
||||
@@ -77,7 +77,7 @@ def main() -> int:
|
||||
print(
|
||||
"\nRepair:\n"
|
||||
" python3 tools/strings-migrate/fix_escapes.py --no-unwrap-quotes \\\n"
|
||||
" commons/src/commonMain/composeResources\n"
|
||||
" commonsUI/src/commonMain/composeResources\n"
|
||||
"(--no-unwrap-quotes is mandatory on already-migrated files.)",
|
||||
file=out,
|
||||
)
|
||||
|
||||
@@ -47,7 +47,7 @@ Walk the imports. The usual offenders:
|
||||
| `android.util.Log` | Replace with `quartz` `PlatformLog` (already multiplatform). |
|
||||
| `android.graphics.Bitmap` | Almost never needed by Amy. Keep in Android and split the function. |
|
||||
| `android.net.Uri` | Replace with `kotlinx.io` path types or a plain `String`. |
|
||||
| `androidx.compose.*` | Must stay out of `commons/commonMain` unless you're in a Compose-Multiplatform module. Amy doesn't depend on Compose. |
|
||||
| `androidx.compose.*` | Compose UI (`ui`/`foundation`/`material3`), Coil and `Res` must stay out of `commons` entirely — they belong in `:commonsUI`, which Amy never depends on. Only the Compose *runtime* (`@Stable`, snapshot state) is allowed in `commons`. |
|
||||
|
||||
### Step 3 — Pick a migration strategy per dependency
|
||||
|
||||
@@ -66,7 +66,7 @@ Walk the imports. The usual offenders:
|
||||
# Target location depends on what it is:
|
||||
# - Protocol → quartz/src/commonMain/kotlin/…
|
||||
# - Business logic → commons/src/commonMain/kotlin/…
|
||||
# - UI → commons/src/commonMain/… (needs Compose Multiplatform)
|
||||
# - UI → commonsUI/src/commonMain/… (needs Compose Multiplatform; never used by amy)
|
||||
git mv amethyst/src/main/java/com/.../FollowListManager.kt \
|
||||
commons/src/commonMain/kotlin/com/.../FollowListManager.kt
|
||||
```
|
||||
|
||||
@@ -24,7 +24,7 @@ Visual UI patterns for sharing composables across Android and Desktop.
|
||||
|
||||
## Philosophy: Share by Default
|
||||
|
||||
**Default to `commons/commonMain`** unless platform experts indicate otherwise.
|
||||
**Default to `commonsUI/commonMain`** (shared composables live in `:commonsUI`, the Compose half of the shared layer; headless state/ViewModels stay in `:commons`) unless platform experts indicate otherwise.
|
||||
|
||||
### Always Share
|
||||
|
||||
@@ -416,7 +416,7 @@ fun DataScreen(uiState: UiState) {
|
||||
}
|
||||
```
|
||||
|
||||
**Components** (all in `commons/commonMain`):
|
||||
**Components** (all in `commonsUI/commonMain`):
|
||||
- `LoadingState` - Progress indicator + message
|
||||
- `EmptyState` - Empty message + optional refresh button
|
||||
- `ErrorState` - Error message + optional retry button
|
||||
@@ -527,12 +527,12 @@ fun FeedList(items: List<Item>) {
|
||||
|
||||
| Task | Pattern | Location |
|
||||
|------|---------|----------|
|
||||
| Reusable UI | State hoisting | commons/commonMain |
|
||||
| Reusable UI | State hoisting | commonsUI/commonMain |
|
||||
| Simple state | remember { mutableStateOf() } | Composable scope |
|
||||
| Derived state | derivedStateOf { } | remember block |
|
||||
| Async → state | produceState { } | Composable function |
|
||||
| Custom icons | roboBuilder + PathData | commons/icons |
|
||||
| Loading/Error | LoadingState, ErrorState | commons/ui/components |
|
||||
| Custom icons | roboBuilder + PathData | commonsUI/icons |
|
||||
| Loading/Error | LoadingState, ErrorState | commonsUI/ui/components |
|
||||
| Theme colors | MaterialTheme.colorScheme | Any @Composable |
|
||||
| Navigation | Delegate to platform expert | amethyst/, desktopApp/ |
|
||||
|
||||
@@ -540,7 +540,7 @@ fun FeedList(items: List<Item>) {
|
||||
|
||||
### Creating a Shared Component
|
||||
|
||||
1. Start in `commons/src/commonMain/kotlin/.../ui/components/`
|
||||
1. Start in `commonsUI/src/commonMain/kotlin/.../ui/components/`
|
||||
2. Use Material3 primitives only
|
||||
3. Hoist state (parameters for data, callbacks for events)
|
||||
4. Add modifier parameter
|
||||
@@ -551,7 +551,7 @@ fun FeedList(items: List<Item>) {
|
||||
|
||||
1. Read current implementation in `amethyst/` or `desktopApp/`
|
||||
2. Identify pure visual logic (no platform APIs)
|
||||
3. Create in `commons/commonMain` with hoisted state
|
||||
3. Create in `commonsUI/commonMain` with hoisted state
|
||||
4. Replace platform implementations with shared component
|
||||
5. Keep platform-specific wrappers if needed
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Shared Composables Catalog
|
||||
|
||||
This catalog documents shared UI components in `commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/`.
|
||||
This catalog documents shared UI components in `commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/` (the Compose half of the shared layer; headless state stays in `commons`).
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
commons/src/commonMain/kotlin/.../commons/ui/
|
||||
commonsUI/src/commonMain/kotlin/.../commons/ui/
|
||||
├── components/ # Reusable UI components
|
||||
├── screens/ # Screen-level composables
|
||||
├── theme/ # Theming and styling
|
||||
@@ -232,7 +232,7 @@ private val pathData1 = PathData {
|
||||
```
|
||||
|
||||
**roboBuilder** - Custom ImageVector.Builder DSL
|
||||
- Located in: `commons/robohash/`
|
||||
- Located in: `commonsUI/.../commons/robohash/`
|
||||
- Pattern: Builder-based, composable paths
|
||||
- Parts: Face, Eyes, Mouth, Body, Accessory (0-9 variants each)
|
||||
- Colors: Dynamic (fgColor parameter) + Black constants
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: feed-patterns
|
||||
description: Feed composition and data-access layer patterns in Amethyst. Use when adding or modifying a feed (home, profile, hashtag, bookmarks, notifications, DMs, communities), working with the shared `FeedFilter` / `AdditiveFeedFilter` / `ChangesFlowFilter` / `FeedContentState` in `commons/.../ui/feeds/`, the Android-only `AdditiveComplexFeedFilter` / `FilterByListParams` in `amethyst/.../ui/dal/`, or extending the `FeedViewModel` family in `commons/.../viewmodels/`. Covers how feeds scan `LocalCache`, react to changes, apply ordering, and render through Compose.
|
||||
description: Feed composition and data-access layer patterns in Amethyst. Use when adding or modifying a feed (home, profile, hashtag, bookmarks, notifications, DMs, communities), working with the shared `FeedFilter` / `AdditiveFeedFilter` / `ChangesFlowFilter` / `FeedContentState` in `commons/.../feeds/`, the Android-only `AdditiveComplexFeedFilter` / `FilterByListParams` in `amethyst/.../ui/dal/`, or extending the `FeedViewModel` family in `commons/.../viewmodels/`. Covers how feeds scan `LocalCache`, react to changes, apply ordering, and render through Compose.
|
||||
---
|
||||
|
||||
# Feed Patterns
|
||||
@@ -25,7 +25,7 @@ Amethyst's "feed" abstraction is: a `FeedFilter` that decides which notes belong
|
||||
│ ◄── MarmotGroupFeedViewModel │
|
||||
│ │
|
||||
│ │
|
||||
│ commons/.../ui/feeds/ (shared, KMP) │
|
||||
│ commons/.../feeds/ (shared, KMP) │
|
||||
│ IFeedFilter / FeedFilter<T> (abstract base) │
|
||||
│ IAdditiveFeedFilter / AdditiveFeedFilter<T> │
|
||||
│ ChangesFlowFilter │
|
||||
@@ -68,7 +68,7 @@ Amethyst's "feed" abstraction is: a `FeedFilter` that decides which notes belong
|
||||
|
||||
### Shared filter bases (commons)
|
||||
|
||||
`commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/`:
|
||||
`commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/feeds/`:
|
||||
|
||||
- **`FeedFilter.kt`** — `abstract class FeedFilter<T> : IFeedFilter<T>`. Has `feed(): List<T>` (the sync query against the cache), `feedKey(): String` (identity used to cache), `limit()`, and `loadTop()`.
|
||||
- **`AdditiveFeedFilter.kt`** — `abstract class AdditiveFeedFilter<T> : FeedFilter<T>(), IAdditiveFeedFilter<T>`. Adds incremental updates (the "additive" part): `updateListWith(oldList, newItems)` runs `applyFilter(newItems)` and grafts accepted items onto the existing list (re-`sort` + `take(limit())`) without recomputing everything.
|
||||
@@ -100,7 +100,7 @@ Concrete filters (Home, Hashtag, Profile, Bookmark, Notifications, Communities,
|
||||
|
||||
## Filter Sharing (Android vs Desktop)
|
||||
|
||||
- The filter **base classes** (`FeedFilter`, `AdditiveFeedFilter`, `ChangesFlowFilter`) and feed state (`FeedContentState`) are in `commons/.../ui/feeds/` — **shared**. ViewModels are in `commons/.../viewmodels/` — **shared**.
|
||||
- The filter **base classes** (`FeedFilter`, `AdditiveFeedFilter`, `ChangesFlowFilter`) and feed state (`FeedContentState`) are in `commons/.../feeds/` — **shared**. ViewModels are in `commons/.../viewmodels/` — **shared**.
|
||||
- The **concrete** filters are platform-local: Android's in `amethyst/.../ui/screen/loggedIn/*/dal/`, Desktop's in `desktopApp/.../feeds/`. `amethyst/.../ui/dal/` keeps Android-only helpers (`AdditiveComplexFeedFilter`, `FilterByListParams`, `DefaultFeedOrder`) plus back-compat typealiases.
|
||||
- When porting a feed, share the concrete filter only if both platforms need identical inclusion rules.
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ There are two separate `strings.xml` trees, each with its own default `values/`
|
||||
| Tree | Default file | Per-locale file |
|
||||
|------|--------------|-----------------|
|
||||
| **amethyst** (Android app) | `amethyst/src/main/res/values/strings.xml` | `amethyst/src/main/res/values-<locale>/strings.xml` |
|
||||
| **commons** (KMP Compose resources, shared by Android + Desktop) | `commons/src/commonMain/composeResources/values/strings.xml` | `commons/src/commonMain/composeResources/values-<locale>/strings.xml` |
|
||||
| **commonsUI** (KMP Compose resources, shared by Android + Desktop) | `commonsUI/src/commonMain/composeResources/values/strings.xml` | `commonsUI/src/commonMain/composeResources/values-<locale>/strings.xml` |
|
||||
|
||||
The `commons` tree appeared when shared event-renderer composables were extracted out of `amethyst/` into `commons/` (Compose Multiplatform `stringResource`). It is **not** a copy of the amethyst tree — the vast majority of its keys are commons-only; only a small handful overlap. Every diff/count/translate command below works on either tree by swapping the base path — **run the whole technique once per tree** and report them separately (each maps to its own Crowdin file, so the counts should reconcile against two different Crowdin UI numbers).
|
||||
The `commonsUI` tree appeared when shared event-renderer composables were extracted out of `amethyst/` into `commons/` — now `commonsUI/` since the UI split (Compose Multiplatform `stringResource`). It is **not** a copy of the amethyst tree — the vast majority of its keys are commons-only; only a small handful overlap. Every diff/count/translate command below works on either tree by swapping the base path — **run the whole technique once per tree** and report them separately (each maps to its own Crowdin file, so the counts should reconcile against two different Crowdin UI numbers).
|
||||
|
||||
**Locale-qualifier caveat:** `commons` uses the same region-qualified locale dirs as amethyst for our four targets (`values-cs`, `values-de-rDE`, `values-sv-rSE`, `values-pt-rBR`), but the *full* set of locale dirs differs between trees. Enumerate `values-*` under each tree's own base rather than assuming they match.
|
||||
|
||||
@@ -37,7 +37,7 @@ The `commons` tree appeared when shared event-renderer composables were extracte
|
||||
Detect name-overlap **and flag value mismatches** in one pass:
|
||||
|
||||
```bash
|
||||
cdef=commons/src/commonMain/composeResources/values/strings.xml
|
||||
cdef=commonsUI/src/commonMain/composeResources/values/strings.xml
|
||||
adef=amethyst/src/main/res/values/strings.xml
|
||||
comm -12 \
|
||||
<(grep '<string name=' "$cdef" | sed 's/.*name="\([^"]*\)".*/\1/' | sort -u) \
|
||||
@@ -54,7 +54,7 @@ Only `SAFE-COPY` keys may be copied verbatim. For `VALUE-DIFFERS`, translate the
|
||||
**Whitespace-quote convention differs between trees.** Android string resources use surrounding double-quotes to preserve leading/trailing whitespace (`"replying to "`). The **commons Compose-resources tree does NOT use this convention** — it authors trailing/leading spaces raw and unquoted (`replying to `). So when copying/translating a commons string with edge whitespace, **match the commons source: raw spaces, no wrapping quotes.** (Mistake we made: we copied amethyst's quoted `"replying to "` into commons, where the quotes would render literally.) A quick check for stray quote-wrapping you introduced:
|
||||
|
||||
```bash
|
||||
grep -nE '<string name="[^"]*">"' commons/src/commonMain/composeResources/values-*/strings.xml
|
||||
grep -nE '<string name="[^"]*">"' commonsUI/src/commonMain/composeResources/values-*/strings.xml
|
||||
# The commons English tree has zero quote-wrapped values — any hit in a locale file is almost certainly a bad copy from amethyst.
|
||||
```
|
||||
|
||||
@@ -147,14 +147,14 @@ Default: amethyst/src/main/res/values/strings.xml
|
||||
Target: amethyst/src/main/res/values-<locale>/strings.xml
|
||||
|
||||
# commons tree
|
||||
Default: commons/src/commonMain/composeResources/values/strings.xml
|
||||
Target: commons/src/commonMain/composeResources/values-<locale>/strings.xml
|
||||
Default: commonsUI/src/commonMain/composeResources/values/strings.xml
|
||||
Target: commonsUI/src/commonMain/composeResources/values-<locale>/strings.xml
|
||||
```
|
||||
|
||||
A convenient way to run the whole technique twice is to loop over the two base dirs:
|
||||
|
||||
```bash
|
||||
for base in amethyst/src/main/res commons/src/commonMain/composeResources; do
|
||||
for base in amethyst/src/main/res commonsUI/src/commonMain/composeResources; do
|
||||
echo "########## tree: $base ##########"
|
||||
# ... run the diff/count/value-extraction commands with $base/values[...] ...
|
||||
done
|
||||
@@ -273,8 +273,8 @@ Flag and offer to fix:
|
||||
# hardcode "1" (or other literal digits) instead of using a placeholder.
|
||||
# Looks at default + all values-* locales, in BOTH resource trees.
|
||||
for f in amethyst/src/main/res/values/strings.xml amethyst/src/main/res/values-*/strings.xml \
|
||||
commons/src/commonMain/composeResources/values/strings.xml \
|
||||
commons/src/commonMain/composeResources/values-*/strings.xml; do
|
||||
commonsUI/src/commonMain/composeResources/values/strings.xml \
|
||||
commonsUI/src/commonMain/composeResources/values-*/strings.xml; do
|
||||
awk -v file="$f" '
|
||||
/<plurals/ { in_plurals = 1; name = $0; sub(/.*name="/, "", name); sub(/".*/, "", name) }
|
||||
in_plurals && /quantity="one"/ {
|
||||
@@ -294,8 +294,8 @@ Then scan for dead `quantity="zero"` entries. CLDR's `zero` category is integer-
|
||||
|
||||
```bash
|
||||
for f in amethyst/src/main/res/values/strings.xml amethyst/src/main/res/values-*/strings.xml \
|
||||
commons/src/commonMain/composeResources/values/strings.xml \
|
||||
commons/src/commonMain/composeResources/values-*/strings.xml; do
|
||||
commonsUI/src/commonMain/composeResources/values/strings.xml \
|
||||
commonsUI/src/commonMain/composeResources/values-*/strings.xml; do
|
||||
# Skip Arabic, Latvian and Welsh — they natively use the zero category.
|
||||
# (Latvian's zero covers 0, 10, 11-19, 20, 30, … — stripping it breaks most counts.)
|
||||
case "$f" in
|
||||
@@ -328,7 +328,7 @@ itre = re.compile(r'<item quantity="([^"]+)"[^>]*>(.*?)</item>', re.S)
|
||||
# (?<!\\) is REQUIRED: \%2$d is an escaped literal, not a placeholder.
|
||||
phre = re.compile(r'(?<!\\)%(?:(\d+)\$)?([sdf])')
|
||||
sig = lambda t: sorted(m.group(0) for m in phre.finditer(t))
|
||||
for base in ['amethyst/src/main/res', 'commons/src/commonMain/composeResources']:
|
||||
for base in ['amethyst/src/main/res', 'commonsUI/src/commonMain/composeResources']:
|
||||
d = io.open(f'{base}/values/strings.xml', encoding='utf-8').read()
|
||||
dstr = {m.group(1): sig(m.group(2)) for m in keyre.finditer(d)}
|
||||
dpl = {}
|
||||
@@ -354,7 +354,7 @@ PY
|
||||
# Empty plural items render as nothing at runtime — always a bug.
|
||||
grep -rn '<item quantity="[a-z]*"></item>' \
|
||||
amethyst/src/main/res/values*/strings.xml \
|
||||
commons/src/commonMain/composeResources/values*/strings.xml
|
||||
commonsUI/src/commonMain/composeResources/values*/strings.xml
|
||||
```
|
||||
|
||||
Three things this scan taught us, all of which it now encodes:
|
||||
@@ -543,7 +543,7 @@ When adding translated strings to locale files:
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- **Scanning only the amethyst tree** — there are now **two** Crowdin-managed `strings.xml` trees (`amethyst/src/main/res` and `commons/src/commonMain/composeResources`). A key extracted into `commons/` will never show up in the amethyst diff. Run the whole technique once per tree (see "Resource trees") and report each separately.
|
||||
- **Scanning only the amethyst tree** — there are now **two** Crowdin-managed `strings.xml` trees (`amethyst/src/main/res` and `commonsUI/src/commonMain/composeResources`). A key extracted into `commonsUI/` will never show up in the amethyst diff. Run the whole technique once per tree (see "Resource trees") and report each separately.
|
||||
- **Copying an overlapping `commons` translation by key name alone** — a shared key name does NOT mean shared English. `napplet_card_permissions` is "What it can access" in commons but "Permissions:" in amethyst; copying by name produced the wrong string. Diff the English *values* first; copy verbatim only when they're byte-identical, else translate fresh (see "Overlap" in Resource trees).
|
||||
- **Applying amethyst's `"…"` whitespace-quote convention to a commons string** — the commons Compose-resources tree authors edge whitespace raw and unquoted; wrapping quotes copied from amethyst render literally there. Match the commons source format.
|
||||
- **Trying to "dedupe" the amethyst↔commons value-overlap** — it's required architecture (commons can't depend on amethyst, so shared composables need their own `Res.string` catalog), not an error. Don't fold consolidation into a translation pass.
|
||||
|
||||
@@ -383,7 +383,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
||||
| State (business logic) | commonMain or commons/jvmAndroid | Reusable StateFlow patterns |
|
||||
| **ViewModels** | **commons/commonMain/viewmodels/** | **StateFlow/SharedFlow + logic shareable, Compose MP lifecycle compatible** |
|
||||
| UI formatters (pure) | commons/commonMain | Reusable, no dependencies |
|
||||
| UI components (simple) | commons/commonMain | Cards, buttons, dialogs |
|
||||
| UI components (simple) | commonsUI/commonMain | Cards, buttons, dialogs (Compose UI never goes in `commons`) |
|
||||
| **Screen layouts** | **Platform-specific** | **Window vs Activity, sidebar vs bottom nav** |
|
||||
| Navigation | Platform-specific only | Activity vs Window too different |
|
||||
| Permissions | Platform-specific only | APIs incompatible |
|
||||
|
||||
@@ -17,7 +17,7 @@ The layer between `LocalCache`/`Account` and the raw relay connection. Ensures c
|
||||
|
||||
## Layout
|
||||
|
||||
All under `commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/`:
|
||||
All under `commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/` (the `@Composable` entry points — `observeUser*`, `*FilterAssemblerSubscription`, `KeyDataSourceSubscription` — sit in the same package but in `commonsUI/src/commonMain/…`, the Compose half of the shared layer):
|
||||
|
||||
```
|
||||
relayClient/
|
||||
|
||||
@@ -45,7 +45,16 @@ jobs:
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
|
||||
|
||||
- name: Linter (gradle)
|
||||
run: ./gradlew spotlessCheck :quartz:verifyKmpPurity :commons:verifyKmpPurity
|
||||
# The three metadata compiles resolve commonMain against only the
|
||||
# deps every target shares, which is the Apple classpath — a
|
||||
# dependency that reaches JVM transitively (okio via OkHttp) but is
|
||||
# missing for iOS fails here, on Linux, instead of in test-quartz-ios.
|
||||
run: |
|
||||
./gradlew spotlessCheck \
|
||||
:quartz:verifyKmpPurity :commons:verifyKmpPurity :commonsUI:verifyKmpPurity \
|
||||
:quartz:compileCommonMainKotlinMetadata \
|
||||
:commons:compileCommonMainKotlinMetadata \
|
||||
:commonsUI:compileCommonMainKotlinMetadata
|
||||
|
||||
build-desktop:
|
||||
needs: lint
|
||||
@@ -93,7 +102,7 @@ jobs:
|
||||
|
||||
- name: Test + Build Desktop (gradle)
|
||||
run: |
|
||||
CMD="./gradlew :quartz:jvmTest :commons:jvmTest :nestsClient:jvmTest :cli:test :desktopApp:test :desktopApp:${{ matrix.desktop-task }}"
|
||||
CMD="./gradlew :quartz:jvmTest :commons:jvmTest :commonsUI:jvmTest :nestsClient:jvmTest :cli:test :desktopApp:test :desktopApp:${{ matrix.desktop-task }}"
|
||||
if [ "${{ runner.os }}" = "Linux" ]; then
|
||||
xvfb-run --auto-servernum $CMD
|
||||
else
|
||||
@@ -129,6 +138,7 @@ jobs:
|
||||
path: |
|
||||
quartz/build/reports/tests
|
||||
commons/build/reports/tests
|
||||
commonsUI/build/reports/tests
|
||||
nestsClient/build/reports/tests
|
||||
cli/build/reports/tests
|
||||
desktopApp/build/reports/tests
|
||||
@@ -307,11 +317,15 @@ jobs:
|
||||
# :commons:jvmTest stays green — this is the job that catches it.
|
||||
# - compileTestKotlinIosArm64 catches device-only compile drift
|
||||
# (iosArm64 = aarch64-apple-ios) without needing a physical device.
|
||||
# :commonsUI (the Compose half split out of :commons) gets the same
|
||||
# treatment so the shared composables keep compiling on Apple targets.
|
||||
- name: Test Commons on iOS
|
||||
run: |
|
||||
./gradlew \
|
||||
:commons:iosSimulatorArm64Test \
|
||||
:commons:compileTestKotlinIosArm64
|
||||
:commons:compileTestKotlinIosArm64 \
|
||||
:commonsUI:iosSimulatorArm64Test \
|
||||
:commonsUI:compileTestKotlinIosArm64
|
||||
|
||||
- name: Upload iOS Test Reports
|
||||
uses: actions/upload-artifact@v7
|
||||
@@ -363,6 +377,7 @@ jobs:
|
||||
:amethyst:lintPlayBenchmark \
|
||||
:quartz:jvmTest \
|
||||
:commons:jvmTest \
|
||||
:commonsUI:jvmTest \
|
||||
:nestsClient:jvmTest \
|
||||
:amethyst:testFdroidDebugUnitTest \
|
||||
:amethyst:testPlayDebugUnitTest \
|
||||
|
||||
@@ -568,22 +568,22 @@ jobs:
|
||||
( cd "$SRC" && tar czf "$OLDPWD/dist/amy-${VER}-jvm.tar.gz" bin lib )
|
||||
echo "Collected: dist/amy-${VER}-jvm.tar.gz"
|
||||
|
||||
- name: Enforce CLI size budget (200 MB per asset)
|
||||
- name: Enforce CLI size budget (120 MB per asset)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# The plan at cli/plans/2026-04-21-cli-distribution.md §size-budget
|
||||
# targets < 80 MB, but :commons currently leaks Compose + Skiko as
|
||||
# transitive deps (~40 MB of unused UI jars). Budget is set to
|
||||
# 200 MB until commons is split into core + ui modules — track that
|
||||
# as a follow-up. Until then, this gate just catches pathological
|
||||
# regressions (e.g. accidental :amethyst dep pulling Android libs).
|
||||
# Measured after the :commons / :commonsUI split (1.15.2, Linux x64):
|
||||
# amy-*-jvm.tar.gz 55 MB, amy-*.tar.gz (jlink image) 80 MB, lib/ 60 MB
|
||||
# on disk. The budget sits 50% above the largest asset so a Compose /
|
||||
# Skiko / Android leak (+25-40 MB compressed) trips it, while the
|
||||
# per-OS JRE variance of the jlink image does not. The "Assert no
|
||||
# Compose UI" step above is the precise check; this is the coarse one.
|
||||
fail=0
|
||||
for f in dist/*; do
|
||||
if [[ -f "$f" ]]; then
|
||||
size=$(wc -c < "$f")
|
||||
mb=$(( size / 1048576 ))
|
||||
if (( size > 209715200 )); then
|
||||
echo "::error file=$f::asset is ${mb} MB — exceeds 200 MB amy budget"
|
||||
if (( size > 125829120 )); then
|
||||
echo "::error file=$f::asset is ${mb} MB — exceeds 120 MB amy budget"
|
||||
fail=1
|
||||
else
|
||||
echo "OK: $f — ${mb} MB"
|
||||
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
# Both files in crowdin.yml are declared `type: android`, so Crowdin's Android
|
||||
# serializer escapes apostrophes on the way down: `l'URL` comes back as `l\'URL`.
|
||||
# That is correct for amethyst/src/main/res/, which aapt un-escapes at build time,
|
||||
# and WRONG for commons/.../composeResources/, where Compose resolves only \uXXXX,
|
||||
# and WRONG for commonsUI/.../composeResources/, where Compose resolves only \uXXXX,
|
||||
# \n and \t and leaves \' \" \? \@ alone -- so the backslash reaches the screen.
|
||||
#
|
||||
# Without this step every sync reopens the same regression and CI's
|
||||
@@ -76,14 +76,14 @@ jobs:
|
||||
- name: Convert Android escaping to Compose escaping in the shared catalog
|
||||
run: |
|
||||
python3 tools/strings-migrate/fix_escapes.py --no-unwrap-quotes \
|
||||
commons/src/commonMain/composeResources
|
||||
commonsUI/src/commonMain/composeResources
|
||||
|
||||
# Assert the conversion actually satisfied the check that guards main, so a case
|
||||
# the converter cannot repair fails the sync loudly here instead of opening a red
|
||||
# PR. Known gap if this ever trips: fix_escapes.py only rewrites text inside
|
||||
# <string>/<item> elements, while the check scans the whole file -- an escape in an
|
||||
# XML comment (comments do propagate into the locale files) has to be fixed at the
|
||||
# source string in commons/.../composeResources/values/strings.xml by hand.
|
||||
# source string in commonsUI/.../composeResources/values/strings.xml by hand.
|
||||
- name: Verify the shared catalog is free of Android-only escaping
|
||||
run: .claude/hooks/compose_escaping_check.py
|
||||
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
branch: l10n_crowdin_translations
|
||||
add-paths: |
|
||||
amethyst/src/main/res/**/strings.xml
|
||||
commons/src/commonMain/composeResources/**/strings.xml
|
||||
commonsUI/src/commonMain/composeResources/**/strings.xml
|
||||
docs/changelog/translators.json
|
||||
commit-message: 'chore: sync Crowdin translations and seed translator npub placeholders'
|
||||
title: 'New Crowdin Translations'
|
||||
|
||||
+8
-6
@@ -96,7 +96,7 @@ and each has its own guide:
|
||||
|
||||
| Artifact | Committed at | Regenerate when | Guide |
|
||||
|---|---|---|---|
|
||||
| **Material Symbols subset font** | `commons/src/commonMain/composeResources/font/material_symbols_outlined.ttf` | You add/remove a `MaterialSymbol("\uXXXX")` codepoint in `MaterialSymbols.kt`, or bump the upstream font | [`tools/material-symbols-subset/README.md`](tools/material-symbols-subset/README.md) — run `./tools/material-symbols-subset/subset.sh` |
|
||||
| **Material Symbols subset font** | `commonsUI/src/commonMain/composeResources/font/material_symbols_outlined.ttf` | You add/remove a `MaterialSymbol("\uXXXX")` codepoint in `MaterialSymbols.kt`, or bump the upstream font | [`tools/material-symbols-subset/README.md`](tools/material-symbols-subset/README.md) — run `./tools/material-symbols-subset/subset.sh` |
|
||||
| **Arti (Tor) native libs** | `amethyst/src/main/jniLibs/*.so` | You update the pinned Arti version, change the JNI wrapper, or want to reproduce the binaries | [`tools/arti-build/README.md`](tools/arti-build/README.md) |
|
||||
|
||||
> **Material Symbols is mandatory after icon changes.** The bundled font is a
|
||||
@@ -466,8 +466,8 @@ Homebrew removes the quarantine attribute on its own downloads.
|
||||
> with `dry_run=true` — the sign+notarize step runs regardless of `dry_run` and
|
||||
> now prints the per-file notary log on a non-`Accepted` verdict. If it comes
|
||||
> back `Invalid`, the fix is to codesign the dylibs *inside* those jars before
|
||||
> zipping (and/or strip the unused `skiko`/Compose jars from the CLI image — the
|
||||
> `:commons` core/ui split the size budget already flags). The **desktop** app
|
||||
> zipping (the unused `skiko`/Compose jars left the CLI image with the
|
||||
> `:commons` / `:commonsUI` split). The **desktop** app
|
||||
> bundles the same jars through Compose/jpackage notarization, so run a desktop
|
||||
> dry-run too; its in-jar handling differs and is likewise unverified.
|
||||
|
||||
@@ -686,9 +686,11 @@ Caveats that the maintainer must weigh before submitting:
|
||||
- **Pre-built-jar scrutiny.** homebrew-core prefers source builds; downloading
|
||||
a jar bundle is an accepted-but-reviewed pattern for JVM tools. Be ready to
|
||||
justify it (sandboxed Gradle can't fetch Maven deps).
|
||||
- **Bundle size.** The bundle is ~70 MB today because `:commons` leaks
|
||||
Compose/Skiko jars onto the CLI classpath. Trimming that (a `:commons`
|
||||
core/ui split) would shrink it and smooth review — tracked as a follow-up.
|
||||
- **Bundle size.** The bundle used to be ~70 MB because `:commons` leaked
|
||||
Compose/Skiko jars onto the CLI classpath. Compose UI now lives in
|
||||
`:commonsUI`, which `:cli` does not depend on: the JVM tarball is ~55 MB
|
||||
and the jlink image tarball ~80 MB (1.15.2, Linux x64). The release
|
||||
workflow caps every amy asset at 120 MB.
|
||||
|
||||
After the formula merges, the `livecheck` block lets homebrew-core's BrewTestBot
|
||||
auto-open version-bump PRs on each stable release — no token or workflow on our
|
||||
|
||||
@@ -175,9 +175,13 @@ device. PRs that introduce any of them will be sent back.
|
||||
|
||||
### KMP source-set discipline
|
||||
|
||||
- **Android-only imports don't belong in `commons/commonMain` or
|
||||
`quartz/commonMain`.** Use `expect`/`actual` for platform-specific
|
||||
bits, or move the Android-specific code to `androidMain`.
|
||||
- **Android-only imports don't belong in `commons/commonMain`,
|
||||
`commonsUI/commonMain` or `quartz/commonMain`.** Use `expect`/`actual`
|
||||
for platform-specific bits, or move the Android-specific code to
|
||||
`androidMain`.
|
||||
- **Compose UI (`ui`/`foundation`/`material3`), Coil and `Res` don't belong
|
||||
in `commons` at all** — that module is on the CLI classpath. Put the file
|
||||
in `commonsUI` (same package) instead.
|
||||
|
||||
### Logging
|
||||
|
||||
|
||||
+8
-5
@@ -3,7 +3,7 @@
|
||||
Thanks for your interest in improving Amethyst. This document captures the
|
||||
expectations, conventions, and review rules for code, documentation, and
|
||||
translation contributions across all modules in this repository (`amethyst/`,
|
||||
`desktopApp/`, `quartz/`, `commons/`, `cli/`, `quic/`, `nestsClient/`).
|
||||
`desktopApp/`, `quartz/`, `commons/`, `commonsUI/`, `cli/`, `quic/`, `nestsClient/`).
|
||||
|
||||
By contributing, you agree to license your work under the MIT license. Any
|
||||
work contributed where you are not the original author must contain its
|
||||
@@ -157,7 +157,8 @@ Common Gradle entry points:
|
||||
Modules:
|
||||
|
||||
- `quartz/` — Nostr KMP library (protocol, crypto, models). **No UI.**
|
||||
- `commons/` — Shared Compose Multiplatform UI, icons, ViewModels, flows.
|
||||
- `commons/` — Shared headless layer: models, ViewModels, flows, relay client. **No Compose UI** (the CLI depends on it).
|
||||
- `commonsUI/` — Shared Compose Multiplatform UI, icons, theme, Compose resources, on top of `commons`.
|
||||
- `quic/` — Pure-Kotlin QUIC v1 + HTTP/3 + WebTransport.
|
||||
- `nestsClient/` — Audio-rooms client (NIP-53) built on `:quic` and
|
||||
`:quartz`.
|
||||
@@ -175,7 +176,8 @@ of PR churn. Place new code by purpose:
|
||||
| What you're adding | Goes in |
|
||||
|---|---|
|
||||
| Nostr event types, NIPs, tags, signing, crypto, Bech32 | `quartz/commonMain/` |
|
||||
| Shared Composables, icons, ViewModels, StateFlows | `commons/commonMain/viewmodels/` or `commons/commonMain/` |
|
||||
| Shared ViewModels, StateFlows, relay subscriptions | `commons/commonMain/viewmodels/` or `commons/commonMain/` |
|
||||
| Shared Composables, icons, theme | `commonsUI/commonMain/` (same packages as `commons`) |
|
||||
| Android-only screen, navigation, system integration | `amethyst/` |
|
||||
| Desktop-only window, sidebar, menu bar, shortcut | `desktopApp/` |
|
||||
| `amy <verb>` subcommand (thin assembly only) | `cli/src/main/kotlin/.../cli/` |
|
||||
@@ -188,8 +190,9 @@ Hard rules:
|
||||
- `cli/` has **no Nostr protocol or business logic** — it's a thin assembly
|
||||
layer over `quartz` + `commons`. If your CLI command needs new behavior,
|
||||
extract it into `commons/` first.
|
||||
- ViewModels belong in `commons/commonMain/`. Only screens (the Composable
|
||||
that wires layout + navigation) stay in the platform module.
|
||||
- ViewModels belong in `commons/commonMain/`; shared composables in
|
||||
`commonsUI/commonMain/`. Only screens (the Composable that wires layout +
|
||||
navigation) stay in the platform module.
|
||||
- For platform-specific behavior in a shared file, use `expect`/`actual`.
|
||||
|
||||
## Workflow
|
||||
|
||||
@@ -405,6 +405,7 @@ dependencies {
|
||||
|
||||
implementation(project(":quartz"))
|
||||
implementation(project(":commons"))
|
||||
implementation(project(":commonsUI"))
|
||||
implementation(project(":nestsClient"))
|
||||
// Agent text stream previews: the raw-QUIC binding plus the QUIC
|
||||
// stack under it (for the certificate validator it requires).
|
||||
|
||||
@@ -184,6 +184,7 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.drop
|
||||
@@ -647,6 +648,41 @@ class AppModules(
|
||||
onionCache = onionLocationCache,
|
||||
)
|
||||
|
||||
// Drops pooled connections once per real Tor route change. When the user switches
|
||||
// Tor on, the direct clients' idle sockets to real hosts would otherwise sit in the
|
||||
// pool for its 5-minute keepalive after the user has asked for everything to go
|
||||
// through Tor. No request could use them either way -- OkHttp keys the pool by
|
||||
// `Address`, which includes the proxy, so a connection on a dead route is already
|
||||
// unreachable -- which is why this is hygiene and not correctness, and why it is
|
||||
// fine for it to be a little late.
|
||||
//
|
||||
// Every source here is a plain StateFlow, so subscribing costs nothing. Deliberately
|
||||
// NOT torManager.activePortOrNull: that chains to TorManager.status, whose upstream
|
||||
// is WhileSubscribed and calls service.start() when collected, so a process-lifetime
|
||||
// subscription there would hold Arti's control flow open forever -- the same hazard
|
||||
// the battery ledger above documents and sidesteps the same way.
|
||||
//
|
||||
// Also deliberately not the per-feature Tor switches (imagesViaTor, videosViaTor, ...):
|
||||
// those change which of the two existing clients a request picks, not the route either
|
||||
// one uses, so no pooled connection goes stale.
|
||||
init {
|
||||
applicationIOScope.launch {
|
||||
combine(
|
||||
torPrefs.torType,
|
||||
torPrefs.externalSocksPort,
|
||||
torService.status.map { it.socksPort },
|
||||
) { torType, externalPort, artiPort -> Triple(torType, externalPort, artiPort) }
|
||||
.distinctUntilChanged()
|
||||
// Only later moves count; the route in force at process construction is the
|
||||
// status quo, and nothing is pooled yet to evict.
|
||||
.drop(1)
|
||||
.collect {
|
||||
okHttpClients.factory.evictPooledConnections()
|
||||
okHttpClientForRelays.factory.evictPooledConnections()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Connects the INostrClient class with okHttp
|
||||
val websocketBuilder =
|
||||
OkHttpWebSocket.Builder(
|
||||
|
||||
+8
@@ -320,6 +320,14 @@ class NotificationRelayService : Service() {
|
||||
}
|
||||
|
||||
launch {
|
||||
// This flow used to over-report: it is fed by socket callbacks, and until
|
||||
// the OkHttp adapters answered a relay's CLOSE frame a relay-initiated close
|
||||
// produced none (no onClosed, no onFailure, and a silent cancel()
|
||||
// afterwards), so after the feeds tore down in the background it carried
|
||||
// hundreds of already-dropped relays for minutes. The pool now clears it
|
||||
// itself whenever it lets a relay go, and every transport reports its
|
||||
// session end exactly once (see WebSocket), so what it emits is the count.
|
||||
//
|
||||
// sample() caps how often we touch the notification. During feed
|
||||
// load/teardown connectedRelaysFlow churns dozens of times per second;
|
||||
// posting on every delta blows past Android's notification rate limit
|
||||
|
||||
+63
-24
@@ -34,6 +34,7 @@ import kotlinx.coroutines.launch
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
class OkHttpWebSocket(
|
||||
val url: NormalizedRelayUrl,
|
||||
@@ -41,7 +42,17 @@ class OkHttpWebSocket(
|
||||
val out: WebSocketListener,
|
||||
) : WebSocket {
|
||||
private var usingOkHttp: OkHttpClient? = null
|
||||
private var socket: okhttp3.WebSocket? = null
|
||||
|
||||
@Volatile private var socket: okhttp3.WebSocket? = null
|
||||
|
||||
/**
|
||||
* Set once, by whichever of `onClosed`, `onFailure` or [disconnect] ends the session first.
|
||||
* One adapter is one session (the relay client builds a fresh one per dial, and OkHttp binds
|
||||
* exactly one socket to the listener), so a callback only has to ask whether the session
|
||||
* already ended. See quartz's `BasicOkHttpWebSocket` for the full reasoning; the two adapters
|
||||
* differ only in how [needsReconnect] is decided.
|
||||
*/
|
||||
private val ended = AtomicBoolean(false)
|
||||
|
||||
fun buildRequest() = Request.Builder().url(url.url).build()
|
||||
|
||||
@@ -68,8 +79,10 @@ class OkHttpWebSocket(
|
||||
}
|
||||
|
||||
override fun connect() {
|
||||
usingOkHttp = httpClient(url)
|
||||
socket = usingOkHttp?.newWebSocket(buildRequest(), OkHttpWebsocketListener(out))
|
||||
if (socket != null || ended.get()) return
|
||||
val client = httpClient(url)
|
||||
usingOkHttp = client
|
||||
socket = client.newWebSocket(buildRequest(), OkHttpWebsocketListener(out))
|
||||
}
|
||||
|
||||
inner class OkHttpWebsocketListener(
|
||||
@@ -91,35 +104,60 @@ class OkHttpWebSocket(
|
||||
}
|
||||
}
|
||||
|
||||
/** Claims the session's single terminal report. False if it already ended. */
|
||||
private fun endSession(): Boolean {
|
||||
if (!ended.compareAndSet(false, true)) return false
|
||||
socket = null
|
||||
incomingMessages.close()
|
||||
job.cancel()
|
||||
scope.cancel()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOpen(
|
||||
webSocket: okhttp3.WebSocket,
|
||||
response: Response,
|
||||
) = out.onOpen(
|
||||
(response.receivedResponseAtMillis - response.sentRequestAtMillis).toInt(),
|
||||
response.headers["Sec-WebSocket-Extensions"]?.contains("permessage-deflate") ?: false,
|
||||
)
|
||||
) {
|
||||
if (ended.get()) return
|
||||
out.onOpen(
|
||||
(response.receivedResponseAtMillis - response.sentRequestAtMillis).toInt(),
|
||||
response.headers["Sec-WebSocket-Extensions"]?.contains("permessage-deflate") ?: false,
|
||||
)
|
||||
}
|
||||
|
||||
override fun onMessage(
|
||||
webSocket: okhttp3.WebSocket,
|
||||
text: String,
|
||||
) {
|
||||
// Asynchronously send the received message to the channel.
|
||||
// `trySendBlocking` is used here for simplicity within the callback,
|
||||
// but it's important to understand potential thread blocking if the buffer is full.
|
||||
if (ended.get()) return
|
||||
// Never blocks (unlimited channel): the OkHttp reader thread must
|
||||
// stay free to keep draining the socket.
|
||||
incomingMessages.trySendBlocking(text)
|
||||
}
|
||||
|
||||
override fun onClosing(
|
||||
webSocket: okhttp3.WebSocket,
|
||||
code: Int,
|
||||
reason: String,
|
||||
) {
|
||||
// The relay sent a CLOSE frame. OkHttp fires onClosed only once BOTH peers have sent
|
||||
// one, and sending ours is the application's job (WebSocketListener KDoc; its own
|
||||
// WebSocketEcho recipe does exactly this). Unanswered, the socket sat half-closed:
|
||||
// no onClosed, no onFailure, send() still accepted and discarded, a later cancel()
|
||||
// silent too -- so the relay client believed it was connected until the 120s ping
|
||||
// path failed up to two intervals later.
|
||||
//
|
||||
// Always 1000 rather than echoing `code`: close() validates the code it writes and
|
||||
// throws on the reserved ones (1005, 1006, 1015), and a relay may send anything.
|
||||
webSocket.close(1000, null)
|
||||
}
|
||||
|
||||
override fun onClosed(
|
||||
webSocket: okhttp3.WebSocket,
|
||||
code: Int,
|
||||
reason: String,
|
||||
) {
|
||||
// Close the channel on failure, and propagate the error.
|
||||
incomingMessages.close()
|
||||
job.cancel()
|
||||
scope.cancel()
|
||||
|
||||
socket = null
|
||||
if (!endSession()) return
|
||||
out.onClosed(code, reason)
|
||||
}
|
||||
|
||||
@@ -128,12 +166,7 @@ class OkHttpWebSocket(
|
||||
t: Throwable,
|
||||
response: Response?,
|
||||
) {
|
||||
// Close the channel on failure, and propagate the error.
|
||||
incomingMessages.close()
|
||||
job.cancel()
|
||||
scope.cancel()
|
||||
|
||||
socket = null
|
||||
if (!endSession()) return
|
||||
out.onFailure(t, response?.code, response?.message)
|
||||
}
|
||||
}
|
||||
@@ -153,9 +186,15 @@ class OkHttpWebSocket(
|
||||
}
|
||||
|
||||
override fun disconnect() {
|
||||
// uses cancel to kill the SEND stack that might be waiting
|
||||
socket?.cancel()
|
||||
// Claim the session ourselves and cancel (which also kills a SEND stack that might be
|
||||
// waiting): OkHttp's cancel() raises no callback when no reader is left to fail, and when
|
||||
// it does the failure arrives later on its own thread. The relay client needs the answer
|
||||
// now, and must not hear from this socket again.
|
||||
val closing = socket ?: return
|
||||
if (!ended.compareAndSet(false, true)) return
|
||||
socket = null
|
||||
closing.cancel()
|
||||
out.onClosed(1000, "client disconnect")
|
||||
}
|
||||
|
||||
override fun send(msg: String): Boolean = socket?.send(msg) ?: false
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@ fun RenderTopButtonsPreview() {
|
||||
ThemeComparisonColumn {
|
||||
Box(Modifier.background(BitcoinOrange)) {
|
||||
RenderTopButtons(
|
||||
mediaData = MediaItemData("http://test.mp4"),
|
||||
mediaData = MediaItemData("https://test.mp4"),
|
||||
hasMultipleQualities = false,
|
||||
qualityButton = {},
|
||||
controllerVisible = remember { mutableStateOf(true) },
|
||||
|
||||
@@ -47,10 +47,13 @@ import coil3.compose.SubcomposeAsyncImage
|
||||
import coil3.compose.SubcomposeAsyncImageContent
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.gif
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation
|
||||
import com.vitorpamplona.amethyst.model.MediaAspectRatioCache
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.Font10SP
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size40dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size6dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.SmallBorder
|
||||
import com.vitorpamplona.amethyst.ui.theme.imageModifier
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag
|
||||
@@ -72,6 +75,15 @@ fun GifVideoView(
|
||||
// remember() to avoid the recompute would cost more (slot read + N equality checks)
|
||||
// than the work it saves; that's why this stays as a plain expression.
|
||||
val ratio = dimensions?.aspectRatioOrNull() ?: MediaAspectRatioCache.get(videoUri)
|
||||
|
||||
// Mirrors [mediaSizingModifier]: Crop gets fillMaxSize() and a known ratio gets
|
||||
// aspectRatio(), both of which bound the height. Everything else is a bare
|
||||
// fillMaxWidth() that wraps its content, and only THAT case needs a loading state
|
||||
// with intrinsic height to keep the note from collapsing to nothing. Keying the
|
||||
// fallback on `ratio` alone would put raw URL text inside every Crop card cell --
|
||||
// MyAsyncImage passes dimensions/blurhash/thumbhash all null, so a gif in a card
|
||||
// slot hits this on first load, before MediaAspectRatioCache knows its size.
|
||||
val heightIsBounded = contentScale == ContentScale.Crop || ratio != null
|
||||
val autoPlay = accountViewModel.settings.autoPlayVideos()
|
||||
val borderModifier = if (roundedCorner) MaterialTheme.colorScheme.imageModifier else Modifier
|
||||
val context = LocalContext.current
|
||||
@@ -108,13 +120,29 @@ fun GifVideoView(
|
||||
|
||||
when (state) {
|
||||
is AsyncImagePainter.State.Loading -> {
|
||||
DisplayBlurHash(
|
||||
blurhash,
|
||||
contentDescription,
|
||||
contentScale,
|
||||
Modifier.fillMaxSize(),
|
||||
thumbhash = thumbhash,
|
||||
)
|
||||
// When the height is unbounded (see [heightIsBounded]) this branch MUST
|
||||
// emit something with an intrinsic height, or the box wraps nothing and the
|
||||
// whole note collapses to zero -- no picture, no URL, no spinner, just a gap
|
||||
// in the feed until the load finishes. DisplayBlurHash renders NOTHING when
|
||||
// both hashes are absent (placeholderModel returns null), which is exactly
|
||||
// what a no-imeta post hits. Mirrors UrlImageView's ladder.
|
||||
if (blurhash != null || thumbhash != null) {
|
||||
DisplayBlurHash(
|
||||
blurhash,
|
||||
contentDescription,
|
||||
contentScale,
|
||||
Modifier.fillMaxSize(),
|
||||
thumbhash = thumbhash,
|
||||
)
|
||||
} else if (heightIsBounded) {
|
||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
LoadingAnimation(Size40dp, Size6dp)
|
||||
}
|
||||
} else {
|
||||
WaitAndDisplay {
|
||||
DisplayUrlWithLoadingSymbol(videoUri)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is AsyncImagePainter.State.Success -> {
|
||||
|
||||
+3
-3
@@ -23,13 +23,13 @@ package com.vitorpamplona.amethyst.ui.feeds
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveComplexFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.feeds.InvalidatableContent
|
||||
import com.vitorpamplona.amethyst.commons.feeds.LoadedFeedState
|
||||
import com.vitorpamplona.amethyst.commons.model.Channel
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.service.BundledInsert
|
||||
import com.vitorpamplona.amethyst.commons.service.BundledUpdate
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveComplexFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.InvalidatableContent
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.LoadedFeedState
|
||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
package com.vitorpamplona.amethyst.ui.feeds
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.vitorpamplona.amethyst.commons.feeds.LoadedFeedState
|
||||
import com.vitorpamplona.amethyst.commons.model.Channel
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.LoadedFeedState
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
@Stable
|
||||
|
||||
@@ -28,8 +28,8 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@@ -31,7 +31,7 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||
|
||||
@@ -34,6 +34,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import coil3.imageLoader
|
||||
import coil3.request.ImageRequest
|
||||
import coil3.request.SuccessResult
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.commons.richtext.CachedRichTextParser
|
||||
@@ -42,7 +43,6 @@ import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo
|
||||
import com.vitorpamplona.amethyst.commons.richtext.RichTextParser
|
||||
import com.vitorpamplona.amethyst.commons.richtext.RichTextViewerState
|
||||
import com.vitorpamplona.amethyst.commons.richtext.UrlParser
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.model.MediaAspectRatioCache
|
||||
import com.vitorpamplona.amethyst.model.UrlCachedPreviewer
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@@ -36,7 +36,7 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.InvalidatableContent
|
||||
import com.vitorpamplona.amethyst.commons.feeds.InvalidatableContent
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.LocalDisappearingScaffoldPadding
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.feeds
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.lifecycle.compose.LifecycleResumeEffect
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.InvalidatableContent
|
||||
import com.vitorpamplona.amethyst.commons.feeds.InvalidatableContent
|
||||
|
||||
@Composable
|
||||
fun WatchLifecycleAndUpdateModel(model: InvalidatableContent) {
|
||||
|
||||
@@ -29,8 +29,8 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.CardFeedContentState
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@@ -61,8 +61,10 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.model.AddressableNote
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.concord.ConcordChannel
|
||||
import com.vitorpamplona.amethyst.commons.model.isCommunityDefinition
|
||||
import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel
|
||||
import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel
|
||||
import com.vitorpamplona.amethyst.commons.model.replyingDirectlyTo
|
||||
import com.vitorpamplona.amethyst.commons.model.textNoteModifications
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.approve
|
||||
@@ -78,8 +80,6 @@ import com.vitorpamplona.amethyst.commons.ui.note.QuietMark
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.RenderCashuMint
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.RenderFedimint
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.RenderMintRecommendation
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.isCommunityDefinition
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.replyingDirectlyTo
|
||||
import com.vitorpamplona.amethyst.commons.ui.state.produceCachedStateAsync
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannelPicture
|
||||
|
||||
@@ -46,7 +46,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ChessChallenge
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ChessGameViewer
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ui.ChessGameViewer
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.chess_accept
|
||||
import com.vitorpamplona.amethyst.commons.resources.chess_decline
|
||||
|
||||
@@ -35,10 +35,10 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.vitorpamplona.amethyst.commons.model.EmptyTagList
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.replyingDirectlyTo
|
||||
import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.ReplyToLabel
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.replyingDirectlyTo
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
|
||||
import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
|
||||
|
||||
@@ -34,8 +34,8 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.vitorpamplona.amethyst.commons.model.EmptyTagList
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.replyingDirectlyTo
|
||||
import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.replyingDirectlyTo
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
|
||||
import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.FeedViewModel
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.FeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.feeds.FeedEmpty
|
||||
|
||||
@@ -25,10 +25,10 @@ import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.feeds.InvalidatableContent
|
||||
import com.vitorpamplona.amethyst.commons.model.User
|
||||
import com.vitorpamplona.amethyst.commons.service.BundledUpdate
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.InvalidatableContent
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
|
||||
|
||||
+1
-1
@@ -22,9 +22,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
||||
|
||||
import android.content.ComponentCallbacks2
|
||||
import com.vitorpamplona.amethyst.Amethyst
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||
|
||||
+1
-1
@@ -42,6 +42,7 @@ import com.vitorpamplona.amethyst.LocalPreferences
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.audio.VisualizerStyle
|
||||
import com.vitorpamplona.amethyst.commons.cashu.ops.describeMintError
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.model.AddressableNote
|
||||
import com.vitorpamplona.amethyst.commons.model.Dao
|
||||
import com.vitorpamplona.amethyst.commons.model.LiveHiddenUsers
|
||||
@@ -65,7 +66,6 @@ import com.vitorpamplona.amethyst.commons.service.http.IRoleBasedHttpClientBuild
|
||||
import com.vitorpamplona.amethyst.commons.service.pow.PoWCategory
|
||||
import com.vitorpamplona.amethyst.commons.tor.TorType
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.notifications.CardFeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.state.GenericBaseCache
|
||||
import com.vitorpamplona.amethyst.commons.ui.state.GenericBaseCacheAsync
|
||||
|
||||
+1
-1
@@ -21,10 +21,10 @@
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedTopNavPerRelayFilterSet
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter
|
||||
import com.vitorpamplona.amethyst.commons.relayClient.topNavFeeds.TopNavFeedQueryState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox
|
||||
import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState
|
||||
|
||||
+1
-1
@@ -20,10 +20,10 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.articles.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox
|
||||
import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState
|
||||
|
||||
+1
-1
@@ -20,10 +20,10 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
|
||||
|
||||
+1
-1
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
|
||||
class BookmarkPrivateFeedFilter(
|
||||
|
||||
+1
-1
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
|
||||
class BookmarkPublicFeedFilter(
|
||||
|
||||
+1
-1
@@ -214,7 +214,7 @@ private fun Picture(
|
||||
onValueChange = { bookmarkGroupInfoViewModel.picture.value = it },
|
||||
placeholder = {
|
||||
Text(
|
||||
text = "http://mygroup.com/logo.jpg",
|
||||
text = "https://mygroup.com/logo.jpg",
|
||||
color = MaterialTheme.colorScheme.placeholderText,
|
||||
)
|
||||
},
|
||||
|
||||
+1
-1
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.old.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
|
||||
class OldBookmarkPrivateFeedFilter(
|
||||
|
||||
+1
-1
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.old.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
|
||||
class OldBookmarkPublicFeedFilter(
|
||||
|
||||
+1
-1
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.podcasts.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.quartz.nipXXPodcasting20.metadata.isPodcastEvent
|
||||
|
||||
|
||||
+1
-1
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.repositories.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.feeds.WatchLifecycleAndUpdateModel
|
||||
import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar
|
||||
|
||||
+2
-2
@@ -47,6 +47,8 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
@@ -56,8 +58,6 @@ import com.vitorpamplona.amethyst.commons.resources.calendar_collection_count
|
||||
import com.vitorpamplona.amethyst.commons.resources.calendar_empty_collections_subtitle
|
||||
import com.vitorpamplona.amethyst.commons.resources.calendar_empty_collections_title
|
||||
import com.vitorpamplona.amethyst.commons.resources.calendar_export_event
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox
|
||||
|
||||
+2
-2
@@ -51,6 +51,8 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.nip52Calendar.appointmentView
|
||||
import com.vitorpamplona.amethyst.commons.model.nip52Calendar.calendarLocalDayKeyRange
|
||||
@@ -63,8 +65,6 @@ import com.vitorpamplona.amethyst.commons.resources.calendar_empty_day_subtitle
|
||||
import com.vitorpamplona.amethyst.commons.resources.calendar_empty_day_title
|
||||
import com.vitorpamplona.amethyst.commons.resources.calendar_nav_next_day
|
||||
import com.vitorpamplona.amethyst.commons.resources.calendar_nav_previous_day
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||
|
||||
+2
-2
@@ -38,6 +38,8 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.nip52Calendar.calendarEndSeconds
|
||||
import com.vitorpamplona.amethyst.commons.model.nip52Calendar.calendarStartSeconds
|
||||
@@ -46,8 +48,6 @@ import com.vitorpamplona.amethyst.commons.resources.calendar_empty_feed_subtitle
|
||||
import com.vitorpamplona.amethyst.commons.resources.calendar_empty_feed_title
|
||||
import com.vitorpamplona.amethyst.commons.resources.calendar_section_past
|
||||
import com.vitorpamplona.amethyst.commons.resources.calendar_section_upcoming
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox
|
||||
import com.vitorpamplona.amethyst.ui.feeds.WatchScrollToTop
|
||||
|
||||
+2
-2
@@ -53,6 +53,8 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.model.nip52Calendar.MONTH_GRID_MAX_LANES
|
||||
import com.vitorpamplona.amethyst.commons.model.nip52Calendar.MonthGridBarSegment
|
||||
import com.vitorpamplona.amethyst.commons.model.nip52Calendar.computeMonthGridBars
|
||||
@@ -62,8 +64,6 @@ import com.vitorpamplona.amethyst.commons.resources.calendar_day_a11y_selected_s
|
||||
import com.vitorpamplona.amethyst.commons.resources.calendar_day_a11y_today_suffix
|
||||
import com.vitorpamplona.amethyst.commons.resources.calendar_nav_next_month
|
||||
import com.vitorpamplona.amethyst.commons.resources.calendar_nav_previous_month
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
+2
-2
@@ -51,6 +51,8 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.nip52Calendar.groupByDayKeyExpanded
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
@@ -60,8 +62,6 @@ import com.vitorpamplona.amethyst.commons.resources.calendar_empty_week_subtitle
|
||||
import com.vitorpamplona.amethyst.commons.resources.calendar_empty_week_title
|
||||
import com.vitorpamplona.amethyst.commons.resources.calendar_nav_next_week
|
||||
import com.vitorpamplona.amethyst.commons.resources.calendar_nav_previous_week
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.feeds.WatchLifecycleAndUpdateModel
|
||||
import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar
|
||||
|
||||
+1
-1
@@ -20,10 +20,10 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.nip52Calendar.upcomingFirstCalendarOrder
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
|
||||
|
||||
+1
-1
@@ -20,9 +20,9 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
|
||||
|
||||
+2
-2
@@ -36,9 +36,9 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.feeds.FeedEmpty
|
||||
import com.vitorpamplona.amethyst.ui.feeds.FeedError
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.MarmotGroupFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.feeds.MarmotGroupFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.ListChangeFeedViewModel
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
|
||||
+2
-2
@@ -38,13 +38,13 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.model.privateChatLastReadRoute
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.chats_history_proto_nip04
|
||||
import com.vitorpamplona.amethyst.commons.resources.chats_history_proto_nip17
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.DmHistoryLoadingCard
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachCursor
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachDetailDialog
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachMarkers
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.dal
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.ChatroomFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.feeds.ChatroomFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.ListChangeFeedViewModel
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
|
||||
+2
-2
@@ -54,14 +54,14 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.model.concord.ConcordCommunitySession
|
||||
import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.ShowEmojiSuggestionList
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.concord_dissolved_read_only
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.DmHistoryLoadingCard
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachCursor
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachMarkers
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachSentinels
|
||||
|
||||
+2
-2
@@ -20,10 +20,10 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.feeds.ChangesFlowFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Channel
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.ChangesFlowFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.isMinichatReply
|
||||
|
||||
+1
-1
@@ -285,7 +285,7 @@ private fun Picture(
|
||||
onValueChange = { postViewModel.channelPicture.value = it },
|
||||
placeholder = {
|
||||
Text(
|
||||
text = "http://mygroup.com/logo.jpg",
|
||||
text = "https://mygroup.com/logo.jpg",
|
||||
color = MaterialTheme.colorScheme.placeholderText,
|
||||
)
|
||||
},
|
||||
|
||||
+2
-2
@@ -39,6 +39,8 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.buzz.BuzzRelayDialect
|
||||
import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel
|
||||
@@ -46,8 +48,6 @@ import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.relay_group_invite_only_to_post
|
||||
import com.vitorpamplona.amethyst.commons.resources.relay_group_join_to_post
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.DmHistoryLoadingCard
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachCursor
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachMarkers
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachSentinels
|
||||
|
||||
+1
-1
@@ -56,6 +56,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
@@ -68,7 +69,6 @@ import com.vitorpamplona.amethyst.commons.resources.relay_group_browse_title
|
||||
import com.vitorpamplona.amethyst.commons.resources.relay_group_favorite_relay
|
||||
import com.vitorpamplona.amethyst.commons.resources.relay_group_message_count_short_capped
|
||||
import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.model.nip11RelayInfo.WarmNip11
|
||||
import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo
|
||||
|
||||
+1
-1
@@ -20,12 +20,12 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet
|
||||
import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.GroupDiscoveryConstraint
|
||||
import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.nip11RelayInfo.isRelaySignedRelayGroup
|
||||
|
||||
+1
-1
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType
|
||||
import com.vitorpamplona.amethyst.commons.model.concord.ConcordChannel
|
||||
@@ -28,7 +29,6 @@ import com.vitorpamplona.amethyst.commons.model.geohashChat.GeohashChatChannel
|
||||
import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel
|
||||
import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupViewMode
|
||||
import com.vitorpamplona.amethyst.commons.model.publicChatChannelIdOf
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.util.replace
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
|
||||
+1
-1
@@ -20,9 +20,9 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.util.replace
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
|
||||
+2
-2
@@ -38,6 +38,8 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.marmotGroups.MarmotGroupChatroom
|
||||
import com.vitorpamplona.amethyst.commons.relayClient.paging.PagingStatus
|
||||
@@ -45,8 +47,6 @@ import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.chats_history_proto_nip04
|
||||
import com.vitorpamplona.amethyst.commons.resources.chats_history_proto_nip17
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.DmHistoryLoadingCard
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachCursor
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachDetailDialog
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachMarkers
|
||||
|
||||
+1
-1
@@ -40,6 +40,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
@@ -47,7 +48,6 @@ import com.vitorpamplona.amethyst.commons.resources.mark_all_as_read
|
||||
import com.vitorpamplona.amethyst.commons.resources.mark_all_known_as_read
|
||||
import com.vitorpamplona.amethyst.commons.resources.mark_all_new_as_read
|
||||
import com.vitorpamplona.amethyst.commons.resources.mark_as_read_dialog_title
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.components.M3ActionDialog
|
||||
import com.vitorpamplona.amethyst.ui.components.M3ActionRow
|
||||
import com.vitorpamplona.amethyst.ui.components.M3ActionSection
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.feeds.ScrollStateKeys
|
||||
import com.vitorpamplona.amethyst.ui.feeds.WatchLifecycleAndUpdateModel
|
||||
import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.feeds.ScrollStateKeys
|
||||
import com.vitorpamplona.amethyst.ui.feeds.WatchLifecycleAndUpdateModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ import com.google.accompanist.adaptive.FoldAwareConfiguration
|
||||
import com.google.accompanist.adaptive.HorizontalTwoPaneStrategy
|
||||
import com.google.accompanist.adaptive.TwoPane
|
||||
import com.google.accompanist.adaptive.calculateDisplayFeatures
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.components.getActivity
|
||||
import com.vitorpamplona.amethyst.ui.insets.imePaddingSafe
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar
|
||||
|
||||
+1
-1
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.share
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
|
||||
|
||||
|
||||
+1
-1
@@ -35,10 +35,10 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.share_to_dm_start_new
|
||||
import com.vitorpamplona.amethyst.commons.resources.share_to_dm_title
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.feeds.WatchLifecycleAndUpdateModel
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
|
||||
+3
-3
@@ -61,10 +61,10 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ChessBroadcastBanner
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ChessBroadcastStatus
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ChessSyncBanner
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.LiveChessGameScreen
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ui.ChessBroadcastBanner
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ui.ChessSyncBanner
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ui.LiveChessGameScreen
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.chess_game_id
|
||||
import com.vitorpamplona.amethyst.commons.resources.chess_game_not_found
|
||||
|
||||
+9
-9
@@ -62,16 +62,16 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ActiveGameCard
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ChallengeCard
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ChessChallenge
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ChessSyncBanner
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.CompletedGameCard
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.NewChessGameDialog
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.OutgoingChallengeCard
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.OverlappingAvatars
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.PublicGameCard
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.SpectatingGameCard
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ui.ActiveGameCard
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ui.ChallengeCard
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ui.ChessSyncBanner
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ui.CompletedGameCard
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ui.NewChessGameDialog
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ui.OutgoingChallengeCard
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ui.OverlappingAvatars
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ui.PublicGameCard
|
||||
import com.vitorpamplona.amethyst.commons.nip64Chess.ui.SpectatingGameCard
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.dismiss
|
||||
import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox
|
||||
|
||||
+1
-1
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chess.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
|
||||
|
||||
+1
-1
@@ -20,9 +20,9 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.AddressableNote
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
|
||||
|
||||
+1
-1
@@ -20,9 +20,9 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.AddressableNote
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
|
||||
|
||||
+2
-2
@@ -32,8 +32,8 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.feeds.FeedEmpty
|
||||
|
||||
+2
-2
@@ -51,10 +51,10 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.feeds.FeedEmpty
|
||||
|
||||
+1
-1
@@ -20,10 +20,10 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip23LongForm
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
|
||||
|
||||
+1
-1
@@ -20,9 +20,9 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip28Chats
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
|
||||
|
||||
+1
-1
@@ -20,10 +20,10 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip51FollowSets
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
|
||||
|
||||
+1
-1
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip53LiveActivities
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allFollows.AllFollowsByOutboxTopNavFilter
|
||||
@@ -29,7 +30,6 @@ import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.author.Aut
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.community.SingleCommunityTopNavFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.MutedAuthorsByOutboxTopNavFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.MutedAuthorsByProxyTopNavFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.ParticipantListBuilder
|
||||
|
||||
+1
-1
@@ -20,10 +20,10 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip72Communities
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.mapNotNullIntoSet
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
|
||||
|
||||
+1
-1
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip90DVMs
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter
|
||||
@@ -30,7 +31,6 @@ import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.author.Aut
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.community.SingleCommunityTopNavFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.MutedAuthorsByOutboxTopNavFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.MutedAuthorsByProxyTopNavFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.ParticipantListBuilder
|
||||
|
||||
+1
-1
@@ -20,10 +20,10 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip99Classifieds
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
|
||||
|
||||
+2
-2
@@ -42,6 +42,8 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
@@ -49,8 +51,6 @@ import com.vitorpamplona.amethyst.commons.resources.delete_all
|
||||
import com.vitorpamplona.amethyst.commons.resources.delete_all_drafts_confirmation
|
||||
import com.vitorpamplona.amethyst.commons.resources.no
|
||||
import com.vitorpamplona.amethyst.commons.resources.yes
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.components.SwipeToDeleteWithConfirmation
|
||||
import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox
|
||||
|
||||
+1
-1
@@ -20,9 +20,9 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.drafts.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder
|
||||
|
||||
+1
-1
@@ -20,9 +20,9 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.observables.CreatedAtComparator
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
|
||||
|
||||
+2
-2
@@ -35,9 +35,9 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.feeds.FeedEmpty
|
||||
|
||||
+1
-1
@@ -20,10 +20,10 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.browse.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
|
||||
|
||||
+1
-1
@@ -20,13 +20,13 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.AddressableNote
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows.AllUserFollowsByOutboxTopNavFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows.AllUserFollowsByProxyTopNavFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.MutedAuthorsByOutboxTopNavFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.MutedAuthorsByProxyTopNavFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
|
||||
|
||||
+2
-2
@@ -20,13 +20,13 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.dal
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.feeds.isRenderableRepost
|
||||
import com.vitorpamplona.amethyst.commons.model.AddressableNote
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows.AllUserFollowsByOutboxTopNavFilter
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows.AllUserFollowsByProxyTopNavFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.AdditiveFeedFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.isRenderableRepost
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.ui.dal.FilterByListParams
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user