diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 886a0dfe3e..bb25787d7d 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -11,9 +11,11 @@ contain implementations of Nostr specifications and utilities to help implement `concord/` (`cordXX`), `buzz/`, plus the binding-agnostic RFC 9420 engine in `mls/`. A new protocol over Nostr belongs here as a package, not as a Gradle module; `quic`/`nestsClient`/`marmotQuic` are modules because they are transports with no Nostr in them. Commons stores -shared code between Amethyst Android (`amethyst`) and Amethyst Desktop (`desktopApp`). The Desktop -App is designed to be mouse first and so uses a completely different screen and navigation -architecture while sharing the back end components with the android counterpart. `cli` ships `amy`, +shared code between Amethyst Android (`amethyst`) and Amethyst Desktop (`desktopApp`). Android now +also ships on laptops, so the direction is **one UI**: every screen and the navigation shell at every +window size move to `commonsUI`, `amethyst` shrinks to an Android shim, and a new `desktopApp` +becomes a JVM shim that renders the same UI (see `commons/plans/2026-09-27-one-ui-android-desktop.md`). +Until it lands, today's `desktopApp` still has its own mouse-first screens and navigation. `cli` ships `amy`, a non-interactive JVM command-line client that drives the same `quartz` + `commons` code — used by humans, agents, and interop tests. `quic` is a from-scratch pure-Kotlin QUIC v1 + HTTP/3 + WebTransport client (no JNI, no BouncyCastle), built because no Android-compatible Java QUIC library @@ -105,7 +107,9 @@ amethyst/ codecs. Not WebTransport — the binding has its own ALPNs and writes frames straight onto QUIC streams, so it deliberately does not reuse `nestsClient`'s `WebTransportSession`. -- `amethyst/` & `desktopApp/` = Platform-native layouts and navigation +- `amethyst/` & `desktopApp/` = Platform shims: process/window entry points, services, system + integrations and the actuals of shared ports. Screens and navigation are shared UI and are + moving to `commonsUI` (today's `desktopApp` screens are legacy, to be replaced). - `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 `:commonsUI`, `:amethyst` or `:desktopApp`. @@ -207,10 +211,21 @@ etc. instead of re-implementing them. (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). + **Screens and navigation are shared too**: screen composables, the nav host, + and the navigation chrome for every window size (bottom bar, rail, permanent + drawer) belong in `commonsUI`, because Android runs on laptops and the new + Desktop app renders the same UI. Adapt to the window with `ScreenLayoutSpec` + / `LocalScreenLayout`, not with a per-platform screen. +- **Keep native** → only what is the platform itself: the process/window entry + point (Android `Activity`/`Service`, Desktop `Window`/tray/menu bar), + system integrations (notifications, file pickers, share sheets, camera, + media3, WebView, keyring/Keystore), and the platform `actual`s or port + implementations the shared UI calls. A new screen goes in `commonsUI` when + its dependencies allow — `AccountViewModel` itself is in `commonsUI` + (`commons.viewmodels`), reaching Android through `AccountViewModelHost`. A + screen that still needs an app-only helper may live in `amethyst/`, but keep + Android APIs out of it (behind a port or slot) so it can move later. Don't add screens to today's `desktopApp` + that the shared UI will have to re-create. When extracting a composable: move it to `commonsUI/commonMain/` (see `/compose-expert`), add expect/actual for any platform behavior (see @@ -429,8 +444,11 @@ Do this before considering the task complete. at byte level (`perl -CSD -pe 's/\x{202E}/\\u202E/g'`). ### Navigation Shell -- **Desktop**: Sidebar + main content area -- **Android**: Bottom navigation +One shell, picked by window size rather than by platform: `ScreenLayoutSpec` +chooses the bottom bar (compact), the rail, or the permanent drawer (wide, +landscape, tall enough), and docks the notification panel on very wide windows. +It is moving to `commonsUI` with `AppNavigation`. Today's `desktopApp` still has +its own sidebar shell, which will be replaced. ## Git Workflow diff --git a/.claude/skills/compose-expert/SKILL.md b/.claude/skills/compose-expert/SKILL.md index e6eced37b1..c5c6afdc30 100644 --- a/.claude/skills/compose-expert/SKILL.md +++ b/.claude/skills/compose-expert/SKILL.md @@ -1,6 +1,6 @@ --- name: compose-expert -description: Advanced Compose Multiplatform UI patterns for shared composables. Use when working with visual UI components, state management patterns (remember, derivedStateOf, produceState), recomposition optimization (@Stable/@Immutable visual usage), Material3 theming, custom ImageVector icons, or determining whether to share UI in commonMain vs keep platform-specific. Delegates navigation to android-expert/desktop-expert. Complements kotlin-expert (handles Kotlin language aspects of state/annotations). +description: Advanced Compose Multiplatform UI patterns for shared composables. Use when working with visual UI components, state management patterns (remember, derivedStateOf, produceState), recomposition optimization (@Stable/@Immutable visual usage), Material3 theming, custom ImageVector icons, or determining whether to share UI in commonMain vs keep platform-specific. Delegates platform entry points (Activity, Window, tray) to android-expert/desktop-expert; the navigation shell itself is shared UI. Complements kotlin-expert (handles Kotlin language aspects of state/annotations). --- # Compose Multiplatform Expert @@ -34,12 +34,17 @@ Visual UI patterns for sharing composables across Android and Desktop. - **Theme utilities**: Color calculations, style helpers - **Material3 components**: Any UI using Material primitives +**Screens and navigation are shared too.** Android also ships on laptops and the new +Desktop app renders the same UI, so screens, the nav host and the bottom bar / rail / +permanent drawer all belong in `commonsUI`. They adapt to the window with +`ScreenLayoutSpec` / `LocalScreenLayout`, not per platform. See +`commons/plans/2026-09-27-one-ui-android-desktop.md`. + ### Keep Platform-Specific -- **Navigation structure**: Bottom nav (Android) vs Sidebar (Desktop) -- **Screen layouts**: Platform-specific scaffolding -- **System integrations**: File pickers, notifications, share sheets -- **Platform UX**: Gestures, keyboard shortcuts, window management +- **Entry points**: Android `Activity`/`Service`, Desktop `Window`, tray, menu bar +- **System integrations**: File pickers, notifications, share sheets, camera, media3, WebView +- **Platform leaves inside shared UI**: behind expect/actual or a slot the shim fills ### Decision Framework @@ -563,12 +568,14 @@ fun FeedList(items: List) { 4. Add caching if generated dynamically 5. Wrap in @Composable for easy use -### Navigation (Delegate) +### Navigation -For navigation patterns: -- Android bottom nav → `android-expert` -- Desktop sidebar → `desktop-expert` -- Multi-window → `desktop-expert` +The navigation shell is shared (`ScreenLayoutSpec` picks bottom bar, rail or permanent +drawer by window size) and is moving to `commonsUI` with `AppNavigation`. Delegate only +the platform leaves: +- Activity / intent plumbing → `android-expert` +- Window, tray, menu bar, multi-window → `desktop-expert` +- Today's legacy `desktopApp` sidebar shell → `desktop-expert` (to be replaced) ## Related Skills diff --git a/.claude/skills/desktop-expert/SKILL.md b/.claude/skills/desktop-expert/SKILL.md index 477880202d..b9def76159 100644 --- a/.claude/skills/desktop-expert/SKILL.md +++ b/.claude/skills/desktop-expert/SKILL.md @@ -248,9 +248,16 @@ application { ## 5. Desktop Navigation Patterns -### NavigationRail (Current Pattern) +### NavigationRail (Current Pattern — legacy) -Desktop uses **NavigationRail** (vertical sidebar) instead of Android's bottom navigation. +> **Being replaced.** Android now also ships on laptops, and the plan is one UI: the +> shared navigation shell (bottom bar / rail / permanent drawer picked by window size +> via `ScreenLayoutSpec`) moves to `commonsUI`, and a new `desktopApp` becomes a JVM +> shim that renders it. Don't grow this sidebar shell or add Desktop-only screens; see +> `commons/plans/2026-09-27-one-ui-android-desktop.md`. What stays Desktop-specific is +> the window, tray, menu bar, keyboard shortcuts and file system integration. + +Today's desktop app uses **NavigationRail** (vertical sidebar) instead of Android's bottom navigation. ```kotlin Row(Modifier.fillMaxSize()) { diff --git a/.claude/skills/kotlin-multiplatform/SKILL.md b/.claude/skills/kotlin-multiplatform/SKILL.md index bd21f16742..87e6172025 100644 --- a/.claude/skills/kotlin-multiplatform/SKILL.md +++ b/.claude/skills/kotlin-multiplatform/SKILL.md @@ -52,8 +52,9 @@ Q: Does it vary by platform or by JVM vs non-JVM? │ Example: Jackson JSON parsing (JVM library) │ └─ Complex/UI-related - → Keep platform-specific - Example: Navigation (Activity vs Window too different) + → Share it in commonsUI; expect/actual or a slot only for the platform leaf + Example: Navigation. One shell in commonsUI, picked by window size + (ScreenLayoutSpec); only the Activity / Window entry point is native Final check: Q: Maintenance cost of abstraction < duplication cost? @@ -85,10 +86,13 @@ val jvmAndroid = create("jvmAndroid") { ``` **Why:** Jackson is JVM-only, works on Android + Desktop, not iOS/web. -**Navigation → platform-specific:** -- Android: `MainActivity` (Activity + Compose Navigation) -- Desktop: `Window` + sidebar + MenuBar -**Why:** UI paradigms fundamentally different. +**Navigation → shared, entry points → platform-specific:** +- Shared (`commonsUI`, moving there): the nav host, bottom bar / rail / + permanent drawer, chosen by window size via `ScreenLayoutSpec` +- Android: `MainActivity` hosts it; Desktop: a `Window` (+ MenuBar, tray) hosts it +**Why:** Android runs on laptops too, and the new Desktop app renders the same +UI. See `commons/plans/2026-09-27-one-ui-android-desktop.md`. Today's +`desktopApp` sidebar shell is legacy. ## Mental Model: Source Sets as Dependency Graph @@ -183,15 +187,15 @@ Quick decision guidelines based on codebase patterns: ### Sometimes Abstract - **Business logic:** YES - state machines, data processing - **ViewModels:** YES - state + business logic shareable (StateFlow/SharedFlow) -- **Screen layouts:** NO - platform-native (Window vs Activity) -- **Why:** ViewModels contain platform-agnostic state; Screens render differently per platform +- **Screen layouts:** YES - shared in `commonsUI`; they adapt to window size, not platform +- **Why:** One UI for Android (phones to laptops) and Desktop; only entry points differ ### Rarely Abstract - **Complex UI components** (composables with heavy platform dependencies) - **Why:** Platform paradigms can differ significantly ### Never Abstract -- **Navigation** (Activity vs Window fundamentally different) +- **Process / window entry points** (Activity, Service, Window, tray) - **Permissions** (Android vs iOS APIs incompatible) - **Platform UX patterns** - **Why:** Too platform-specific, abstraction creates leaky APIs @@ -203,7 +207,7 @@ Quick decision guidelines based on codebase patterns: | PubKeyFormatter, ZapFormatter | ✅ YES | Pure Kotlin, no platform APIs | | TimeAgoFormatter | ⚠️ ABSTRACTED | Needs StringProvider for localized strings | | ViewModels (state + logic) | ✅ YES | StateFlow/SharedFlow platform-agnostic, Compose Multiplatform lifecycle compatible | -| Screen layouts (Scaffold, nav) | ❌ NO | Window vs Activity, sidebar vs bottom nav fundamentally different | +| Screen layouts (Scaffold, nav) | ✅ YES (moving) | One UI; `ScreenLayoutSpec` picks bottom bar / rail / drawer by window size | | Image loading (Coil) | ⚠️ ABSTRACTED | Coil 3.x supports KMP, needs expect/actual wrapper | ## expect/actual Mechanics @@ -333,8 +337,9 @@ fun validateSignature(...) { ... } // Duplicated! // ❌ BAD expect fun NavigationComponent(...) ``` -**Why:** Navigation paradigms too different (Activity vs Window) -**Fix:** Keep platform-specific, accept duplication +**Why:** It forks the whole navigation UI per platform. +**Fix:** Write the navigation once in `commonsUI`; put only the platform leaf +(an Activity result, a file picker) behind expect/actual or a slot ### 2. Under-Sharing **Problem:** Duplicating business logic across platforms @@ -384,8 +389,8 @@ import com.fasterxml.jackson.databind.ObjectMapper | **ViewModels** | **commons/commonMain/viewmodels/** | **StateFlow/SharedFlow + logic shareable, Compose MP lifecycle compatible** | | UI formatters (pure) | commons/commonMain | Reusable, no dependencies | | 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 | +| **Screen layouts** | **commonsUI** | **One UI; adapt to window size with `ScreenLayoutSpec`** | +| Navigation | commonsUI (entry point native) | Nav host + chrome shared; Activity / Window hosts it | | Permissions | Platform-specific only | APIs incompatible | | Platform UX (menus, etc.) | Platform-specific only | Native feel required | diff --git a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt index ac29d4281a..ddc2cd97a1 100644 --- a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt +++ b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt @@ -25,18 +25,19 @@ import android.graphics.Color import androidx.core.graphics.createBitmap import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.mediaServers.DEFAULT_MEDIA_SERVERS import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType +import com.vitorpamplona.amethyst.commons.model.nipB7Blossom.BlossomServerListState import com.vitorpamplona.amethyst.commons.service.http.DefaultContentTypeInterceptor -import com.vitorpamplona.amethyst.model.AccountSettings -import com.vitorpamplona.amethyst.model.nipB7Blossom.BlossomServerListState -import com.vitorpamplona.amethyst.service.uploads.FileHeader +import com.vitorpamplona.amethyst.commons.service.upload.FileHeader import com.vitorpamplona.amethyst.service.uploads.ImageDownloader import com.vitorpamplona.amethyst.service.uploads.blossom.BlossomUploader import com.vitorpamplona.amethyst.service.uploads.nip96.Nip96Uploader import com.vitorpamplona.amethyst.service.uploads.nip96.ServerInfoRetriever +import com.vitorpamplona.amethyst.service.uploads.prepare import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal diff --git a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/NotificationFeedFilterModeOverrideTest.kt b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/NotificationFeedFilterModeOverrideTest.kt index 8c8bf58097..65d9a131b9 100644 --- a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/NotificationFeedFilterModeOverrideTest.kt +++ b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/NotificationFeedFilterModeOverrideTest.kt @@ -21,19 +21,25 @@ package com.vitorpamplona.amethyst import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.model.AccountSettings +import com.vitorpamplona.amethyst.commons.model.InMemoryGeohashIdentityStore import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.location.LocationResult +import com.vitorpamplona.amethyst.commons.model.marmot.MarmotGroupNotifier +import com.vitorpamplona.amethyst.commons.model.nip46Signer.Nip46ConsentPrompter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter +import com.vitorpamplona.amethyst.commons.notifications.dal.NotificationFeedFilter import com.vitorpamplona.amethyst.commons.relayClient.assemblers.CashuMintDirectoryFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.nip47WalletConnect.NWCPaymentFilterAssembler +import com.vitorpamplona.amethyst.commons.service.http.EncryptionKeyCache import com.vitorpamplona.amethyst.commons.service.http.OkHttpWebSocket -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.AccountSettings -import com.vitorpamplona.amethyst.service.location.LocationState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.dal.NotificationFeedFilter +import com.vitorpamplona.amethyst.model.accountsCache.defaultMarmotStreamTransport import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.nip03Timestamp.EmptyOtsResolverBuilder +import com.vitorpamplona.quartz.nip60Cashu.mintApi.OkHttpMintTransport import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob @@ -83,14 +89,21 @@ class NotificationFeedFilterModeOverrideTest { Account( settings = AccountSettings(keyPair = keyPair), signer = NostrSignerInternal(keyPair), - geolocationFlow = { MutableStateFlow(LocationState.LocationResult.Loading) }, + geolocationFlow = { MutableStateFlow(LocationResult.Loading) }, nwcFilterAssembler = { NWCPaymentFilterAssembler(client) }, cashuMintDirectoryFilterAssembler = { CashuMintDirectoryFilterAssembler(client) }, - okHttpClientForMoney = { OkHttpClient() }, + cashuMintTransport = OkHttpMintTransport { OkHttpClient() }, otsResolverBuilder = { EmptyOtsResolverBuilder.build() }, cache = LocalCache, client = client, scope = scope, + appVersion = "test", + encryptionKeyCache = EncryptionKeyCache(), + saveSettings = {}, + marmotNotifier = { MarmotGroupNotifier.None }, + nip46Consent = Nip46ConsentPrompter.Unanswered, + geohashIdentityStore = InMemoryGeohashIdentityStore(), + marmotStreamTransportFactory = ::defaultMarmotStreamTransport, ) } diff --git a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ThreadDualAxisChartAssemblerTest.kt b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ThreadDualAxisChartAssemblerTest.kt index 06c0b9ba0c..ddf0bfda40 100644 --- a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ThreadDualAxisChartAssemblerTest.kt +++ b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ThreadDualAxisChartAssemblerTest.kt @@ -21,14 +21,19 @@ package com.vitorpamplona.amethyst import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.model.AccountSettings +import com.vitorpamplona.amethyst.commons.model.InMemoryGeohashIdentityStore import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.location.LocationResult +import com.vitorpamplona.amethyst.commons.model.marmot.MarmotGroupNotifier +import com.vitorpamplona.amethyst.commons.model.nip46Signer.Nip46ConsentPrompter import com.vitorpamplona.amethyst.commons.relayClient.assemblers.CashuMintDirectoryFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.nip47WalletConnect.NWCPaymentFilterAssembler +import com.vitorpamplona.amethyst.commons.service.http.EncryptionKeyCache import com.vitorpamplona.amethyst.commons.service.http.OkHttpWebSocket import com.vitorpamplona.amethyst.commons.viewmodels.thread.ThreadFeedFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.AccountSettings -import com.vitorpamplona.amethyst.service.location.LocationState +import com.vitorpamplona.amethyst.model.accountsCache.defaultMarmotStreamTransport import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair import com.vitorpamplona.quartz.nip01Core.crypto.verify @@ -37,6 +42,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip03Timestamp.EmptyOtsResolverBuilder +import com.vitorpamplona.quartz.nip60Cashu.mintApi.OkHttpMintTransport import junit.framework.TestCase import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -73,14 +79,21 @@ class ThreadDualAxisChartAssemblerTest { Account( settings = AccountSettings(keyPair = keyPair), signer = NostrSignerInternal(keyPair), - geolocationFlow = { MutableStateFlow(LocationState.LocationResult.Loading) }, + geolocationFlow = { MutableStateFlow(LocationResult.Loading) }, nwcFilterAssembler = { NWCPaymentFilterAssembler(client) }, cashuMintDirectoryFilterAssembler = { CashuMintDirectoryFilterAssembler(client) }, - okHttpClientForMoney = { OkHttpClient() }, + cashuMintTransport = OkHttpMintTransport { OkHttpClient() }, otsResolverBuilder = { EmptyOtsResolverBuilder.build() }, cache = LocalCache, client = client, scope = scope, + appVersion = "test", + encryptionKeyCache = EncryptionKeyCache(), + saveSettings = {}, + marmotNotifier = { MarmotGroupNotifier.None }, + nip46Consent = Nip46ConsentPrompter.Unanswered, + geohashIdentityStore = InMemoryGeohashIdentityStore(), + marmotStreamTransportFactory = ::defaultMarmotStreamTransport, ) val db = diff --git a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ui/components/AudioPlayerBoxOverflowTest.kt b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ui/components/AudioPlayerBoxOverflowTest.kt index c9f738a88b..e4b2a58ce9 100644 --- a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ui/components/AudioPlayerBoxOverflowTest.kt +++ b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ui/components/AudioPlayerBoxOverflowTest.kt @@ -30,6 +30,7 @@ import androidx.compose.ui.layout.positionInRoot import androidx.compose.ui.test.junit4.v2.createComposeRule import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.vitorpamplona.amethyst.commons.ui.components.mediaSizingModifier import com.vitorpamplona.amethyst.service.playback.composable.audioSquare import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue diff --git a/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/CachedTranslation.kt b/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/FlavorTranslationPlatform.kt similarity index 78% rename from amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/CachedTranslation.kt rename to amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/FlavorTranslationPlatform.kt index 1388e9a5bc..badf92628b 100644 --- a/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/CachedTranslation.kt +++ b/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/FlavorTranslationPlatform.kt @@ -20,13 +20,7 @@ */ package com.vitorpamplona.amethyst.ui.components -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.components.TranslationPlatform -/** - * No translation service in this flavor, so no note is ever translated and the copy-text - * menus never need to offer a "Copy Translated" option. - */ -fun cachedTranslation( - content: String, - accountViewModel: AccountViewModel, -): String? = null +/** No translation service in this flavor, so the content is always its own "translation". */ +val FlavorTranslationPlatform: TranslationPlatform = TranslationPlatform.None diff --git a/amethyst/src/main/generated/baselineProfiles/baseline-prof.txt b/amethyst/src/main/generated/baselineProfiles/baseline-prof.txt index 90f8c4c78e..c883f4bd5a 100644 --- a/amethyst/src/main/generated/baselineProfiles/baseline-prof.txt +++ b/amethyst/src/main/generated/baselineProfiles/baseline-prof.txt @@ -23113,8 +23113,8 @@ SPLcom/vitorpamplona/amethyst/commons/model/AccentColorType;->()V SPLcom/vitorpamplona/amethyst/commons/model/AccentColorType;->(Ljava/lang/String;III)V SPLcom/vitorpamplona/amethyst/commons/model/AccentColorType;->valueOf(Ljava/lang/String;)Lcom/vitorpamplona/amethyst/commons/model/AccentColorType; SPLcom/vitorpamplona/amethyst/commons/model/AccentColorType;->values()[Lcom/vitorpamplona/amethyst/commons/model/AccentColorType; -Lcom/vitorpamplona/amethyst/model/Account; -Lcom/vitorpamplona/amethyst/model/AccountSettings; +Lcom/vitorpamplona/amethyst/commons/model/Account; +Lcom/vitorpamplona/amethyst/commons/model/AccountSettings; Lcom/vitorpamplona/amethyst/model/AntiSpamFilter; SPLcom/vitorpamplona/amethyst/model/AntiSpamFilter;->()V SPLcom/vitorpamplona/amethyst/model/AntiSpamFilter;->()V @@ -23944,7 +23944,7 @@ SPLcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatche Lcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher$start$1; SPLcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher$start$1;->(Lcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher;Lkotlin/coroutines/Continuation;)V SPLcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher$start$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation; -SPLcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher$start$1;->invokeSuspend$lambda$0(Lcom/vitorpamplona/amethyst/model/Account;Lcom/vitorpamplona/amethyst/model/Account;)Z +SPLcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher$start$1;->invokeSuspend$lambda$0(Lcom/vitorpamplona/amethyst/commons/model/Account;Lcom/vitorpamplona/amethyst/commons/model/Account;)Z SPLcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher$start$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object; Lcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher$start$1$$ExternalSyntheticLambda0; SPLcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher$start$1$$ExternalSyntheticLambda0;->()V @@ -23952,7 +23952,7 @@ SPLcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatche Lcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher$start$1$2; SPLcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher$start$1$2;->(Lcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher;Lkotlin/coroutines/Continuation;)V SPLcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher$start$1$2;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation; -SPLcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher$start$1$2;->invoke(Lcom/vitorpamplona/amethyst/model/Account;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +SPLcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher$start$1$2;->invoke(Lcom/vitorpamplona/amethyst/commons/model/Account;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; SPLcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher$start$1$2;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; SPLcom/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher$start$1$2;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object; Lcom/vitorpamplona/amethyst/service/notifications/PokeyReceiver; @@ -24802,7 +24802,7 @@ Lcom/vitorpamplona/amethyst/ui/screen/AccountSessionManager; SPLcom/vitorpamplona/amethyst/ui/screen/AccountSessionManager;->()V SPLcom/vitorpamplona/amethyst/ui/screen/AccountSessionManager;->(Lcom/vitorpamplona/amethyst/model/accountsCache/AccountCacheState;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lcom/vitorpamplona/amethyst/LocalPreferences;Lkotlinx/coroutines/CoroutineScope;)V SPLcom/vitorpamplona/amethyst/ui/screen/AccountSessionManager;->getAccountContent()Lkotlinx/coroutines/flow/StateFlow; -SPLcom/vitorpamplona/amethyst/ui/screen/AccountSessionManager;->loggedInAccount()Lcom/vitorpamplona/amethyst/model/Account; +SPLcom/vitorpamplona/amethyst/ui/screen/AccountSessionManager;->loggedInAccount()Lcom/vitorpamplona/amethyst/commons/model/Account; SPLcom/vitorpamplona/amethyst/ui/screen/AccountSessionManager;->loginWithDefaultAccount$default(Lcom/vitorpamplona/amethyst/ui/screen/AccountSessionManager;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; SPLcom/vitorpamplona/amethyst/ui/screen/AccountSessionManager;->loginWithDefaultAccount(Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; SPLcom/vitorpamplona/amethyst/ui/screen/AccountSessionManager;->loginWithDefaultAccountIfLoggedOff()V diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt index 8332fb8ed8..67254b7b40 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt @@ -26,6 +26,7 @@ import android.os.Build import com.vitorpamplona.amethyst.commons.favorites.FavoriteApp import com.vitorpamplona.amethyst.commons.service.http.HttpClientEnvironment import com.vitorpamplona.amethyst.commons.service.http.MediaCallEventListener +import com.vitorpamplona.amethyst.commons.util.AndroidDebugFlag import com.vitorpamplona.amethyst.favorites.WebShortcuts import com.vitorpamplona.amethyst.napplet.WebAppNetworkRegistry import com.vitorpamplona.amethyst.napplet.WebSitePermissionRegistry @@ -114,6 +115,9 @@ class Amethyst : Application() { override fun onCreate() { super.onCreate() + // Before anything logs: shared code's debug-only logging (commons `logTime`) reads this + // instead of the app's BuildConfig, in both processes. + AndroidDebugFlag.enabled = isDebug Log.d("AmethystApp") { "onCreate $this" } // Application.onCreate runs in every process. The sandboxed napplet host diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/AmethystLocalCacheHost.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/AmethystLocalCacheHost.kt index 48b2b8e81c..a0c3ec1830 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/AmethystLocalCacheHost.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/AmethystLocalCacheHost.kt @@ -28,6 +28,7 @@ import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStats import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl +import com.vitorpamplona.quartz.nip11RelayInfo.Nip11RelayInformation import com.vitorpamplona.quartz.nip57Zaps.validate.LnurlEndpointCache import com.vitorpamplona.quartz.nip57Zaps.validate.LnurlEndpointInfo import kotlinx.coroutines.CoroutineScope @@ -56,8 +57,11 @@ class AmethystLocalCacheHost( override fun relaySelfPubKey(relay: NormalizedRelayUrl): HexKey? = modules.nip11Cache.getFromCache(relay).self - // The zap path's LNURL cache is a quartz-side singleton the outbound-zap resolver - // fills; it is jvmAndroid-only, which is why the cache reads it through here. + override fun relayInfo(relay: NormalizedRelayUrl): Nip11RelayInformation = modules.nip11Cache.getFromCache(relay) + + override val nip11Cache get() = modules.nip11Cache + + // The zap path's LNURL cache is a quartz-side singleton the outbound-zap resolver fills. override fun lnurlEndpoint(lnurlpUrl: String): LnurlEndpointInfo? = LnurlEndpointCache.get(lnurlpUrl) override fun assertNotMainThread() = checkNotInMainThread() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/AndroidGeohashIdentityStore.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/AndroidGeohashIdentityStore.kt new file mode 100644 index 0000000000..33316b2374 --- /dev/null +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/AndroidGeohashIdentityStore.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst + +import androidx.core.content.edit +import com.vitorpamplona.amethyst.commons.model.GeohashIdentityStore +import com.vitorpamplona.amethyst.commons.model.preferences.GeohashIdentitySecrets +import com.vitorpamplona.amethyst.commons.model.preferences.readLegacyGeohashIdentity +import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray +import com.vitorpamplona.quartz.nip19Bech32.toNpub + +/** + * The account's geohash identity in [accountSecretsStore], copied on first read out of the + * encrypted SharedPreferences file older versions wrote, and mirrored back there until + * [LocalPreferences.LEGACY_WRITES_RETIRED] (so a rollback keeps the seed and the nickname). + */ +class AndroidGeohashIdentityStore( + private val pubKeyHex: HexKey, +) : GeohashIdentityStore { + /** + * The npub the current store is keyed by. + * + * The legacy file is keyed by the pubkey *hex* — the old code passed + * `signer.pubKey` where every other caller passes an npub, so the identity + * lived in `secret_keeper_`, a different file from the account's own + * `secret_keeper_`. The copy below reads that file and writes the + * npub-keyed store, which is what folds this orphan back in with the rest. + */ + private val npub by lazy { pubKeyHex.hexToByteArray().toNpub() } + + /** + * What `secret_keeper_` holds. + * + * Only called when the store has nothing yet: opening this file creates it, + * so reading it unconditionally would resurrect it after the cleanup has + * deleted it. Touches disk; callers are off the main thread. + */ + private fun legacy(): GeohashIdentitySecrets = readLegacyGeohashIdentity(LegacySharedPreferences(Amethyst.instance.encryptedStorage(pubKeyHex))) + + override suspend fun read(): GeohashIdentitySecrets = accountSecretsStore.readGeohashIdentity(npub) { legacy() } + + override suspend fun write(value: GeohashIdentitySecrets) = accountSecretsStore.mirrorGeohashIdentity(npub, value) + + // Mirrored, not moved: the legacy file stays readable until the legacy writes are retired + // app-wide. Gated on the same switch as every other mirror. + override fun mirrorLegacyNickname(nickname: String) { + if (!LocalPreferences.LEGACY_WRITES_RETIRED) { + Amethyst.instance.encryptedStorage(pubKeyHex).edit { putString(PREF_NICKNAME, nickname) } + } + } + + override fun mirrorLegacyDeviceSeed(seedHex: String) { + if (!LocalPreferences.LEGACY_WRITES_RETIRED) { + Amethyst.instance.encryptedStorage(pubKeyHex).edit { putString(PREF_KEY, seedHex) } + } + } + + companion object { + private const val PREF_KEY = "geohash_chat_device_seed" + private const val PREF_NICKNAME = "geohash_chat_nickname" + } +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt index d601bce11d..0e857e8564 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt @@ -32,6 +32,7 @@ import com.vitorpamplona.amethyst.commons.browser.BrowserIconRegistry import com.vitorpamplona.amethyst.commons.connectedApps.DataStoreNostrSignerPermissionStore import com.vitorpamplona.amethyst.commons.connectedApps.nip46.DataStoreNip46ClientStore import com.vitorpamplona.amethyst.commons.favorites.FavoriteAppsRegistry +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.UiSettings import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -53,6 +54,7 @@ import com.vitorpamplona.amethyst.commons.napplet.permissions.NappletPermissionL import com.vitorpamplona.amethyst.commons.relayClient.BlockedRelayFilteringClient import com.vitorpamplona.amethyst.commons.relayClient.diagnostics.BootRelayDiagnostics import com.vitorpamplona.amethyst.commons.relayClient.event.EventFinderQueryState +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.RelaySubscriptionsCoordinator import com.vitorpamplona.amethyst.commons.relayClient.speedLogger.RelaySpeedLogger import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderQueryState import com.vitorpamplona.amethyst.commons.relays.health.TorCircuitHealthTracker @@ -63,6 +65,8 @@ import com.vitorpamplona.amethyst.commons.robohash.CachedRobohash import com.vitorpamplona.amethyst.commons.scheduledposts.ScheduledPostStore import com.vitorpamplona.amethyst.commons.scheduledposts.ScheduledPostWorkGate import com.vitorpamplona.amethyst.commons.service.connectivity.ConnectivityStatus +import com.vitorpamplona.amethyst.commons.service.georelay.GeoRelayCsvLoader +import com.vitorpamplona.amethyst.commons.service.georelay.GeohashRelays import com.vitorpamplona.amethyst.commons.service.http.BlossomReadAuthInterceptor import com.vitorpamplona.amethyst.commons.service.http.BlossomReadAuthTokenProvider import com.vitorpamplona.amethyst.commons.service.http.DualHttpClientManager @@ -78,7 +82,7 @@ import com.vitorpamplona.amethyst.commons.service.pow.PoWPublishQueue import com.vitorpamplona.amethyst.commons.state.UiSettingsState import com.vitorpamplona.amethyst.commons.tor.TorRelayState import com.vitorpamplona.amethyst.commons.tor.TorSettings -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.connectedApps.consent.Nip46ConsentBridge import com.vitorpamplona.amethyst.model.accountsCache.AccountCacheState import com.vitorpamplona.amethyst.model.nip60Cashu.CashuPreferences import com.vitorpamplona.amethyst.model.preferences.UiSharedPreferences @@ -115,7 +119,6 @@ import com.vitorpamplona.amethyst.service.relayClient.CacheClientConnector import com.vitorpamplona.amethyst.service.relayClient.RelayProxyClientConnector import com.vitorpamplona.amethyst.service.relayClient.authCommand.model.AuthCoordinator import com.vitorpamplona.amethyst.service.relayClient.notifyCommand.model.NotifyCoordinator -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.RelaySubscriptionsCoordinator import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountSubscriptionRegistry import com.vitorpamplona.amethyst.service.resourceusage.BatteryDrainSampler import com.vitorpamplona.amethyst.service.resourceusage.ForegroundTimeIntegrator @@ -199,6 +202,7 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.drop +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge @@ -240,6 +244,13 @@ class AppModules( private val _trimLevelEvents = MutableSharedFlow(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) val trimLevelEvents = _trimLevelEvents.asSharedFlow() + /** + * Fires when memory is tight enough that feeds should drop the strong Note references they + * hold: the process is on the system LRU list, the strongest level the OS still delivers + * since API 34, or the heap watchdog raised the same level itself. + */ + val memoryPressureEvents: Flow = trimLevelEvents.filter { it >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND }.map { } + /** * The app-wide DataStore files — the ones that belong to the install rather * than to an account. [AccountPreferenceStores] is the same idea keyed by @@ -769,6 +780,8 @@ class AppModules( // event, which is why this sits next to the cache rather than in a later init block. init { cache.appHost = AmethystLocalCacheHost(this, isDebug) + // Geohash chats route through the live georelays directory, fetched over this app's clients. + GeohashRelays.liveRelayLoader = { GeoRelayCsvLoader { okHttpClients.getHttpClient(false) }.fetch() } } // NIP-BC onchain zap verification backend. Wired up once at app init so @@ -1035,6 +1048,13 @@ class AppModules( otsResolverBuilder = { otsResolverBuilder.build() }, cache = cache, client = client, + appVersion = BuildConfig.VERSION_NAME, + encryptionKeyCache = keyCache, + saveSettings = { LocalPreferences.saveToEncryptedStorage(it) }, + // A provider: notificationDispatcher is declared further down this class. + marmotNotifier = { notificationDispatcher }, + nip46Consent = Nip46ConsentBridge, + geohashIdentityStore = { AndroidGeohashIdentityStore(it) }, rootFilesDir = { appContext.filesDir }, powQueue = { powPublishQueue }, meterSigner = { MeteringNostrSigner(it, resourceUsage) }, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/DebugUtils.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/DebugUtils.kt index 0a1b68b98f..ac9ca338d1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/DebugUtils.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/DebugUtils.kt @@ -32,8 +32,6 @@ import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.LogLevel import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.pointerSizeInBytes -import kotlin.time.DurationUnit -import kotlin.time.measureTimedValue @Suppress("SENSELESS_COMPARISON") val isDebug = BuildConfig.DEBUG || BuildConfig.BUILD_TYPE == "benchmark" @@ -236,36 +234,6 @@ fun debugState(context: Context) { } } -inline fun logTime( - debugMessage: String, - minToReportMs: Int = 1, - block: () -> T, -): T = - if (isDebug) { - val (result, elapsed) = measureTimedValue(block) - if (elapsed.inWholeMilliseconds > minToReportMs) { - Log.d("DEBUG-TIME") { "${elapsed.toString(DurationUnit.MILLISECONDS, 3).padStart(12)}: $debugMessage" } - } - result - } else { - block() - } - -inline fun logTime( - debugMessage: (T) -> String, - minToReportMs: Int = 1, - block: () -> T, -): T = - if (isDebug) { - val (result, elapsed) = measureTimedValue(block) - if (elapsed.inWholeMilliseconds > minToReportMs) { - Log.d("DEBUG-TIME") { "${elapsed.toString(DurationUnit.MILLISECONDS, 3).padStart(12)}: ${debugMessage(result)}" } - } - result - } else { - block() - } - fun debug( tag: String, debugMessage: String, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 707167a37c..aa9a38f897 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -25,6 +25,7 @@ import android.content.Context import android.content.SharedPreferences import androidx.compose.runtime.Immutable import androidx.core.content.edit +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.HomeFeedType import com.vitorpamplona.amethyst.commons.model.UiSettings import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType @@ -60,7 +61,6 @@ import com.vitorpamplona.amethyst.commons.model.preferences.readLegacyAccountSec import com.vitorpamplona.amethyst.commons.model.preferences.readLegacyGeohashIdentity import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthPolicy -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.backups.BackupConflictStorage import com.vitorpamplona.amethyst.model.nip60Cashu.CashuPreferences import com.vitorpamplona.amethyst.model.preferences.UiSharedPreferences @@ -329,7 +329,7 @@ object LocalPreferences { * `amethyst/plans/2026-09-23-encrypted-storage-retirement.md`. * * `internal` rather than private because the mirror is not all in this - * file: [com.vitorpamplona.amethyst.model.GeohashChatIdentityState] writes + * file: [com.vitorpamplona.amethyst.commons.model.GeohashChatIdentityState] writes * the location-chat identity into its own legacy file and reads this to * know when to stop. Private, it would have kept writing after the flip * and the switch would only half work. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip46Signer/Nip46ConsentBridge.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/connectedApps/consent/Nip46ConsentBridge.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip46Signer/Nip46ConsentBridge.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/connectedApps/consent/Nip46ConsentBridge.kt index 53cb197ab9..cb6f90f81a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip46Signer/Nip46ConsentBridge.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/connectedApps/consent/Nip46ConsentBridge.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip46Signer +package com.vitorpamplona.amethyst.connectedApps.consent import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.connectedApps.nip46.Nip46PermissionAuthorizer @@ -26,14 +26,12 @@ import com.vitorpamplona.amethyst.commons.connectedApps.signers.AppConnectResult import com.vitorpamplona.amethyst.commons.connectedApps.signers.NostrSignerOp import com.vitorpamplona.amethyst.commons.connectedApps.signers.SignerOpGrant import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.nip46Signer.Nip46ConsentPrompter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.nip46_signer_allow_always_for import com.vitorpamplona.amethyst.commons.resources.nip46_signer_decrypt_failed import com.vitorpamplona.amethyst.commons.resources.nip46_signer_remote_app import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.connectedApps.consent.SignerConnectCoordinator -import com.vitorpamplona.amethyst.connectedApps.consent.SignerConnectInfo -import com.vitorpamplona.amethyst.connectedApps.consent.SignerConsentCoordinator import com.vitorpamplona.amethyst.napplet.label import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner @@ -53,7 +51,7 @@ import kotlinx.coroutines.withTimeoutOrNull * Runs only in the main process (the signer never runs in `:napplet`), so [Amethyst.instance] is set; * the coordinators launch their Activity from the application context. */ -object Nip46ConsentBridge { +object Nip46ConsentBridge : Nip46ConsentPrompter { /** * Upper bound on how long a consent prompt may block the signer's single-consumer loop. A user who * ignores the dialog eventually fails the request closed (deny / declined) instead of wedging the @@ -62,7 +60,7 @@ object Nip46ConsentBridge { private const val CONSENT_TIMEOUT_MS = 120_000L /** First-connect consent: show the app's self-declared identity and let the user pick a trust level. */ - suspend fun requestConnect( + override suspend fun requestConnect( coordinate: String, clientPubKey: HexKey, request: BunkerRequestConnect, @@ -96,7 +94,7 @@ object Nip46ConsentBridge { * [requestedOps] so the user gives informed consent before those ops are pre-granted. Returns the * user's [AppConnectResult] (or [AppConnectResult.Cancelled] if the prompt is never answered). */ - suspend fun requestNostrConnectConsent( + override suspend fun requestNostrConnectConsent( coordinate: String, name: String?, url: String?, @@ -133,7 +131,7 @@ object Nip46ConsentBridge { * user approves — and it is bounded by [Nip46ConsentInfoBuilder.DECRYPT_PREVIEW_TIMEOUT_MS] so a slow or failing signer * degrades to an explanatory message instead of hanging or blanking the prompt. */ - suspend fun requestOp( + override suspend fun requestOp( coordinate: String, clientPubKey: HexKey, op: NostrSignerOp, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip46Signer/Nip46ConsentInfoBuilder.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/connectedApps/consent/Nip46ConsentInfoBuilder.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip46Signer/Nip46ConsentInfoBuilder.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/connectedApps/consent/Nip46ConsentInfoBuilder.kt index 9841b7f48f..c8eebe886a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip46Signer/Nip46ConsentInfoBuilder.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/connectedApps/consent/Nip46ConsentInfoBuilder.kt @@ -18,12 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip46Signer +package com.vitorpamplona.amethyst.connectedApps.consent import com.vitorpamplona.amethyst.commons.connectedApps.nip46.Nip46PermissionAuthorizer.Companion.decryptCounterparty import com.vitorpamplona.amethyst.commons.connectedApps.nip46.Nip46PermissionAuthorizer.Companion.toNarrowSignerOp import com.vitorpamplona.amethyst.commons.connectedApps.signers.NostrSignerOp -import com.vitorpamplona.amethyst.connectedApps.consent.SignerConsentInfo import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper import com.vitorpamplona.quartz.nip19Bech32.entities.NPub diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/connectedApps/consent/SignerConsentActivity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/connectedApps/consent/SignerConsentActivity.kt index 7d610c2ffd..e5dfa30710 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/connectedApps/consent/SignerConsentActivity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/connectedApps/consent/SignerConsentActivity.kt @@ -95,12 +95,12 @@ import com.vitorpamplona.amethyst.commons.resources.nip46_signer_batch_select_no import com.vitorpamplona.amethyst.commons.resources.nip46_signer_batch_signing_as import com.vitorpamplona.amethyst.commons.resources.nip46_signer_batch_title import com.vitorpamplona.amethyst.commons.resources.nip46_signer_messages_with +import com.vitorpamplona.amethyst.commons.service.call.CallSessionBridge import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.call.CallSessionBridge -import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.theme.AmethystTheme import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip59Giftwrap.rumors.RumorAssembler diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/favorites/FavoriteNostrAppPreloader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/favorites/FavoriteNostrAppPreloader.kt index 8d240b33b1..ded8b58a2f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/favorites/FavoriteNostrAppPreloader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/favorites/FavoriteNostrAppPreloader.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.amethyst.commons.favorites.FavoriteApp import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relayClient.event.EventFinderQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Pre-fetches the addressable events behind the user's favorited [FavoriteApp.NostrApp]s (nSites / @@ -41,7 +41,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel * * This subscribes each favorited coordinate to the shared * [EventFinder][com.vitorpamplona.amethyst.commons.relayClient.event.EventFinderFilterAssembler] - * — the same lifecycle-aware loader [observeNote][com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote] + * — the same lifecycle-aware loader [observeNote][com.vitorpamplona.amethyst.commons.relayClient.event.observeNote] * uses — so the manifests fetch (via the author's outbox relays) as soon as the launcher opens and are * already in [LocalCache] by the time the user taps. The loader drops each coordinate from its filter * once the event arrives, so this is a one-shot fetch, not a standing feed. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/accountsCache/AccountCacheState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/accountsCache/AccountCacheState.kt index 0a711f801f..4157379fb2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/accountsCache/AccountCacheState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/accountsCache/AccountCacheState.kt @@ -26,21 +26,28 @@ import com.vitorpamplona.amethyst.commons.connectedApps.nip46.InMemoryNip46Clien import com.vitorpamplona.amethyst.commons.connectedApps.nip46.Nip46ClientStore import com.vitorpamplona.amethyst.commons.connectedApps.signers.InMemoryNostrSignerPermissionStore import com.vitorpamplona.amethyst.commons.connectedApps.signers.NostrSignerPermissionStore +import com.vitorpamplona.amethyst.commons.cordn.KeyStoreCordnBlobCipher import com.vitorpamplona.amethyst.commons.marmot.EncryptedKeyPackageBundleStore import com.vitorpamplona.amethyst.commons.marmot.EncryptedMarmotMessageStore import com.vitorpamplona.amethyst.commons.marmot.EncryptedMlsGroupStateStore import com.vitorpamplona.amethyst.commons.marmot.EncryptedPublishObligationStore import com.vitorpamplona.amethyst.commons.marmot.InMemoryMlsGroupStateStore +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.model.AccountSettings +import com.vitorpamplona.amethyst.commons.model.GeohashIdentityStore import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import com.vitorpamplona.amethyst.commons.model.marmot.AndroidIngestDedupStore import com.vitorpamplona.amethyst.commons.model.marmot.AndroidPushStateStore +import com.vitorpamplona.amethyst.commons.model.marmot.MarmotGroupNotifier +import com.vitorpamplona.amethyst.commons.model.nip46Signer.Nip46ConsentPrompter import com.vitorpamplona.amethyst.commons.model.preferences.AppPreferenceStores import com.vitorpamplona.amethyst.commons.relayClient.nip47WalletConnect.NWCPaymentFilterAssembler import com.vitorpamplona.amethyst.commons.relayauth.DataStoreRelayAuthPermissionStore +import com.vitorpamplona.amethyst.commons.service.http.EncryptionKeyCache import com.vitorpamplona.amethyst.commons.service.pow.PoWPublishQueue -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.AccountSettings -import com.vitorpamplona.amethyst.service.location.LocationState +import com.vitorpamplona.marmotquic.QuicAgentTextStreamTransport +import com.vitorpamplona.quartz.marmot.appComponents.agentTextStream.transport.MarmotQuicTransport import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient @@ -48,9 +55,11 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.nip03Timestamp.OtsResolver import com.vitorpamplona.quartz.nip55AndroidSigner.client.NostrSignerExternal +import com.vitorpamplona.quartz.nip60Cashu.mintApi.OkHttpMintTransport import com.vitorpamplona.quartz.nip89AppHandlers.clientTag.NostrSignerWithClientTag import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.cache.LargeCache +import com.vitorpamplona.quic.tls.JdkCertificateValidator import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -59,18 +68,31 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.update +import okhttp3.OkHttpClient import okio.Path.Companion.toOkioPath import java.io.File class AccountCacheState( - val geolocationFlow: () -> StateFlow, + val geolocationFlow: () -> StateFlow, val nwcFilterAssembler: () -> NWCPaymentFilterAssembler, val cashuMintDirectoryFilterAssembler: () -> com.vitorpamplona.amethyst.commons.relayClient.assemblers.CashuMintDirectoryFilterAssembler, - val okHttpClientForMoney: (String) -> okhttp3.OkHttpClient, + val okHttpClientForMoney: (String) -> OkHttpClient, val contentResolverFn: () -> ContentResolver, val otsResolverBuilder: () -> OtsResolver, val cache: LocalCache, val client: INostrClient, + /** The running app's version name, handed to every [Account] it builds. */ + val appVersion: String, + /** App-wide media decryption keys, shared by every [Account]. */ + val encryptionKeyCache: EncryptionKeyCache, + /** Persists an account's settings (the app's encrypted storage). */ + val saveSettings: suspend (AccountSettings) -> Unit, + /** Announces Marmot Welcomes and group messages; shared by every [Account]. */ + val marmotNotifier: () -> MarmotGroupNotifier, + /** The NIP-46 consent dialogs, shared by every [Account]. */ + val nip46Consent: Nip46ConsentPrompter, + /** Builds the store for one account's geohash-chat identity, keyed by its pubkey. */ + val geohashIdentityStore: (HexKey) -> GeohashIdentityStore, val rootFilesDir: () -> File = { File("") }, val powQueue: () -> PoWPublishQueue? = { null }, /** Optional resource-ledger wrapper applied to every account signer (see MeteringNostrSigner). */ @@ -341,10 +363,18 @@ class AccountCacheState( geolocationFlow = geolocationFlow, nwcFilterAssembler = nwcFilterAssembler, cashuMintDirectoryFilterAssembler = cashuMintDirectoryFilterAssembler, - okHttpClientForMoney = okHttpClientForMoney, + cashuMintTransport = OkHttpMintTransport(okHttpClientForMoney), otsResolverBuilder = otsResolverBuilder, cache = cache, client = client, + appVersion = appVersion, + encryptionKeyCache = encryptionKeyCache, + saveSettings = saveSettings, + marmotNotifier = marmotNotifier, + nip46Consent = nip46Consent, + geohashIdentityStore = geohashIdentityStore(signer.pubKey), + marmotStreamTransportFactory = ::defaultMarmotStreamTransport, + cordnBlobCipher = { KeyStoreCordnBlobCipher() }, scope = CoroutineScope( Dispatchers.IO + @@ -356,7 +386,7 @@ class AccountCacheState( // The same per-account directory the Marmot stores use. cordn // scopes itself further by coordinator underneath it, because a // gid is unique only within one (spec/00.md §4). - cordnFilesDir = accountDir, + cordnFilesDir = accountDir.toOkioPath(), mlsGroupStateStore = mlsStore, marmotMessageStore = marmotMessageStore, marmotKeyPackageStore = marmotKeyPackageStore, @@ -392,3 +422,14 @@ class AccountCacheState( const val CLIENT_TAG_NAME = "Amethyst" } } + +/** + * The app's raw-QUIC transport for Marmot agent text stream previews (`transports/quic.md`). + * Preview brokers are commonly self-signed and the binding expects that; the platform trust + * store is still the default answer, and a deployment that pins does it here. + */ +fun defaultMarmotStreamTransport(scope: CoroutineScope): MarmotQuicTransport = + QuicAgentTextStreamTransport( + parentScope = scope, + certificateValidator = JdkCertificateValidator(), + ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/cordn/CordnMediaService.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/cordn/CordnMediaService.kt index 678f62e288..bf83ec3197 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/cordn/CordnMediaService.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/cordn/CordnMediaService.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.model.cordn import android.content.Context import com.vitorpamplona.amethyst.Amethyst -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.service.uploads.blossom.BlossomUploader import com.vitorpamplona.quartz.cordn.appEncryptedMedia.CordnBlobUpload import com.vitorpamplona.quartz.cordn.appEncryptedMedia.CordnEncryptedMedia diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip11RelayInfo/RelaySupportsNip.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip11RelayInfo/RelaySupportsNip.kt deleted file mode 100644 index 6cf7b588c7..0000000000 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip11RelayInfo/RelaySupportsNip.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.amethyst.model.nip11RelayInfo - -import com.vitorpamplona.amethyst.Amethyst -import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel -import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.isRelaySignedRelayGroup -import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl - -/** - * Whether [relay]'s cached NIP-11 document advertises support for [nip] (as a decimal string, e.g. - * "29"). Reads only the in-memory cache — it never blocks on a network fetch — so it returns false - * for a relay whose NIP-11 hasn't been loaded yet. Callers that need the answer to become true must - * warm the document first (e.g. `loadRelayInfo`), then re-evaluate once it resolves. - */ -fun relayAdvertisesNip( - relay: NormalizedRelayUrl, - nip: String, -): Boolean = - Amethyst.instance.nip11Cache - .getFromCache(relay) - .supported_nips - ?.any { it == nip } == true - -/** NIP-29 (relay-based groups): the relay must run it for its groups to be real. */ -fun relayAdvertisesNip29(relay: NormalizedRelayUrl): Boolean = relayAdvertisesNip(relay, "29") - -/** [isRelaySignedRelayGroup] reading the host relay's cached NIP-11 doc (for non-Compose callers). */ -fun isRelaySignedRelayGroup(channel: RelayGroupChannel): Boolean = isRelaySignedRelayGroup(channel, Amethyst.instance.nip11Cache.getFromCache(channel.groupId.relayUrl)) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nipB7Blossom/BlossomServerListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nipB7Blossom/BlossomServerListState.kt deleted file mode 100644 index 3a3f92bb11..0000000000 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nipB7Blossom/BlossomServerListState.kt +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.amethyst.model.nipB7Blossom - -import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.commons.model.NoteState -import com.vitorpamplona.amethyst.commons.model.cache.ICacheProvider -import com.vitorpamplona.amethyst.commons.model.mediaServers.DEFAULT_MEDIA_SERVERS -import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName -import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType -import com.vitorpamplona.amethyst.model.AccountSettings -import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner -import com.vitorpamplona.quartz.nipB7Blossom.BlossomAuthorizationEvent -import com.vitorpamplona.quartz.nipB7Blossom.BlossomServersEvent -import com.vitorpamplona.quartz.utils.Rfc3986 -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.onStart -import kotlinx.coroutines.flow.stateIn - -class BlossomServerListState( - val signer: NostrSigner, - val cache: ICacheProvider, - val scope: CoroutineScope, - val settings: AccountSettings, -) { - // Creates a long-term reference for this note so that the GC doesn't collect the note it self - val blossomListNote = cache.getOrCreateAddressableNote(getBlossomServersAddress()) - - fun getBlossomServersAddress() = BlossomServersEvent.createAddress(signer.pubKey) - - fun getBlossomServersListFlow(): StateFlow = blossomListNote.flow().metadata.stateFlow - - fun getBlossomServersList(): BlossomServersEvent? = blossomListNote.event as? BlossomServersEvent - - fun normalizeServers(note: Note): List { - val event = note.event as? BlossomServersEvent - return event?.servers() ?: emptyList() - } - - fun host(url: String): String = - try { - Rfc3986.host(url).removePrefix("cdn.").removePrefix("blossom.") - } catch (e: Exception) { - url.removePrefix("cdn.").removePrefix("blossom.") - } - - val flow = - getBlossomServersListFlow() - .map { - normalizeServers(it.note) - }.flowOn(Dispatchers.IO) - .stateIn( - scope, - SharingStarted.Eagerly, - emptyList(), - ) - - fun mergeServerList(blossom: List?): List = blossom?.map { ServerName(host(it), it, ServerType.Blossom) }?.ifEmpty { DEFAULT_MEDIA_SERVERS } ?: DEFAULT_MEDIA_SERVERS - - val hostNameFlow: StateFlow> = - flow - .map { blossoms -> - mergeServerList(blossoms) - }.onStart { - emit(mergeServerList(flow.value)) - }.onEach { servers -> - resetTargetOrNull(flow.value, servers, settings.defaultFileServer)?.let { - settings.changeDefaultFileServer(it) - } - }.flowOn(Dispatchers.IO) - .stateIn( - scope, - SharingStarted.Eagerly, - DEFAULT_MEDIA_SERVERS, - ) - - suspend fun saveBlossomServersList(servers: List): BlossomServersEvent { - val serverList = getBlossomServersList() - - return if (serverList != null && serverList.tags.isNotEmpty()) { - BlossomServersEvent.updateRelayList( - earlierVersion = serverList, - servers = servers, - signer = signer, - ) - } else { - BlossomServersEvent.createFromScratch( - relays = servers, - signer = signer, - ) - } - } - - suspend fun createBlossomUploadAuth( - hash: HexKey, - size: Long, - alt: String, - servers: List = emptyList(), - ): BlossomAuthorizationEvent = BlossomAuthorizationEvent.createUploadAuth(hash, size, alt, signer, servers) - - suspend fun createBlossomMediaAuth( - hash: HexKey, - size: Long, - alt: String, - servers: List = emptyList(), - ): BlossomAuthorizationEvent = BlossomAuthorizationEvent.createMediaAuth(hash, size, alt, signer, servers) - - suspend fun createBlossomDeleteAuth( - hash: HexKey, - alt: String, - servers: List = emptyList(), - ): BlossomAuthorizationEvent = BlossomAuthorizationEvent.createDeleteAuth(hash, alt, signer, servers) - - suspend fun createBlossomListAuth( - alt: String, - servers: List = emptyList(), - ): BlossomAuthorizationEvent = BlossomAuthorizationEvent.createListAuth(signer, alt, servers) -} - -/** - * Decides whether the persisted default file server must be reset, and to what. - * - * Returns the new default server, or `null` when no change should happen. - * - * The guard on [rawList] being non-empty is what prevents the startup race: before the user's - * [BlossomServersEvent] (kind 10063) loads from cache/relay, [rawList] is empty and [merged] is the - * transient [DEFAULT_MEDIA_SERVERS] fallback. Resetting against that fallback would clobber the - * locally-saved pick on every launch. Only reset once a real, loaded list is in hand and it no - * longer contains the current pick (e.g. the user removed it from their list). - */ -fun resetTargetOrNull( - rawList: List, - merged: List, - current: ServerName, -): ServerName? = - if (rawList.isNotEmpty() && merged.none { it == current }) { - merged.firstOrNull() ?: DEFAULT_MEDIA_SERVERS[0] - } else { - null - } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/torState/AccountsTorStateConnector.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/torState/AccountsTorStateConnector.kt index 8476c746b8..cdeddf9c21 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/torState/AccountsTorStateConnector.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/torState/AccountsTorStateConnector.kt @@ -20,8 +20,8 @@ */ package com.vitorpamplona.amethyst.model.torState +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.tor.TorRelayState -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.accountsCache.AccountCacheState import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.utils.Log diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/zap/RailCapability.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/zap/RailCapability.kt index 993c9e1355..e4d7fd1897 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/zap/RailCapability.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/zap/RailCapability.kt @@ -21,12 +21,12 @@ package com.vitorpamplona.amethyst.model.zap import androidx.compose.runtime.Immutable +import com.vitorpamplona.amethyst.commons.model.MIN_ONCHAIN_ZAP_SATS import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.nip60Cashu.CashuWalletState import com.vitorpamplona.amethyst.commons.model.payments.PayToRailMatcher import com.vitorpamplona.amethyst.commons.model.payments.PaymentTargetTypes -import com.vitorpamplona.amethyst.model.MIN_ONCHAIN_ZAP_SATS -import com.vitorpamplona.amethyst.model.nip60Cashu.CashuWalletState import com.vitorpamplona.amethyst.service.payments.PayToAppAvailability import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip57Zaps.splits.BaseZapSplitSetup diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletBrokerService.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletBrokerService.kt index 30007d4ec8..d5b822e42c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletBrokerService.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletBrokerService.kt @@ -36,6 +36,7 @@ import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.browser.BrowserSitePermission import com.vitorpamplona.amethyst.commons.connectedApps.signers.NostrSignerPermissionLedger import com.vitorpamplona.amethyst.commons.favorites.FavoriteApp +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.napplet.NappletBroker import com.vitorpamplona.amethyst.commons.napplet.NappletCapability import com.vitorpamplona.amethyst.commons.napplet.NappletIdentity @@ -44,7 +45,6 @@ import com.vitorpamplona.amethyst.commons.napplet.NappletRequestRouter import com.vitorpamplona.amethyst.commons.napplet.protocol.NappletProtocolJson import com.vitorpamplona.amethyst.commons.napplet.protocol.NappletResponse import com.vitorpamplona.amethyst.favorites.WebShortcuts -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.napplet.gateways.AccountNappletGateways import com.vitorpamplona.amethyst.napplethost.NappletIpc import com.vitorpamplona.amethyst.ui.MainActivity diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletConsentSummary.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletConsentSummary.kt index 8b0065aea7..6c2326efbd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletConsentSummary.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletConsentSummary.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.napplet import android.content.Context import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.browser.OmniboxInput +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.napplet.NappletCapability import com.vitorpamplona.amethyst.commons.napplet.NappletIdentity import com.vitorpamplona.amethyst.commons.napplet.protocol.NappletRequest @@ -63,7 +64,6 @@ import com.vitorpamplona.amethyst.commons.resources.napplet_consent_upload import com.vitorpamplona.amethyst.commons.resources.napplet_fallback_title import com.vitorpamplona.amethyst.commons.ui.loadPluralStringRes import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.lightning.LnInvoiceUtil import com.vitorpamplona.quartz.nip01Core.core.fastForEach import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletLiveSubscriptions.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletLiveSubscriptions.kt index 51e81fd117..089e83d431 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletLiveSubscriptions.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletLiveSubscriptions.kt @@ -20,9 +20,9 @@ */ package com.vitorpamplona.amethyst.napplet +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.napplet.NappletRelayCleartext import com.vitorpamplona.amethyst.commons.napplet.protocol.NappletProtocolJson -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.SubscriptionListener diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NostrSignerOpLabels.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NostrSignerOpLabels.kt index 9ff3361771..1d46b6ece6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NostrSignerOpLabels.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NostrSignerOpLabels.kt @@ -38,9 +38,9 @@ import com.vitorpamplona.amethyst.commons.resources.napplet_op_encrypt import com.vitorpamplona.amethyst.commons.resources.napplet_op_sign_kind_named import com.vitorpamplona.amethyst.commons.resources.nip46_signer_allow_always_for import com.vitorpamplona.amethyst.commons.ui.loadStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.kindNameFor import com.vitorpamplona.amethyst.connectedApps.consent.SignerConnectInfo import com.vitorpamplona.amethyst.connectedApps.consent.SignerConsentInfo -import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.kindNameFor import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/gateways/AccountIdentityReader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/gateways/AccountIdentityReader.kt index 8bc8f18df3..7d58479296 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/gateways/AccountIdentityReader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/gateways/AccountIdentityReader.kt @@ -20,7 +20,7 @@ */ package com.vitorpamplona.amethyst.napplet.gateways -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip51Lists.muteList.tags.UserTag import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/gateways/AccountNappletGateways.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/gateways/AccountNappletGateways.kt index 5ef586ecff..2b5f2e7af8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/gateways/AccountNappletGateways.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/gateways/AccountNappletGateways.kt @@ -30,6 +30,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.connectedApps.signers.NostrConnectPrompt import com.vitorpamplona.amethyst.commons.connectedApps.signers.NostrSignerConsentPrompt import com.vitorpamplona.amethyst.commons.connectedApps.signers.NostrSignerPermissionLedger +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.napplet.NappletBroker import com.vitorpamplona.amethyst.commons.napplet.NappletConsentPrompt import com.vitorpamplona.amethyst.commons.napplet.NappletIdentityGateway @@ -51,7 +52,6 @@ import com.vitorpamplona.amethyst.commons.resources.napplet_cap_notify import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.connectedApps.consent.SignerConnectCoordinator import com.vitorpamplona.amethyst.connectedApps.consent.SignerConsentCoordinator -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.napplet.NappletConsentCoordinator import com.vitorpamplona.amethyst.napplet.NappletConsentSummary import com.vitorpamplona.amethyst.napplet.buildConnectInfo diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/gateways/NappletResourceFetcher.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/gateways/NappletResourceFetcher.kt index 32ca910f6f..827a125659 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/gateways/NappletResourceFetcher.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/gateways/NappletResourceFetcher.kt @@ -21,9 +21,9 @@ package com.vitorpamplona.amethyst.napplet.gateways import android.util.Base64 +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.napplet.NappletResource import com.vitorpamplona.amethyst.commons.napplet.NappletResourceResult -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.napplet.NappletNetworkRegistry import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.Event diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/ClinkOfferPayer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/ClinkOfferPayer.kt index a5911dc6c7..711c20d74e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/ClinkOfferPayer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/ClinkOfferPayer.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.Amethyst -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.quartz.experimental.clink.client.OfferClient import com.vitorpamplona.quartz.experimental.clink.offers.OfferEvent import com.vitorpamplona.quartz.experimental.clink.offers.OfferResponse diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallForegroundService.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallForegroundService.kt index 4997abf8b9..9ab26c62e8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallForegroundService.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallForegroundService.kt @@ -37,6 +37,7 @@ import androidx.core.content.ContextCompat import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.nipACWebRtcCalls.CallState +import com.vitorpamplona.amethyst.commons.service.call.CallSessionBridge import com.vitorpamplona.amethyst.ui.call.CallActivity import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.runBlocking diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallNotificationReceiver.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallNotificationReceiver.kt index 449840f3b0..c12dd151c7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallNotificationReceiver.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallNotificationReceiver.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.service.call import android.content.BroadcastReceiver import android.content.Context import android.content.Intent +import com.vitorpamplona.amethyst.commons.service.call.CallSessionBridge import com.vitorpamplona.amethyst.service.call.notification.CallNotifier import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/IceServerConfig.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/IceServerConfig.kt index e62f1a3712..30efa00e53 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/IceServerConfig.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/IceServerConfig.kt @@ -20,7 +20,7 @@ */ package com.vitorpamplona.amethyst.service.call -import com.vitorpamplona.amethyst.model.CallTurnServer +import com.vitorpamplona.amethyst.commons.model.CallTurnServer import org.webrtc.PeerConnection object IceServerConfig { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/crashreports/DisplayCrashMessages.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/crashreports/DisplayCrashMessages.kt index 591db30f24..238ac2793d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/crashreports/DisplayCrashMessages.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/crashreports/DisplayCrashMessages.kt @@ -44,11 +44,11 @@ import com.vitorpamplona.amethyst.commons.resources.crashreport_found_send import com.vitorpamplona.amethyst.commons.resources.would_you_like_to_send_the_recent_crash_report_to_amethyst_in_a_dm_no_personal_information_will_be_shared import com.vitorpamplona.amethyst.commons.service.crashreports.DEV_REPORT_PUBKEY import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeToMessage import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size16dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer -import com.vitorpamplona.amethyst.ui.navigation.routes.routeToMessage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/eventCache/MemoryTrimmingService.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/eventCache/MemoryTrimmingService.kt index bfaade94b4..e070b2c702 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/eventCache/MemoryTrimmingService.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/eventCache/MemoryTrimmingService.kt @@ -22,8 +22,8 @@ package com.vitorpamplona.amethyst.service.eventCache import android.content.ComponentCallbacks2 import com.vitorpamplona.amethyst.AccountInfo +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip19Bech32.decodePublicKeyAsHexOrNull import com.vitorpamplona.quartz.utils.Log import java.util.concurrent.atomic.AtomicBoolean diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/LocationState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/LocationState.kt index 82ad1bed00..34743eeada 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/LocationState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/LocationState.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.amethyst.service.location import android.content.Context import android.location.Location import android.location.LocationManager +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import com.vitorpamplona.quartz.experimental.bitchat.geohash.GeohashChannelLevel -import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeoHash import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeohashPrecision import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope @@ -100,16 +100,6 @@ class LocationState( const val SUBSCRIPTION_STOP_TIMEOUT_MS: Long = 5_000L } - sealed class LocationResult { - data class Success( - val geoHash: GeoHash, - ) : LocationResult() - - object LackPermission : LocationResult() - - object Loading : LocationResult() - } - private enum class Gate { NoPermission, Paused, Listen } private var hasLocationPermission = MutableStateFlow(false) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/AlwaysOnNotificationServiceManager.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/AlwaysOnNotificationServiceManager.kt index c00e7c506c..b7ce6c9616 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/AlwaysOnNotificationServiceManager.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/AlwaysOnNotificationServiceManager.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.service.notifications import android.content.Context import com.vitorpamplona.amethyst.LocalPreferences -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.model.accountsCache.AccountCacheState import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountSubscriptionRegistry import com.vitorpamplona.quartz.nip01Core.core.HexKey @@ -58,9 +58,9 @@ import kotlinx.coroutines.launch * and expects the one they land on to be current, so all of them keep their own notifications, * DMs and gift wraps live. This costs nothing once the app is away — it ends with the screen. * - **While the app is away: only the accounts that opted in**, via - * [com.vitorpamplona.amethyst.model.AccountSettings.alwaysOnNotificationService] ("Keep this + * [com.vitorpamplona.amethyst.commons.model.AccountSettings.alwaysOnNotificationService] ("Keep this * account active in the background") or their NIP-46 signer toggle - * ([com.vitorpamplona.amethyst.model.AccountSettings.nip46SignerEnabled]). + * ([com.vitorpamplona.amethyst.commons.model.AccountSettings.nip46SignerEnabled]). * * That is what the setting's name promises, and for a while it did not hold: participation gated * subscriptions everywhere, so an account you had not opted in for showed no notifications even diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt index b596797b6a..b7857698e1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt @@ -30,17 +30,18 @@ import coil3.request.ImageRequest import coil3.request.allowHardware import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.LocalPreferences +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.isMutedPublicChatMessage import com.vitorpamplona.amethyst.commons.nipACWebRtcCalls.CallManager +import com.vitorpamplona.amethyst.commons.notifications.dal.NotificationFeedFilter import com.vitorpamplona.amethyst.commons.relayClient.event.EventFinderQueryState import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderQueryState import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_notification_chess_challenge_accepted import com.vitorpamplona.amethyst.commons.resources.app_notification_chess_your_turn import com.vitorpamplona.amethyst.commons.resources.app_notification_poll_channel_message -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.call.notification.CallNotifier import com.vitorpamplona.amethyst.service.notifications.renderers.ArticleNotification import com.vitorpamplona.amethyst.service.notifications.renderers.BadgeNotification @@ -57,7 +58,6 @@ import com.vitorpamplona.amethyst.service.notifications.renderers.RepostNotifica import com.vitorpamplona.amethyst.service.notifications.renderers.ZapNotification import com.vitorpamplona.amethyst.service.relayClient.authCommand.model.ScreenAuthAccount import com.vitorpamplona.amethyst.ui.MainActivity -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.dal.NotificationFeedFilter import com.vitorpamplona.quartz.buzz.stream.StreamMessageV2Event import com.vitorpamplona.quartz.experimental.notifications.wake.WakeUpEvent import com.vitorpamplona.quartz.marmot.mip02Welcome.WelcomeEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationDispatcher.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationDispatcher.kt index b7f3b0908b..1d29e6d745 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationDispatcher.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationDispatcher.kt @@ -22,10 +22,11 @@ package com.vitorpamplona.amethyst.service.notifications import android.content.Context import com.vitorpamplona.amethyst.LocalPreferences +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.marmot.MarmotGroupNotifier +import com.vitorpamplona.amethyst.commons.notifications.dal.NotificationFeedFilter import com.vitorpamplona.amethyst.service.notifications.renderers.BuzzDmNotification -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.dal.NotificationFeedFilter import com.vitorpamplona.quartz.buzz.stream.StreamMessageV2Event import com.vitorpamplona.quartz.experimental.notifications.wake.WakeUpEvent import com.vitorpamplona.quartz.marmot.mip02Welcome.WelcomeEvent @@ -96,7 +97,7 @@ class NotificationDispatcher( private val scope: CoroutineScope, /** Forwarded to [EventNotificationConsumer]: reports wakelock held-time to the resource-usage ledger. */ onWakeLockHeld: ((heldMs: Long) -> Unit)? = null, -) { +) : MarmotGroupNotifier { companion object { private const val TAG = "NotificationDispatcher" @@ -306,7 +307,7 @@ class NotificationDispatcher( * routing. Called from processMarmotWelcomeFlow once MLS group join * succeeds — at which point we know which account the invite was for. */ - suspend fun notifyWelcome( + override suspend fun notifyWelcome( event: WelcomeEvent, account: Account, ) { @@ -322,10 +323,10 @@ class NotificationDispatcher( * Direct-invocation entry point for Marmot kind:445 group messages. * Bypasses the cache-observer path because GroupEvents are routed by * the `h` tag (nostr_group_id), not by `p` tag. Called from - * [com.vitorpamplona.amethyst.ui.screen.loggedIn.GroupEventHandler] + * [com.vitorpamplona.amethyst.commons.model.GroupEventHandler] * once the MLS-decrypted inner event has been parsed and indexed. */ - suspend fun notifyGroupMessage( + override suspend fun notifyGroupMessage( innerEvent: ChatEvent, nostrGroupId: String, account: Account, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationEnricher.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationEnricher.kt index b6422968a4..df0157e3ee 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationEnricher.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationEnricher.kt @@ -23,11 +23,11 @@ package com.vitorpamplona.amethyst.service.notifications import android.content.Context import android.os.PowerManager import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.relayClient.event.EventFinderQueryState import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderQueryState -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.relayClient.authCommand.model.ScreenAuthAccount import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationRoutes.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationRoutes.kt index 05ce0b5f58..573f97cea0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationRoutes.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NotificationRoutes.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.amethyst.service.notifications import android.app.NotificationManager import android.content.Context import androidx.core.content.ContextCompat +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey import com.vitorpamplona.quartz.nip19Bech32.toNpub diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher.kt index f74bddd9b8..3c6b94cc0c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/NwcPaymentNotificationWatcher.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.service.notifications import android.content.Context -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.service.notifications.renderers.NwcPaymentNotifier import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -36,7 +36,7 @@ import kotlinx.coroutines.launch * account's connected NWC wallets. * * The relay subscription that receives these events is NOT here — it lives in - * [com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip47WalletConnect.NwcNotificationsEoseManager], + * [com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip47WalletConnect.NwcNotificationsEoseManager], * grouped with the account's always-on zap/notification inbox subscriptions so it * shares their lifecycle (open while logged in, warm in the background). That * manager decrypts each notification and publishes non-zap payments to diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt index 2ea9481a0f..ff50538a22 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt @@ -24,8 +24,8 @@ import com.vitorpamplona.amethyst.AccountInfo import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.LocalPreferences +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.isDebug -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip42RelayAuth.RelayAuthEvent import com.vitorpamplona.quartz.utils.Log diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ArticleNotification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ArticleNotification.kt index f25f03ad42..bdb675c0e7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ArticleNotification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ArticleNotification.kt @@ -21,12 +21,12 @@ package com.vitorpamplona.amethyst.service.notifications.renderers import android.content.Context +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_notification_articles_channel_message import com.vitorpamplona.amethyst.commons.resources.app_notification_articles_channel_message_highlight import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.notifications.NotificationCategory import com.vitorpamplona.amethyst.service.notifications.NotificationContent import com.vitorpamplona.amethyst.service.notifications.NotificationEnricher diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/BadgeNotification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/BadgeNotification.kt index 1311aa6853..635a7f8b52 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/BadgeNotification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/BadgeNotification.kt @@ -21,12 +21,12 @@ package com.vitorpamplona.amethyst.service.notifications.renderers import android.content.Context +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_notification_badges_channel_message import com.vitorpamplona.amethyst.commons.resources.app_notification_badges_channel_message_from import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.notifications.NotificationCategory import com.vitorpamplona.amethyst.service.notifications.NotificationEnricher import com.vitorpamplona.amethyst.service.notifications.NotificationRoutes diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/BuzzDmNotification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/BuzzDmNotification.kt index bb9de23cb3..666758cc26 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/BuzzDmNotification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/BuzzDmNotification.kt @@ -21,13 +21,13 @@ package com.vitorpamplona.amethyst.service.notifications.renderers import android.content.Context +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_notification_new_message import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.notifications.NotificationCategory import com.vitorpamplona.amethyst.service.notifications.NotificationEnricher import com.vitorpamplona.amethyst.service.notifications.NotificationRoutes diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ChessNotification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ChessNotification.kt index 16e90743e8..263df2e421 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ChessNotification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ChessNotification.kt @@ -21,12 +21,12 @@ package com.vitorpamplona.amethyst.service.notifications.renderers import android.content.Context +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_notification_chess_channel_name import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.isDebug -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.notifications.NotificationCategory import com.vitorpamplona.amethyst.service.notifications.NotificationEnricher import com.vitorpamplona.amethyst.service.notifications.NotificationRoutes diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/CodeNotification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/CodeNotification.kt index 27e75daa4e..9a2021d43d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/CodeNotification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/CodeNotification.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.amethyst.service.notifications.renderers import android.content.Context +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_notification_code_channel_message_issue @@ -39,7 +40,6 @@ import com.vitorpamplona.amethyst.commons.resources.app_notification_code_channe import com.vitorpamplona.amethyst.commons.resources.app_notification_code_channel_message_status_draft import com.vitorpamplona.amethyst.commons.resources.app_notification_code_channel_message_status_open import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.notifications.NotificationCategory import com.vitorpamplona.amethyst.service.notifications.NotificationContent import com.vitorpamplona.amethyst.service.notifications.NotificationEnricher diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/DirectMessageNotification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/DirectMessageNotification.kt index 6935da0691..80d8f92e46 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/DirectMessageNotification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/DirectMessageNotification.kt @@ -21,9 +21,9 @@ package com.vitorpamplona.amethyst.service.notifications.renderers import android.content.Context +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.notifications.NotificationCategory import com.vitorpamplona.amethyst.service.notifications.NotificationContent import com.vitorpamplona.amethyst.service.notifications.NotificationEnricher diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/GroupMessageNotification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/GroupMessageNotification.kt index fe2b5b62bd..7a7ec1c1da 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/GroupMessageNotification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/GroupMessageNotification.kt @@ -21,12 +21,12 @@ package com.vitorpamplona.amethyst.service.notifications.renderers import android.content.Context +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_notification_added_to_group import com.vitorpamplona.amethyst.commons.resources.app_notification_new_message import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.notifications.NotificationCategory import com.vitorpamplona.amethyst.service.notifications.NotificationEnricher import com.vitorpamplona.amethyst.service.notifications.NotificationRoutes diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/MediaNotification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/MediaNotification.kt index df898a6dca..42b4222dbd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/MediaNotification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/MediaNotification.kt @@ -21,12 +21,12 @@ package com.vitorpamplona.amethyst.service.notifications.renderers import android.content.Context +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_notification_media_channel_message_photo import com.vitorpamplona.amethyst.commons.resources.app_notification_media_channel_message_video import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.notifications.NotificationCategory import com.vitorpamplona.amethyst.service.notifications.NotificationContent import com.vitorpamplona.amethyst.service.notifications.NotificationEnricher diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/MentionNotification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/MentionNotification.kt index c088acfbbc..3f8d5fff0c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/MentionNotification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/MentionNotification.kt @@ -21,11 +21,11 @@ package com.vitorpamplona.amethyst.service.notifications.renderers import android.content.Context +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_notification_mentions_channel_message import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.notifications.NotificationCategory import com.vitorpamplona.amethyst.service.notifications.NotificationContent import com.vitorpamplona.amethyst.service.notifications.NotificationEnricher diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/NwcPaymentNotifier.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/NwcPaymentNotifier.kt index 16c5fc2538..931fd6845f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/NwcPaymentNotifier.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/NwcPaymentNotifier.kt @@ -21,11 +21,11 @@ package com.vitorpamplona.amethyst.service.notifications.renderers import android.content.Context +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_notification_payments_channel_message import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.notifications.NotificationCategory import com.vitorpamplona.amethyst.service.notifications.NotificationRoutes import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.postStandard diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ReactionNotification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ReactionNotification.kt index ef9dce7e28..0570b46bce 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ReactionNotification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ReactionNotification.kt @@ -21,12 +21,12 @@ package com.vitorpamplona.amethyst.service.notifications.renderers import android.content.Context +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_notification_reactions_channel_message import com.vitorpamplona.amethyst.commons.resources.app_notification_reactions_channel_message_for import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.notifications.NotificationCategory import com.vitorpamplona.amethyst.service.notifications.NotificationContent import com.vitorpamplona.amethyst.service.notifications.NotificationEnricher diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ReplyNotification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ReplyNotification.kt index 14119485f4..f8bb2d5828 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ReplyNotification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ReplyNotification.kt @@ -21,12 +21,12 @@ package com.vitorpamplona.amethyst.service.notifications.renderers import android.content.Context +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_notification_me import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.notifications.NotificationCategory import com.vitorpamplona.amethyst.service.notifications.NotificationContent import com.vitorpamplona.amethyst.service.notifications.NotificationEnricher diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/RepostNotification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/RepostNotification.kt index ad780d38b5..2e278ca683 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/RepostNotification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/RepostNotification.kt @@ -21,11 +21,11 @@ package com.vitorpamplona.amethyst.service.notifications.renderers import android.content.Context +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_notification_reposts_channel_message import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.notifications.NotificationCategory import com.vitorpamplona.amethyst.service.notifications.NotificationContent import com.vitorpamplona.amethyst.service.notifications.NotificationEnricher diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ZapNotification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ZapNotification.kt index 67c9c9e6cb..d6674e156b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ZapNotification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/renderers/ZapNotification.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.amethyst.service.notifications.renderers import android.content.Context +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -32,7 +33,6 @@ import com.vitorpamplona.amethyst.commons.resources.app_notification_zaps_channe import com.vitorpamplona.amethyst.commons.resources.app_notification_zaps_channel_message_from import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.notifications.NotificationCategory import com.vitorpamplona.amethyst.service.notifications.NotificationContent import com.vitorpamplona.amethyst.service.notifications.NotificationEnricher diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/LoadThumbAndThenVideoView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/LoadThumbAndThenVideoView.kt index 0189aa04ab..c8df4d4b00 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/LoadThumbAndThenVideoView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/LoadThumbAndThenVideoView.kt @@ -32,7 +32,7 @@ import androidx.compose.ui.platform.LocalContext import coil3.asDrawable import coil3.imageLoader import coil3.request.ImageRequest -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/RenderVideoPlayer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/RenderVideoPlayer.kt index 33712cfdd0..6463ff915f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/RenderVideoPlayer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/RenderVideoPlayer.kt @@ -46,6 +46,7 @@ import androidx.media3.common.util.UnstableApi import androidx.media3.ui.compose.ContentFrame import androidx.media3.ui.compose.SURFACE_TYPE_TEXTURE_VIEW import com.vitorpamplona.amethyst.commons.ui.components.getDialogWindow +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.playback.composable.controls.BottomGradientOverlay import com.vitorpamplona.amethyst.service.playback.composable.controls.FullscreenSwipeControlsState import com.vitorpamplona.amethyst.service.playback.composable.controls.FullscreenSwipeLevelIndicator @@ -63,7 +64,6 @@ import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.LoadedMe import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.isHlsMedia import com.vitorpamplona.amethyst.service.playback.composable.wavefront.AudioPlayingAnimation import com.vitorpamplona.amethyst.service.playback.composable.wavefront.rememberIsAudioTrack -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel internal const val SKIP_SECONDS = 10 internal const val SKIP_MILLIS = SKIP_SECONDS * 1000L diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoView.kt index 404413b883..86b6b2fdf6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoView.kt @@ -30,31 +30,26 @@ import androidx.compose.foundation.layout.size import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.Immutable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale +import com.vitorpamplona.amethyst.commons.audio.WaveformData +import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.commons.model.nip71Video.CaptionTrack +import com.vitorpamplona.amethyst.commons.ui.components.DisplayBlurHash +import com.vitorpamplona.amethyst.commons.ui.components.ImageUrlWithDownloadButton import com.vitorpamplona.amethyst.commons.ui.note.DownloadForOfflineIcon import com.vitorpamplona.amethyst.commons.ui.theme.Size75dp import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier import com.vitorpamplona.amethyst.commons.ui.theme.videoGalleryModifier -import com.vitorpamplona.amethyst.model.MediaAspectRatioCache -import com.vitorpamplona.amethyst.ui.components.DisplayBlurHash -import com.vitorpamplona.amethyst.ui.components.ImageUrlWithDownloadButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf -@Immutable -class WaveformData( - val wave: List, -) - @Composable fun VideoView( videoUri: String, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoViewInner.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoViewInner.kt index 020af20e41..a3bc505dea 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoViewInner.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoViewInner.kt @@ -26,10 +26,11 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale +import com.vitorpamplona.amethyst.commons.audio.WaveformData import com.vitorpamplona.amethyst.commons.model.nip71Video.CaptionTrack +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.playback.composable.mainVideo.VideoPlayerActiveMutex import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.GetMediaItem -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/controls/OverflowMenu.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/controls/OverflowMenu.kt index 3e549275c0..f74789a9c4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/controls/OverflowMenu.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/controls/OverflowMenu.kt @@ -40,6 +40,7 @@ import androidx.compose.ui.tooling.preview.Preview import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.VideoPlayerAction import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.call_settings_video_quality import com.vitorpamplona.amethyst.commons.resources.download_to_phone @@ -59,7 +60,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size50Modifier import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.VolumeBottomIconSize -import com.vitorpamplona.amethyst.model.VideoPlayerAction import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/controls/RenderTopButtons.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/controls/RenderTopButtons.kt index cd0a3d15dd..18348acf29 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/controls/RenderTopButtons.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/controls/RenderTopButtons.kt @@ -55,6 +55,8 @@ import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.VideoButtonLocation +import com.vitorpamplona.amethyst.commons.model.VideoPlayerAction import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.captions_turn_off import com.vitorpamplona.amethyst.commons.resources.captions_turn_on @@ -70,8 +72,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.PinBottomIconSize import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size50Modifier import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.model.VideoButtonLocation -import com.vitorpamplona.amethyst.model.VideoPlayerAction +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.service.cast.CastRequest import com.vitorpamplona.amethyst.service.cast.CastSessionState import com.vitorpamplona.amethyst.service.cast.resolveCastLiveness @@ -85,8 +87,7 @@ import com.vitorpamplona.amethyst.ui.cast.CastDevicePickerDialog import com.vitorpamplona.amethyst.ui.cast.rememberCastWithLocalNetworkPermission import com.vitorpamplona.amethyst.ui.components.ShareMediaAction import com.vitorpamplona.amethyst.ui.components.getActivity -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.ui.screen.loggedIn.saveMediaToGallery import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/mediaitem/GetMediaItem.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/mediaitem/GetMediaItem.kt index e777945a9a..785480c2d5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/mediaitem/GetMediaItem.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/mediaitem/GetMediaItem.kt @@ -25,9 +25,9 @@ import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.audio.WaveformData import com.vitorpamplona.amethyst.commons.model.nip71Video.CaptionTrack import com.vitorpamplona.amethyst.commons.ui.state.produceCachedState -import com.vitorpamplona.amethyst.service.playback.composable.WaveformData import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/mediaitem/MediaItemData.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/mediaitem/MediaItemData.kt index a140f0b37e..7ff0500dae 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/mediaitem/MediaItemData.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/mediaitem/MediaItemData.kt @@ -22,8 +22,8 @@ package com.vitorpamplona.amethyst.service.playback.composable.mediaitem import androidx.compose.runtime.Immutable import androidx.media3.common.MediaItem +import com.vitorpamplona.amethyst.commons.audio.WaveformData import com.vitorpamplona.amethyst.commons.model.nip71Video.CaptionTrack -import com.vitorpamplona.amethyst.service.playback.composable.WaveformData import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/AudioPlayingAnimation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/AudioPlayingAnimation.kt index 05da0bf1c8..631c17d06f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/AudioPlayingAnimation.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/AudioPlayingAnimation.kt @@ -44,9 +44,9 @@ import androidx.media3.common.Tracks import com.vitorpamplona.amethyst.commons.audio.AudioVisualizer import com.vitorpamplona.amethyst.commons.audio.Spectrum import com.vitorpamplona.amethyst.commons.audio.VisualizerStyle +import com.vitorpamplona.amethyst.commons.audio.WaveformData import com.vitorpamplona.amethyst.commons.audio.delayedByFrames import com.vitorpamplona.amethyst.service.playback.composable.MediaControllerState -import com.vitorpamplona.amethyst.service.playback.composable.WaveformData import com.vitorpamplona.amethyst.service.playback.playerPool.PcmTapRegistry import kotlinx.coroutines.flow.emptyFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/SyntheticWaveform.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/SyntheticWaveform.kt index a9f2a26726..c4fcbd672c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/SyntheticWaveform.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/SyntheticWaveform.kt @@ -20,12 +20,13 @@ */ package com.vitorpamplona.amethyst.service.playback.composable.wavefront -import com.vitorpamplona.amethyst.service.playback.composable.WaveformData +import com.vitorpamplona.amethyst.commons.audio.WaveformData +import kotlin.math.PI import kotlin.math.sin import kotlin.random.Random private const val SYNTHETIC_WAVEFORM_SAMPLES = 96 -private const val TWO_PI = (Math.PI * 2).toFloat() +private const val TWO_PI = (PI * 2).toFloat() /** * Builds a stable, decorative waveform from a [seed] (usually an event id). ExoPlayer drives @@ -57,7 +58,7 @@ fun syntheticWaveformFor(seed: String): WaveformData { List(SYNTHETIC_WAVEFORM_SAMPLES) { index -> val phase = index.toFloat() / SYNTHETIC_WAVEFORM_SAMPLES // Optional gentle fade so some taper at the ends, others stay even. - val envelope = 1f - envelopeStrength * (1f - sin(phase * Math.PI).toFloat()) + val envelope = 1f - envelopeStrength * (1f - sin(phase * PI).toFloat()) val carrier = sin(phase * TWO_PI * carrierCycles + phaseOffset) * carrierWeight val noise = (rng.nextFloat() - 0.5f) * 2f * noiseStrength ((baseline + carrier + noise) * envelope).coerceIn(0.05f, 1.0f) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/Waveform.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/Waveform.kt index e4bc115142..bec6b628bc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/Waveform.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/Waveform.kt @@ -36,9 +36,9 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.media3.common.Player import com.linc.audiowaveform.infiniteLinearGradient +import com.vitorpamplona.amethyst.commons.audio.WaveformData import com.vitorpamplona.amethyst.commons.ui.components.AudioWaveformReadOnly import com.vitorpamplona.amethyst.service.playback.composable.MediaControllerState -import com.vitorpamplona.amethyst.service.playback.composable.WaveformData @Composable fun Waveform( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/diskCache/HlsLivenessCache.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/diskCache/HlsLivenessCache.kt index f7a5de2759..9361030ca7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/diskCache/HlsLivenessCache.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/diskCache/HlsLivenessCache.kt @@ -34,7 +34,7 @@ import androidx.collection.LruCache * * A URL is permanently one or the other, and the recorder overwrites with the latest verdict on * every timeline change, so a transient early value self-corrects. Backed by a bounded, thread-safe - * [LruCache] (same convention as [com.vitorpamplona.amethyst.model.MediaAspectRatioCache]) so a long + * [LruCache] (same convention as [com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache]) so a long * feed session over many distinct URLs can't grow it without bound — an evicted entry just relearns * on its next play, which is one uncached play, the same negligible cost as a process restart. */ diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/IntentExtras.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/IntentExtras.kt index cb2248312e..53f1ddd1b9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/IntentExtras.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/IntentExtras.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.service.playback.pip import android.graphics.Rect import android.os.Bundle -import com.vitorpamplona.amethyst.service.playback.composable.WaveformData +import com.vitorpamplona.amethyst.commons.audio.WaveformData import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.MediaItemData import com.vitorpamplona.quartz.utils.ensure diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PiPFromIntents.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PiPFromIntents.kt index 815338ac8c..ffc8d81c55 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PiPFromIntents.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PiPFromIntents.kt @@ -30,7 +30,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.platform.LocalContext import androidx.core.util.Consumer -import com.vitorpamplona.amethyst.model.MediaAspectRatioCache +import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.service.playback.composable.DEFAULT_MUTED_SETTING import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.MediaItemData import com.vitorpamplona.amethyst.ui.components.getActivity diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoView.kt index 2e544edff9..1373f456ad 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoView.kt @@ -40,10 +40,10 @@ import androidx.media3.common.util.UnstableApi import androidx.media3.ui.compose.ContentFrame import androidx.media3.ui.compose.state.rememberMuteButtonState import androidx.media3.ui.compose.state.rememberPlayPauseButtonState +import com.vitorpamplona.amethyst.commons.audio.WaveformData +import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.commons.ui.theme.VoiceHeightModifier -import com.vitorpamplona.amethyst.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.service.playback.composable.MediaControllerState -import com.vitorpamplona.amethyst.service.playback.composable.WaveformData import com.vitorpamplona.amethyst.service.playback.composable.controls.PIP_PRESHRINK_MAX_SHORT_SIDE_PX import com.vitorpamplona.amethyst.service.playback.composable.controls.constrainVideoQualityToViewport import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.MediaItemData diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/ExoPlayerBuilder.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/ExoPlayerBuilder.kt index ae2c4d0964..aa969245d4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/ExoPlayerBuilder.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/ExoPlayerBuilder.kt @@ -32,7 +32,7 @@ import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.audio.AudioSink import androidx.media3.exoplayer.audio.DefaultAudioSink import androidx.media3.exoplayer.audio.TeeAudioProcessor -import com.vitorpamplona.amethyst.model.MediaAspectRatioCache +import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.service.playback.diskCache.VideoCache import com.vitorpamplona.amethyst.service.playback.playerPool.aspectRatio.AspectRatioCacher import com.vitorpamplona.amethyst.service.playback.playerPool.positions.CurrentPlayPositionCacher diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/aspectRatio/AspectRatioCacher.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/aspectRatio/AspectRatioCacher.kt index 6285d178c6..70a29f9e43 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/aspectRatio/AspectRatioCacher.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/aspectRatio/AspectRatioCacher.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.service.playback.playerPool.aspectRatio import androidx.media3.common.MediaItem import androidx.media3.common.Player import androidx.media3.common.VideoSize -import com.vitorpamplona.amethyst.model.MutableMediaAspectRatioCache +import com.vitorpamplona.amethyst.commons.model.MutableMediaAspectRatioCache class AspectRatioCacher( val cache: MutableMediaAspectRatioCache, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/pow/PowJobRestorer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/pow/PowJobRestorer.kt index 2dfdcfb482..19b201c89e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/pow/PowJobRestorer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/pow/PowJobRestorer.kt @@ -20,12 +20,12 @@ */ package com.vitorpamplona.amethyst.service.pow +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.scheduledposts.ScheduledPost import com.vitorpamplona.amethyst.commons.scheduledposts.ScheduledPostStore import com.vitorpamplona.amethyst.commons.service.pow.PersistedPoWJob import com.vitorpamplona.amethyst.commons.service.pow.PoWJobStore import com.vitorpamplona.amethyst.commons.service.pow.PoWPublishQueue -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/pow/PowKindLabel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/pow/PowKindLabel.kt index 9df5ed65fe..e6bf084fea 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/pow/PowKindLabel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/pow/PowKindLabel.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.service.pow import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.boost import com.vitorpamplona.amethyst.commons.resources.post import com.vitorpamplona.amethyst.commons.resources.pow_kind_chat_message @@ -30,6 +29,7 @@ import com.vitorpamplona.amethyst.commons.resources.private_message import com.vitorpamplona.amethyst.commons.resources.reaction import com.vitorpamplona.amethyst.commons.resources.voice_post import com.vitorpamplona.amethyst.commons.resources.voice_reply +import com.vitorpamplona.amethyst.commons.service.pow.powKindLabelRes import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent import com.vitorpamplona.quartz.nip18Reposts.RepostEvent import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent @@ -39,24 +39,6 @@ import com.vitorpamplona.quartz.nip56Reports.ReportEvent import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceEvent import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceReplyEvent -import org.jetbrains.compose.resources.StringResource - -/** - * The one user-facing label for "what is being mined": shared by the - * broadcast banner, the mining foreground notification, and failure toasts - * so a job is described the same way everywhere it appears. - */ -fun powKindLabelRes(kind: Int): StringResource = - when (kind) { - ReactionEvent.KIND -> Res.string.reaction - RepostEvent.KIND, GenericRepostEvent.KIND -> Res.string.boost - VoiceEvent.KIND -> Res.string.voice_post - VoiceReplyEvent.KIND -> Res.string.voice_reply - ReportEvent.KIND -> Res.string.pow_kind_report - GiftWrapEvent.KIND -> Res.string.private_message - ChannelMessageEvent.KIND, LiveActivitiesChatMessageEvent.KIND -> Res.string.pow_kind_chat_message - else -> Res.string.post - } /** * Android-resource twin of [powKindLabelRes], for [com.vitorpamplona.amethyst.service.pow.PowMiningForegroundService]. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/compose/AccountDataSourceSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/compose/AccountDataSourceSubscription.kt index 194c106cea..e18640b30a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/compose/AccountDataSourceSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/compose/AccountDataSourceSubscription.kt @@ -24,9 +24,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.relayClient.authCommand.model.AuthCoordinator import com.vitorpamplona.amethyst.service.relayClient.authCommand.model.ScreenAuthAccount -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @Composable fun RelayAuthSubscription(accountViewModel: AccountViewModel) = RelayAuthSubscription(accountViewModel, Amethyst.instance.authCoordinator) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/compose/RelayAuthPromptHost.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/compose/RelayAuthPromptHost.kt index 82eefe3b7c..08759214ca 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/compose/RelayAuthPromptHost.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/compose/RelayAuthPromptHost.kt @@ -64,8 +64,11 @@ import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.model.Channel import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo import com.vitorpamplona.amethyst.commons.relayClient.auth.RelayAuthPrompt import com.vitorpamplona.amethyst.commons.relayClient.auth.UserAuthChoice +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannel +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.relayauth.AuthPurpose import com.vitorpamplona.amethyst.commons.relayauth.AuthPurposeKind import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthPolicy @@ -98,15 +101,12 @@ import com.vitorpamplona.amethyst.commons.resources.relay_auth_why_send_dm import com.vitorpamplona.amethyst.commons.resources.relay_auth_why_thread import com.vitorpamplona.amethyst.commons.resources.relay_auth_why_thread_with import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.RelayIconFilter -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/AuthCoordinator.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/AuthCoordinator.kt index 94791b4670..a5c9242612 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/AuthCoordinator.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/AuthCoordinator.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.amethyst.service.relayClient.authCommand.model import androidx.compose.runtime.Stable +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.buzz.BuzzRelayDialect import com.vitorpamplona.amethyst.commons.relayClient.auth.ListWithUniqueSetCache import com.vitorpamplona.amethyst.commons.relayClient.auth.RelayAuthFirstParty @@ -32,7 +33,6 @@ import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthDecision import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthPolicy import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthVerdict import com.vitorpamplona.amethyst.isDebug -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/notifyCommand/compose/DisplayNotifyMessages.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/notifyCommand/compose/DisplayNotifyMessages.kt index 33a258e3a3..f79f9873d6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/notifyCommand/compose/DisplayNotifyMessages.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/notifyCommand/compose/DisplayNotifyMessages.kt @@ -27,7 +27,7 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.payment_required_title import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/notifyCommand/compose/NotifyRequestDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/notifyCommand/compose/NotifyRequestDialog.kt index a5e64d98bb..e268a9d483 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/notifyCommand/compose/NotifyRequestDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/notifyCommand/compose/NotifyRequestDialog.kt @@ -42,13 +42,13 @@ import com.vitorpamplona.amethyst.commons.model.EmptyTagList import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.error_dialog_button_ok import com.vitorpamplona.amethyst.commons.resources.notify_block_relay +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size16dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @Composable fun NotifyRequestDialog( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/notifyCommand/model/NotifyCoordinator.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/notifyCommand/model/NotifyCoordinator.kt index 4d3d1722ba..5dbef48825 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/notifyCommand/model/NotifyCoordinator.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/notifyCommand/model/NotifyCoordinator.kt @@ -21,8 +21,8 @@ package com.vitorpamplona.amethyst.service.relayClient.notifyCommand.model import android.util.LruCache +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.relayClient.notify.NotifyRequestsCache -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.RelayConnectionListener diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountFilterAssemblerSubscription.kt index 0af31be8c8..d4193aa5eb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountFilterAssemblerSubscription.kt @@ -22,8 +22,10 @@ package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountFilterAssembler +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountUiQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun AccountFilterAssemblerSubscription(accountViewModel: AccountViewModel) = diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountForegroundFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountForegroundFilterAssemblerSubscription.kt index cc3614e05d..2861e4d0c9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountForegroundFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountForegroundFilterAssemblerSubscription.kt @@ -22,8 +22,10 @@ package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountForegroundFilterAssembler +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountUiQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun AccountForegroundFilterAssemblerSubscription(accountViewModel: AccountViewModel) = diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountSubscriptionRegistry.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountSubscriptionRegistry.kt index 96aabf0ef3..39d965ce64 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountSubscriptionRegistry.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountSubscriptionRegistry.kt @@ -20,7 +20,9 @@ */ package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountFilterAssembler +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.utils.Log diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip28PublicChats/ChannelMetadataWatcherSubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip28PublicChats/ChannelMetadataWatcherSubAssembler.kt index f9e976b2c2..bd63a2da4f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip28PublicChats/ChannelMetadataWatcherSubAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip28PublicChats/ChannelMetadataWatcherSubAssembler.kt @@ -24,8 +24,8 @@ import com.vitorpamplona.amethyst.commons.model.Channel import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.commons.relayClient.channel.nip28PublicChats.filterChannelMetadataUpdatesById import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUniqueIdEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.ChannelFinderQueryState import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.ChannelFinderQueryState import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter @@ -36,14 +36,16 @@ class ChannelMetadataWatcherSubAssembler( override fun updateFilter( key: ChannelFinderQueryState, since: SincePerRelayMap?, - ): List = - if (key.channel is PublicChatChannel) { - key.channel.relays().flatMap { - filterChannelMetadataUpdatesById(it, listOf(key.channel), since?.get(it)?.time) + ): List { + val channel = key.channel + return if (channel is PublicChatChannel) { + channel.relays().flatMap { + filterChannelMetadataUpdatesById(it, listOf(channel), since?.get(it)?.time) } } else { emptyList() } + } /** * Only one key per channel. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip53LiveActivities/LiveActivityWatcherSubAssembly.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip53LiveActivities/LiveActivityWatcherSubAssembly.kt index 0a5eaec2cd..41fa3b98bd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip53LiveActivities/LiveActivityWatcherSubAssembly.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip53LiveActivities/LiveActivityWatcherSubAssembly.kt @@ -24,8 +24,8 @@ import com.vitorpamplona.amethyst.commons.model.Channel import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel import com.vitorpamplona.amethyst.commons.relayClient.channel.nip53LiveActivities.filterLiveStreamUpdatesByAddress import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUniqueIdEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.ChannelFinderQueryState import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.ChannelFinderQueryState import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter @@ -40,14 +40,16 @@ class LiveActivityWatcherSubAssembly( override fun updateFilter( key: ChannelFinderQueryState, since: SincePerRelayMap?, - ): List = - if (key.channel is LiveActivitiesChannel) { - key.channel.relays().flatMap { - filterLiveStreamUpdatesByAddress(it, listOf(key.channel), since?.get(it)?.time) + ): List { + val channel = key.channel + return if (channel is LiveActivitiesChannel) { + channel.relays().flatMap { + filterLiveStreamUpdatesByAddress(it, listOf(channel), since?.get(it)?.time) } } else { emptyList() } + } /** * Only one key per channel. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/nwc/NWCFinderFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/nwc/NWCFinderFilterAssemblerSubscription.kt index 6f7d9e6064..8936bc37e8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/nwc/NWCFinderFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/nwc/NWCFinderFilterAssemblerSubscription.kt @@ -27,7 +27,7 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.relayClient.nip47WalletConnect.NWCPaymentFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.nip47WalletConnect.NWCPaymentQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip47WalletConnect.events.NwcRequestEvent @SuppressLint("StateFlowValueCalledInComposition") diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/searchCommand/TextSearchDataSourceSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/searchCommand/TextSearchDataSourceSubscription.kt index 87cb9880c0..bd1d0545e7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/searchCommand/TextSearchDataSourceSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/searchCommand/TextSearchDataSourceSubscription.kt @@ -21,8 +21,9 @@ package com.vitorpamplona.amethyst.service.relayClient.searchCommand import androidx.compose.runtime.Composable +import com.vitorpamplona.amethyst.commons.relayClient.searchCommand.SearchFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.search.SearchBarViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/resourceusage/DisplayResourceUsageAlert.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/resourceusage/DisplayResourceUsageAlert.kt index 045ef43c4a..42e56f82ce 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/resourceusage/DisplayResourceUsageAlert.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/resourceusage/DisplayResourceUsageAlert.kt @@ -46,10 +46,10 @@ import com.vitorpamplona.amethyst.commons.resources.resource_usage_reason_reconn import com.vitorpamplona.amethyst.commons.resources.resource_usage_reason_wakelock import com.vitorpamplona.amethyst.commons.service.crashreports.DEV_REPORT_PUBKEY import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeToMessage import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.routes.routeToMessage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/FileHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/FileHeaderPreparation.kt similarity index 54% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/FileHeader.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/FileHeaderPreparation.kt index 8cc09181ae..4368ee72bd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/FileHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/FileHeaderPreparation.kt @@ -21,8 +21,7 @@ package com.vitorpamplona.amethyst.service.uploads import android.media.MediaDataSource -import com.vitorpamplona.amethyst.commons.service.image.BlurhashWrapper -import com.vitorpamplona.amethyst.commons.service.image.ThumbhashWrapper +import com.vitorpamplona.amethyst.commons.service.upload.FileHeader import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag import com.vitorpamplona.quartz.utils.Log @@ -31,58 +30,45 @@ import kotlinx.coroutines.CancellationException import okhttp3.OkHttpClient import java.io.IOException -class FileHeader( - val mimeType: String?, - val hash: String, - val size: Int, - val dim: DimensionTag?, - val blurHash: BlurhashWrapper?, - val thumbHash: ThumbhashWrapper? = null, -) { - class UnableToDownload( - val fileUrl: String, - ) : Exception() +/** Downloads [fileUrl] and computes its [FileHeader] with [prepare]. */ +suspend fun FileHeader.Companion.prepare( + fileUrl: String, + mimeType: String?, + dimPrecomputed: DimensionTag?, + okHttpClient: (String) -> OkHttpClient, +): Result = + try { + val imageData: ImageDownloader.Blob? = ImageDownloader().waitAndGetImage(fileUrl, okHttpClient) - companion object { - suspend fun prepare( - fileUrl: String, - mimeType: String?, - dimPrecomputed: DimensionTag?, - okHttpClient: (String) -> OkHttpClient, - ): Result = - try { - val imageData: ImageDownloader.Blob? = ImageDownloader().waitAndGetImage(fileUrl, okHttpClient) - - if (imageData != null) { - prepare(imageData.bytes, mimeType ?: imageData.contentType, dimPrecomputed) - } else { - Result.failure(UnableToDownload(fileUrl)) - } - } catch (e: Exception) { - if (e is CancellationException) throw e - Log.e("ImageDownload") { "Couldn't download image from server: ${e.message}" } - Result.failure(e) - } - - fun prepare( - data: ByteArray, - mimeType: String?, - dimPrecomputed: DimensionTag?, - ): Result = - try { - val hash = sha256(data).toHexKey() - val size = data.size - - val preview = PreviewMetadataCalculator.computeFromBytes(data, mimeType, dimPrecomputed) - - Result.success(FileHeader(mimeType, hash, size, preview.dim, preview.blurhash, preview.thumbhash)) - } catch (e: Exception) { - if (e is CancellationException) throw e - Log.e("ImageDownload") { "Couldn't convert image in to File Header: ${e.message}" } - Result.failure(e) - } + if (imageData != null) { + prepare(imageData.bytes, mimeType ?: imageData.contentType, dimPrecomputed) + } else { + Result.failure(FileHeader.UnableToDownload(fileUrl)) + } + } catch (e: Exception) { + if (e is CancellationException) throw e + Log.e("ImageDownload") { "Couldn't download image from server: ${e.message}" } + Result.failure(e) + } + +/** Hashes [data] and decodes its dimensions and preview hashes (Android media APIs). */ +fun FileHeader.Companion.prepare( + data: ByteArray, + mimeType: String?, + dimPrecomputed: DimensionTag?, +): Result = + try { + val hash = sha256(data).toHexKey() + val size = data.size + + val preview = PreviewMetadataCalculator.computeFromBytes(data, mimeType, dimPrecomputed) + + Result.success(FileHeader(mimeType, hash, size, preview.dim, preview.blurhash, preview.thumbhash)) + } catch (e: Exception) { + if (e is CancellationException) throw e + Log.e("ImageDownload") { "Couldn't convert image in to File Header: ${e.message}" } + Result.failure(e) } -} class ByteArrayMediaDataSource( var imageData: ByteArray, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/MultiOrchestrator.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/MultiOrchestrator.kt index 4abc711481..797688b86c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/MultiOrchestrator.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/MultiOrchestrator.kt @@ -25,8 +25,8 @@ import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMediaProcessing import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/UploadOrchestrator.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/UploadOrchestrator.kt index bf59f45883..af41342da5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/UploadOrchestrator.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/UploadOrchestrator.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.service.uploads import android.content.Context import android.net.Uri import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType import com.vitorpamplona.amethyst.commons.model.mediaServers.blossomUploadOrder @@ -39,7 +40,7 @@ import com.vitorpamplona.amethyst.commons.resources.server_did_not_provide_a_url import com.vitorpamplona.amethyst.commons.resources.upload_cancelled import com.vitorpamplona.amethyst.commons.service.upload.BlossomClient import com.vitorpamplona.amethyst.commons.service.upload.BlossomPaymentException -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.service.upload.FileHeader import com.vitorpamplona.amethyst.service.uploads.UploadingState.UploadingFinalState import com.vitorpamplona.amethyst.service.uploads.blossom.BlossomUploader import com.vitorpamplona.amethyst.service.uploads.nip96.Nip96Uploader diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/BlossomMirrorQueue.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/BlossomMirrorQueue.kt index 8bbd9f0c26..2c83671ee0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/BlossomMirrorQueue.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/BlossomMirrorQueue.kt @@ -22,8 +22,8 @@ package com.vitorpamplona.amethyst.service.uploads.blossom import androidx.compose.runtime.Immutable import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.service.upload.BlossomClient -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/BlossomPaymentHandler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/BlossomPaymentHandler.kt index db16a4d518..62e75c9ed6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/BlossomPaymentHandler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/BlossomPaymentHandler.kt @@ -20,7 +20,7 @@ */ package com.vitorpamplona.amethyst.service.uploads.blossom -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.quartz.lightning.LnInvoiceUtil import com.vitorpamplona.quartz.nip47WalletConnect.rpc.PayInvoiceSuccessResponse import com.vitorpamplona.quartz.nipB7Blossom.BlossomPaymentProof diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/BlossomUploader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/BlossomUploader.kt index dc1531c46c..3367d8b7ab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/BlossomUploader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/BlossomUploader.kt @@ -28,9 +28,9 @@ import android.webkit.MimeTypeMap import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.failed_to_delete_with_message import com.vitorpamplona.amethyst.commons.resources.failed_to_upload_to_server_with_message +import com.vitorpamplona.amethyst.commons.service.HttpStatusMessages import com.vitorpamplona.amethyst.commons.service.upload.BlossomPaymentException import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.service.HttpStatusMessages import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.service.uploads.MediaUploadResult import com.vitorpamplona.amethyst.service.uploads.PreviewMetadataCalculator diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/hls/HlsBlobUploaderFactory.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/hls/HlsBlobUploaderFactory.kt index b94bb799c1..ffc280a8b1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/hls/HlsBlobUploaderFactory.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/hls/HlsBlobUploaderFactory.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.service.uploads.hls import android.content.Context import androidx.core.net.toUri import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.uploads.blossom.BlossomUploader import com.vitorpamplona.amethyst.service.uploads.nip96.Nip96Uploader import okhttp3.OkHttpClient diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/nip96/Nip96Uploader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/nip96/Nip96Uploader.kt index affded5569..5b5fa59daa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/nip96/Nip96Uploader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/nip96/Nip96Uploader.kt @@ -30,8 +30,8 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.failed_to_delete_with_message import com.vitorpamplona.amethyst.commons.resources.failed_to_upload_to_server_with_message +import com.vitorpamplona.amethyst.commons.service.HttpStatusMessages import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.service.HttpStatusMessages import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.service.uploads.AVIF_EXTENSION import com.vitorpamplona.amethyst.service.uploads.AVIF_MIME diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index e21a488fe6..33902c8bde 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -28,13 +28,15 @@ import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.actions.ConcordActions +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.richtext.RichTextParser +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeForPointer import com.vitorpamplona.amethyst.commons.ui.note.elements.NowProvider import com.vitorpamplona.amethyst.debugState -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.lang.LanguageTranslatorService import com.vitorpamplona.amethyst.service.notifications.NotificationRelayService import com.vitorpamplona.amethyst.service.notifications.NotificationRoutes @@ -42,8 +44,6 @@ import com.vitorpamplona.amethyst.service.playback.composable.DEFAULT_MUTED_SETT import com.vitorpamplona.amethyst.service.playback.pip.BackgroundMedia import com.vitorpamplona.amethyst.ui.navigation.findParameterValue import com.vitorpamplona.amethyst.ui.navigation.findQueryParameterValue -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.navigation.routes.routeForPointer import com.vitorpamplona.amethyst.ui.screen.AccountScreen import com.vitorpamplona.amethyst.ui.theme.AmethystTheme import com.vitorpamplona.quartz.buzz.invite.BuzzInviteLink diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt index b9d4cbe885..ef3dd4ae99 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt @@ -71,6 +71,7 @@ import coil3.compose.AsyncImage import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.add_bitcoin_invoice import com.vitorpamplona.amethyst.commons.resources.cancel_bitcoin_invoice @@ -79,11 +80,15 @@ import com.vitorpamplona.amethyst.commons.resources.lightning_invoice import com.vitorpamplona.amethyst.commons.resources.what_s_on_your_mind import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDialog +import com.vitorpamplona.amethyst.commons.ui.components.BechLink import com.vitorpamplona.amethyst.commons.ui.components.OutlinedThinPaddingTextField import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.PostingTopBar +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.note.creators.invoice.AddLnInvoiceButton +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.types.ReplyRenderType import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.text.MentionPreservingInputTransformation import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange @@ -95,18 +100,13 @@ import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightPa import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier import com.vitorpamplona.amethyst.commons.ui.theme.subtleBorder +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.playback.composable.VideoView -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery -import com.vitorpamplona.amethyst.ui.components.BechLink import com.vitorpamplona.amethyst.ui.components.LoadUrlPreview -import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest import com.vitorpamplona.amethyst.ui.note.creators.uploads.ImageVideoDescription -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.types.ReplyRenderType -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.delay import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt index 2998dc0ce6..02deee05dc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostViewModel.kt @@ -30,6 +30,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName @@ -41,17 +42,16 @@ import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.commons.service.upload.MediaUploadTracker import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation import com.vitorpamplona.amethyst.commons.ui.loadStringRes +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.ui.text.onUiThread -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMediaProcessing -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.UserSuggestionAnchor import com.vitorpamplona.quartz.experimental.nip95.data.FileStorageEvent import com.vitorpamplona.quartz.experimental.nip95.header.FileStorageHeaderEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt index c6aa0ea930..a42bbb8c5c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt @@ -28,6 +28,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.VideoPostKind import com.vitorpamplona.amethyst.commons.model.mediaServers.DEFAULT_MEDIA_SERVERS import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName @@ -38,13 +39,12 @@ import com.vitorpamplona.amethyst.commons.resources.read_only_user import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMediaProcessing -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt index 905d049668..9f534be04a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt @@ -81,10 +81,10 @@ import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.Settin import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.ShowImageUploadGallery import com.vitorpamplona.amethyst.ui.components.SetDialogToEdgeToEdge -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsRow import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataScreen.kt index fa67f172dd..9e95251d74 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataScreen.kt @@ -80,8 +80,8 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SavingTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectSingleFromGallery -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt index 59d3b695a8..049774718c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt @@ -25,7 +25,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.avif_metadata_strip_failed @@ -34,7 +34,7 @@ import com.vitorpamplona.amethyst.commons.resources.metadata_strip_failed_title import com.vitorpamplona.amethyst.commons.resources.metadata_strip_failed_upload_cancelled import com.vitorpamplona.amethyst.commons.resources.server_did_not_provide_a_url_after_uploading import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.AvifMetadataNotVerifiableException import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.MediaCompressor @@ -42,7 +42,6 @@ import com.vitorpamplona.amethyst.service.uploads.MetadataStripper import com.vitorpamplona.amethyst.service.uploads.blossom.BlossomUploader import com.vitorpamplona.amethyst.service.uploads.nip96.Nip96Uploader import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip39ExtIdentities.GitHubIdentity import com.vitorpamplona.quartz.nip39ExtIdentities.MastodonIdentity import com.vitorpamplona.quartz.nip39ExtIdentities.TwitterIdentity @@ -263,7 +262,7 @@ class NewUserMetadataViewModel : ViewModel() { alt = null, sensitiveContent = null, serverBaseUrl = account.settings.defaultFileServer.baseUrl, - okHttpClient = Amethyst.instance.roleBasedHttpClientBuilder::okHttpClientForUploads, + okHttpClient = accountViewModel.httpClientBuilder::okHttpClientForUploads, onProgress = {}, httpAuth = account::createHTTPAuthorization, context = context, @@ -276,7 +275,7 @@ class NewUserMetadataViewModel : ViewModel() { alt = null, sensitiveContent = null, serverBaseUrl = account.settings.defaultFileServer.baseUrl, - okHttpClient = Amethyst.instance.roleBasedHttpClientBuilder::okHttpClientForUploads, + okHttpClient = accountViewModel.httpClientBuilder::okHttpClientForUploads, httpAuth = account::createBlossomUploadAuth, context = context, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/bolt12Offers/Bolt12OffersScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/bolt12Offers/Bolt12OffersScreen.kt index de9f190cb8..61f916c933 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/bolt12Offers/Bolt12OffersScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/bolt12Offers/Bolt12OffersScreen.kt @@ -74,7 +74,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header.abbreviateBolt12Offer import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.SettingsCategory diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/bolt12Offers/Bolt12OffersViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/bolt12Offers/Bolt12OffersViewModel.kt index 924cf8bf81..bf3c50e88e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/bolt12Offers/Bolt12OffersViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/bolt12Offers/Bolt12OffersViewModel.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.amethyst.ui.actions.bolt12Offers import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nipB1Bolt12Zaps.bolt12.Bolt12Bech32 import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/AllMediaServersLIstView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/AllMediaServersLIstView.kt index e8c09e4a3d..008284575f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/AllMediaServersLIstView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/AllMediaServersLIstView.kt @@ -103,7 +103,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.warningColor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.utils.Rfc3986 import org.jetbrains.compose.resources.StringResource diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/AllMediaServersScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/AllMediaServersScreen.kt index 7480a31d96..e7ba0dafeb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/AllMediaServersScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/AllMediaServersScreen.kt @@ -63,7 +63,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackBu import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun AllMediaServersScreen( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomBlobManagerScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomBlobManagerScreen.kt index 7be384edf5..13069aa9df 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomBlobManagerScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomBlobManagerScreen.kt @@ -131,13 +131,13 @@ import com.vitorpamplona.amethyst.commons.resources.retry import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor import com.vitorpamplona.amethyst.commons.ui.theme.grayText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.playback.composable.VideoViewInner -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip56Reports.ReportType import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomBlobManagerViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomBlobManagerViewModel.kt index f05abc756b..9fdeb86075 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomBlobManagerViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomBlobManagerViewModel.kt @@ -25,13 +25,13 @@ import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.service.upload.BlossomClient import com.vitorpamplona.amethyst.commons.service.upload.BlossomPaymentException -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.blossom.BlossomMirrorQueue import com.vitorpamplona.amethyst.service.uploads.blossom.BlossomPaymentHandler import com.vitorpamplona.amethyst.service.uploads.blossom.PaymentPromptLedger -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip56Reports.ReportType import com.vitorpamplona.quartz.nipB7Blossom.BlossomPaymentProof diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomImportScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomImportScreen.kt index dc460a2fab..f6ff467acc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomImportScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomImportScreen.kt @@ -89,7 +89,7 @@ import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** Vibrant palette for server monograms; picked deterministically from the host name. */ private val ImportMonogramColors = diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomImportViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomImportViewModel.kt index 6b4479d039..c2653a636e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomImportViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomImportViewModel.kt @@ -25,12 +25,12 @@ import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.DEFAULT_MEDIA_SERVERS import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType import com.vitorpamplona.amethyst.commons.service.upload.BlossomClient -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.blossom.BlossomMirrorQueue -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nipB7Blossom.BlossomServerUrl import com.vitorpamplona.quartz.nipB7Blossom.BlossomUploadResult diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomServersViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomServersViewModel.kt index 757b5c7023..ed9db6061a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomServersViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomServersViewModel.kt @@ -25,11 +25,11 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.commons.mediaServers.MediaServerHealthProbe import com.vitorpamplona.amethyst.commons.mediaServers.ServerHealth +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType import com.vitorpamplona.amethyst.commons.service.http.IRoleBasedHttpClientBuilder -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.Rfc3986 import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/nestsServers/NestsServersScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/nestsServers/NestsServersScreen.kt index 9621ce58e5..d72db6f0ea 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/nestsServers/NestsServersScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/nestsServers/NestsServersScreen.kt @@ -82,8 +82,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.mediaServers.AllMediaServersScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.SettingsCategory import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.SettingsCategoryWithButton import com.vitorpamplona.quartz.nip01Core.tags.references.HttpUrlFormatter diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/nestsServers/NestsServersViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/nestsServers/NestsServersViewModel.kt index 5630acf173..e0b423d838 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/nestsServers/NestsServersViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/nestsServers/NestsServersViewModel.kt @@ -22,9 +22,9 @@ package com.vitorpamplona.amethyst.ui.actions.nestsServers import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.mediaServers.BlossomServersViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip53LiveActivities.nestsServers.NestsServer import com.vitorpamplona.quartz.nip53LiveActivities.nestsServers.NestsServersEvent import com.vitorpamplona.quartz.utils.Rfc3986 diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/paymentTargets/PaymentTargetsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/paymentTargets/PaymentTargetsScreen.kt index 3be6faab17..1ff0fb807a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/paymentTargets/PaymentTargetsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/paymentTargets/PaymentTargetsScreen.kt @@ -72,7 +72,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.SettingsCategory import com.vitorpamplona.quartz.nipA3PaymentTargets.PaymentTarget diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/paymentTargets/PaymentTargetsViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/paymentTargets/PaymentTargetsViewModel.kt index 4192f2599a..d7850cb550 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/paymentTargets/PaymentTargetsViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/paymentTargets/PaymentTargetsViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.actions.paymentTargets import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.payments.PaymentTargetTypes -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nipA3PaymentTargets.PaymentTarget import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/ShowImageUploadItem.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/ShowImageUploadItem.kt index 9064d7ecf7..d508587166 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/ShowImageUploadItem.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/ShowImageUploadItem.kt @@ -78,17 +78,17 @@ import com.vitorpamplona.amethyst.commons.resources.uploading_state_hashing import com.vitorpamplona.amethyst.commons.resources.uploading_state_ready import com.vitorpamplona.amethyst.commons.resources.uploading_state_server_processing import com.vitorpamplona.amethyst.commons.resources.uploading_state_uploading +import com.vitorpamplona.amethyst.commons.ui.components.AutoNonlazyGrid import com.vitorpamplona.amethyst.commons.ui.note.CloseIcon import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size40Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.playback.composable.VideoView import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadingState -import com.vitorpamplona.amethyst.ui.components.AutoNonlazyGrid -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/broadcast/BroadcastBanner.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/broadcast/BroadcastBanner.kt index 7d5519812c..37afb26a79 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/broadcast/BroadcastBanner.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/broadcast/BroadcastBanner.kt @@ -100,6 +100,7 @@ import com.vitorpamplona.amethyst.commons.service.broadcast.BroadcastStatus import com.vitorpamplona.amethyst.commons.service.broadcast.RelayResult import com.vitorpamplona.amethyst.commons.service.pow.PoWEstimator import com.vitorpamplona.amethyst.commons.service.pow.PoWJobState +import com.vitorpamplona.amethyst.commons.service.pow.powKindLabelRes import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn @@ -107,7 +108,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor import com.vitorpamplona.amethyst.commons.ui.theme.warningColor import com.vitorpamplona.amethyst.service.pow.deviceHashesPerSecond import com.vitorpamplona.amethyst.service.pow.formatTimeLeft -import com.vitorpamplona.amethyst.service.pow.powKindLabelRes import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent import com.vitorpamplona.quartz.nip18Reposts.RepostEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/broadcast/DisplayBroadcastProgress.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/broadcast/DisplayBroadcastProgress.kt index 1c9c1f1772..bb1266fd1f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/broadcast/DisplayBroadcastProgress.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/broadcast/DisplayBroadcastProgress.kt @@ -41,7 +41,7 @@ import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.model.BooleanType import com.vitorpamplona.amethyst.commons.service.broadcast.BroadcastEvent import com.vitorpamplona.amethyst.commons.service.pow.PoWJobState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallActivity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallActivity.kt index b0ed3e7385..f8e74da6e7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallActivity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallActivity.kt @@ -41,7 +41,7 @@ import androidx.core.content.ContextCompat import androidx.lifecycle.lifecycleScope import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.nipACWebRtcCalls.CallState -import com.vitorpamplona.amethyst.service.call.CallSessionBridge +import com.vitorpamplona.amethyst.commons.service.call.CallSessionBridge import com.vitorpamplona.amethyst.service.call.notification.CallNotifier import com.vitorpamplona.amethyst.service.relayClient.authCommand.compose.RelayAuthSubscription import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountFilterAssemblerSubscription diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallScreen.kt index b1f6c3cb6d..93d00acb4d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallScreen.kt @@ -72,8 +72,8 @@ import com.vitorpamplona.amethyst.commons.resources.call_incoming_video import com.vitorpamplona.amethyst.commons.resources.call_incoming_voice import com.vitorpamplona.amethyst.commons.resources.call_reject import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.call.session.CallSession -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.delay import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallWidgets.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallWidgets.kt index 94e0ca9fcf..329858a8e2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallWidgets.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallWidgets.kt @@ -52,12 +52,12 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.call_calling import com.vitorpamplona.amethyst.commons.resources.call_duration_hours_minutes_seconds import com.vitorpamplona.amethyst.commons.resources.call_duration_minutes_seconds +import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.note.BaseUserPicture -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import org.webrtc.RendererCommon import org.webrtc.SurfaceViewRenderer import org.webrtc.VideoTrack diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/ConnectedCallUI.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/ConnectedCallUI.kt index 965d5369ba..ca20c11a7a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/ConnectedCallUI.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/ConnectedCallUI.kt @@ -74,12 +74,12 @@ import com.vitorpamplona.amethyst.commons.resources.call_search_users import com.vitorpamplona.amethyst.commons.resources.call_speaker import com.vitorpamplona.amethyst.commons.resources.call_switch_camera import com.vitorpamplona.amethyst.commons.resources.call_unmute +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.call.AudioRoute import com.vitorpamplona.amethyst.ui.call.session.CallSession -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.delay import org.webrtc.VideoTrack diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/PipCallUI.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/PipCallUI.kt index f13e5535df..5027623d5d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/PipCallUI.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/PipCallUI.kt @@ -43,8 +43,8 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.commons.nipACWebRtcCalls.CallState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.call.session.CallSession -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.delay import org.webrtc.VideoTrack diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/session/CallSession.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/session/CallSession.kt index 6cfbd3fa28..ddb9520049 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/session/CallSession.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/session/CallSession.kt @@ -86,7 +86,7 @@ class CallSession( private val publishWrap: suspend (EphemeralGiftWrapEvent) -> Unit, private val signerProvider: suspend () -> com.vitorpamplona.quartz.nip01Core.signers.NostrSigner, localPubKey: HexKey, - private val settingsProvider: () -> com.vitorpamplona.amethyst.model.AccountSettings, + private val settingsProvider: () -> com.vitorpamplona.amethyst.commons.model.AccountSettings, ) : AutoCloseable { private var peerSessionMgr = PeerSessionManager(localPubKey) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AmethystRichText.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AmethystRichText.kt index 176ba467b5..c124b14cfe 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AmethystRichText.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AmethystRichText.kt @@ -21,22 +21,17 @@ package com.vitorpamplona.amethyst.ui.components import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists -import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.richtext.BlossomUriSegment import com.vitorpamplona.amethyst.commons.richtext.BuzzInviteLinkSegment -import com.vitorpamplona.amethyst.commons.richtext.CachedRichTextParser import com.vitorpamplona.amethyst.commons.richtext.CashuSegment import com.vitorpamplona.amethyst.commons.richtext.ClinkOfferSegment import com.vitorpamplona.amethyst.commons.richtext.ConcordInviteLinkSegment @@ -52,24 +47,26 @@ import com.vitorpamplona.amethyst.commons.richtext.RichTextViewerState import com.vitorpamplona.amethyst.commons.richtext.SecretEmoji import com.vitorpamplona.amethyst.commons.richtext.Segment import com.vitorpamplona.amethyst.commons.richtext.WithdrawSegment +import com.vitorpamplona.amethyst.commons.ui.components.BechLink import com.vitorpamplona.amethyst.commons.ui.components.ClickableBuzzInviteLink import com.vitorpamplona.amethyst.commons.ui.components.ClickableConcordInviteLink import com.vitorpamplona.amethyst.commons.ui.components.ClickableEmail import com.vitorpamplona.amethyst.commons.ui.components.ClickablePhone import com.vitorpamplona.amethyst.commons.ui.components.ClickableRelayGroupLink import com.vitorpamplona.amethyst.commons.ui.components.ClickableRelayUrl +import com.vitorpamplona.amethyst.commons.ui.components.ClickableUrlOrBlossom +import com.vitorpamplona.amethyst.commons.ui.components.ConcordInviteCard import com.vitorpamplona.amethyst.commons.ui.components.NowhereLinkCard +import com.vitorpamplona.amethyst.commons.ui.components.RichTextViewer +import com.vitorpamplona.amethyst.commons.ui.components.TagLink import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.commons.ui.richtext.LocalRichTextInteractions -import com.vitorpamplona.amethyst.commons.ui.richtext.LocalRichTextSegmentRenderer -import com.vitorpamplona.amethyst.commons.ui.richtext.RichTextInteractions +import com.vitorpamplona.amethyst.commons.ui.richtext.RichTextPlatform import com.vitorpamplona.amethyst.commons.ui.richtext.RichTextSegmentRenderer import com.vitorpamplona.amethyst.commons.ui.theme.HalfVertPadding +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.markdown.RenderContentAsMarkdown import com.vitorpamplona.amethyst.ui.note.creators.invoice.ClinkOfferPreview import com.vitorpamplona.amethyst.ui.note.creators.invoice.MayBeInvoicePreview -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.commons.ui.richtext.RichTextViewer as CommonsRichTextViewer /** * The Android implementation of the shared [RichTextSegmentRenderer] contract: it @@ -79,7 +76,7 @@ import com.vitorpamplona.amethyst.commons.ui.richtext.RichTextViewer as CommonsR * leaves need but that the cross-platform contract deliberately keeps out of its * method signatures. * - * Recreate one per [CommonsBackedRichTextViewer] call (it captures per-call state); + * Recreate one per [RichTextViewer] call (it captures per-call state); * it is cheap and [remember]ed against its inputs so the CompositionLocal doesn't * churn its readers. */ @@ -118,7 +115,7 @@ class AmethystRichTextSegmentRenderer( } } } else { - ClickableUrl(segment.segmentText, segment.segmentText) + ClickableUrlOrBlossom(segment.segmentText, segment.segmentText) } } @@ -193,7 +190,7 @@ class AmethystRichTextSegmentRenderer( url: String, displayText: String, modifier: Modifier, - ) = ClickableUrl(displayText, url) + ) = ClickableUrlOrBlossom(displayText, url) @Composable override fun Email( @@ -240,7 +237,7 @@ class AmethystRichTextSegmentRenderer( if (canPreview) { NowhereLinkCard(segment) } else { - ClickableUrl(segment.segmentText, segment.segmentText) + ClickableUrlOrBlossom(segment.segmentText, segment.segmentText) } } @@ -255,63 +252,37 @@ class AmethystRichTextSegmentRenderer( } /** - * Renders rich text through the shared cross-platform [CommonsRichTextViewer] core. - * This is the production plain-text path that [RichTextViewer] delegates to: it - * parses with the existing [CachedRichTextParser], keeps the markdown path native, - * and for plain rich text provides the Android segment renderer - * ([AmethystRichTextSegmentRenderer]) plus the universal interactions into the two - * CompositionLocals the core reads. - * - * The core renders text, custom emoji, and hashtags (with their shared inline - * icons) itself; every divergent segment routes back to Amethyst's existing - * leaves through the renderer. Note: url/email/phone open via the platform URI - * handler rather than Amethyst's per-type Clickable* composables, so their tap - * behavior is the generic open action (rendering is unchanged clickable text). + * Android's [RichTextPlatform]: its segment renderer ([AmethystRichTextSegmentRenderer]) and its + * markdown renderer. Installed in the app theme, so every screen's rich text gets them. */ -@Composable -fun CommonsBackedRichTextViewer( - content: String, - canPreview: Boolean, - quotesLeft: Int, - modifier: Modifier, - tags: ImmutableListOfLists, - backgroundColor: MutableState, - callbackUri: String? = null, - authorPubKey: String? = null, - accountViewModel: AccountViewModel, - nav: INav, -) { - Column(modifier = modifier) { - if (remember(content) { CachedRichTextParser.isMarkdown(content) }) { - RenderContentAsMarkdown(content, tags, canPreview, quotesLeft, backgroundColor, callbackUri, accountViewModel, nav) - return@Column - } +object AndroidRichTextPlatform : RichTextPlatform { + override fun segmentRenderer( + accountViewModel: AccountViewModel, + nav: INav, + backgroundColor: MutableState, + callbackUri: String?, + canPreview: Boolean, + ): RichTextSegmentRenderer = AmethystRichTextSegmentRenderer(accountViewModel, nav, backgroundColor, callbackUri, canPreview) - val state by remember(content, tags) { - mutableStateOf(CachedRichTextParser.parseText(content, tags, callbackUri, authorPubKey)) - } + @Composable + override fun Markdown( + content: String, + tags: ImmutableListOfLists, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + callbackUri: String?, + accountViewModel: AccountViewModel, + nav: INav, + ) = RenderContentAsMarkdown(content, tags, canPreview, quotesLeft, backgroundColor, callbackUri, accountViewModel, nav) - val renderer = - remember(accountViewModel, nav, backgroundColor, callbackUri, canPreview) { - AmethystRichTextSegmentRenderer(accountViewModel, nav, backgroundColor, callbackUri, canPreview) - } - - val interactions = - remember(nav) { - RichTextInteractions( - onClickHashtag = { nav.nav(Route.Hashtag(it.lowercase())) }, - ) - } - - CompositionLocalProvider( - LocalRichTextSegmentRenderer provides renderer, - LocalRichTextInteractions provides interactions, - ) { - CommonsRichTextViewer( - state = state, - canPreview = canPreview, - quotesLeft = quotesLeft, - ) - } - } + @Composable + override fun SecretMessage( + content: RichTextViewerState, + callbackUri: String?, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) = CoreSecretMessage(content, callbackUri, quotesLeft, backgroundColor, accountViewModel, nav) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt index 08537874f9..e9877987bb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/CashuRedeem.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.components -import android.content.Context import android.content.Intent import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row @@ -68,8 +67,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size18Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.cashu.CachedCashuParser -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip60Cashu.token.CashuToken import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.CancellationException @@ -131,7 +130,7 @@ fun CashuPreviewPreview() { ThemeComparisonColumn { CashuPreviewNew( token = CashuToken("token", "https://mint.example.com", 32400, listOf(), "sat", "Thanks for the coffee!"), - melt = { _, _, _ -> }, + melt = { _, _ -> }, toast = { _, _ -> }, ) } @@ -159,7 +158,7 @@ private fun cashuAmountLabel( @Composable fun CashuPreviewNew( token: CashuToken, - melt: (CashuToken, Context, (String, String) -> Unit) -> Unit, + melt: (CashuToken, (String, String) -> Unit) -> Unit, toast: (String, String) -> Unit, ) { val cashuStr = stringRes(Res.string.cashu) @@ -213,7 +212,7 @@ fun CashuPreviewNew( Button( onClick = { isRedeeming = true - melt(token, context) { title, message -> + melt(token) { title, message -> toast(title, message) isRedeeming = false } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt index ba2ab54aed..9ca86cece2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt @@ -35,10 +35,10 @@ import com.vitorpamplona.amethyst.commons.resources.error_dialog_pay_withdraw_er import com.vitorpamplona.amethyst.commons.resources.no_wallet_found import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.note.ErrorMessageDialog import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.note.ErrorMessageDialog +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.payViaIntent -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.lightning.LnWithdrawalUtil import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/FullScreenViewerChrome.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/FullScreenViewerChrome.kt index 96c0050c96..c4afdf88f1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/FullScreenViewerChrome.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/FullScreenViewerChrome.kt @@ -73,7 +73,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.Size15dp import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.ui.screen.loggedIn.saveMediaToGallery import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/GifVideoView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/GifVideoView.kt index 445c3ac47f..5fe03bb5a3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/GifVideoView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/GifVideoView.kt @@ -45,17 +45,22 @@ import coil3.asDrawable import coil3.compose.AsyncImagePainter import coil3.compose.SubcomposeAsyncImage import coil3.compose.SubcomposeAsyncImageContent +import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.gif +import com.vitorpamplona.amethyst.commons.ui.components.ClickableUrlOrBlossom +import com.vitorpamplona.amethyst.commons.ui.components.DisplayBlurHash +import com.vitorpamplona.amethyst.commons.ui.components.DisplayUrlWithLoadingSymbol import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation +import com.vitorpamplona.amethyst.commons.ui.components.WaitAndDisplay +import com.vitorpamplona.amethyst.commons.ui.components.mediaSizingModifier import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Font10SP import com.vitorpamplona.amethyst.commons.ui.theme.Size40dp import com.vitorpamplona.amethyst.commons.ui.theme.Size6dp import com.vitorpamplona.amethyst.commons.ui.theme.SmallBorder import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier -import com.vitorpamplona.amethyst.model.MediaAspectRatioCache -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag @Composable @@ -155,7 +160,7 @@ fun GifVideoView( } is AsyncImagePainter.State.Error -> { - ClickableUrl(urlText = videoUri, url = videoUri) + ClickableUrlOrBlossom(urlText = videoUri, url = videoUri) } else -> {} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ImageGallery.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ImageGallery.kt index cec3c9c52d..7f6eccf130 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ImageGallery.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ImageGallery.kt @@ -41,13 +41,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.commons.richtext.ImageGalleryParagraph import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.RichTextViewerState import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp -import com.vitorpamplona.amethyst.model.MediaAspectRatioCache -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.delay diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/InlineQuoteRenderer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/InlineQuoteRenderer.kt index b0ae8fab8e..728be96715 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/InlineQuoteRenderer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/InlineQuoteRenderer.kt @@ -21,44 +21,12 @@ package com.vitorpamplona.amethyst.ui.components import androidx.compose.material3.MaterialTheme -import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.compositionLocalOf -import androidx.compose.ui.graphics.Color -import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.components.InlineQuoteRenderer +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.note.types.ReplyRenderType import com.vitorpamplona.amethyst.commons.ui.theme.innerPostModifier -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.note.types.ReplyRenderType -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -/** - * Strategy for rendering a note quoted inline in another note's text (a - * `nostr:nevent1...`/`nostr:note1...` mention with preview budget left, or a - * legacy `#[index]` event tag). - * - * Both rich-text paths (plain and markdown) funnel through [DisplayFullNote], - * which reads [LocalInlineQuoteRenderer], so providing a different renderer - * re-skins inline quotes for a whole subtree without threading a parameter - * through the parser stack. Chat bubbles use this to keep a quoted chat - * message in the chat reply design instead of the default quoted-note card - * (see `chatInlineQuoteRenderer`). - * - * A renderer draws only the quoted note itself; any leftover characters - * around the mention stay with the caller ([DisplayFullNote]). - */ -fun interface InlineQuoteRenderer { - @Composable - fun Render( - note: Note, - quotesLeft: Int, - backgroundColor: MutableState, - accountViewModel: AccountViewModel, - nav: INav, - ) -} - -/** The quoted-note card used everywhere outside chats. */ +/** The quoted-note card used everywhere outside chats; the app installs it in its theme root. */ val DefaultInlineQuoteRenderer = InlineQuoteRenderer { note, quotesLeft, backgroundColor, accountViewModel, nav -> NoteCompose( @@ -72,5 +40,3 @@ val DefaultInlineQuoteRenderer = nav = nav, ) } - -val LocalInlineQuoteRenderer = compositionLocalOf { DefaultInlineQuoteRenderer } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt index 5087df059e..b94dcd5092 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt @@ -29,13 +29,17 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.MediaUrlPdf import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo +import com.vitorpamplona.amethyst.commons.ui.components.ClickableUrlOrBlossom import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.components.DisplayUrlWithLoadingSymbol import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewCard import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewState +import com.vitorpamplona.amethyst.commons.ui.components.WaitAndDisplay import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.HalfVertPadding +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.model.UrlCachedPreviewer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.screen.loggedIn.urlPreview @Composable fun LoadUrlPreview( @@ -46,7 +50,7 @@ fun LoadUrlPreview( nav: INav? = null, ) { if (!accountViewModel.settings.showUrlPreview()) { - ClickableUrl(urlText, url) + ClickableUrlOrBlossom(urlText, url) } else { LoadUrlPreviewDirect(url, urlText, callbackUri, accountViewModel, nav) } @@ -96,7 +100,7 @@ fun LoadUrlPreviewDirect( } else -> { - ClickableUrl(urlText, url) + ClickableUrlOrBlossom(urlText, url) } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RelayGroupCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RelayGroupCard.kt index c66949e508..d5d831ccd4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RelayGroupCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RelayGroupCard.kt @@ -62,10 +62,10 @@ import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncIma import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.LoadRelayGroupChannel +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.LoadRelayGroupChannel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import com.vitorpamplona.quartz.nip29RelayGroups.GroupInviteLink diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ReusableZapButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ReusableZapButton.kt index ca7a265089..24239668ff 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ReusableZapButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ReusableZapButton.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.components -import android.content.Context import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -47,6 +46,7 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.donate_now import com.vitorpamplona.amethyst.commons.resources.draft_note @@ -56,24 +56,23 @@ import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_ import com.vitorpamplona.amethyst.commons.resources.no_wallet_found import com.vitorpamplona.amethyst.commons.resources.no_zap_amount_setup_long_press_to_change import com.vitorpamplona.amethyst.commons.resources.thank_you +import com.vitorpamplona.amethyst.commons.service.ZapPaymentHandler import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled import com.vitorpamplona.amethyst.commons.ui.components.toasts.multiline.UserBasedErrorMessage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.ZapIcon import com.vitorpamplona.amethyst.commons.ui.note.ZappedIcon +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.navigateToReloadMint import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ModifierWidth3dp import com.vitorpamplona.amethyst.commons.ui.theme.Size14Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp -import com.vitorpamplona.amethyst.service.ZapPaymentHandler -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.UserFinderFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.ObserveZapIcon import com.vitorpamplona.amethyst.ui.note.ZapAmountChoicePopup import com.vitorpamplona.amethyst.ui.note.payViaIntent -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.OnchainZapSendDialog -import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.navigateToReloadMint import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.collections.immutable.ImmutableList @@ -138,7 +137,6 @@ fun ReusableZapButton( handleZapClick( baseNote = baseNote, accountViewModel = accountViewModel, - context = context, zapAmountChoices = config.zapAmountChoices, onZapStarts = { zapStartingTime = TimeUtils.now() }, onZappingProgress = { progress -> @@ -310,7 +308,6 @@ fun ReusableZapButton( private fun handleZapClick( baseNote: Note, accountViewModel: AccountViewModel, - context: Context, zapAmountChoices: List?, onZapStarts: () -> Unit, onZappingProgress: (Float) -> Unit, @@ -353,7 +350,6 @@ private fun handleZapClick( amount * 1000, null, "", - context, showErrorIfNoLnAddress = false, onError = onError, onProgress = { onZappingProgress(it) }, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextPlatformLeaves.kt similarity index 62% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextPlatformLeaves.kt index 38e6e84d96..ea1bc972ac 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextPlatformLeaves.kt @@ -22,21 +22,13 @@ package com.vitorpamplona.amethyst.ui.components import androidx.compose.foundation.border import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi -import androidx.compose.foundation.layout.FlowRow -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.text.InlineTextContent -import androidx.compose.foundation.text.appendInlineContent -import androidx.compose.material3.Icon import androidx.compose.material3.LocalTextStyle -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue @@ -47,30 +39,14 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.platform.LocalFontFamilyResolver -import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.TextMeasurer -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.text.withStyle import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.em import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.emojicoder.EmojiCoder import com.vitorpamplona.amethyst.commons.model.EmptyTagList import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists -import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route -import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.richtext.Base64Segment import com.vitorpamplona.amethyst.commons.richtext.BechSegment import com.vitorpamplona.amethyst.commons.richtext.BlossomUriSegment @@ -89,7 +65,6 @@ import com.vitorpamplona.amethyst.commons.richtext.InvoiceSegment import com.vitorpamplona.amethyst.commons.richtext.LinkSegment import com.vitorpamplona.amethyst.commons.richtext.MathSegment import com.vitorpamplona.amethyst.commons.richtext.NowhereLinkSegment -import com.vitorpamplona.amethyst.commons.richtext.ParagraphState import com.vitorpamplona.amethyst.commons.richtext.PdfSegment import com.vitorpamplona.amethyst.commons.richtext.PhoneSegment import com.vitorpamplona.amethyst.commons.richtext.RegularTextSegment @@ -102,6 +77,7 @@ import com.vitorpamplona.amethyst.commons.richtext.Segment import com.vitorpamplona.amethyst.commons.richtext.VideoSegment import com.vitorpamplona.amethyst.commons.richtext.WithdrawSegment import com.vitorpamplona.amethyst.commons.ui.components.AnimatedBorderTextCornerRadius +import com.vitorpamplona.amethyst.commons.ui.components.BechLink import com.vitorpamplona.amethyst.commons.ui.components.ClickableBuzzInviteLink import com.vitorpamplona.amethyst.commons.ui.components.ClickableConcordInviteLink import com.vitorpamplona.amethyst.commons.ui.components.ClickableEmail @@ -109,66 +85,29 @@ import com.vitorpamplona.amethyst.commons.ui.components.ClickablePhone import com.vitorpamplona.amethyst.commons.ui.components.ClickableRelayGroupLink import com.vitorpamplona.amethyst.commons.ui.components.ClickableRelayUrl import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary -import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.components.ClickableUrlOrBlossom +import com.vitorpamplona.amethyst.commons.ui.components.ConcordInviteCard +import com.vitorpamplona.amethyst.commons.ui.components.CreateClickableText +import com.vitorpamplona.amethyst.commons.ui.components.HashTag import com.vitorpamplona.amethyst.commons.ui.components.NowhereLinkCard +import com.vitorpamplona.amethyst.commons.ui.components.RenderCustomEmoji +import com.vitorpamplona.amethyst.commons.ui.components.RenderRegular +import com.vitorpamplona.amethyst.commons.ui.components.RenderTextParagraph +import com.vitorpamplona.amethyst.commons.ui.components.TagLink +import com.vitorpamplona.amethyst.commons.ui.components.measureSpaceWidth +import com.vitorpamplona.amethyst.commons.ui.components.rememberBlossomUriOpener import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.commons.ui.richtext.CreateClickableTextWithEmoji -import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji -import com.vitorpamplona.amethyst.commons.ui.richtext.HashtagIcon -import com.vitorpamplona.amethyst.commons.ui.richtext.checkForHashtagWithIcon -import com.vitorpamplona.amethyst.commons.ui.state.produceCachedState import com.vitorpamplona.amethyst.commons.ui.theme.CashuCardBorders import com.vitorpamplona.amethyst.commons.ui.theme.HalfVertPadding -import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.commons.ui.theme.inlinePlaceholder -import com.vitorpamplona.amethyst.commons.util.toShortDisplay -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.UserFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserDisplayNickname -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.service.uploads.blossom.bud10.openBlossomUriAsIntent -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.note.creators.invoice.ClinkOfferPreview import com.vitorpamplona.amethyst.ui.note.creators.invoice.MayBeInvoicePreview -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel -import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nipB7Blossom.BlossomUri import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -/** - * Renders Nostr rich text. The plain (non-markdown) path now runs through the - * cross-platform [com.vitorpamplona.amethyst.commons.ui.richtext.RichTextViewer] - * core via [CommonsBackedRichTextViewer]; this entry is kept so its ~55 call sites - * are untouched. The Android-specific markdown path stays here. - */ -@Composable -fun RichTextViewer( - content: String, - canPreview: Boolean, - quotesLeft: Int, - modifier: Modifier, - tags: ImmutableListOfLists, - backgroundColor: MutableState, - callbackUri: String? = null, - authorPubKey: String? = null, - accountViewModel: AccountViewModel, - nav: INav, -) = CommonsBackedRichTextViewer( - content = content, - canPreview = canPreview, - quotesLeft = quotesLeft, - modifier = modifier, - tags = tags, - backgroundColor = backgroundColor, - callbackUri = callbackUri, - authorPubKey = authorPubKey, - accountViewModel = accountViewModel, - nav = nav, -) - @Preview @Composable fun RenderStrangeNamePreview() { @@ -252,7 +191,7 @@ fun RenderRegularPreview() { // is HashIndexUserSegment -> TagLink(word, accountViewModel, nav) // is HashIndexEventSegment -> TagLink(word, true, backgroundColorState, accountViewModel, nav) is LinkSegment -> { - ClickableUrl(word.segmentText, word.segmentText) + ClickableUrlOrBlossom(word.segmentText, word.segmentText) } is RegularTextSegment -> { @@ -293,7 +232,7 @@ fun RenderRegularPreview2() { // is HashIndexUserSegment -> TagLink(word, accountViewModel, nav) // is HashIndexEventSegment -> TagLink(word, true, backgroundColorState, accountViewModel, nav) - is LinkSegment -> ClickableUrl(word.segmentText, word.segmentText) + is LinkSegment -> ClickableUrlOrBlossom(word.segmentText, word.segmentText) is RegularTextSegment -> Text(word.segmentText) @@ -356,88 +295,6 @@ fun RenderRegularPreview3() { } } -@Composable -fun RenderTextParagraph( - paragraph: ParagraphState, - spaceWidth: Dp, - modifier: Modifier, - renderWord: @Composable (word: Segment) -> Unit, -) { - FlowRow( - modifier = modifier, - horizontalArrangement = Arrangement.spacedBy(spaceWidth), - // Center items on the cross axis so a taller item (an equation, whose image - // is taller than a text line) sits centered on the line instead of hanging - // below the baseline. No-op for the common all-text row. - itemVerticalAlignment = Alignment.CenterVertically, - ) { - paragraph.words.forEach { word -> - renderWord(word) - } - } -} - -@OptIn(ExperimentalLayoutApi::class) -@Composable -fun RenderRegular( - content: String, - tags: ImmutableListOfLists, - callbackUri: String? = null, - authorPubKey: String? = null, - renderParagraph: @Composable (ParagraphState, state: RichTextViewerState, Dp, modifier: Modifier) -> Unit, -) { - val state by remember(content, tags) { mutableStateOf(CachedRichTextParser.parseText(content, tags, callbackUri, authorPubKey)) } - - val spaceWidth = measureSpaceWidth(LocalTextStyle.current) - - val currentTextStyle = LocalTextStyle.current - - val textStyle = - remember(currentTextStyle) { - currentTextStyle.copy( - lineHeight = 1.3.em, - ) - } - - Column { - // FlowRow doesn't work well with paragraphs. So we need to split them - state.paragraphs.forEach { paragraph -> - CompositionLocalProvider( - LocalLayoutDirection provides - if (paragraph.isRTL) { - LayoutDirection.Rtl - } else { - LayoutDirection.Ltr - }, - LocalTextStyle provides textStyle, - ) { - renderParagraph( - paragraph, - state, - spaceWidth, - Modifier.align(if (paragraph.isRTL) Alignment.End else Alignment.Start), - ) - } - } - } -} - -@Composable -fun measureSpaceWidth(textStyle: TextStyle): Dp { - val fontFamilyResolver = LocalFontFamilyResolver.current - val density = LocalDensity.current - val layoutDirection = LocalLayoutDirection.current - - return remember(fontFamilyResolver, density, layoutDirection, textStyle) { - val widthPx = - TextMeasurer(fontFamilyResolver, density, layoutDirection, 1) - .measure(" ", textStyle) - .size - .width - with(density) { widthPx.toDp() } - } -} - @Composable private fun RenderWordWithoutPreview( word: Segment, @@ -448,17 +305,17 @@ private fun RenderWordWithoutPreview( ) { when (word) { // Don't preview Images - is ImageSegment -> ClickableUrl(word.segmentText, word.segmentText) + is ImageSegment -> ClickableUrlOrBlossom(word.segmentText, word.segmentText) // Don't preview Videos - is VideoSegment -> ClickableUrl(word.segmentText, word.segmentText) + is VideoSegment -> ClickableUrlOrBlossom(word.segmentText, word.segmentText) // Don't preview PDFs - is PdfSegment -> ClickableUrl(word.segmentText, word.segmentText) + is PdfSegment -> ClickableUrlOrBlossom(word.segmentText, word.segmentText) - is LinkSegment -> ClickableUrl(word.segmentText, word.segmentText) + is LinkSegment -> ClickableUrlOrBlossom(word.segmentText, word.segmentText) - is NowhereLinkSegment -> ClickableUrl(word.segmentText, word.segmentText) + is NowhereLinkSegment -> ClickableUrlOrBlossom(word.segmentText, word.segmentText) is EmojiSegment -> RenderCustomEmoji(word.segmentText, state) @@ -588,13 +445,13 @@ fun ClickableBlossomUri( blossomUri: String, accountViewModel: AccountViewModel, ) { - val context = LocalContext.current + val blossomOpener = rememberBlossomUriOpener() ClickableTextPrimary( text = remember { BlossomUri.parse(blossomUri)?.filename() ?: blossomUri }, maxLines = 1, overflow = TextOverflow.MiddleEllipsis, - onClick = { openBlossomUriAsIntent(context, blossomUri, accountViewModel.toastManager::toast) }, + onClick = { blossomOpener.open(blossomUri) { title, message -> accountViewModel.toastManager.toast(title, message) } }, ) } @@ -616,7 +473,7 @@ fun BlossomUriRendererNoPreview( val serverResult = serverResultState.value if (serverResult != null && serverResult.serverUrl.isNotBlank()) { - ClickableUrl(serverResult.uri.filename(), serverResult.serverUrl) + ClickableUrlOrBlossom(serverResult.uri.filename(), serverResult.serverUrl) } else { ClickableBlossomUri(word, accountViewModel) } @@ -637,77 +494,7 @@ private fun ZoomableContentView( @Composable private fun NoProtocolUrlRenderer(url: String) { - ClickableUrl(url, "https://$url") -} - -@Composable -fun RenderCustomEmoji( - word: String, - state: RichTextViewerState, -) { - CreateTextWithEmoji( - text = word, - emojis = state.customEmoji, - ) -} - -@Composable -fun BechLink( - word: String, - canPreview: Boolean, - quotesLeft: Int, - backgroundColor: MutableState, - accountViewModel: AccountViewModel, - nav: INav, -) { - val loadedLink by produceCachedState(cache = accountViewModel.bechLinkCache, key = word) - - val baseNote = loadedLink?.baseNote - - // Preload the placeholder's author NIP-65 outbox so a missing quoted event can be fetched from there. - baseNote?.author?.let { author -> - UserFinderFilterAssemblerSubscription(author, accountViewModel) - } - - if (canPreview && quotesLeft > 0 && baseNote != null) { - Row { - DisplayFullNote( - note = baseNote, - extraChars = loadedLink?.nip19?.additionalChars?.ifBlank { null }, - quotesLeft = quotesLeft, - backgroundColor = backgroundColor, - accountViewModel = accountViewModel, - nav = nav, - ) - } - } else if (loadedLink?.nip19 != null) { - ClickableRoute(word, loadedLink?.nip19!!, accountViewModel, nav) - } else { - val text = - remember(word) { - if (word.length > 16) { - word.replaceRange(8, word.length - 8, ":") - } else { - word - } - } - - Text(text = text, maxLines = 1) - } -} - -@Composable -fun DisplayFullNote( - note: Note, - extraChars: String?, - quotesLeft: Int, - backgroundColor: MutableState, - accountViewModel: AccountViewModel, - nav: INav, -) { - LocalInlineQuoteRenderer.current.Render(note, quotesLeft, backgroundColor, accountViewModel, nav) - - extraChars?.let { Text(it) } + ClickableUrlOrBlossom(url, "https://$url") } @Composable @@ -803,197 +590,3 @@ fun CoreSecretMessage( } } } - -@Composable -fun HashTag( - segment: HashTagSegment, - nav: INav, -) { - val primary = MaterialTheme.colorScheme.primary - val background = MaterialTheme.colorScheme.onBackground - val hashtagIcon: HashtagIcon? = checkForHashtagWithIcon(segment.hashtag) - - val annotatedTermsString = - remember(segment.segmentText) { - buildAnnotatedString { - withStyle(SpanStyle(color = primary)) { - pushStringAnnotation("routeToHashtag", "") - append("#${segment.hashtag}") - pop() - } - - if (hashtagIcon != null) { - withStyle(SpanStyle(color = primary)) { - pushStringAnnotation("routeToHashtag", "") - appendInlineContent("inlineContent", "[icon]") - pop() - } - } - - segment.extras?.let { withStyle(SpanStyle(color = background)) { append(it) } } - } - } - - Text( - text = annotatedTermsString, - modifier = - remember { - Modifier.clickable { - nav.nav(Route.Hashtag(segment.hashtag.lowercase())) - } - }, - inlineContent = - if (hashtagIcon != null) { - mapOf("inlineContent" to inlineIcon(hashtagIcon)) - } else { - emptyMap() - }, - ) -} - -@Composable -private fun inlineIcon(hashtagIcon: HashtagIcon) = - InlineTextContent(inlinePlaceholder) { - Icon( - imageVector = hashtagIcon.icon, - contentDescription = hashtagIcon.description, - tint = Color.Unspecified, - modifier = hashtagIcon.modifier, - ) - } - -@Composable -fun TagLink( - word: HashIndexUserSegment, - accountViewModel: AccountViewModel, - nav: INav, -) { - LoadUser(baseUserHex = word.hex) { - if (it == null) { - Text(text = word.segmentText) - } else { - Row { - DisplayUserFromTag(it, accountViewModel, nav) - word.extras?.let { it2 -> - Text(text = it2) - } - } - } - } -} - -@Composable -fun LoadNote( - baseNoteHex: String, - content: @Composable (Note?) -> Unit, -) { - var note by - remember(baseNoteHex) { mutableStateOf(LocalCache.getNoteIfExists(baseNoteHex)) } - - if (note == null) { - LaunchedEffect(key1 = baseNoteHex) { - note = LocalCache.checkGetOrCreateNote(baseNoteHex) - } - } - - content(note) -} - -@Composable -fun TagLink( - word: HashIndexEventSegment, - canPreview: Boolean, - quotesLeft: Int, - backgroundColor: MutableState, - accountViewModel: AccountViewModel, - nav: INav, -) { - LoadNote(baseNoteHex = word.hex) { - if (it == null) { - Text(text = remember { word.segmentText.toShortDisplay() }) - } else { - Row { - DisplayNoteFromTag( - it, - word.extras, - canPreview, - quotesLeft, - accountViewModel, - backgroundColor, - nav, - ) - } - } - } -} - -@Preview -@Composable -fun DisplayNoteFromTagPreview() { - val dummyPost = - TextNoteEvent( - id = "0b6d941c46411a95edb1c93da7ad6ca26370497d8c7b7d621f5cb59f48841bad", - pubKey = "6dd3b72e325da7383b275eef1c66131ba4664326e162bc060527509b4e33ae43", - createdAt = 1753988264, - tags = emptyArray(), - content = "test", - sig = "ec39e60722a083cccbd2d82d2827e13f5499fa7cbcedac5b76011a844c077473adb629d50d01fab147835ac6c8a3d5ba9aaddd87d6723f0c3c864b9119fc4356", - ) - - LocalCache.justConsume(dummyPost, null, true) - val note = LocalCache.getOrCreateNote(dummyPost.id) - - ThemeComparisonColumn( - toPreview = { - ClickableTextPrimary( - text = "@${note.idNote().toShortDisplay()}", - onClick = { }, - ) - }, - ) -} - -@Composable -private fun DisplayNoteFromTag( - baseNote: Note, - addedChars: String?, - canPreview: Boolean, - quotesLeft: Int, - accountViewModel: AccountViewModel, - backgroundColor: MutableState, - nav: INav, -) { - if (canPreview && quotesLeft > 0) { - LocalInlineQuoteRenderer.current.Render(baseNote, quotesLeft, backgroundColor, accountViewModel, nav) - } else { - ClickableTextPrimary( - text = "@${baseNote.idNote().toShortDisplay()}", - onClick = { routeFor(baseNote, accountViewModel.account)?.let { nav.nav(it) } }, - ) - } - - addedChars?.ifBlank { null }?.let { Text(text = it) } -} - -@Composable -private fun DisplayUserFromTag( - baseUser: User, - accountViewModel: AccountViewModel, - nav: INav, -) { - val meta by observeUserInfo(baseUser, accountViewModel) - val nickname by observeUserDisplayNickname(baseUser, accountViewModel) - val petName = nickname?.petName - - CrossfadeIfEnabled(targetState = meta, label = "DisplayUserFromTag") { - Row { - CreateClickableTextWithEmoji( - clickablePart = remember(meta, petName) { petName ?: it?.info?.bestName() ?: baseUser.pubkeyDisplayHex() }, - maxLines = 1, - route = remember(baseUser) { routeFor(baseUser) }, - nav = nav, - tags = if (petName != null) nickname?.tags else it?.tags, - ) - } - } -} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt index 3d9d867150..fbb54dbea1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt @@ -65,6 +65,7 @@ import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.core.net.toUri import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.failed_to_save_the_image import com.vitorpamplona.amethyst.commons.resources.failed_to_save_the_pdf @@ -80,17 +81,17 @@ import com.vitorpamplona.amethyst.commons.richtext.MediaUrlContent import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.MediaUrlPdf import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo +import com.vitorpamplona.amethyst.commons.richtext.localJavaFile import com.vitorpamplona.amethyst.commons.ui.components.SlidingCarousel import com.vitorpamplona.amethyst.commons.ui.components.getActivityWindow import com.vitorpamplona.amethyst.commons.ui.components.getDialogWindow import com.vitorpamplona.amethyst.commons.ui.components.rememberViewerControlsVisibility import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier -import com.vitorpamplona.amethyst.model.MediaAspectRatioCache +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.playback.composable.VideoViewInner import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.isHlsMedia import com.vitorpamplona.amethyst.ui.actions.MediaSaverToDisk -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.filter @@ -424,7 +425,7 @@ internal suspend fun saveMediaToGallery( }, ) } else if (content is MediaPreloadedContent) { - content.localFile?.let { + content.localJavaFile?.let { MediaSaverToDisk.save( it, content.mimeType, @@ -566,7 +567,7 @@ private fun RenderImageOrVideo( Modifier.fillMaxWidth() } - content.localFile?.let { + content.localJavaFile?.let { val ratio = content.dim?.aspectRatioOrNull() ?: MediaAspectRatioCache.get(it.toUri().toString()) val modifier = diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index 9c064731ca..4d70f3f355 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -24,14 +24,10 @@ import android.content.Context import android.content.Intent import android.widget.Toast import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.AnimatedVisibilityScope import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.IntrinsicSize -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size @@ -39,7 +35,6 @@ import androidx.compose.foundation.layout.width import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState @@ -59,15 +54,8 @@ import androidx.compose.ui.layout.boundsInWindow import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalUriHandler -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.buildAnnotatedString -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.text.withStyle -import androidx.compose.ui.unit.dp import androidx.core.net.toUri import androidx.lifecycle.viewModelScope -import coil3.compose.AsyncImage import coil3.compose.AsyncImagePainter import coil3.compose.SubcomposeAsyncImage import coil3.compose.SubcomposeAsyncImageContent @@ -75,9 +63,9 @@ import coil3.request.ImageRequest import coil3.size.Size import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.vitorpamplona.amethyst.Amethyst -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.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.add_media_to_gallery import com.vitorpamplona.amethyst.commons.resources.copy_the_note_id_to_the_clipboard @@ -91,6 +79,7 @@ import com.vitorpamplona.amethyst.commons.resources.media_actions_dialog_title import com.vitorpamplona.amethyst.commons.resources.media_added import com.vitorpamplona.amethyst.commons.resources.media_added_to_profile_gallery import com.vitorpamplona.amethyst.commons.resources.media_download_has_started_toast +import com.vitorpamplona.amethyst.commons.resources.original import com.vitorpamplona.amethyst.commons.resources.share_image import com.vitorpamplona.amethyst.commons.resources.share_video import com.vitorpamplona.amethyst.commons.resources.unable_to_share_image @@ -105,34 +94,39 @@ import com.vitorpamplona.amethyst.commons.richtext.MediaUrlPdf import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.commons.richtext.isAnimatedMediaUrl -import com.vitorpamplona.amethyst.commons.service.image.placeholderModel +import com.vitorpamplona.amethyst.commons.richtext.localJavaFile +import com.vitorpamplona.amethyst.commons.ui.components.BlurhashBackdrop +import com.vitorpamplona.amethyst.commons.ui.components.ClickableUrlOrBlossom +import com.vitorpamplona.amethyst.commons.ui.components.ContentWarningGate import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.components.DisplayBlurHash +import com.vitorpamplona.amethyst.commons.ui.components.DisplayUrlWithLoadingSymbol +import com.vitorpamplona.amethyst.commons.ui.components.ImageUrlWithDownloadButton import com.vitorpamplona.amethyst.commons.ui.components.InformationDialog import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation import com.vitorpamplona.amethyst.commons.ui.components.M3ActionDialog import com.vitorpamplona.amethyst.commons.ui.components.M3ActionRow import com.vitorpamplona.amethyst.commons.ui.components.M3ActionSection +import com.vitorpamplona.amethyst.commons.ui.components.WaitAndDisplay +import com.vitorpamplona.amethyst.commons.ui.components.mediaSizingModifier import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.loadStringRes +import com.vitorpamplona.amethyst.commons.ui.note.BlankNote import com.vitorpamplona.amethyst.commons.ui.note.DownloadForOfflineIcon +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp -import com.vitorpamplona.amethyst.commons.ui.theme.Size24dp import com.vitorpamplona.amethyst.commons.ui.theme.Size30Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size40dp import com.vitorpamplona.amethyst.commons.ui.theme.Size6dp import com.vitorpamplona.amethyst.commons.ui.theme.Size75dp import com.vitorpamplona.amethyst.commons.ui.theme.hashVerifierMark import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier -import com.vitorpamplona.amethyst.model.MediaAspectRatioCache +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.images.BlossomFetcher import com.vitorpamplona.amethyst.service.playback.composable.VideoView -import com.vitorpamplona.amethyst.service.uploads.blossom.bud10.openBlossomUriAsIntent import com.vitorpamplona.amethyst.ui.components.pdf.PdfPreviewCard import com.vitorpamplona.amethyst.ui.components.pdf.PdfViewerDialog -import com.vitorpamplona.amethyst.ui.note.BlankNote -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.screen.loggedIn.saveMediaToGallery import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip19Bech32.Nip19Parser import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent @@ -152,7 +146,6 @@ import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.coroutines.executeAsync import okio.sink -import org.jetbrains.compose.resources.StringResource import java.io.File import java.io.IOException @@ -290,7 +283,7 @@ fun ZoomableContentView( is MediaLocalImage -> { if (content.isAnimatedMedia()) { - content.localFile?.let { + content.localJavaFile?.let { GifVideoView( videoUri = it.toUri().toString(), contentDescription = content.description, @@ -318,7 +311,7 @@ fun ZoomableContentView( } is MediaLocalVideo -> { - content.localFile?.let { + content.localJavaFile?.let { Box( modifier = Modifier.fillMaxWidth().then(boundsTrackingModifier), contentAlignment = Alignment.Center, @@ -400,19 +393,19 @@ fun LocalImageView( ) } - val ratio = remember(content) { content.dim?.aspectRatioOrNull() ?: MediaAspectRatioCache.get(content.localFile.toString()) } + val ratio = remember(content) { content.dim?.aspectRatioOrNull() ?: MediaAspectRatioCache.get(content.localJavaFile.toString()) } val context = LocalContext.current val imageModel = if (fullResolution) { - remember(content.localFile, context) { + remember(content.localJavaFile, context) { ImageRequest .Builder(context) - .data(content.localFile) + .data(content.localJavaFile) .size(Size.ORIGINAL) .build() } } else { - content.localFile + content.localJavaFile } CrossfadeIfEnabled(targetState = showImage.value, contentAlignment = Alignment.Center) { imageVisible -> if (imageVisible) { @@ -466,7 +459,7 @@ fun LocalImageView( SideEffect { val drawable = (state as AsyncImagePainter.State.Success).result.image - MediaAspectRatioCache.add(content.localFile.toString(), drawable.width, drawable.height) + MediaAspectRatioCache.add(content.localJavaFile.toString(), drawable.width, drawable.height) } content.isVerified?.let { @@ -598,7 +591,7 @@ fun UrlImageView( } is AsyncImagePainter.State.Error -> { - ClickableUrl(urlText = "${content.url} ", url = content.url) + ClickableUrlOrBlossom(urlText = "${content.url} ", url = content.url) } is AsyncImagePainter.State.Success -> { @@ -644,71 +637,6 @@ fun UrlImageView( } } -@Composable -fun ImageUrlWithDownloadButton( - url: String, - showImage: MutableState, -) { - val uri = LocalUriHandler.current - - val primary = MaterialTheme.colorScheme.primary - val background = MaterialTheme.colorScheme.onBackground - - val regularText = remember { SpanStyle(color = background) } - val clickableTextStyle = remember { SpanStyle(color = primary) } - - val annotatedTermsString = - remember { - buildAnnotatedString { - withStyle(clickableTextStyle) { - pushStringAnnotation("routeToImage", "") - append("$url ") - pop() - } - - withStyle(clickableTextStyle) { - pushStringAnnotation("routeToImage", "") - pop() - } - - withStyle(regularText) { append(" ") } - } - } - - val pressIndicator = - remember { - Modifier - .fillMaxWidth() - .clickable { runCatching { uri.openUri(url) } } - } - - Row( - modifier = - Modifier - .width(IntrinsicSize.Max), - horizontalArrangement = Arrangement.spacedBy(2.dp), - ) { - Text( - text = annotatedTermsString, - modifier = - pressIndicator - .weight(1f, fill = false), - overflow = TextOverflow.Ellipsis, - maxLines = 1, - ) - InlineDownloadIcon(showImage) - } -} - -@Composable -private fun InlineDownloadIcon(showImage: MutableState) = - IconButton( - modifier = Modifier.size(Size20dp), - onClick = { showImage.value = true }, - ) { - DownloadForOfflineIcon(Size24dp) - } - @Composable fun ShowHashAnimated( content: MediaUrlImage, @@ -760,161 +688,6 @@ fun BaseMediaContent.isAnimatedMedia(): Boolean = false } -@Composable -fun WaitAndDisplay(content: @Composable (AnimatedVisibilityScope.() -> Unit)) { - val visible = remember { mutableStateOf(false) } - - LaunchedEffect(Unit) { - delay(200) - visible.value = true - } - - AnimatedVisibility( - visible = visible.value, - enter = fadeIn(), - exit = fadeOut(), - content = content, - ) -} - -@Composable -fun DisplayUrlWithLoadingSymbol( - content: BaseMediaContent, - onError: (StringResource, StringResource) -> Unit = { _, _ -> }, -) { - val uri = LocalUriHandler.current - - val primary = MaterialTheme.colorScheme.primary - val background = MaterialTheme.colorScheme.onBackground - - val regularText = remember { SpanStyle(color = background) } - val clickableTextStyle = remember { SpanStyle(color = primary) } - - val context = LocalContext.current - - val annotatedTermsString = - remember { - buildAnnotatedString { - if (content is MediaUrlContent) { - withStyle(clickableTextStyle) { - pushStringAnnotation("routeToImage", "") - append(content.url + " ") - pop() - } - } else { - withStyle(regularText) { append("Loading content...") } - } - - withStyle(clickableTextStyle) { - pushStringAnnotation("routeToImage", "") - pop() - } - - withStyle(regularText) { append(" ") } - } - } - - val pressIndicator = - remember { - if (content is MediaUrlContent) { - Modifier.clickable { - if (content.url.startsWith("blossom:")) { - openBlossomUriAsIntent(context, content.url, onError) - } else { - runCatching { uri.openUri(content.url) } - } - } - } else { - Modifier - } - } - - Row( - modifier = - Modifier - .width(IntrinsicSize.Max), - horizontalArrangement = Arrangement.spacedBy(2.dp), - ) { - Text( - text = annotatedTermsString, - modifier = pressIndicator.weight(1f, fill = false), - overflow = TextOverflow.MiddleEllipsis, - maxLines = 1, - ) - InlineLoadingIcon() - } -} - -@Composable -fun DisplayUrlWithLoadingSymbol( - url: String, - onError: (StringResource, StringResource) -> Unit = { _, _ -> }, -) { - val uri = LocalUriHandler.current - - val primary = MaterialTheme.colorScheme.primary - val annotatedTermsString = - remember { - buildAnnotatedString { - withStyle(SpanStyle(color = primary)) { - pushStringAnnotation("routeToImage", "") - append("$url ") - pop() - } - } - } - - val context = LocalContext.current - - val pressIndicator = - remember { - Modifier.clickable { - if (url.startsWith("blossom:")) { - openBlossomUriAsIntent(context, url, onError) - } else { - runCatching { - uri.openUri(url) - } - } - } - } - - Row( - modifier = Modifier.width(IntrinsicSize.Max), - horizontalArrangement = Arrangement.spacedBy(2.dp), - ) { - Text( - text = annotatedTermsString, - modifier = pressIndicator.weight(1f, fill = false), - overflow = TextOverflow.Ellipsis, - maxLines = 1, - ) - InlineLoadingIcon() - } -} - -@Composable -private fun InlineLoadingIcon() = LoadingAnimation() - -@Composable -fun DisplayBlurHash( - blurhash: String?, - description: String?, - contentScale: ContentScale, - modifier: Modifier, - thumbhash: String? = null, -) { - val model = - placeholderModel(thumbhash, blurhash) ?: return - - AsyncImage( - model = model, - contentDescription = description, - contentScale = contentScale, - modifier = modifier, - ) -} - @Composable fun ShareMediaAction( accountViewModel: AccountViewModel, @@ -938,7 +711,7 @@ fun ShareMediaAction( } else if (content is MediaPreloadedContent) { ShareMediaAction( popupExpanded = popupExpanded, - videoUri = content.localFile?.toUri().toString(), + videoUri = content.localJavaFile?.toUri().toString(), postNostrUri = content.uri, blurhash = content.blurhash, dim = content.dim, @@ -1082,7 +855,7 @@ fun ShareMediaAction( } is MediaLocalVideo -> { - content.localFile?.let { localFile -> + content.localJavaFile?.let { localFile -> M3ActionRow(icon = MaterialSymbols.Share, text = stringRes(Res.string.share_video)) { accountViewModel.viewModelScope.launch { shareLocalVideoFile(context, localFile, mimeType) } onDismiss() @@ -1293,7 +1066,7 @@ private fun HashVerificationSymbol(verifiedHash: Boolean) { }, ) { Icon( - painter = painterRes(R.drawable.original, 1), + painter = painterRes(Res.drawable.original, 1), contentDescription = stringRes(id = Res.string.hash_verification_passed), modifier = Size30Modifier, tint = MaterialTheme.colorScheme.primary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt index ec7489ccfc..f332aa5ba3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt @@ -34,21 +34,21 @@ import com.halilibo.richtext.ui.MediaRenderer import com.halilibo.richtext.ui.string.InlineContent import com.halilibo.richtext.ui.string.RichTextString import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.RichTextParser +import com.vitorpamplona.amethyst.commons.ui.components.DisplayFullNote +import com.vitorpamplona.amethyst.commons.ui.components.DisplayUser import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.richtext.HashtagIcon import com.vitorpamplona.amethyst.commons.ui.richtext.checkForHashtagWithIcon import com.vitorpamplona.amethyst.commons.ui.theme.Font17SP import com.vitorpamplona.amethyst.commons.ui.theme.Size17Modifier -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.components.DisplayFullNote -import com.vitorpamplona.amethyst.ui.components.DisplayUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.LoadedBechLink import com.vitorpamplona.amethyst.ui.components.LoadUrlPreview import com.vitorpamplona.amethyst.ui.components.ZoomableContentView import com.vitorpamplona.amethyst.ui.fragmentHashtagOrNull -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.LoadedBechLink import com.vitorpamplona.quartz.nip19Bech32.entities.NAddress import com.vitorpamplona.quartz.nip19Bech32.entities.NEmbed import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/RenderContentAsMarkdown.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/RenderContentAsMarkdown.kt index 2b0d73753f..ba24f0c0bd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/RenderContentAsMarkdown.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/RenderContentAsMarkdown.kt @@ -49,9 +49,9 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.MarkdownTextStyle import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow import com.vitorpamplona.amethyst.commons.ui.theme.markdownStyle +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.model.UrlCachedPreviewer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.amethyst.ui.uriToRoute import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent import com.vitorpamplona.quartz.nip23LongContent.LongFormContentEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/namecoin/NamecoinResolutionRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/namecoin/NamecoinResolutionRow.kt index 6d43336b09..c49bffebb1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/namecoin/NamecoinResolutionRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/namecoin/NamecoinResolutionRow.kt @@ -51,8 +51,8 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.nip05DnsIdentifiers.namecoin.NamecoinResolveState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinResolveOutcome import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay @@ -101,7 +101,7 @@ fun mapOutcomeToResolveState(outcome: NamecoinResolveOutcome): NamecoinResolveSt /** * Lightweight syntactic check: does this look like something we should * route to Namecoin? Mirrors [com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinNameResolver.isNamecoinIdentifier] - * but tolerates a leading `@` (matches the dropdown's [com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState.userSearchTermOrNull]). + * but tolerates a leading `@` (matches the dropdown's [com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState.userSearchTermOrNull]). * * Accepted shapes: * - `host.bit` and `user@host.bit` (domain namespace) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/pdf/PdfPreviewCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/pdf/PdfPreviewCard.kt index 6e218e60c6..3349b6198c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/pdf/PdfPreviewCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/pdf/PdfPreviewCard.kt @@ -46,8 +46,10 @@ import androidx.compose.ui.platform.LocalWindowInfo import androidx.core.graphics.createBitmap import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.commons.richtext.MediaUrlPdf import com.vitorpamplona.amethyst.commons.service.pdf.PdfFetcher +import com.vitorpamplona.amethyst.commons.ui.components.ClickableUrlOrBlossom import com.vitorpamplona.amethyst.commons.ui.components.FileAttachmentRow import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer @@ -55,10 +57,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size40dp import com.vitorpamplona.amethyst.commons.ui.theme.Size6dp import com.vitorpamplona.amethyst.commons.ui.theme.innerPostModifier import com.vitorpamplona.amethyst.commons.util.extractFilename -import com.vitorpamplona.amethyst.model.MediaAspectRatioCache -import com.vitorpamplona.amethyst.ui.components.ClickableUrl +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.ShareMediaAction -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException @@ -192,7 +192,7 @@ private fun LoadedPdfPreviewCard( } is PdfLoadState.Failed -> { - ClickableUrl(urlText = content.url, url = content.url) + ClickableUrlOrBlossom(urlText = content.url, url = content.url) } is PdfLoadState.Ready -> { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/pdf/PdfViewerDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/pdf/PdfViewerDialog.kt index 4376d12716..4974b016e7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/pdf/PdfViewerDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/pdf/PdfViewerDialog.kt @@ -68,12 +68,12 @@ import com.vitorpamplona.amethyst.commons.ui.components.getDialogWindow import com.vitorpamplona.amethyst.commons.ui.components.rememberViewerControlsVisibility import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.ImmersiveSystemBarsEffect import com.vitorpamplona.amethyst.ui.components.ViewerBackButton import com.vitorpamplona.amethyst.ui.components.ViewerControlsRow import com.vitorpamplona.amethyst.ui.components.ViewerSaveToGalleryButton import com.vitorpamplona.amethyst.ui.components.ViewerShareButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/toasts/DisplayErrorMessages.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/toasts/DisplayErrorMessages.kt index c17b98d42c..ed6b6caa14 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/toasts/DisplayErrorMessages.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/toasts/DisplayErrorMessages.kt @@ -32,8 +32,8 @@ import com.vitorpamplona.amethyst.commons.ui.components.toasts.ToastManager import com.vitorpamplona.amethyst.commons.ui.components.toasts.multiline.MultiErrorToastMsg import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.toasts.multiline.MultiUserErrorMessageDialog -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @Composable fun DisplayErrorMessages( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/toasts/multiline/ErrorList.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/toasts/multiline/ErrorList.kt index 8eebdce932..48f01c9515 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/toasts/multiline/ErrorList.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/toasts/multiline/ErrorList.kt @@ -41,17 +41,20 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.error_dialog_talk_to_user import com.vitorpamplona.amethyst.commons.resources.error_dialog_talk_to_user_name import com.vitorpamplona.amethyst.commons.resources.error_dialog_zap_error +import com.vitorpamplona.amethyst.commons.resources.ic_dm import com.vitorpamplona.amethyst.commons.ui.components.toasts.multiline.MultiErrorToastMsg import com.vitorpamplona.amethyst.commons.ui.components.toasts.multiline.UserBasedErrorMessage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeToMessage +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier @@ -61,11 +64,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size40dp import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.navigation.routes.routeToMessage -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext @@ -146,7 +146,7 @@ fun ErrorRow( } ?: stringRes(Res.string.error_dialog_talk_to_user) Icon( - painter = painterRes(R.drawable.ic_dm, 2), + painter = painterRes(Res.drawable.ic_dm, 2), contentDescription = descriptor, modifier = Size20Modifier, tint = MaterialTheme.colorScheme.primary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/toasts/multiline/MultiUserErrorMessageDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/toasts/multiline/MultiUserErrorMessageDialog.kt index 0777b48775..a210327a9b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/toasts/multiline/MultiUserErrorMessageDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/toasts/multiline/MultiUserErrorMessageDialog.kt @@ -41,8 +41,8 @@ import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size16dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/WatchScrollToTop.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/WatchScrollToTop.kt index d0d7daa8c5..b6f9a552ee 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/WatchScrollToTop.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/WatchScrollToTop.kt @@ -25,7 +25,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.ui.screen.loggedIn.notifications.CardFeedContentState +import com.vitorpamplona.amethyst.commons.notifications.CardFeedContentState @Composable fun WatchScrollToTop( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayoutPreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayoutPreview.kt index c2b95a98e3..f492bdb7bf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayoutPreview.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayoutPreview.kt @@ -32,19 +32,19 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.tooling.preview.Preview -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.github import com.vitorpamplona.amethyst.commons.resources.profile_banner import com.vitorpamplona.amethyst.commons.ui.components.NewItemsBubble import com.vitorpamplona.amethyst.commons.ui.layouts.ChatHeaderLayout import com.vitorpamplona.amethyst.commons.ui.layouts.listItem.SlimListItem import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgo +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.Height4dpModifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.painterRes import com.vitorpamplona.quartz.utils.TimeUtils private const val PREVIEW_AUTHOR = "This is my author" @@ -58,7 +58,7 @@ fun ChannelNamePreview() { ChatHeaderLayout( channelPicture = { Image( - painter = painterRes(R.drawable.github, 1), + painter = painterRes(Res.drawable.github, 1), contentDescription = stringRes(id = Res.string.profile_banner), contentScale = ContentScale.FillWidth, ) @@ -92,7 +92,7 @@ fun ChannelNamePreview() { }, leadingContent = { Image( - painter = painterRes(R.drawable.github, 2), + painter = painterRes(Res.drawable.github, 2), contentDescription = stringRes(id = Res.string.profile_banner), contentScale = ContentScale.FillWidth, modifier = Size55Modifier, @@ -117,7 +117,7 @@ fun ChannelNamePreview() { }, leadingContent = { Image( - painter = painterRes(R.drawable.github, 2), + painter = painterRes(Res.drawable.github, 2), contentDescription = stringRes(id = Res.string.profile_banner), contentScale = ContentScale.FillWidth, modifier = Size55Modifier, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayoutPreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayoutPreview.kt index 2f26c2e73e..cd163e89d9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayoutPreview.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayoutPreview.kt @@ -33,12 +33,13 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.sp -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.github import com.vitorpamplona.amethyst.commons.resources.profile_banner import com.vitorpamplona.amethyst.commons.ui.layouts.LeftPictureLayout import com.vitorpamplona.amethyst.commons.ui.note.LikeIcon import com.vitorpamplona.amethyst.commons.ui.note.ZappedIcon +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.commons.ui.theme.Size16Modifier @@ -47,7 +48,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.note.TextCount -import com.vitorpamplona.amethyst.ui.painterRes @Composable @Preview @@ -60,7 +60,7 @@ fun LeftPictureLayoutPreviewCard() { LeftPictureLayout( onImage = { Image( - painter = painterRes(R.drawable.github, 3), + painter = painterRes(Res.drawable.github, 3), contentDescription = stringRes(id = Res.string.profile_banner), contentScale = ContentScale.FillWidth, modifier = Modifier.fillMaxSize().clip(QuoteBorder), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/listItem/SlimListItemPreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/listItem/SlimListItemPreview.kt index 2243aa9c6c..8ab8cdd253 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/listItem/SlimListItemPreview.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/listItem/SlimListItemPreview.kt @@ -32,19 +32,19 @@ import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.tooling.preview.Preview -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.github import com.vitorpamplona.amethyst.commons.resources.profile_banner import com.vitorpamplona.amethyst.commons.ui.components.NewItemsBubble import com.vitorpamplona.amethyst.commons.ui.layouts.ChatHeaderLayout import com.vitorpamplona.amethyst.commons.ui.layouts.listItem.SlimListItem import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgo +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.Height4dpModifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.painterRes import com.vitorpamplona.quartz.utils.TimeUtils private const val PREVIEW_AUTHOR = "This is my author" @@ -58,7 +58,7 @@ fun ChannelNamePreview() { ChatHeaderLayout( channelPicture = { Image( - painter = painterRes(R.drawable.github, 1), + painter = painterRes(Res.drawable.github, 1), contentDescription = stringRes(id = Res.string.profile_banner), contentScale = ContentScale.FillWidth, ) @@ -92,7 +92,7 @@ fun ChannelNamePreview() { }, leadingContent = { Image( - painter = painterRes(R.drawable.github, 2), + painter = painterRes(Res.drawable.github, 2), contentDescription = stringRes(id = Res.string.profile_banner), contentScale = ContentScale.FillWidth, modifier = Size55Modifier, @@ -118,7 +118,7 @@ fun ChannelNamePreview() { }, leadingContent = { Image( - painter = painterRes(R.drawable.github, 2), + painter = painterRes(Res.drawable.github, 2), contentDescription = stringRes(id = Res.string.profile_banner), contentScale = ContentScale.FillWidth, modifier = Size55Modifier, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt index 79c3116611..2531c35626 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt @@ -62,6 +62,66 @@ import com.vitorpamplona.amethyst.commons.resources.invalid_nip19_uri_descriptio import com.vitorpamplona.amethyst.commons.ui.layouts.LocalScreenLayout import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.LocalTabReselectCoordinator import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.TabReselectCoordinator +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.apps.recommendations.ProfileAppRecommendationsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.badges.profile.ProfileBadgesScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.default.BookmarkListScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.list.ListOfBookmarkGroupsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.membershipManagement.ArticleBookmarkListManagementScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.membershipManagement.PostBookmarkListManagementScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.podcasts.BookmarkedPodcastsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.repositories.BookmarkedRepositoriesScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.buzz.AgentPersonaEditScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.buzz.BuzzForumPostScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.buzz.BuzzNewDmScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.cordnGroup.CordnInvitationsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.geohashChat.GeohashTeleportScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord.ConcordInviteScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord.ConcordMembersScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.RelayGroupDiscoveryScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.RelayGroupMembersScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.RelayGroupThreadsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.communities.CommunityScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.contactList.ContactListUsersScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.drafts.DraftListScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.browse.BrowseEmojiSetsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.list.ListOfEmojiPacksScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.membershipManagement.EmojiPackSelectionScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.membershipManagement.MyEmojiListScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.geocaches.hunt.GeocacheHuntScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.geocaches.hunt.NewGeocacheHuntScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.gitRepositories.GitRepositoriesScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.highlights.HighlightsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.interestSets.display.InterestSetScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.interestSets.list.ListOfInterestSetsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.interestSets.list.metadata.InterestSetMetadataScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.lists.list.ListOfPeopleListsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.lists.memberEdit.FollowListAndPackAndUserScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.music.MusicPlaylistsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.music.MusicTracksScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.newUser.ImportFollowListPickFollowsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.newUser.ImportFollowListSelectUserScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.nsites.NsitesScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.pinnednotes.PinnedNotesScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts.PodcastEpisodesScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts.PodcastsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts.authoring.PodcastAuthoringScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.polls.PollsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.polls.results.PollResultsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.eventsync.EventSyncScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.nip43.RelayMembersScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.vanish.VanishEventsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings.CallSettingsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings.MessagesSettingsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings.ReactionsSettingsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.softwareapps.SoftwareAppsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.AddWalletScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.CashuMintRecommendationsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.CashuMintsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.CashuWalletSettingsScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.ReloadMintScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.TopUpMintScreen +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts.WorkoutsScreen +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.crashreports.DisplayCrashMessages import com.vitorpamplona.amethyst.service.relayClient.authCommand.compose.RelayAuthPromptHost import com.vitorpamplona.amethyst.service.relayClient.notifyCommand.compose.DisplayNotifyMessages @@ -92,34 +152,22 @@ import com.vitorpamplona.amethyst.ui.note.share.ShareNoteAsImageScreen import com.vitorpamplona.amethyst.ui.note.share.ShareNoteAsQrScreen import com.vitorpamplona.amethyst.ui.screen.AccountSessionManager import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountSwitcherAndLeftDrawerLayout -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.apps.recommendations.ProfileAppRecommendationsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.articles.ArticlesScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.backups.BackupConflictReviewScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.BadgesScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.award.AwardBadgeScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.profile.ProfileBadgesScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default.BookmarkListScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.display.BookmarkGroupScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.list.ListOfBookmarkGroupsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.list.metadata.BookmarkGroupMetadataScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.membershipManagement.ArticleBookmarkListManagementScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.membershipManagement.PostBookmarkListManagementScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.old.OldBookmarkListScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.podcasts.BookmarkedPodcastsScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.repositories.BookmarkedRepositoriesScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.browser.BrowserScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.browser.WebAppScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.AgentAttestationScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.AgentConsoleScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.AgentPersonaEditScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.AgentWorkBoardScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.BuzzCanvasScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.BuzzDmListScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.BuzzForumPostScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.BuzzForumThreadScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.BuzzInviteScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.BuzzNewDmScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.JobBoardScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.WorkflowRunBoardScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.CalendarCollectionsScreen @@ -133,10 +181,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.cordnGroup.CordnCreat import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.cordnGroup.CordnGroupChatScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.cordnGroup.CordnGroupInfoScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.cordnGroup.CordnGroupListScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.cordnGroup.CordnInvitationsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.geohashChat.GeohashChatScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.geohashChat.GeohashChatsScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.geohashChat.GeohashTeleportScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.geohashChat.NewGeohashChatScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.CreateGroupScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.EditGroupInfoScreen @@ -153,8 +199,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concor import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.ConcordEditScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.ConcordHomeScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.ConcordInviteLinksScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.ConcordInviteScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.ConcordMembersScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.ephemChat.EphemeralChatScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.ephemChat.metadata.NewEphemeralChatScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.PublicChatChannelScreen @@ -164,23 +208,17 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayG import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.RelayGroupChannelListScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.RelayGroupChatScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.RelayGroupCreateScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.RelayGroupDiscoveryScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.RelayGroupEditScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.RelayGroupMembersScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.RelayGroupThreadsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.MessagesScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.share.ShareToDMScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chess.ChessGameScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.chess.ChessLobbyScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.CommunityScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.list.CommunitiesScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.newCommunity.EditCommunityScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.newCommunity.NewCommunityScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.contactList.ContactListUsersScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.DiscoverScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip23LongForm.LongFormPostScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip99Classifieds.NewProductScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.drafts.DraftListScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.DvmContentDiscoveryScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.favorites.FavoriteAlgoFeedsListScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.EmbeddedTabAccountWatcher @@ -188,12 +226,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.EmbeddedTabLayer import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.EmbeddedTabPreloader import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.EmbeddedTabThemeWatcher import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.FavoriteAppManifestPreloader -import com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.browse.BrowseEmojiSetsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.display.EmojiPackScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.list.ListOfEmojiPacksScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.list.metadata.EmojiPackMetadataScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.membershipManagement.EmojiPackSelectionScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.membershipManagement.MyEmojiListScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.favorites.FavoriteAppsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.favorites.NostrAppScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.FollowPackFeedScreen @@ -201,8 +235,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.list.FollowPack import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.GeocachesScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.create.NewGeocacheScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.detail.GeocacheDetailScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.hunt.GeocacheHuntScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.hunt.NewGeocacheHuntScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.log.LogGeocacheFindScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.geohash.GeoHashPostScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.geohash.GeoHashScreen @@ -211,30 +243,21 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.GitRepositoryCodeSc import com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.GitRepositoryIssuesScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.GitRepositoryPullsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.GitRepositoryScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepositories.GitRepositoriesScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.HashtagPostScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.HashtagScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.highlights.HighlightsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.highlights.NewHighlightScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.HomeScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.ShortNotePostScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.VoiceReplyScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.nip75Goals.NewGoalScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.interestSets.display.InterestSetScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.interestSets.list.ListOfInterestSetsScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.interestSets.list.metadata.InterestSetMetadataScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.keyBackup.AccountBackupScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.display.lists.PeopleListScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.display.packs.FollowPackScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list.ListOfPeopleListsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list.metadata.FollowPackMetadataScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list.metadata.PeopleListMetadataScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.memberEdit.FollowListAndPackAndUserScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.livestreams.LiveStreamsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.longs.LongsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.AddToMusicPlaylistSheet -import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.MusicPlaylistsScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.MusicTracksScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.NewMusicPlaylistScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.NewMusicTrackScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.napplets.ConnectedAppDetailScreen @@ -242,23 +265,14 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.napplets.ConnectedAppsScree import com.vitorpamplona.amethyst.ui.screen.loggedIn.napplets.NappletsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.NestsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.lobby.NestLobbyScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.newUser.ImportFollowListPickFollowsScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.newUser.ImportFollowListSelectUserScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.NotificationScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.publicMessages.NewPublicMessageScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.nsites.NsitesScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.pictures.PicturesScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.pinnednotes.PinnedNotesScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.PodcastEpisodesScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.PodcastScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.PodcastsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.authoring.EditPodcastShowScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.authoring.NewPodcastEpisodeScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.authoring.NewPodcastTrailerScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.authoring.PodcastAuthoringScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.polls.PollPostScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.polls.PollsScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.polls.results.PollResultsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.privacy.PrivacyOptionsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.products.ProductsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.ProfileScreen @@ -271,31 +285,25 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.relay.RelayFeedScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.relayauth.RelayAuthSettingsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.AllRelayListScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.RelayInformationScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.eventsync.EventSyncScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.nip43.RelayMembersScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.nip86.RelayManagementScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.subscriptions.ActiveSubscriptionsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.vanish.RequestToVanishScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.vanish.VanishEventsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.scheduledposts.ScheduledPostsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.search.SearchScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.AllSettingsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.AudioVisualizerSettingsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.BlockedUsersScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.BottomBarSettingsScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.CallSettingsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.ComposeSettingsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.DrawerSettingsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.HiddenWordsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.HomeTabsSettingsScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.MessagesSettingsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.MutedThreadsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.NIP47SetupScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.NamecoinSettingsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.NotificationSettingsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.OtsSettingsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.ProfileUiSettingsScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.ReactionsSettingsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.ResourceUsageScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SecurityFiltersScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsScreen @@ -313,7 +321,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.nip46.Nip46Connect import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.nip46.Nip46SignerScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.shorts.ShortsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.softwareapps.SoftwareAppDetailScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.softwareapps.SoftwareAppsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.ThreadScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.url.UrlPostScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.url.UrlScreen @@ -321,14 +328,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.VideoScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.hls.NewHlsVideoScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.AddClinkDebitWalletScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.AddNwcWalletScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.AddWalletScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.CashuMintRecommendationsScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.CashuMintsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.CashuWalletScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.CashuWalletSettingsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.OnchainTransactionsScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.ReloadMintScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.TopUpMintScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.WalletDetailScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.WalletReceiveScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.WalletScreen @@ -337,7 +338,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.WalletTransactionsSc import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.wizard.CashuWalletWizardScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.webBookmarks.WebBookmarksScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.NewWorkoutScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.WorkoutsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.fitness.MyFitnessScreen import com.vitorpamplona.amethyst.ui.screen.loggedOff.AddAccountDialog import com.vitorpamplona.amethyst.ui.uriToRoute diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/bottombars/AppBottomBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/bottombars/AppBottomBar.kt index efaf7c00ca..6b17157a0b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/bottombars/AppBottomBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/bottombars/AppBottomBar.kt @@ -63,8 +63,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size10Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size25Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size27Modifier import com.vitorpamplona.amethyst.commons.ui.theme.onSurface65 +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.favorites.rememberNappletIconModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel /** Content height of the [AppBottomBar] (the 50.dp Column inside [RenderBottomMenu]), * exclusive of the system navigation-bar inset. Used by FAB callers that want to diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/bottombars/AppNavigationRail.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/bottombars/AppNavigationRail.kt index a4397757b0..d34b55cf9c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/bottombars/AppNavigationRail.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/bottombars/AppNavigationRail.kt @@ -40,10 +40,10 @@ import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.model.navigation.BottomBarEntry import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.LocalTabReselectCoordinator +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.LoggedInUserPictureDrawer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.Nav import com.vitorpamplona.amethyst.ui.navigation.routes.getRouteWithArguments -import com.vitorpamplona.amethyst.ui.navigation.topbars.LoggedInUserPictureDrawer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel /** * Medium-width windows: a left rail that carries the same user-configured destinations as the diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/bottombars/GroupBottomBarEntries.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/bottombars/GroupBottomBarEntries.kt index 7b12bb38e1..570e5518e9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/bottombars/GroupBottomBarEntries.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/bottombars/GroupBottomBarEntries.kt @@ -37,16 +37,16 @@ import com.vitorpamplona.amethyst.commons.model.ChannelState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.BottomBarEntry import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.ChannelFinderFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.concord_home_title import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.ChannelFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.rememberConcordImageModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/bottombars/NavBarItem.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/bottombars/NavBarItem.kt index b649c9da45..5182e8e66c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/bottombars/NavBarItem.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/bottombars/NavBarItem.kt @@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.navigation.bottombars import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols -import com.vitorpamplona.amethyst.commons.model.navigation.BottomBarEntry import com.vitorpamplona.amethyst.commons.model.navigation.GeocacheTab import com.vitorpamplona.amethyst.commons.model.navigation.NavBarItem import com.vitorpamplona.amethyst.commons.model.navigation.Route @@ -86,7 +85,7 @@ import com.vitorpamplona.amethyst.commons.resources.software_apps import com.vitorpamplona.amethyst.commons.resources.wallet import com.vitorpamplona.amethyst.commons.resources.web_bookmarks import com.vitorpamplona.amethyst.commons.resources.workouts -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import org.jetbrains.compose.resources.StringResource data class NavBarItemDef( @@ -488,18 +487,6 @@ val NavBarCatalog: Map = ), ) -val DefaultBottomBarItems: List = - listOf( - NavBarItem.HOME, - NavBarItem.MESSAGES, - NavBarItem.WALLET, - NavBarItem.BROWSER, - NavBarItem.NOTIFICATIONS, - ) - -/** The default bottom bar as unified entries (all built-in; favorites are added by the user). */ -val DefaultBottomBarEntries: List = DefaultBottomBarItems.map { BottomBarEntry.BuiltIn(it) } - /** * A titled, collapsible group of selectable destinations in the bottom-bar settings picker. The * catalog's [linkedMapOf] insertion order is hand-maintained and reads as scattered in the flat diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/AccountSwitchBottomSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/AccountSwitchBottomSheet.kt index f3fe6c163e..3548ae4a5a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/AccountSwitchBottomSheet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/AccountSwitchBottomSheet.kt @@ -59,6 +59,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.account_switch_active_account import com.vitorpamplona.amethyst.commons.resources.account_switch_add_account_btn @@ -81,9 +82,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.AccountPictureModifier import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp import com.vitorpamplona.amethyst.commons.util.toShortDisplay -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.AccountSessionManager -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedOff.AddAccountDialog import com.vitorpamplona.quartz.nip19Bech32.decodePublicKeyAsHexOrNull import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/DrawerContent.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/DrawerContent.kt index 91a4198d97..757f7ebc0c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/DrawerContent.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/DrawerContent.kt @@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.ui.navigation.drawer import androidx.compose.animation.animateContentSize import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable @@ -89,16 +90,20 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil3.compose.AsyncImage import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.BuildConfig -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.navigation.DrawerSectionId import com.vitorpamplona.amethyst.commons.model.navigation.NavBarItem import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserAssertionsFollowerCount +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserStatuses import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.bookmarks import com.vitorpamplona.amethyst.commons.resources.drafts @@ -107,12 +112,14 @@ import com.vitorpamplona.amethyst.commons.resources.drawer_section_feeds import com.vitorpamplona.amethyst.commons.resources.drawer_section_you import com.vitorpamplona.amethyst.commons.resources.followers import com.vitorpamplona.amethyst.commons.resources.following +import com.vitorpamplona.amethyst.commons.resources.ic_qrcode import com.vitorpamplona.amethyst.commons.resources.longs import com.vitorpamplona.amethyst.commons.resources.pictures import com.vitorpamplona.amethyst.commons.resources.profile import com.vitorpamplona.amethyst.commons.resources.profile_banner import com.vitorpamplona.amethyst.commons.resources.profile_image import com.vitorpamplona.amethyst.commons.resources.relay_setup +import com.vitorpamplona.amethyst.commons.resources.relays import com.vitorpamplona.amethyst.commons.resources.route_chess import com.vitorpamplona.amethyst.commons.resources.share_hls_video import com.vitorpamplona.amethyst.commons.resources.show_npub_as_a_qr_code @@ -122,6 +129,8 @@ import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncIma import com.vitorpamplona.amethyst.commons.ui.layouts.PermanentDrawerWidth import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes @@ -145,18 +154,12 @@ import com.vitorpamplona.amethyst.commons.ui.theme.bannerModifier import com.vitorpamplona.amethyst.commons.ui.theme.drawerSpacing import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.profileContentHeaderModifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.isDebug -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserAssertionsFollowerCount -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserStatuses import com.vitorpamplona.amethyst.ui.navigation.bottombars.NavBarCatalog import com.vitorpamplona.amethyst.ui.navigation.bottombars.NavBarItemDef -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import kotlinx.coroutines.flow.Flow @@ -297,8 +300,8 @@ fun ProfileContentTemplate( modifier = bannerModifier, ) } else { - AsyncImage( - model = R.drawable.profile_banner, + Image( + painter = painterRes(Res.drawable.profile_banner, 3), contentDescription = stringRes(Res.string.profile_banner), contentScale = ContentScale.Crop, modifier = bannerModifier, @@ -1004,7 +1007,7 @@ fun IconRowRelays( verticalAlignment = Alignment.CenterVertically, ) { Icon( - painter = painterRes(R.drawable.relays, 4), + painter = painterRes(Res.drawable.relays, 4), contentDescription = stringRes(Res.string.relay_setup), modifier = Size22Modifier, tint = MaterialTheme.colorScheme.onSurface, @@ -1101,7 +1104,7 @@ fun BottomContent( }, ) { Icon( - painter = painterRes(R.drawable.ic_qrcode, 2), + painter = painterRes(Res.drawable.ic_qrcode, 2), contentDescription = stringRes(id = Res.string.show_npub_as_a_qr_code), modifier = Size24Modifier, tint = MaterialTheme.colorScheme.primary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/topbars/AroundMeLocationLabel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/topbars/AroundMeLocationLabel.kt new file mode 100644 index 0000000000..9ebc663f23 --- /dev/null +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/topbars/AroundMeLocationLabel.kt @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.ui.navigation.topbars + +import android.Manifest +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.google.accompanist.permissions.ExperimentalPermissionsApi +import com.google.accompanist.permissions.isGranted +import com.google.accompanist.permissions.rememberPermissionState +import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.location.LocationResult +import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.lack_location_permissions +import com.vitorpamplona.amethyst.commons.resources.loading_location +import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation +import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.ui.theme.Font12SP +import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer +import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName + +/** The "around me" feed's subtitle: asks for location, then shows the city it resolved to. */ +@OptIn(ExperimentalPermissionsApi::class) +@Composable +fun AndroidAroundMeLocationLabel() { + val locationPermissionState = rememberPermissionState(Manifest.permission.ACCESS_COARSE_LOCATION) + if (!locationPermissionState.status.isGranted) { + LaunchedEffect(locationPermissionState) { locationPermissionState.launchPermissionRequest() } + + Text( + text = stringRes(Res.string.lack_location_permissions), + fontSize = Font12SP, + lineHeight = 12.sp, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } else { + val location by Amethyst.instance.locationManager.geohashStateFlow + .collectAsStateWithLifecycle() + + when (val myLocation = location) { + is LocationResult.Success -> { + LoadCityName( + geohashStr = myLocation.geoHash.toString(), + onLoading = { + Row { + Text( + text = "(${myLocation.geoHash})", + fontSize = Font12SP, + lineHeight = 12.sp, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + Spacer(modifier = StdHorzSpacer) + LoadingAnimation(indicatorSize = 12.dp, circleWidth = 2.dp) + } + }, + ) { cityName -> + Text( + text = "($cityName)", + fontSize = Font12SP, + lineHeight = 12.sp, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + } + + LocationResult.LackPermission -> { + Text( + text = stringRes(Res.string.lack_location_permissions), + fontSize = Font12SP, + lineHeight = 12.sp, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + + LocationResult.Loading -> { + Text( + text = stringRes(Res.string.loading_location), + fontSize = Font12SP, + lineHeight = 12.sp, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + } + } +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/AcceptedByRelaysGallery.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/AcceptedByRelaysGallery.kt index 0735cca0a7..cf70e06be6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/AcceptedByRelaysGallery.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/AcceptedByRelaysGallery.kt @@ -40,6 +40,7 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.accepted_by_relays import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.RenderRelay import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.MediumRelayIconModifier import com.vitorpamplona.amethyst.commons.ui.theme.NotificationIconModifier @@ -47,7 +48,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp import com.vitorpamplona.amethyst.commons.ui.theme.StdStartPadding import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt index ff1515cf19..e91aeca7df 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt @@ -41,19 +41,20 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.notifications.BadgeCard +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.new_badge_award_notif import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.calculateBackgroundColor +import com.vitorpamplona.amethyst.commons.ui.note.elements.MoreOptionsButton import com.vitorpamplona.amethyst.commons.ui.note.timeAgo +import com.vitorpamplona.amethyst.commons.ui.note.types.AcceptBadgeControls +import com.vitorpamplona.amethyst.commons.ui.note.types.BadgeDisplay import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton -import com.vitorpamplona.amethyst.ui.note.types.AcceptBadgeControls -import com.vitorpamplona.amethyst.ui.note.types.BadgeDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.BadgeCard +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip58Badges.award.BadgeAwardEvent @OptIn(ExperimentalFoundationApi::class) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Bolt12ZapGallery.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Bolt12ZapGallery.kt index ae70fc9d85..4631db52f4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Bolt12ZapGallery.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Bolt12ZapGallery.kt @@ -37,16 +37,18 @@ import androidx.compose.ui.draw.alpha import com.vitorpamplona.amethyst.commons.model.Bolt12ZapEntry import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteZaps import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.CrossfadeToDisplayAmount +import com.vitorpamplona.amethyst.commons.ui.note.WatchUserMetadataAndFollowsAndRenderUserProfilePictureOrDefaultAuthor import com.vitorpamplona.amethyst.commons.ui.note.ZappedIcon import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp import com.vitorpamplona.amethyst.commons.ui.theme.Size35Modifier import com.vitorpamplona.amethyst.commons.ui.theme.StdStartPadding import com.vitorpamplona.amethyst.commons.ui.theme.WidthAuthorPictureModifier import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteZaps -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nipB1Bolt12Zaps.zap.Bolt12ZapEvent import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/DrawPlayName.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/DrawPlayName.kt new file mode 100644 index 0000000000..8a1da30e23 --- /dev/null +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/DrawPlayName.kt @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.ui.note + +import android.content.Context +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.platform.LocalContext +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.compose.LocalLifecycleOwner +import com.vitorpamplona.amethyst.commons.ui.note.PlayIcon +import com.vitorpamplona.amethyst.commons.ui.theme.StdButtonSizeModifier +import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.service.tts.TextToSpeechHelper +import com.vitorpamplona.quartz.utils.Log + +@Composable +fun DrawPlayName(name: String) { + val context = LocalContext.current + val lifecycleOwner = LocalLifecycleOwner.current + + IconButton(onClick = { speak(name, context, lifecycleOwner) }, modifier = StdButtonSizeModifier) { + PlayIcon( + modifier = StdButtonSizeModifier, + tint = MaterialTheme.colorScheme.placeholderText, + ) + } +} + +private fun speak( + message: String, + context: Context, + owner: LifecycleOwner, +) { + TextToSpeechHelper + .getInstance(context) + .registerLifecycle(owner) + .speak(message) + .highlight() + .onDone { Log.d("TextToSpeak", "speak: done") } + .onError { Log.d("TextToSpeak") { "speak error: $it" } } +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt index f032bbb99f..2e61b8b6a0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt @@ -39,15 +39,18 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.notifications.MessageSetCard +import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.ic_dm import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.note.calculateBackgroundColor +import com.vitorpamplona.amethyst.commons.ui.note.elements.NoteDropDownMenu +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.theme.StdStartPadding -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.elements.NoteDropDownMenu -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.MessageSetCard +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.coroutines.launch @OptIn(ExperimentalFoundationApi::class) @@ -122,7 +125,7 @@ fun MessageSetCompose( fun MessageIconBox() { Box(Modifier.width(55.dp).padding(top = 5.dp, end = 5.dp)) { Icon( - painter = painterRes(R.drawable.ic_dm, 4), + painter = painterRes(Res.drawable.ic_dm, 4), null, modifier = Modifier.size(16.dp).align(Alignment.TopEnd), tint = MaterialTheme.colorScheme.primary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NutzapGallery.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NutzapGallery.kt index f97e5b0712..970f7100bc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NutzapGallery.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NutzapGallery.kt @@ -39,9 +39,13 @@ import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NutzapEntry import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteZaps import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.nutzap import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.CrossfadeToDisplayAmount +import com.vitorpamplona.amethyst.commons.ui.note.WatchUserMetadataAndFollowsAndRenderUserProfilePictureOrDefaultAuthor import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp @@ -49,9 +53,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size35Modifier import com.vitorpamplona.amethyst.commons.ui.theme.StdStartPadding import com.vitorpamplona.amethyst.commons.ui.theme.WidthAuthorPictureModifier import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteZaps -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NutzapUserSetCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NutzapUserSetCompose.kt index 1665f2cc2f..71a58a5700 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NutzapUserSetCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NutzapUserSetCompose.kt @@ -37,10 +37,18 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.hashtags.Cashu import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons +import com.vitorpamplona.amethyst.commons.model.ZapAmountCommentNotification import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.notifications.NutzapUserSetCard import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.nutzap import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.AboutDisplay +import com.vitorpamplona.amethyst.commons.ui.note.AuthorGalleryZaps +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.calculateBackgroundColor import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer @@ -48,9 +56,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.NutzapUserSetCard +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip61Nutzaps.nutzap.NutzapEvent import com.vitorpamplona.quartz.nip61Nutzaps.nutzap.claimedSatsTotal import kotlinx.collections.immutable.ImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/OnchainZapGallery.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/OnchainZapGallery.kt index e7db7e7b22..d156a1b0cc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/OnchainZapGallery.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/OnchainZapGallery.kt @@ -42,17 +42,19 @@ import com.vitorpamplona.amethyst.commons.model.OnchainZapEntry import com.vitorpamplona.amethyst.commons.model.OnchainZapStatus import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteZaps import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.CrossfadeToDisplayAmount import com.vitorpamplona.amethyst.commons.ui.note.OnchainZappedIcon import com.vitorpamplona.amethyst.commons.ui.note.PendingClockBadge +import com.vitorpamplona.amethyst.commons.ui.note.WatchUserMetadataAndFollowsAndRenderUserProfilePictureOrDefaultAuthor import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp import com.vitorpamplona.amethyst.commons.ui.theme.Size35Modifier import com.vitorpamplona.amethyst.commons.ui.theme.StdStartPadding import com.vitorpamplona.amethyst.commons.ui.theme.WidthAuthorPictureModifier import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteZaps -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index ea9b705ab1..7bda67d532 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -109,7 +109,6 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Popup import androidx.compose.ui.window.PopupProperties import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -120,11 +119,26 @@ import com.vitorpamplona.amethyst.commons.hashtags.Cashu import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.MIN_ONCHAIN_ZAP_SATS import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.model.ReactionRowAction +import com.vitorpamplona.amethyst.commons.model.ReactionRowItem import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.model.ZapraiserStatus import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.model.payments.PaymentTargetTypes +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteReactionCount +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteReactions +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteReferences +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteReplyCount +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteRepostCount +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteReposts +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteRepostsBy +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteZaps +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.boost import com.vitorpamplona.amethyst.commons.resources.close_all_reactions_to_this_post @@ -151,6 +165,7 @@ import com.vitorpamplona.amethyst.commons.resources.quote import com.vitorpamplona.amethyst.commons.resources.read_only_user import com.vitorpamplona.amethyst.commons.resources.reload_mint_title import com.vitorpamplona.amethyst.commons.resources.sats_to_complete +import com.vitorpamplona.amethyst.commons.service.ZapPaymentHandler import com.vitorpamplona.amethyst.commons.ui.components.AnimatedBorderTextCornerRadius import com.vitorpamplona.amethyst.commons.ui.components.ClickableBox import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled @@ -158,20 +173,29 @@ import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable import com.vitorpamplona.amethyst.commons.ui.components.toasts.multiline.UserBasedErrorMessage import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeReplyTo import com.vitorpamplona.amethyst.commons.ui.note.ChangeReactionIcon import com.vitorpamplona.amethyst.commons.ui.note.CommentIcon import com.vitorpamplona.amethyst.commons.ui.note.ExpandLessIcon import com.vitorpamplona.amethyst.commons.ui.note.ExpandMoreIcon import com.vitorpamplona.amethyst.commons.ui.note.LikeIcon import com.vitorpamplona.amethyst.commons.ui.note.LikedIcon +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.note.OutlinedZapIcon +import com.vitorpamplona.amethyst.commons.ui.note.RenderBoostGallery +import com.vitorpamplona.amethyst.commons.ui.note.RenderLikeGallery +import com.vitorpamplona.amethyst.commons.ui.note.RenderReaction +import com.vitorpamplona.amethyst.commons.ui.note.RenderZapGallery import com.vitorpamplona.amethyst.commons.ui.note.RepostIcon import com.vitorpamplona.amethyst.commons.ui.note.RepostedIcon import com.vitorpamplona.amethyst.commons.ui.note.ShareIcon import com.vitorpamplona.amethyst.commons.ui.note.VoiceReplyIcon import com.vitorpamplona.amethyst.commons.ui.note.ZapIcon import com.vitorpamplona.amethyst.commons.ui.note.ZappedIcon +import com.vitorpamplona.amethyst.commons.ui.note.elements.ShareOptionsBottomSheet +import com.vitorpamplona.amethyst.commons.ui.note.types.EditState import com.vitorpamplona.amethyst.commons.ui.richtext.InLineIconRenderer +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.navigateToReloadMint import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder @@ -208,36 +232,18 @@ import com.vitorpamplona.amethyst.commons.ui.theme.reactionBox import com.vitorpamplona.amethyst.commons.ui.theme.ripple24dp import com.vitorpamplona.amethyst.commons.ui.theme.selectedReactionBoxModifier import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.model.MIN_ONCHAIN_ZAP_SATS -import com.vitorpamplona.amethyst.model.ReactionRowAction -import com.vitorpamplona.amethyst.model.ReactionRowItem +import com.vitorpamplona.amethyst.commons.util.showCount +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.model.zap.CashuRailStatus import com.vitorpamplona.amethyst.model.zap.RailCapability import com.vitorpamplona.amethyst.model.zap.RailCapabilityResolver -import com.vitorpamplona.amethyst.service.ZapPaymentHandler import com.vitorpamplona.amethyst.service.payments.PayToAppAvailability -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteReactionCount -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteReactions -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteReferences -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteReplyCount -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteRepostCount -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteReposts -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteRepostsBy -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteZaps import com.vitorpamplona.amethyst.service.relayClient.reqCommand.nwc.NWCFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo import com.vitorpamplona.amethyst.ui.actions.uploads.MAX_VOICE_RECORD_SECONDS import com.vitorpamplona.amethyst.ui.actions.uploads.RecordAudioBox -import com.vitorpamplona.amethyst.ui.navigation.routes.routeReplyTo -import com.vitorpamplona.amethyst.ui.note.elements.ShareOptionsBottomSheet -import com.vitorpamplona.amethyst.ui.note.types.EditState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header.PaymentTargetsDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header.paymentTargetStyleFor import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.OnchainZapSendDialog -import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.navigateToReloadMint import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent @@ -518,11 +524,6 @@ fun LoadAndDisplayZapraiser( } } -@Immutable data class ZapraiserStatus( - val progress: Float, - val left: String, -) - @Composable fun RenderZapRaiser( baseNote: Note, @@ -1323,7 +1324,6 @@ fun ZapReaction( zapClick( baseNote, accountViewModel, - context, onZapStarts = { zapStartingTime = TimeUtils.now() }, onZappingProgress = { progress: Float -> scope.launch { zappingProgress = progress } }, onMultipleChoices = { @@ -1483,7 +1483,6 @@ fun ZapReaction( fun zapClick( baseNote: Note, accountViewModel: AccountViewModel, - context: Context, onZapStarts: () -> Unit, onZappingProgress: (Float) -> Unit, onMultipleChoices: () -> Unit, @@ -1531,7 +1530,6 @@ fun zapClick( choices.first() * 1000, null, "", - context, onError = onError, onProgress = { onZappingProgress(it) }, onPayViaIntent = onPayViaIntent, @@ -2066,55 +2064,6 @@ private fun ActionableReactionButton( } } -@Composable -fun RenderReaction(reactionType: String) { - if (reactionType.startsWith(":")) { - val noStartColon = reactionType.removePrefix(":") - val url = noStartColon.substringAfter(":") - - InLineIconRenderer( - persistentListOf( - CustomEmoji.ImageUrlType(url), - ), - style = SpanStyle(color = MaterialTheme.colorScheme.onBackground), - maxLines = 1, - fontSize = 22.sp, - ) - } else { - when (reactionType) { - "+" -> { - LikedIcon(modifier = Size28Modifier) - } - - "-" -> { - Text( - text = "\uD83D\uDC4E", - color = MaterialTheme.colorScheme.onBackground, - maxLines = 1, - fontSize = 22.sp, - ) - } - - else -> { - if (EmojiCoder.isCoded(reactionType)) { - AnimatedBorderTextCornerRadius( - reactionType, - color = MaterialTheme.colorScheme.onBackground, - fontSize = 20.sp, - ) - } else { - Text( - reactionType, - color = MaterialTheme.colorScheme.onBackground, - maxLines = 1, - fontSize = 22.sp, - ) - } - } - } - } -} - @Composable fun ZapAmountChoicePopup( baseNote: Note, @@ -2324,7 +2273,6 @@ fun ZapAmountChoicePopup( onPayViaIntent: (ImmutableList) -> Unit, onReloadNutzap: (Long) -> Unit = {}, ) { - val context = LocalContext.current val yOffset = with(LocalDensity.current) { -popupYOffset.toPx().toInt() } Popup( @@ -2348,7 +2296,6 @@ fun ZapAmountChoicePopup( amountInSats * 1000, null, "", - context, true, onError, onProgress, @@ -2908,15 +2855,3 @@ private fun ZapChipPreviewRow( onChangeAmount = {}, ) } - -fun showCount(count: Int?): String { - if (count == null) return "" - if (count == 0) return "" - - return when { - count >= 1000000000 -> "${(count / 1000000000f).roundToInt()}G" - count >= 1000000 -> "${(count / 1000000f).roundToInt()}M" - count >= 10000 -> "${(count / 1000f).roundToInt()}k" - else -> "$count" - } -} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt index a0837b22fe..d715cd288c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt @@ -36,19 +36,19 @@ import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.and import com.vitorpamplona.amethyst.commons.resources.replying_to +import com.vitorpamplona.amethyst.commons.ui.components.CreateClickableTextWithEmoji import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.richtext.CreateClickableTextWithEmoji import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.lessImportantLink import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt index 415645df86..67c91f3f9f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt @@ -71,27 +71,28 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.ViewModel import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.emojicoder.EmojiCoder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEventAndMapNotNull import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.add import com.vitorpamplona.amethyst.commons.resources.new_reaction_symbol import com.vitorpamplona.amethyst.commons.ui.components.AnimatedBorderTextCornerRadius import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SavingTopBar import com.vitorpamplona.amethyst.commons.ui.note.LikedIcon +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderEmojiPack import com.vitorpamplona.amethyst.commons.ui.richtext.InLineIconRenderer import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.util.firstFullChar -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEventAndMapNotNull -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.types.RenderEmojiPack -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip30CustomEmoji.CustomEmoji import com.vitorpamplona.quartz.nip30CustomEmoji.EmojiUrlTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt index 82ca56da87..d2f83d0952 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountDialog.kt @@ -119,9 +119,9 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.keyBackup.getFragmentActivity -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountViewModel.kt index 168e937299..d55e9e0ba5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateZapAmountViewModel.kt @@ -26,7 +26,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.ViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip19Bech32.decodePrivateKeyAsHexOrNull diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt index 2c805b398a..244c418142 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserReactionsRow.kt @@ -37,6 +37,7 @@ import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.notifications.NotificationSummaryState import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.today import com.vitorpamplona.amethyst.commons.resources.zaps @@ -50,7 +51,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size24Modifier import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.NotificationSummaryState @Composable fun UserReactionsRow( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt index 06b87aaaa0..f1261acfd5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt @@ -72,6 +72,7 @@ import androidx.core.net.toUri import androidx.lifecycle.ViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.resources.Res @@ -99,10 +100,14 @@ import com.vitorpamplona.amethyst.commons.resources.zap_type_private import com.vitorpamplona.amethyst.commons.resources.zap_type_private_explainer import com.vitorpamplona.amethyst.commons.resources.zap_type_public import com.vitorpamplona.amethyst.commons.resources.zap_type_public_explainer +import com.vitorpamplona.amethyst.commons.service.ZapPaymentHandler import com.vitorpamplona.amethyst.commons.ui.components.toasts.multiline.UserBasedErrorMessage import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.DisplayBlankAuthor +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.note.buttons.CloseButton import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder @@ -113,9 +118,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ZeroPadding import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.ZapPaymentHandler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.OnchainZapSendDialog import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent @@ -152,7 +155,6 @@ fun ZapCustomDialog( accountViewModel: AccountViewModel, baseNote: Note, ) { - val context = LocalContext.current val postViewModel: ZapOptionViewModel = viewModel() LaunchedEffect(accountViewModel) { postViewModel.load(accountViewModel.account) } @@ -372,7 +374,6 @@ fun ZapCustomDialog( postViewModel.value()!! * 1000L, null, postViewModel.customMessage.text, - context, onError = onError, onProgress = onProgress, onPayViaIntent = onPayViaIntent, @@ -493,8 +494,9 @@ fun DisplayPayable( verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(vertical = Size10dp), ) { - if (payable.info.user != null) { - BaseUserPicture(payable.info.user, Size55dp, accountViewModel = accountViewModel) + val payee = payable.info.user + if (payee != null) { + BaseUserPicture(payee, Size55dp, accountViewModel = accountViewModel) } else { DisplayBlankAuthor(size = Size55dp, accountViewModel = accountViewModel) } @@ -502,8 +504,8 @@ fun DisplayPayable( Spacer(modifier = DoubleHorzSpacer) Column(modifier = Modifier.weight(1f)) { - if (payable.info.user != null) { - UsernameDisplay(payable.info.user, accountViewModel = accountViewModel) + if (payee != null) { + UsernameDisplay(payee, accountViewModel = accountViewModel) } else { Text( text = stringRes(id = Res.string.wallet_number, index + 1), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt index f1b75ac218..87a470c620 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt @@ -34,15 +34,21 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.notifications.ZapUserSetCard import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.AboutDisplay +import com.vitorpamplona.amethyst.commons.ui.note.AuthorGalleryZaps +import com.vitorpamplona.amethyst.commons.ui.note.MapZaps +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.note.ZappedIcon +import com.vitorpamplona.amethyst.commons.ui.note.calculateBackgroundColor import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.ZapUserSetCard +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun ZapUserSetCompose( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/emojiSuggestions/WatchAndLoadMyEmojiList.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/emojiSuggestions/WatchAndLoadMyEmojiList.kt index cabe2aafbe..faa85d2e68 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/emojiSuggestions/WatchAndLoadMyEmojiList.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/emojiSuggestions/WatchAndLoadMyEmojiList.kt @@ -22,10 +22,10 @@ package com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEventAndMapNotNull -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEventAndMapNotNull +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.aTag.taggedAddresses import com.vitorpamplona.quartz.nip30CustomEmoji.selection.EmojiListEvent import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/ClinkOfferPreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/ClinkOfferPreview.kt index a0895e6035..9fbe8d74f1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/ClinkOfferPreview.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/ClinkOfferPreview.kt @@ -59,21 +59,21 @@ import com.vitorpamplona.amethyst.commons.resources.pay import com.vitorpamplona.amethyst.commons.resources.sats import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.ErrorMessageDialog +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.commons.ui.theme.Size18Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp import com.vitorpamplona.amethyst.commons.ui.theme.SmallBorder import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.ClinkOfferPayer import com.vitorpamplona.amethyst.ui.components.PaymentCard import com.vitorpamplona.amethyst.ui.components.PaymentCardAmount -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.ErrorMessageDialog -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser import com.vitorpamplona.quartz.experimental.clink.common.SatRange import com.vitorpamplona.quartz.experimental.clink.offers.OfferErrorCode import com.vitorpamplona.quartz.experimental.clink.pointers.ClinkPointerParser diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/InvoicePaymentDispatcher.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/InvoicePaymentDispatcher.kt index b39d83b1e8..30f0867de6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/InvoicePaymentDispatcher.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/InvoicePaymentDispatcher.kt @@ -39,11 +39,11 @@ import com.vitorpamplona.amethyst.commons.resources.clink_debit_no_response import com.vitorpamplona.amethyst.commons.resources.no_wallet_found import com.vitorpamplona.amethyst.commons.resources.pay import com.vitorpamplona.amethyst.commons.resources.sats +import com.vitorpamplona.amethyst.commons.service.nwc.nwcFailureDetail +import com.vitorpamplona.amethyst.commons.service.nwc.nwcTimeoutMessage import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.payViaIntent -import com.vitorpamplona.amethyst.ui.nwc.nwcFailureDetail -import com.vitorpamplona.amethyst.ui.nwc.nwcTimeoutMessage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.lightning.LnInvoiceUtil import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/InvoicePreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/InvoicePreview.kt index 46c455f13c..e3dc21e64a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/InvoicePreview.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/InvoicePreview.kt @@ -48,16 +48,16 @@ import com.vitorpamplona.amethyst.commons.resources.lightning_invoice import com.vitorpamplona.amethyst.commons.resources.pay import com.vitorpamplona.amethyst.commons.resources.sats import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.note.ErrorMessageDialog import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.commons.ui.theme.Size18Modifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.lnurl.CachedLnInvoiceParser import com.vitorpamplona.amethyst.service.lnurl.InvoiceAmount import com.vitorpamplona.amethyst.ui.components.PaymentCard import com.vitorpamplona.amethyst.ui.components.PaymentCardAmount import com.vitorpamplona.amethyst.ui.components.PaymentCardDescription -import com.vitorpamplona.amethyst.ui.note.ErrorMessageDialog -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/InvoiceRequest.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/InvoiceRequest.kt index fe8a3a1090..7b8673f993 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/InvoiceRequest.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/InvoiceRequest.kt @@ -41,7 +41,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType @@ -61,7 +60,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun InvoiceRequest( @@ -73,8 +72,6 @@ fun InvoiceRequest( onNewInvoice: (String) -> Unit, onError: (String, String) -> Unit, ) { - val context = LocalContext.current - Column { Row( verticalAlignment = Alignment.CenterVertically, @@ -155,7 +152,6 @@ fun InvoiceRequest( onNewInvoice = onNewInvoice, onError = onError, onProgress = {}, - context = context, ) }, shape = QuoteBorder, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/NewPostInvoiceRequest.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/NewPostInvoiceRequest.kt index df23e43142..fabde4f787 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/NewPostInvoiceRequest.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/invoice/NewPostInvoiceRequest.kt @@ -22,12 +22,12 @@ package com.vitorpamplona.amethyst.ui.note.creators.invoice import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.lightning_create_and_add_invoice import com.vitorpamplona.amethyst.commons.resources.lightning_invoice import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun NewPostInvoiceRequest( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/location/DisplayLocationObserver.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/location/DisplayLocationObserver.kt index cfd316e3d9..222befd9b0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/location/DisplayLocationObserver.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/location/DisplayLocationObserver.kt @@ -30,6 +30,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.lack_location_permissions import com.vitorpamplona.amethyst.commons.resources.loading_location @@ -37,18 +38,17 @@ import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer -import com.vitorpamplona.amethyst.service.location.LocationState @Composable fun DisplayLocationObserver(viewModel: ILocationGrabber) { val location by viewModel.locationFlow().collectAsStateWithLifecycle() when (val myLocation = location) { - is LocationState.LocationResult.Success -> { + is LocationResult.Success -> { DisplayLocationInTitle(geohash = myLocation.geoHash.toString()) } - LocationState.LocationResult.LackPermission -> { + LocationResult.LackPermission -> { Text( text = stringRes(Res.string.lack_location_permissions), fontSize = 12.sp, @@ -56,7 +56,7 @@ fun DisplayLocationObserver(viewModel: ILocationGrabber) { ) } - LocationState.LocationResult.Loading -> { + LocationResult.Loading -> { Text( text = stringRes(Res.string.loading_location), fontSize = 12.sp, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/location/GeoHashPostSection.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/location/GeoHashPostSection.kt index 2c28e1e9b7..583b757747 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/location/GeoHashPostSection.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/location/GeoHashPostSection.kt @@ -47,6 +47,7 @@ import com.vitorpamplona.amethyst.commons.resources.geohash_title import com.vitorpamplona.amethyst.commons.resources.location_change_place import com.vitorpamplona.amethyst.commons.resources.location_pick_on_map import com.vitorpamplona.amethyst.commons.resources.remove_location +import com.vitorpamplona.amethyst.commons.ui.platform.GeohashLocationPickerDialog import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/location/GeohashLocationPickerDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/location/GeohashLocationPickerDialog.kt index 175a05440e..02445f15df 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/location/GeohashLocationPickerDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/location/GeohashLocationPickerDialog.kt @@ -85,6 +85,7 @@ import com.google.accompanist.permissions.rememberPermissionState import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.cancel import com.vitorpamplona.amethyst.commons.resources.clear @@ -284,8 +285,8 @@ fun GeohashLocationPickerContent( // forever (permission granted yet location off, indoors, emulator with no fix…). val fix = withTimeoutOrNull(GPS_FIX_TIMEOUT_MS) { - locationManager.preciseGeohashStateFlow.first { it is LocationState.LocationResult.Success } - } as? LocationState.LocationResult.Success + locationManager.preciseGeohashStateFlow.first { it is LocationResult.Success } + } as? LocationResult.Success if (fix != null) { recenter = GeoPoint(fix.geoHash.centerLat, fix.geoHash.centerLon) pickedLat = fix.geoHash.centerLat diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/location/ILocationGrabber.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/location/ILocationGrabber.kt index 6940f786ba..9f78db5852 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/location/ILocationGrabber.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/location/ILocationGrabber.kt @@ -20,13 +20,14 @@ */ package com.vitorpamplona.amethyst.ui.note.creators.location +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import com.vitorpamplona.amethyst.service.location.LocationState import kotlinx.coroutines.flow.StateFlow interface ILocationGrabber { fun locationManager(): LocationState - fun locationFlow(): StateFlow + fun locationFlow(): StateFlow /** * A geohash the user picked on the map (via [GeohashLocationPickerDialog]), which diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/notify/AudienceFlap.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/notify/AudienceFlap.kt index 3815e627b2..2e140db2f9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/notify/AudienceFlap.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/notify/AudienceFlap.kt @@ -73,6 +73,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.composer.AudienceGroupChip import com.vitorpamplona.amethyst.commons.model.composer.AudienceSelection +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserName import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.audience_empty_private import com.vitorpamplona.amethyst.commons.resources.audience_empty_public @@ -85,14 +86,13 @@ import com.vitorpamplona.amethyst.commons.resources.notify_mute_user import com.vitorpamplona.amethyst.commons.resources.notify_unmute_user import com.vitorpamplona.amethyst.commons.resources.private_note_visible_to import com.vitorpamplona.amethyst.commons.resources.reply_notify +import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size24dp import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.note.BaseUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableSet diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/notify/AudienceSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/notify/AudienceSheet.kt index 86c454cf7e..d0078663bc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/notify/AudienceSheet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/notify/AudienceSheet.kt @@ -89,6 +89,10 @@ import com.vitorpamplona.amethyst.commons.resources.follow_sets import com.vitorpamplona.amethyst.commons.resources.num_selected import com.vitorpamplona.amethyst.commons.resources.select_all import com.vitorpamplona.amethyst.commons.ui.components.OutlinedThinPaddingTextField +import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness @@ -96,11 +100,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size24dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.warningColor -import com.vitorpamplona.amethyst.ui.note.BaseUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableSet diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/previews/DisplayPreviews.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/previews/DisplayPreviews.kt index 119970dbcd..e0bbc50d32 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/previews/DisplayPreviews.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/previews/DisplayPreviews.kt @@ -35,7 +35,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HalfHorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.Height100Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.SquaredQuoteBorderModifier -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun DisplayPreviews( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/previews/PreviewUrl.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/previews/PreviewUrl.kt index 2ac9b1ee4e..72aa4b9509 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/previews/PreviewUrl.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/previews/PreviewUrl.kt @@ -42,18 +42,19 @@ import androidx.compose.ui.text.style.TextOverflow import coil3.compose.AsyncImage import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.richtext.RichTextParser +import com.vitorpamplona.amethyst.commons.ui.components.ClickableUrlOrBlossom import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.components.DisplayUrlWithLoadingSymbol import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewCard import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewState +import com.vitorpamplona.amethyst.commons.ui.components.WaitAndDisplay import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.state.produceCachedState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.model.UrlCachedPreviewer import com.vitorpamplona.amethyst.service.playback.composable.VideoView -import com.vitorpamplona.amethyst.ui.components.ClickableUrl -import com.vitorpamplona.amethyst.ui.components.DisplayUrlWithLoadingSymbol -import com.vitorpamplona.amethyst.ui.components.WaitAndDisplay -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.screen.loggedIn.urlPreview @Composable fun PreviewUrl( @@ -246,7 +247,7 @@ private fun MyLoadUrlPreviewDirect( ) Text( - text = state.previewInfo.verifiedUrl?.host ?: state.previewInfo.title, + text = state.previewInfo.verifiedHost ?: state.previewInfo.title, style = MaterialTheme.typography.bodyMedium, maxLines = 1, overflow = TextOverflow.Ellipsis, @@ -257,7 +258,7 @@ private fun MyLoadUrlPreviewDirect( else -> { Box(contentAlignment = Alignment.BottomCenter, modifier = Modifier.aspectRatio(1f)) { - ClickableUrl(urlText, url) + ClickableUrlOrBlossom(urlText, url) } } } @@ -320,7 +321,7 @@ private fun MyLoadUrlPreviewDirectFillWidth( } else -> { - ClickableUrl(urlText, url) + ClickableUrlOrBlossom(urlText, url) } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/uploads/ImageVideoDescription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/uploads/ImageVideoDescription.kt index 6ad6df6372..edd9282f5b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/uploads/ImageVideoDescription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/uploads/ImageVideoDescription.kt @@ -100,11 +100,11 @@ import com.vitorpamplona.amethyst.commons.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.subtleBorder +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.ai.MLKitImageLabelService import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMediaProcessing import com.vitorpamplona.amethyst.ui.actions.uploads.ShowImageUploadGallery -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.collections.immutable.toImmutableList @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/zapsplits/ForwardZapTo.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/zapsplits/ForwardZapTo.kt index fc59070ecb..de91bf32bc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/zapsplits/ForwardZapTo.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/zapsplits/ForwardZapTo.kt @@ -46,6 +46,8 @@ import com.vitorpamplona.amethyst.commons.resources.zap_split_search_and_add_use import com.vitorpamplona.amethyst.commons.resources.zap_split_search_and_add_user_placeholder import com.vitorpamplona.amethyst.commons.resources.zap_split_title import com.vitorpamplona.amethyst.commons.ui.components.OutlinedThinPaddingTextField +import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.IZapField import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.ZapSplitIcon import com.vitorpamplona.amethyst.commons.ui.stringRes @@ -55,10 +57,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation -import com.vitorpamplona.amethyst.ui.note.BaseUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlin.math.round @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForDMCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForDMCard.kt index 856bddd12c..6113e1c9a1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForDMCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddInboxRelayForDMCard.kt @@ -37,22 +37,22 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.sp +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.dm_relays_not_found import com.vitorpamplona.amethyst.commons.resources.dm_relays_not_found_create_now import com.vitorpamplona.amethyst.commons.resources.dm_relays_not_found_description import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.BigPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.dm.AddDMRelayListDialog import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip17Dm.settings.DmRelayListEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/NoteHeaderMarkersPreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/NoteHeaderMarkersPreview.kt index 00689c692d..0db82f3c18 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/NoteHeaderMarkersPreview.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/NoteHeaderMarkersPreview.kt @@ -34,13 +34,13 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav +import com.vitorpamplona.amethyst.commons.ui.note.FirstUserInfoRow +import com.vitorpamplona.amethyst.commons.ui.note.types.EditState +import com.vitorpamplona.amethyst.commons.ui.note.types.EmptyState import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.service.location.CachedReversedGeoLocations -import com.vitorpamplona.amethyst.ui.note.FirstUserInfoRow -import com.vitorpamplona.amethyst.ui.note.types.EditState -import com.vitorpamplona.amethyst.ui.note.types.EmptyState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip37Drafts.DraftWrapEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/CommentPostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/CommentPostViewModel.kt index 656bcf3afa..fe18936d50 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/CommentPostViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/CommentPostViewModel.kt @@ -32,6 +32,7 @@ import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User @@ -43,6 +44,7 @@ import com.vitorpamplona.amethyst.commons.model.composer.NewMessageTagger import com.vitorpamplona.amethyst.commons.model.composer.PreviewState import com.vitorpamplona.amethyst.commons.model.composer.SplitBuilder import com.vitorpamplona.amethyst.commons.model.composer.toZapSplitSetup +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiPackState import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiSuggestionState @@ -56,6 +58,7 @@ import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.note.creators.messagefield.IMessageField import com.vitorpamplona.amethyst.commons.ui.note.creators.notify.IAudience +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.IZapField import com.vitorpamplona.amethyst.commons.ui.text.appendSignature import com.vitorpamplona.amethyst.commons.ui.text.currentWord @@ -63,7 +66,7 @@ import com.vitorpamplona.amethyst.commons.ui.text.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.ui.text.onUiThread import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord import com.vitorpamplona.amethyst.commons.ui.text.setTextAndPlaceCursorAtBeginning -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.location.LocationState import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator @@ -71,8 +74,6 @@ import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMediaProcessing import com.vitorpamplona.amethyst.ui.note.creators.location.ILocationGrabber -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.IMetaAttachments import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.UserSuggestionAnchor import com.vitorpamplona.quartz.experimental.nip95.data.FileStorageEvent @@ -275,7 +276,7 @@ open class CommentPostViewModel : // GeoHash var wantsToAddGeoHash by mutableStateOf(false) override var pickedGeoHash by mutableStateOf(null) - var location: StateFlow? = null + var location: StateFlow? = null // ZapRaiser var canAddZapRaiser by mutableStateOf(false) @@ -687,7 +688,7 @@ open class CommentPostViewModel : ) tagger.run() - val geoHash = (if (wantsToAddGeoHash) pickedGeoHash else null) ?: (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString() + val geoHash = (if (wantsToAddGeoHash) pickedGeoHash else null) ?: (location?.value as? LocationResult.Success)?.geoHash?.toString() val emojis = account.emoji.findEmojiTags(tagger.message) val urls = findURLs(tagger.message) @@ -1004,7 +1005,7 @@ open class CommentPostViewModel : viewModelScope.launch(Dispatchers.IO) { iMetaAttachments.downloadAndPrepare(item.link) { - Amethyst.instance.roleBasedHttpClientBuilder.okHttpClientForImage(item.link) + accountViewModel.httpClientBuilder.okHttpClientForImage(item.link) } } @@ -1070,7 +1071,7 @@ open class CommentPostViewModel : draftTag.newVersion() } - override fun locationFlow(): StateFlow { + override fun locationFlow(): StateFlow { if (location == null) { location = locationManager().geohashStateFlow } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/GenericCommentPostScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/GenericCommentPostScreen.kt index 572558dc41..387ff21249 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/GenericCommentPostScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/GenericCommentPostScreen.kt @@ -81,6 +81,8 @@ import com.vitorpamplona.amethyst.commons.resources.zapraiser import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDialog import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.PostingTopBar +import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.ContentSensitivityExplainer import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.MarkAsSensitiveButton import com.vitorpamplona.amethyst.commons.ui.note.creators.expiration.ExpirationDateButton @@ -88,9 +90,13 @@ import com.vitorpamplona.amethyst.commons.ui.note.creators.invoice.AddLnInvoiceB import com.vitorpamplona.amethyst.commons.ui.note.creators.location.AddGeoHashButton import com.vitorpamplona.amethyst.commons.ui.note.creators.secretEmoji.AddSecretEmojiButton import com.vitorpamplona.amethyst.commons.ui.note.creators.secretEmoji.SecretEmojiRequest +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList import com.vitorpamplona.amethyst.commons.ui.note.creators.zapraiser.AddZapraiserButton import com.vitorpamplona.amethyst.commons.ui.note.creators.zapraiser.ZapRaiserRequest import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.ForwardZapToButton +import com.vitorpamplona.amethyst.commons.ui.note.nip22Comments.DisplayExternalId +import com.vitorpamplona.amethyst.commons.ui.note.types.ReplyRenderType +import com.vitorpamplona.amethyst.commons.ui.platform.GeohashLocationPickerDialog import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.text.onUiThread import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp @@ -100,6 +106,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightPage import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia @@ -107,13 +114,10 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.TakePictureButton import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideoButton import com.vitorpamplona.amethyst.ui.components.getActivity import com.vitorpamplona.amethyst.ui.navigation.navs.Nav -import com.vitorpamplona.amethyst.ui.note.BaseUserPicture -import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest import com.vitorpamplona.amethyst.ui.note.creators.location.GeoHashPostSection -import com.vitorpamplona.amethyst.ui.note.creators.location.GeohashLocationPickerDialog import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName import com.vitorpamplona.amethyst.ui.note.creators.messagefield.MessageField import com.vitorpamplona.amethyst.ui.note.creators.notify.AudienceFlap @@ -122,10 +126,7 @@ import com.vitorpamplona.amethyst.ui.note.creators.notify.rememberAudienceLists import com.vitorpamplona.amethyst.ui.note.creators.pow.PowOverrideButton import com.vitorpamplona.amethyst.ui.note.creators.previews.DisplayPreviews import com.vitorpamplona.amethyst.ui.note.creators.uploads.ImageVideoDescription -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.ForwardZapTo -import com.vitorpamplona.amethyst.ui.note.types.ReplyRenderType -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip73ExternalIds.location.GeohashId import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/platform/AndroidNotePlatform.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/platform/AndroidNotePlatform.kt new file mode 100644 index 0000000000..ff1a900619 --- /dev/null +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/platform/AndroidNotePlatform.kt @@ -0,0 +1,601 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.ui.note.platform + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.State +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Rect +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.TextUnit +import com.vitorpamplona.amethyst.commons.audio.WaveformData +import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.richtext.BaseMediaContent +import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable +import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewState +import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.platform.NotePlatform +import com.vitorpamplona.amethyst.commons.ui.note.types.EditState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.model.UrlCachedPreviewer +import com.vitorpamplona.amethyst.ui.screen.loggedIn.urlPreview +import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag +import com.vitorpamplona.quartz.podcasts.PodcastAudio +import kotlinx.collections.immutable.ImmutableList +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderMeetingRoomEvent as AppRenderMeetingRoomEvent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderMeetingRoomPresence as AppRenderMeetingRoomPresence +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderMeetingSpaceEvent as AppRenderMeetingSpaceEvent +import com.vitorpamplona.amethyst.service.playback.composable.VideoView as AppVideoView +import com.vitorpamplona.amethyst.ui.actions.EditPostView as AppEditPostView +import com.vitorpamplona.amethyst.ui.components.GifVideoView as AppGifVideoView +import com.vitorpamplona.amethyst.ui.components.LoadUrlPreview as AppLoadUrlPreview +import com.vitorpamplona.amethyst.ui.components.ZoomableContentView as AppZoomableContentView +import com.vitorpamplona.amethyst.ui.components.ZoomableImageDialog as AppZoomableImageDialog +import com.vitorpamplona.amethyst.ui.components.rememberUrlPreviewState as AppRememberUrlPreviewState +import com.vitorpamplona.amethyst.ui.note.LikeReaction as AppLikeReaction +import com.vitorpamplona.amethyst.ui.note.ReactionsRow as AppReactionsRow +import com.vitorpamplona.amethyst.ui.note.ZapReaction as AppZapReaction +import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName as AppLoadCityName +import com.vitorpamplona.amethyst.ui.note.creators.location.LocationPreviewMap as AppLocationPreviewMap +import com.vitorpamplona.amethyst.ui.note.types.PodcastEpisodeAudioPlayer as AppPodcastEpisodeAudioPlayer +import com.vitorpamplona.amethyst.ui.note.types.RenderAudioFromIMeta as AppRenderAudioFromIMeta +import com.vitorpamplona.amethyst.ui.note.types.RenderAudioHeader as AppRenderAudioHeader +import com.vitorpamplona.amethyst.ui.note.types.RenderAudioTrack as AppRenderAudioTrack +import com.vitorpamplona.amethyst.ui.note.types.RenderAudioWithWaveform as AppRenderAudioWithWaveform +import com.vitorpamplona.amethyst.ui.note.types.RenderCalendarRSVPEvent as AppRenderCalendarRSVPEvent +import com.vitorpamplona.amethyst.ui.note.types.RenderChessGame as AppRenderChessGame +import com.vitorpamplona.amethyst.ui.note.types.RenderGitIssueEvent as AppRenderGitIssueEvent +import com.vitorpamplona.amethyst.ui.note.types.RenderGitPatchEvent as AppRenderGitPatchEvent +import com.vitorpamplona.amethyst.ui.note.types.RenderGitPullRequestEvent as AppRenderGitPullRequestEvent +import com.vitorpamplona.amethyst.ui.note.types.RenderGitPullRequestUpdateEvent as AppRenderGitPullRequestUpdateEvent +import com.vitorpamplona.amethyst.ui.note.types.RenderGitRepositoryEvent as AppRenderGitRepositoryEvent +import com.vitorpamplona.amethyst.ui.note.types.RenderLiveChessChallenge as AppRenderLiveChessChallenge +import com.vitorpamplona.amethyst.ui.note.types.RenderLiveChessGameEnd as AppRenderLiveChessGameEnd +import com.vitorpamplona.amethyst.ui.note.types.RenderMusicTrack as AppRenderMusicTrack +import com.vitorpamplona.amethyst.ui.note.types.RenderNamedNappletEvent as AppRenderNamedNappletEvent +import com.vitorpamplona.amethyst.ui.note.types.RenderNamedSiteEvent as AppRenderNamedSiteEvent +import com.vitorpamplona.amethyst.ui.note.types.RenderRootNappletEvent as AppRenderRootNappletEvent +import com.vitorpamplona.amethyst.ui.note.types.RenderRootSiteEvent as AppRenderRootSiteEvent +import com.vitorpamplona.amethyst.ui.note.types.RenderVoiceTrack as AppRenderVoiceTrack + +/** Android's [NotePlatform]: the app's own media, map, audio, chess, git, napplet and zap composables. */ +object AndroidNotePlatform : NotePlatform { + override fun warmUrlPreview( + url: String, + accountViewModel: AccountViewModel, + ) { + if (UrlCachedPreviewer.cache.get(url) == null) accountViewModel.urlPreview(url) {} + } + + @Composable + override fun rememberUrlPreviewState( + url: String, + accountViewModel: AccountViewModel, + ): UrlPreviewState = AppRememberUrlPreviewState(url, accountViewModel) + + @Composable + override fun RenderAudioHeader( + note: Note, + contentScale: ContentScale, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderAudioHeader(note, contentScale, accountViewModel, nav) + + @Composable + override fun ZoomableContentView( + content: BaseMediaContent, + images: ImmutableList, + roundedCorner: Boolean, + contentScale: ContentScale, + accountViewModel: AccountViewModel, + ) = AppZoomableContentView( + content = content, + images = images, + roundedCorner = roundedCorner, + contentScale = contentScale, + accountViewModel = accountViewModel, + ) + + @Composable + override fun ZoomableImageDialog( + imageUrl: BaseMediaContent, + allImages: ImmutableList, + sourceBounds: Rect?, + onDismiss: () -> Unit, + accountViewModel: AccountViewModel, + ) = AppZoomableImageDialog( + imageUrl = imageUrl, + allImages = allImages, + sourceBounds = sourceBounds, + onDismiss = onDismiss, + accountViewModel = accountViewModel, + ) + + @Composable + override fun GifVideoView( + videoUri: String, + contentDescription: String?, + dimensions: DimensionTag?, + blurhash: String?, + roundedCorner: Boolean, + contentScale: ContentScale, + onDialog: (() -> Unit)?, + accountViewModel: AccountViewModel, + thumbhash: String?, + ) = AppGifVideoView( + videoUri = videoUri, + contentDescription = contentDescription, + dimensions = dimensions, + blurhash = blurhash, + roundedCorner = roundedCorner, + contentScale = contentScale, + onDialog = onDialog, + accountViewModel = accountViewModel, + thumbhash = thumbhash, + ) + + @Composable + override fun VideoView( + videoUri: String, + mimeType: String?, + title: String?, + artworkUri: String?, + authorName: String?, + roundedCorner: Boolean, + contentScale: ContentScale, + nostrUriCallback: String?, + isLiveStream: Boolean, + accountViewModel: AccountViewModel, + ) = AppVideoView( + videoUri = videoUri, + mimeType = mimeType, + title = title, + artworkUri = artworkUri, + authorName = authorName, + roundedCorner = roundedCorner, + contentScale = contentScale, + nostrUriCallback = nostrUriCallback, + isLiveStream = isLiveStream, + accountViewModel = accountViewModel, + ) + + @Composable + override fun UrlPreview( + url: String, + urlText: String, + callbackUri: String?, + accountViewModel: AccountViewModel, + nav: INav?, + ) = AppLoadUrlPreview( + url = url, + urlText = urlText, + callbackUri = callbackUri, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun LocationPreviewMap( + latitude: Double, + longitude: Double, + aspectRatio: Float, + pinColor: Color?, + pinEmoji: String?, + pinAlpha: Float, + ) = AppLocationPreviewMap( + latitude = latitude, + longitude = longitude, + aspectRatio = aspectRatio, + pinColor = pinColor, + pinEmoji = pinEmoji, + pinAlpha = pinAlpha, + ) + + @Composable + override fun LoadCityName( + geohashStr: String, + onLoading: (@Composable () -> Unit)?, + content: @Composable (String) -> Unit, + ) = AppLoadCityName( + geohashStr = geohashStr, + onLoading = onLoading, + content = content, + ) + + @Composable + override fun RenderAudioTrack( + note: Note, + contentScale: ContentScale, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderAudioTrack( + note = note, + contentScale = contentScale, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderMusicTrack( + note: Note, + makeItShort: Boolean, + canPreview: Boolean, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderMusicTrack( + note = note, + makeItShort = makeItShort, + canPreview = canPreview, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun PodcastEpisodeAudioPlayer( + audio: PodcastAudio, + note: Note, + title: String?, + image: String?, + borderModifier: Modifier, + accountViewModel: AccountViewModel, + ) = AppPodcastEpisodeAudioPlayer( + audio = audio, + note = note, + title = title, + image = image, + borderModifier = borderModifier, + accountViewModel = accountViewModel, + ) + + @Composable + override fun RenderVoiceTrack( + note: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderVoiceTrack( + note = note, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderAudioFromIMeta( + note: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderAudioFromIMeta( + note = note, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderAudioWithWaveform( + mediaUrl: String, + title: String?, + mimeType: String?, + waveform: WaveformData?, + note: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderAudioWithWaveform( + mediaUrl = mediaUrl, + title = title, + mimeType = mimeType, + waveform = waveform, + note = note, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderChessGame( + note: Note, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderChessGame( + note = note, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderLiveChessChallenge( + note: Note, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderLiveChessChallenge( + note = note, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderLiveChessGameEnd( + note: Note, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderLiveChessGameEnd( + note = note, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderGitRepositoryEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderGitRepositoryEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderGitPatchEvent( + baseNote: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderGitPatchEvent( + baseNote = baseNote, + makeItShort = makeItShort, + canPreview = canPreview, + quotesLeft = quotesLeft, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderGitIssueEvent( + baseNote: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderGitIssueEvent( + baseNote = baseNote, + makeItShort = makeItShort, + canPreview = canPreview, + quotesLeft = quotesLeft, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderGitPullRequestEvent( + baseNote: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderGitPullRequestEvent( + baseNote = baseNote, + makeItShort = makeItShort, + canPreview = canPreview, + quotesLeft = quotesLeft, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderGitPullRequestUpdateEvent( + baseNote: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderGitPullRequestUpdateEvent( + baseNote = baseNote, + makeItShort = makeItShort, + canPreview = canPreview, + quotesLeft = quotesLeft, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderCalendarRSVPEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderCalendarRSVPEvent( + note = baseNote, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderMeetingSpaceEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderMeetingSpaceEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderMeetingRoomEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderMeetingRoomEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderMeetingRoomPresence( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderMeetingRoomPresence( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderRootNappletEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderRootNappletEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderNamedNappletEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderNamedNappletEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderRootSiteEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderRootSiteEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun RenderNamedSiteEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppRenderNamedSiteEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun ReactionsRow( + baseNote: Note, + showReactionDetail: Boolean, + addPadding: Boolean, + editState: State>?, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppReactionsRow( + baseNote = baseNote, + showReactionDetail = showReactionDetail, + addPadding = addPadding, + editState = editState, + accountViewModel = accountViewModel, + nav = nav, + ) + + @Composable + override fun LikeReaction( + baseNote: Note, + grayTint: Color, + accountViewModel: AccountViewModel, + nav: INav, + iconSize: Dp, + heartSizeModifier: Modifier, + iconFontSize: TextUnit, + showCounter: Boolean, + ) = AppLikeReaction( + baseNote = baseNote, + grayTint = grayTint, + accountViewModel = accountViewModel, + nav = nav, + iconSize = iconSize, + heartSizeModifier = heartSizeModifier, + iconFontSize = iconFontSize, + showCounter = showCounter, + ) + + @Composable + override fun ZapReaction( + baseNote: Note, + grayTint: Color, + accountViewModel: AccountViewModel, + iconSize: Dp, + iconSizeModifier: Modifier, + animationModifier: Modifier, + showCounter: Boolean, + nav: INav, + ) = AppZapReaction( + baseNote = baseNote, + grayTint = grayTint, + accountViewModel = accountViewModel, + iconSize = iconSize, + iconSizeModifier = iconSizeModifier, + animationModifier = animationModifier, + showCounter = showCounter, + nav = nav, + ) + + @Composable + override fun EditPostView( + onClose: () -> Unit, + edit: Note, + versionLookingAt: Note?, + accountViewModel: AccountViewModel, + nav: INav, + ) = AppEditPostView( + onClose = onClose, + edit = edit, + versionLookingAt = versionLookingAt, + accountViewModel = accountViewModel, + nav = nav, + ) +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/QrPayload.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/QrPayload.kt index e07753189c..63ae327439 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/QrPayload.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/QrPayload.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.ui.note.share import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.ui.note.externalLinkForNote +import com.vitorpamplona.amethyst.commons.ui.note.externalLinkForNote /** Which of the two payloads the QR code currently encodes. */ enum class QrPayloadMode { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/ShareNoteAsImageScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/ShareNoteAsImageScreen.kt index 3c37165384..74a9cee072 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/ShareNoteAsImageScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/ShareNoteAsImageScreen.kt @@ -90,19 +90,19 @@ import com.vitorpamplona.amethyst.commons.resources.share_as_image import com.vitorpamplona.amethyst.commons.resources.share_as_image_generating import com.vitorpamplona.amethyst.commons.resources.share_as_image_url import com.vitorpamplona.amethyst.commons.resources.share_as_image_watermark +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.components.TextSpinner import com.vitorpamplona.amethyst.commons.ui.components.TitleExplainer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size18Modifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadingState import com.vitorpamplona.amethyst.ui.actions.uploads.UploadProgressIndicator -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/ShareNoteAsQrScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/ShareNoteAsQrScreen.kt index 70320f2e5d..9044bcecb9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/ShareNoteAsQrScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/ShareNoteAsQrScreen.kt @@ -49,6 +49,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.share_as_qr import com.vitorpamplona.amethyst.commons.resources.share_as_qr_code_description_nostr @@ -57,12 +58,11 @@ import com.vitorpamplona.amethyst.commons.resources.share_as_qr_hint_nostr import com.vitorpamplona.amethyst.commons.resources.share_as_qr_hint_web import com.vitorpamplona.amethyst.commons.resources.share_as_qr_mode_nostr import com.vitorpamplona.amethyst.commons.resources.share_as_qr_mode_web +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.KeepScreenBrightAndAwake import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.QrCodeDrawer diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/SharedNoteCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/SharedNoteCard.kt index f0d9265a41..bf1e6a0050 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/SharedNoteCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/SharedNoteCard.kt @@ -45,6 +45,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.article import com.vitorpamplona.amethyst.commons.resources.content_warning_with_reason @@ -53,12 +54,11 @@ import com.vitorpamplona.amethyst.commons.resources.share_as_qr_kind_picture import com.vitorpamplona.amethyst.commons.resources.share_as_qr_thumbnail_hidden_sensitive import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.RichTextParser +import com.vitorpamplona.amethyst.commons.ui.components.collectContentWarningReasons import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteAuthorPicture import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.components.collectContentWarningReasons -import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.gallery.GalleryThumbnail import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.gallery.UrlImageView import com.vitorpamplona.quartz.experimental.profileGallery.ProfileGalleryEntryEvent @@ -84,7 +84,7 @@ private val ThumbShape = RoundedCornerShape(9.dp) * * The height is fixed on purpose: it keeps the QR code in the same screen position for every * note, so the screen is predictable to hold up to a scanner. That is why this does not use - * [com.vitorpamplona.amethyst.ui.note.NoteCompose] — see the design spec for the full reasoning, + * [com.vitorpamplona.amethyst.commons.ui.note.NoteCompose] — see the design spec for the full reasoning, * but in short, `isQuotedNote` never reaches the media renderer and note images render at their * natural aspect ratio with no height ceiling. */ diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ActivityCardPreviews.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ActivityCardPreviews.kt index d63b6a8880..a87a1a62e7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ActivityCardPreviews.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ActivityCardPreviews.kt @@ -26,11 +26,15 @@ import androidx.compose.runtime.remember import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.model.ZapAmountCommentNotification import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderNutzap +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderOnchainZap +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderReaction +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderZapReceiptCard import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.note.ZapAmountCommentNotification -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent import com.vitorpamplona.quartz.nip61Nutzaps.nutzap.NutzapEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt index 58625979f3..0be9b589bf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt @@ -41,20 +41,20 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import com.vitorpamplona.amethyst.commons.audio.WaveformData import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayUncitedHashtags +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.playback.composable.LoadThumbAndThenVideoView import com.vitorpamplona.amethyst.service.playback.composable.VideoView -import com.vitorpamplona.amethyst.service.playback.composable.WaveformData -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.experimental.audio.header.AudioHeaderEvent import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent import com.vitorpamplona.quartz.experimental.audio.track.tags.ParticipantTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CalendarRsvpRender.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CalendarRsvpRender.kt index 49e6eaebaf..5a898c4e03 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CalendarRsvpRender.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CalendarRsvpRender.kt @@ -41,20 +41,20 @@ import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip52Calendar.appointmentView +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.CalendarRsvpCard +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.WatchNoteEvent import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.CalendarAppointmentLines import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.CalendarDateBadge import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.detailRouteFor import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.formatCalendarRange import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.rememberRelativeTimeLabel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip52Calendar.appt.day.CalendarDateSlotEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Chess.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Chess.kt index a9907ff6f7..d1afd49999 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Chess.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Chess.kt @@ -53,14 +53,14 @@ 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 +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chess.ChessViewModelFactory import com.vitorpamplona.quartz.nip64Chess.challenge.offer.LiveChessGameChallengeEvent import com.vitorpamplona.quartz.nip64Chess.end.LiveChessGameEndEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt index 002c3ad80f..0b2c9ffca1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt @@ -64,6 +64,7 @@ import com.vitorpamplona.amethyst.commons.nip34Git.GitBrowseState import com.vitorpamplona.amethyst.commons.nip34Git.GitRepoSnapshotCache import com.vitorpamplona.amethyst.commons.nip34Git.GitRepositoryBrowserViewModel import com.vitorpamplona.amethyst.commons.nip34Git.ui.GitStatusPill +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.git_branch import com.vitorpamplona.amethyst.commons.resources.git_clone_address @@ -77,9 +78,15 @@ import com.vitorpamplona.amethyst.commons.resources.kind_git_patch import com.vitorpamplona.amethyst.commons.resources.kind_git_pr import com.vitorpamplona.amethyst.commons.resources.kind_git_pr_update import com.vitorpamplona.amethyst.commons.resources.kind_git_repo +import com.vitorpamplona.amethyst.commons.ui.components.ClickableUrlOrBlossom +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.GitDiffView +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.LoadDecryptedContent import com.vitorpamplona.amethyst.commons.ui.note.StatusKind +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayUncitedHashtags import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Font12SP import com.vitorpamplona.amethyst.commons.ui.theme.HalfDoubleVertSpacer @@ -90,14 +97,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size8dp import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.components.ClickableUrl -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.LoadDecryptedContent -import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.GitRepositoryBrowserViewModelFactory import com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.RepoExternalNotice import com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.RepoLanguageBar @@ -206,7 +206,7 @@ private fun LinkRow( modifier = Modifier.size(Size16dp), tint = MaterialTheme.colorScheme.grayText, ) - ClickableUrl( + ClickableUrlOrBlossom( url = url, urlText = url.removePrefix("https://").removePrefix("http://"), style = style, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/GitPullRequestChanges.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/GitPullRequestChanges.kt index 280c29f59c..a30a273e17 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/GitPullRequestChanges.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/GitPullRequestChanges.kt @@ -50,7 +50,7 @@ import com.vitorpamplona.amethyst.commons.resources.git_pr_no_changes import com.vitorpamplona.amethyst.commons.resources.git_pr_view_changes import com.vitorpamplona.amethyst.commons.ui.note.GitDiffView import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip34Git.git.GitHttpClient import com.vitorpamplona.quartz.nip34Git.patch.ParsedPatch import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/GitStatusActions.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/GitStatusActions.kt index 79be00fbe5..76ce59a641 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/GitStatusActions.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/GitStatusActions.kt @@ -28,7 +28,7 @@ import com.vitorpamplona.amethyst.commons.model.GitStatusIndex import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.nip34Git.ui.GitStatusButtons -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MusicTrack.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MusicTrack.kt index 026f8c118c..1fd6a4765a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MusicTrack.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MusicTrack.kt @@ -61,27 +61,27 @@ import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists import com.vitorpamplona.amethyst.commons.music.formatTrackDuration import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeader +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeaderBackground import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Font10SP import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.service.playback.composable.GetVideoController import com.vitorpamplona.amethyst.service.playback.composable.LoadThumbAndThenVideoView import com.vitorpamplona.amethyst.service.playback.composable.PauseControllerWhenInBackground import com.vitorpamplona.amethyst.service.playback.composable.VideoView import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.GetMediaItem import com.vitorpamplona.amethyst.service.playback.composable.wavefront.syntheticWaveformFor -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeaderBackground -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.quartz.experimental.music.track.MusicTrackEvent import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastEpisodeAudioPlayer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastEpisodeAudioPlayer.kt index 21521aaa1e..cd419e24fb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastEpisodeAudioPlayer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastEpisodeAudioPlayer.kt @@ -29,14 +29,16 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import com.vitorpamplona.amethyst.commons.audio.WaveformData import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.ui.note.PodcastSoundbites +import com.vitorpamplona.amethyst.commons.ui.note.types.PodcastChaptersView +import com.vitorpamplona.amethyst.commons.ui.note.types.getAudioMetaWithWaveform +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.playback.composable.GetVideoController import com.vitorpamplona.amethyst.service.playback.composable.PauseControllerWhenInBackground -import com.vitorpamplona.amethyst.service.playback.composable.WaveformData import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.GetMediaItem import com.vitorpamplona.amethyst.service.playback.composable.wavefront.syntheticWaveformFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.podcasts.PodcastAudio import com.vitorpamplona.quartz.podcasts.PodcastEpisode diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastStreamingControl.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastStreamingControl.kt index 82a64df90f..cecdc97d65 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastStreamingControl.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastStreamingControl.kt @@ -58,8 +58,8 @@ import com.vitorpamplona.amethyst.commons.resources.podcast_value_stream_require import com.vitorpamplona.amethyst.commons.resources.podcast_value_streamed_total import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.grayText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.playback.composable.MediaControllerState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.podcasts.PodcastStreamingAccrual import com.vitorpamplona.quartz.podcasts.PodcastValue import kotlinx.coroutines.delay @@ -145,7 +145,6 @@ fun PodcastStreamingControl( podcastName = podcastName, episodeName = episodeName, zappedNote = note, - context = context, streaming = true, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ProfileCardPreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ProfileCardPreview.kt index 8335167a5f..6a5fed4b13 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ProfileCardPreview.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ProfileCardPreview.kt @@ -32,9 +32,10 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderProfileCard import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/StaticWebsite.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/StaticWebsite.kt index fd99c5a8de..f8c8cf0b36 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/StaticWebsite.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/StaticWebsite.kt @@ -27,11 +27,11 @@ import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.StaticWebsiteCard +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.favorites.FavoriteAppLauncher import com.vitorpamplona.amethyst.napplet.NappletLauncher import com.vitorpamplona.amethyst.napplethost.HostProfile import com.vitorpamplona.amethyst.napplethost.NappletBlobPrefetcher -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.favorites.FavoriteToggleButton import com.vitorpamplona.quartz.nip5aStaticWebsites.NamedSiteEvent import com.vitorpamplona.quartz.nip5aStaticWebsites.RootSiteEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/VideoDisplay.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/VideoDisplay.kt index d5fc96afb7..d6017a041d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/VideoDisplay.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/VideoDisplay.kt @@ -25,6 +25,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.layout.ContentScale +import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.nip71Video.selectVideoTrack import com.vitorpamplona.amethyst.commons.richtext.BaseMediaContent @@ -32,13 +33,12 @@ import com.vitorpamplona.amethyst.commons.richtext.MediaContentKind import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo import com.vitorpamplona.amethyst.commons.richtext.RichTextParser -import com.vitorpamplona.amethyst.model.MediaAspectRatioCache -import com.vitorpamplona.amethyst.ui.components.BlurhashBackdrop -import com.vitorpamplona.amethyst.ui.components.ContentWarningGate +import com.vitorpamplona.amethyst.commons.ui.components.BlurhashBackdrop +import com.vitorpamplona.amethyst.commons.ui.components.ContentWarningGate +import com.vitorpamplona.amethyst.commons.ui.components.collectContentWarningReasons +import com.vitorpamplona.amethyst.commons.ui.components.mediaSizingModifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.ZoomableContentView -import com.vitorpamplona.amethyst.ui.components.collectContentWarningReasons -import com.vitorpamplona.amethyst.ui.components.mediaSizingModifier -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip36SensitiveContent.isSensitiveOrNSFW diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/VoiceTrack.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/VoiceTrack.kt index 502b9da0e2..137fc0b083 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/VoiceTrack.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/VoiceTrack.kt @@ -45,6 +45,7 @@ import androidx.media3.common.util.UnstableApi import androidx.media3.ui.compose.ContentFrame import androidx.media3.ui.compose.SURFACE_TYPE_TEXTURE_VIEW import androidx.media3.ui.compose.state.rememberPlayPauseButtonState +import com.vitorpamplona.amethyst.commons.audio.WaveformData import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note @@ -53,17 +54,19 @@ import com.vitorpamplona.amethyst.commons.resources.pause import com.vitorpamplona.amethyst.commons.resources.play import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayUncitedHashtags +import com.vitorpamplona.amethyst.commons.ui.note.types.getAudioMetaWithWaveform import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.MaxWidthPaddingTop5dp import com.vitorpamplona.amethyst.commons.ui.theme.Size50Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size75Modifier import com.vitorpamplona.amethyst.commons.ui.theme.VoiceHeightModifier import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.playback.composable.DEFAULT_MUTED_SETTING import com.vitorpamplona.amethyst.service.playback.composable.GetVideoController import com.vitorpamplona.amethyst.service.playback.composable.MediaControllerState import com.vitorpamplona.amethyst.service.playback.composable.PauseControllerWhenInBackground -import com.vitorpamplona.amethyst.service.playback.composable.WaveformData import com.vitorpamplona.amethyst.service.playback.composable.controls.AnimatedSaveButton import com.vitorpamplona.amethyst.service.playback.composable.controls.AnimatedShareButton import com.vitorpamplona.amethyst.service.playback.composable.controls.MuteButton @@ -76,13 +79,9 @@ import com.vitorpamplona.amethyst.service.playback.composable.wavefront.Waveform import com.vitorpamplona.amethyst.service.playback.pip.PipVideoActivity import com.vitorpamplona.amethyst.ui.components.ShareMediaAction import com.vitorpamplona.amethyst.ui.components.getActivity -import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.amethyst.ui.screen.loggedIn.saveMediaToGallery import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags import com.vitorpamplona.quartz.nip14Subject.subject -import com.vitorpamplona.quartz.nip92IMeta.imetas -import com.vitorpamplona.quartz.nipA0VoiceMessages.AudioMeta import com.vitorpamplona.quartz.nipA0VoiceMessages.BaseVoiceEvent @Composable @@ -320,26 +319,6 @@ fun PlayPauseButton(controllerState: MediaControllerState) { } } -/** - * Extracts AudioMeta from an event's IMeta tags if it has audio content with waveform. - * Returns the first audio IMeta that has a waveform, or null if none found. - */ -fun Event.getAudioMetaWithWaveform(): AudioMeta? { - val audioMetas = imetas().map { AudioMeta.parse(it) } - return audioMetas.firstOrNull { meta -> - meta.waveform != null && - (meta.mimeType == null || meta.mimeType?.startsWith("audio/") == true) - } -} - -/** - * Checks if the event content is primarily an audio attachment (content is just the audio URL). - */ -fun Event.isAudioOnlyContent(): Boolean { - val audioMeta = getAudioMetaWithWaveform() ?: return false - return content.trim() == audioMeta.url -} - /** * Renders audio with waveform for any event type that has audio IMeta attachment. * This allows KIND 1 (TextNoteEvent) and KIND 1111 (CommentEvent) with voice diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/platform/AndroidAppPlatform.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/platform/AndroidAppPlatform.kt new file mode 100644 index 0000000000..47ad8b75a9 --- /dev/null +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/platform/AndroidAppPlatform.kt @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.ui.platform + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppPlatform +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.ui.navigation.topbars.AndroidAroundMeLocationLabel +import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar as AppBottomBarImpl +import com.vitorpamplona.amethyst.ui.note.creators.location.GeohashLocationPickerContent as AppGeohashLocationPickerContent +import com.vitorpamplona.amethyst.ui.note.creators.location.GeohashLocationPickerDialog as AppGeohashLocationPickerDialog + +/** Android's [AppPlatform]: the app's own bottom bar and location label. */ +object AndroidAppPlatform : AppPlatform { + @Composable + override fun AppBottomBar( + selectedRoute: Route?, + nav: INav, + accountViewModel: AccountViewModel, + onClick: (Route) -> Unit, + ) = AppBottomBarImpl(selectedRoute, nav, accountViewModel, onClick) + + @Composable + override fun AroundMeLocationLabel() = AndroidAroundMeLocationLabel() + + @Composable + override fun GeohashLocationPickerDialog( + initialGeohash: String?, + onDismiss: () -> Unit, + onConfirm: (String) -> Unit, + ) = AppGeohashLocationPickerDialog(initialGeohash, onDismiss, onConfirm) + + @Composable + override fun GeohashLocationPickerContent( + initialGeohash: String?, + confirmLabel: String, + onConfirm: (String) -> Unit, + modifier: Modifier, + ) = AppGeohashLocationPickerContent(initialGeohash, confirmLabel, onConfirm, modifier) +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountSessionManager.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountSessionManager.kt index 3c268af808..ed96127a5e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountSessionManager.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountSessionManager.kt @@ -25,9 +25,11 @@ import com.vitorpamplona.amethyst.AccountInfo import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.commons.defaults.DefaultNIP65RelaySet +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.navigation.Route -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.AccountSettings +import com.vitorpamplona.amethyst.commons.nests.room.activity.NestBridge +import com.vitorpamplona.amethyst.commons.service.call.CallSessionBridge import com.vitorpamplona.amethyst.model.accountsCache.AccountCacheState import com.vitorpamplona.amethyst.model.nip60Cashu.CashuPreferences import com.vitorpamplona.amethyst.service.notifications.ConversationShortcuts @@ -366,12 +368,12 @@ class AccountSessionManager( // through a process-singleton bridge. Drop the previous user's // ref before swapping so a stale ref can't survive into the new // session — see [NestBridge]. - com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.activity.NestBridge + NestBridge .clear() // A call belongs to the account that placed it, so end it before swapping users — see // [CallSessionBridge]. This is the real "account switch" hook; MainActivity being // destroyed is not. - com.vitorpamplona.amethyst.service.call.CallSessionBridge + CallSessionBridge .clear() localPreferences.switchToAccount(accountInfo) loginWithDefaultAccount(routeBuilder) @@ -414,10 +416,10 @@ class AccountSessionManager( // Drop the Nest bridge ref before tearing down the // current account so the audio-room activity can't // pick up a stale AccountViewModel — see [NestBridge]. - com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.activity.NestBridge + NestBridge .clear() // End any call this account had running before its state is torn down. - com.vitorpamplona.amethyst.service.call.CallSessionBridge + CallSessionBridge .clear() // log off and relogin with the 0 account localPreferences.deleteAccount(accountInfo) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt index 27f15114a7..767e5dd2f6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt @@ -28,7 +28,7 @@ import androidx.lifecycle.viewmodel.compose.rememberViewModelStoreOwner /** * Provides a [androidx.lifecycle.ViewModelStoreOwner] scoped to the currently logged-in account so - * that every ViewModel created under it (the [com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel] + * that every ViewModel created under it (the [com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel] * and all of its children) lives and dies with that account. * * The owner is keyed by the account's public key via [key]. While the same account stays logged in, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt index d4ffca2d73..75fe22c6e7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt @@ -39,10 +39,10 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox import com.vitorpamplona.amethyst.commons.ui.feeds.StickToTopOnPrepend import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserCompose import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.note.UserCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun RefreshingFeedUserFeedView( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountSwitcherAndLeftDrawerLayout.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountSwitcherAndLeftDrawerLayout.kt index 475ef9d787..d601b4f9a2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountSwitcherAndLeftDrawerLayout.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountSwitcherAndLeftDrawerLayout.kt @@ -51,6 +51,7 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.layouts.LocalScreenLayout import com.vitorpamplona.amethyst.commons.ui.layouts.NavigationStyle import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppNavigationRail import com.vitorpamplona.amethyst.ui.navigation.drawer.AccountSwitchBottomSheet import com.vitorpamplona.amethyst.ui.navigation.drawer.DrawerContent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModelAndroidActions.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModelAndroidActions.kt new file mode 100644 index 0000000000..0fcc03aaa3 --- /dev/null +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModelAndroidActions.kt @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.ui.screen.loggedIn + +import android.content.Context +import android.net.Uri +import android.os.Handler +import android.os.Looper +import android.widget.Toast +import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.marmot.MarmotGroupIconUpload +import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.failed_to_save_the_video +import com.vitorpamplona.amethyst.commons.resources.video_saved_to_the_gallery +import com.vitorpamplona.amethyst.commons.service.isVideoOnline +import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewState +import com.vitorpamplona.amethyst.commons.ui.loadStringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.model.UrlCachedPreviewer +import com.vitorpamplona.amethyst.ui.actions.MediaSaverToDisk +import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.send.MarmotGroupIconUploader +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +// Account actions that need Android (a content Uri, the media store) or the JVM HTTP stack the +// app's OkHttp clients come from. They stay out of AccountViewModel so the view model needs neither. + +fun AccountViewModel.urlPreview( + url: String, + onResult: suspend (UrlPreviewState) -> Unit, +) { + viewModelScope.launch(Dispatchers.IO) { + UrlCachedPreviewer.previewInfo(url, httpClientBuilder::okHttpClientForPreview, onResult) + } +} + +suspend fun AccountViewModel.checkVideoIsOnline(videoUrl: String): Boolean = httpClientBuilder.isVideoOnline(videoUrl) + +/** + * Encrypt + upload a picked image as a group avatar (canonical `marmot-group-image-v1` scheme). + * The returned handle is later passed to [AccountViewModel.updateMarmotGroupMetadata] as + * `MarmotGroupIconChange.Set` to commit it into the group's metadata. Uploading is separated from + * the metadata commit so the (slow) Blossom upload can show its own progress before the commit is + * signed. + */ +suspend fun AccountViewModel.uploadMarmotGroupIcon( + uri: Uri, + mimeType: String?, + context: Context, +): MarmotGroupIconUpload = MarmotGroupIconUploader(account).upload(uri, mimeType, account.settings.defaultFileServer, context) + +fun AccountViewModel.saveMediaToGallery( + videoUri: String?, + mimeType: String?, + localContext: Context, +) { + viewModelScope.launch { + // onSuccess is a plain callback, so the text is resolved here first. + val savedText = loadStringRes(Res.string.video_saved_to_the_gallery) + MediaSaverToDisk.saveDownloadingIfNeeded( + videoUri = videoUri, + okHttpClient = httpClientBuilder::okHttpClientForVideo, + mimeType = mimeType, + localContext = localContext, + resolveBlossom = { + Amethyst.instance.blossomResolver + .findServers(it) + ?.serverUrl + }, + onSuccess = { + Handler(Looper.getMainLooper()).post { + Toast + .makeText(localContext.applicationContext, savedText, Toast.LENGTH_SHORT) + .show() + } + }, + onError = { + toastManager.toast(Res.string.failed_to_save_the_video, null, it) + }, + ) + } +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AndroidAccountViewModelHost.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AndroidAccountViewModelHost.kt new file mode 100644 index 0000000000..a3f5135e7d --- /dev/null +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AndroidAccountViewModelHost.kt @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.ui.screen.loggedIn + +import android.app.NotificationManager +import androidx.core.content.ContextCompat +import com.vitorpamplona.amethyst.AccountInfo +import com.vitorpamplona.amethyst.AppModules +import com.vitorpamplona.amethyst.LocalPreferences +import com.vitorpamplona.amethyst.commons.service.lnurl.LnurlHttpTransport +import com.vitorpamplona.amethyst.commons.service.lnurl.OkHttpLnurlTransport +import com.vitorpamplona.amethyst.commons.service.pow.PoWJobFailure +import com.vitorpamplona.amethyst.commons.tor.MoneyOpRelayRouting +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModelHost +import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.dismissNotificationForEvent +import com.vitorpamplona.amethyst.ui.note.payViaIntent +import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.toHexKey +import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStats +import com.vitorpamplona.quartz.nip01Core.relay.sockets.WebsocketBuilder +import com.vitorpamplona.quartz.nip19Bech32.bech32.bechToBytes +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onStart + +/** [AccountViewModelHost] over the app's [AppModules]. Lazy services are read on first use. */ +class AndroidAccountViewModelHost( + private val modules: AppModules, +) : AccountViewModelHost { + override val memoryPressure: Flow get() = modules.memoryPressureEvents + + override val localBlossomCacheAvailable: Flow get() = modules.localBlossomCacheProbe.available + + override val powPublishFailures: Flow get() = modules.powPublishQueue.failures + + override val relayStats: RelayStats get() = modules.relayStats + + override val websocketBuilder: WebsocketBuilder get() = modules.websocketBuilder + + override val lnurlTransport: LnurlHttpTransport by lazy { OkHttpLnurlTransport(modules.roleBasedHttpClientBuilder::okHttpClientForMoney) } + + override val moneyOpRelays: MoneyOpRelayRouting get() = modules.torEvaluatorFlow + + override val savedAccounts: Flow> = + LocalPreferences + .accountsFlow() + .map { toPubKeys(it) } + .onStart { emit(toPubKeys(LocalPreferences.allSavedAccounts())) } + + override fun dismissNotificationFor(eventId: HexKey) { + ContextCompat + .getSystemService(modules.appContext, NotificationManager::class.java) + ?.dismissNotificationForEvent(eventId) + } + + override fun openLightningWallet(invoice: String): Boolean { + var opened = true + payViaIntent(invoice, modules.appContext, "", onPaid = {}, onError = { opened = false }) + return opened + } + + private fun toPubKeys(accounts: List?): Set = + accounts + ?.mapNotNull { + try { + it.npub.bechToBytes().toHexKey() + } catch (e: Exception) { + if (e is CancellationException) throw e + null + } + }?.toSet() ?: emptySet() +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BottomBarFeedPreloaders.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BottomBarFeedPreloaders.kt index 585669b95c..3029725769 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BottomBarFeedPreloaders.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/BottomBarFeedPreloaders.kt @@ -26,33 +26,34 @@ import androidx.compose.runtime.key import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.navigation.BottomBarEntry import com.vitorpamplona.amethyst.commons.model.navigation.NavBarItem +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelSubscription +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.browse.datasource.BrowseEmojiSetsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.geocaches.datasource.GeocachesFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.gitRepositories.datasource.GitRepositoriesFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.highlights.datasource.HighlightsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.music.datasource.MusicTracksFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts.datasource.PodcastEpisodesFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts.datasource.PodcastsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.polls.datasource.PollsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.softwareapps.datasource.SoftwareAppsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts.datasource.WorkoutsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.articles.datasource.ArticlesFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.datasource.BadgesFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.datasource.CalendarsFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource.ChatroomListFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.list.datasource.CommunitiesListFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.datasource.DiscoveryFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.browse.datasource.BrowseEmojiSetsFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.list.datasource.FollowPacksFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.datasource.GeocachesFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepositories.datasource.GitRepositoriesFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.highlights.datasource.HighlightsFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.HomeFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.livestreams.datasource.LiveStreamsFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.longs.datasource.LongsFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.datasource.MusicTracksFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.datasource.NestsFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.pictures.datasource.PicturesFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.datasource.PodcastEpisodesFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.datasource.PodcastsFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.polls.datasource.PollsFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.products.datasource.ProductsFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.publicChats.datasource.PublicChatsFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.shorts.datasource.ShortsFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.softwareapps.datasource.SoftwareAppsFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.datasource.VideoFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.datasource.WorkoutsFilterAssemblerSubscription /** * Activates the relay subscription for each feed the user has pinned to the bottom diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoggedInPage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoggedInPage.kt index 0dca355381..8312cf5c02 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoggedInPage.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoggedInPage.kt @@ -40,11 +40,13 @@ import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.rememberPermissionState import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.LocalPreferences +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.error_opening_external_signer import com.vitorpamplona.amethyst.commons.resources.error_opening_external_signer_description -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelPreload +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.notifications.PushNotificationUtils import com.vitorpamplona.amethyst.service.relayClient.authCommand.compose.RelayAuthSubscription import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountFilterAssemblerSubscription @@ -53,7 +55,6 @@ import com.vitorpamplona.amethyst.service.resourceusage.innermostSigner import com.vitorpamplona.amethyst.ui.navigation.AppNavigation import com.vitorpamplona.amethyst.ui.screen.AccountSessionManager import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.BuzzDmDiscoveryPreload -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelPreload import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.BuzzDmJoinedChatTailPreload import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupJoinedChatTailPreload import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupJoinedStatePreload @@ -69,18 +70,17 @@ fun LoggedInPage( accountSessionManager: AccountSessionManager, ) { val accountViewModel: AccountViewModel = - viewModel( - key = "AccountViewModel", - factory = - AccountViewModel.Factory( - account = account, - settings = Amethyst.instance.uiState, - torSettings = Amethyst.instance.torPrefs.value, - dataSources = Amethyst.instance.sources, - okHttpClient = Amethyst.instance.roleBasedHttpClientBuilder, - nip05ClientBuilder = { Amethyst.instance.nip05Client }, - ), - ) + viewModel(key = "AccountViewModel") { + AccountViewModel( + account = account, + settings = Amethyst.instance.uiState, + torSettings = Amethyst.instance.torPrefs.value, + dataSources = Amethyst.instance.sources, + httpClientBuilder = Amethyst.instance.roleBasedHttpClientBuilder, + nip05ClientBuilder = { Amethyst.instance.nip05Client }, + host = AndroidAccountViewModelHost(Amethyst.instance), + ) + } LaunchedEffect(Unit) { accountViewModel.firstRoute = route diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/ArticlesFeedLoaded.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/ArticlesFeedLoaded.kt index 13ab488bfd..7ead0106ea 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/ArticlesFeedLoaded.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/ArticlesFeedLoaded.kt @@ -35,7 +35,7 @@ import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.ChannelCardCompose import com.vitorpamplona.quartz.nip23LongContent.LongFormContentEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/ArticlesScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/ArticlesScreen.kt index eeb34795ed..45c41fe5e5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/ArticlesScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/ArticlesScreen.kt @@ -28,15 +28,15 @@ import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.nip23LongContent.ui.NewArticleButton import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.articles.datasource.ArticlesFilterAssemblerSubscription @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/ArticlesTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/ArticlesTopBar.kt index 922e4f8445..8d1ef3f756 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/ArticlesTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/ArticlesTopBar.kt @@ -24,18 +24,18 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip23LongContent.LongFormContentEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/datasource/ArticlesFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/datasource/ArticlesFilterAssemblerSubscription.kt index 58eedf1702..9ca1720f0a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/datasource/ArticlesFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/datasource/ArticlesFilterAssemblerSubscription.kt @@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.articles.ArticlesFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun ArticlesFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictCards.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictCards.kt index 4091812db7..4517e10772 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictCards.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictCards.kt @@ -96,8 +96,8 @@ import com.vitorpamplona.amethyst.commons.resources.backup_conflict_title import com.vitorpamplona.amethyst.commons.resources.backup_review_changed_by_other_app import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.timeAgoNoDot +import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.concord.cord02Community.ConcordCommunityListDiff import com.vitorpamplona.quartz.experimental.ephemChat.list.EphemeralChatListDiff import com.vitorpamplona.quartz.nip01Core.diff.ContentChange diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictEventViews.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictEventViews.kt index b348bb27a9..a081aa07f3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictEventViews.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictEventViews.kt @@ -69,6 +69,8 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannel +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.backup_entry_hashtag import com.vitorpamplona.amethyst.commons.resources.backup_entry_mint @@ -130,24 +132,22 @@ import com.vitorpamplona.amethyst.commons.resources.backup_review_unmuted import com.vitorpamplona.amethyst.commons.resources.backup_review_unmuted_explainer import com.vitorpamplona.amethyst.commons.resources.backup_review_was_named import com.vitorpamplona.amethyst.commons.resources.backup_review_words_and_hashtags +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.elements.BannerImage import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.LoadRelayGroupChannel import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.util.toShortDisplay -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.elements.BannerImage +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.pluralStringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.LoadRelayGroupChannel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.diff.ContentChange diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictListViews.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictListViews.kt index fc4184018b..eba5ffc5f3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictListViews.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictListViews.kt @@ -61,6 +61,8 @@ import com.vitorpamplona.amethyst.commons.model.backups.ReplaceableBackupConflic import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.backup_review_allowed_tag import com.vitorpamplona.amethyst.commons.resources.backup_review_concord_body @@ -110,19 +112,17 @@ import com.vitorpamplona.amethyst.commons.resources.backup_type_communities import com.vitorpamplona.amethyst.commons.resources.backup_type_public_chats import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.LoadPublicChatChannel +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings +import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.util.toShortDisplay -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.LoadPublicChatChannel -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser -import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.concord.cord02Community.ConcordCommunityListDiff import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId import com.vitorpamplona.quartz.experimental.ephemChat.list.EphemeralChatListDiff diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictReviewScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictReviewScreen.kt index 45134b1724..30c307d28f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictReviewScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictReviewScreen.kt @@ -63,6 +63,7 @@ import com.vitorpamplona.amethyst.commons.model.backups.BackupEventType import com.vitorpamplona.amethyst.commons.model.backups.ReplaceableBackupConflict import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.backup_action_block_again import com.vitorpamplona.amethyst.commons.resources.backup_action_keep_count @@ -87,24 +88,23 @@ import com.vitorpamplona.amethyst.commons.resources.backup_conflict_restore_mine import com.vitorpamplona.amethyst.commons.resources.backup_review_changed_by_other_app import com.vitorpamplona.amethyst.commons.resources.backup_review_title_cleared import com.vitorpamplona.amethyst.commons.resources.backup_review_title_updated +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.LoadPublicChatChannel +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.note.timeAgoNoDot +import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.util.toShortDisplay -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.LoadPublicChatChannel -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser -import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.ephemChat.list.EphemeralChatListDiff import com.vitorpamplona.quartz.nip01Core.diff.ContentChange import com.vitorpamplona.quartz.nip01Core.metadata.MetadataDiff diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/BadgesScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/BadgesScreen.kt index 1f84678d6b..654cac5a9a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/BadgesScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/BadgesScreen.kt @@ -27,15 +27,15 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.datasource.BadgesFilterAssemblerSubscription @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/BadgesTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/BadgesTopBar.kt index 2773595236..a98a85ad36 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/BadgesTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/BadgesTopBar.kt @@ -23,17 +23,17 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.badges import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip58Badges.definition.BadgeDefinitionEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/NewBadgeButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/NewBadgeButton.kt index 7234d4424f..2703e96f57 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/NewBadgeButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/NewBadgeButton.kt @@ -30,14 +30,14 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.lifecycle.viewmodel.compose.viewModel -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.ic_compose import com.vitorpamplona.amethyst.commons.resources.new_badge +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.post.NewBadgeDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.post.NewBadgeModel @@ -61,7 +61,7 @@ fun NewBadgeButton(accountViewModel: AccountViewModel) { containerColor = MaterialTheme.colorScheme.primary, ) { Icon( - painter = painterRes(R.drawable.ic_compose, 5), + painter = painterRes(Res.drawable.ic_compose, 5), contentDescription = stringRes(id = Res.string.new_badge), modifier = Size26Modifier, tint = MaterialTheme.colorScheme.onPrimary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/award/AwardBadgeScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/award/AwardBadgeScreen.kt index c5dce60d0b..bcd80f4559 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/award/AwardBadgeScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/award/AwardBadgeScreen.kt @@ -59,12 +59,12 @@ import com.vitorpamplona.amethyst.commons.ui.components.Nip05OrPubkeyLine import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SavingTopBar +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightPage -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/award/AwardBadgeViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/award/AwardBadgeViewModel.kt index 85a86365c2..4b118984b9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/award/AwardBadgeViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/award/AwardBadgeViewModel.kt @@ -25,10 +25,10 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.tags.people.PTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/datasource/BadgesFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/datasource/BadgesFilterAssemblerSubscription.kt index d973e12507..6bdee17125 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/datasource/BadgesFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/datasource/BadgesFilterAssemblerSubscription.kt @@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.badges.BadgesFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun BadgesFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/post/NewBadgeDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/post/NewBadgeDialog.kt index b417ccb3d4..dbb9476edb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/post/NewBadgeDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/post/NewBadgeDialog.kt @@ -92,10 +92,10 @@ import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.Settin import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelect import com.vitorpamplona.amethyst.ui.actions.uploads.ShowImageUploadGallery import com.vitorpamplona.amethyst.ui.components.SetDialogToEdgeToEdge -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsRow import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/post/NewBadgeModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/post/NewBadgeModel.kt index b59ed9928f..b73ecb2534 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/post/NewBadgeModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/post/NewBadgeModel.kt @@ -28,6 +28,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.DEFAULT_MEDIA_SERVERS import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.resources.Res @@ -36,7 +37,6 @@ import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_ import com.vitorpamplona.amethyst.commons.resources.read_only_user import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/ArticleListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/ArticleListView.kt index 897f11f731..38524194f0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/ArticleListView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/ArticleListView.kt @@ -33,9 +33,9 @@ import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/BookmarkGroupItemOptions.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/BookmarkGroupItemOptions.kt index 4c31575212..b6b8eb9a21 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/BookmarkGroupItemOptions.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/BookmarkGroupItemOptions.kt @@ -62,18 +62,18 @@ import com.vitorpamplona.amethyst.commons.ui.components.M3ActionRow import com.vitorpamplona.amethyst.commons.ui.components.M3ActionSection import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeEditDraftTo import com.vitorpamplona.amethyst.commons.ui.note.VerticalDotsIcon +import com.vitorpamplona.amethyst.commons.ui.note.copyNoteTextAction +import com.vitorpamplona.amethyst.commons.ui.note.elements.DropDownParams +import com.vitorpamplona.amethyst.commons.ui.note.elements.observeBookmarksFollowsAndAccount +import com.vitorpamplona.amethyst.commons.ui.note.externalLinkForNote +import com.vitorpamplona.amethyst.commons.ui.note.types.EditState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.report.ReportNoteDialog import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size24Modifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.EditPostView -import com.vitorpamplona.amethyst.ui.navigation.routes.routeEditDraftTo -import com.vitorpamplona.amethyst.ui.note.copyNoteTextAction -import com.vitorpamplona.amethyst.ui.note.elements.DropDownParams -import com.vitorpamplona.amethyst.ui.note.elements.observeBookmarksFollowsAndAccount -import com.vitorpamplona.amethyst.ui.note.externalLinkForNote -import com.vitorpamplona.amethyst.ui.note.types.EditState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.report.ReportNoteDialog import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip23LongContent.LongFormContentEvent import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/BookmarkGroupScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/BookmarkGroupScreen.kt index a951f6deb1..837a4b38b1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/BookmarkGroupScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/BookmarkGroupScreen.kt @@ -80,7 +80,7 @@ import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding import com.vitorpamplona.amethyst.commons.ui.theme.TabRowHeight -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/BookmarkGroupViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/BookmarkGroupViewModel.kt index c23afd9fb3..7d6a37fe6a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/BookmarkGroupViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/BookmarkGroupViewModel.kt @@ -24,7 +24,7 @@ import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.AddressBookmark import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.BookmarkIdTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/PostListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/PostListView.kt index 1bb6113dcb..1deec14d08 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/PostListView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/display/PostListView.kt @@ -33,9 +33,9 @@ import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun RenderPostList( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/metadata/BookmarkGroupMetadataScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/metadata/BookmarkGroupMetadataScreen.kt index e637f79fc8..939def90c5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/metadata/BookmarkGroupMetadataScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/metadata/BookmarkGroupMetadataScreen.kt @@ -61,8 +61,8 @@ import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.SettingsCategoryFirstModifier import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectSingleFromGallery -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.SettingsCategory import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/metadata/BookmarkGroupMetadataViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/metadata/BookmarkGroupMetadataViewModel.kt index 1f2f4bc31a..4cd31cfd2f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/metadata/BookmarkGroupMetadataViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/metadata/BookmarkGroupMetadataViewModel.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType import com.vitorpamplona.amethyst.commons.model.nip51Lists.bookmarkSets.BookmarkSet import com.vitorpamplona.amethyst.commons.resources.Res @@ -40,7 +40,7 @@ import com.vitorpamplona.amethyst.commons.resources.metadata_strip_failed_title import com.vitorpamplona.amethyst.commons.resources.metadata_strip_failed_upload_cancelled import com.vitorpamplona.amethyst.commons.resources.server_did_not_provide_a_url_after_uploading import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.AvifMetadataNotVerifiableException import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.MediaCompressor @@ -48,7 +48,6 @@ import com.vitorpamplona.amethyst.service.uploads.MetadataStripper import com.vitorpamplona.amethyst.service.uploads.blossom.BlossomUploader import com.vitorpamplona.amethyst.service.uploads.nip96.Nip96Uploader import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -182,7 +181,7 @@ class BookmarkGroupMetadataViewModel : ViewModel() { alt = null, sensitiveContent = null, serverBaseUrl = account.settings.defaultFileServer.baseUrl, - okHttpClient = Amethyst.instance.roleBasedHttpClientBuilder::okHttpClientForUploads, + okHttpClient = accountViewModel.httpClientBuilder::okHttpClientForUploads, onProgress = {}, httpAuth = account::createHTTPAuthorization, context = context, @@ -195,7 +194,7 @@ class BookmarkGroupMetadataViewModel : ViewModel() { alt = null, sensitiveContent = null, serverBaseUrl = account.settings.defaultFileServer.baseUrl, - okHttpClient = Amethyst.instance.roleBasedHttpClientBuilder::okHttpClientForUploads, + okHttpClient = accountViewModel.httpClientBuilder::okHttpClientForUploads, httpAuth = account::createBlossomUploadAuth, context = context, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/OldBookmarkListScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/OldBookmarkListScreen.kt index 7c8f92bd13..6ddf7c23a6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/OldBookmarkListScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/OldBookmarkListScreen.kt @@ -59,15 +59,15 @@ import com.vitorpamplona.amethyst.commons.resources.old_bookmarks_title import com.vitorpamplona.amethyst.commons.resources.private_bookmarks import com.vitorpamplona.amethyst.commons.resources.public_bookmarks import com.vitorpamplona.amethyst.commons.ui.components.DeletedItemsBanner +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.TabRowHeight -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.old.dal.OldBookmarkPrivateFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.old.dal.OldBookmarkPublicFeedViewModel import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/dal/OldBookmarkPrivateFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/dal/OldBookmarkPrivateFeedFilter.kt index d2191ed8a3..10732d7ac2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/dal/OldBookmarkPrivateFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/dal/OldBookmarkPrivateFeedFilter.kt @@ -21,8 +21,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.old.dal import com.vitorpamplona.amethyst.commons.feeds.FeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.model.Account class OldBookmarkPrivateFeedFilter( val account: Account, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/dal/OldBookmarkPrivateFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/dal/OldBookmarkPrivateFeedViewModel.kt index 8372ccc220..21702425ae 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/dal/OldBookmarkPrivateFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/dal/OldBookmarkPrivateFeedViewModel.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.old.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel @Stable class OldBookmarkPrivateFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/dal/OldBookmarkPublicFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/dal/OldBookmarkPublicFeedFilter.kt index db18f1075c..cec82a37bb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/dal/OldBookmarkPublicFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/dal/OldBookmarkPublicFeedFilter.kt @@ -21,8 +21,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.old.dal import com.vitorpamplona.amethyst.commons.feeds.FeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.model.Account class OldBookmarkPublicFeedFilter( val account: Account, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/dal/OldBookmarkPublicFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/dal/OldBookmarkPublicFeedViewModel.kt index e02d8c15f1..e0093152d9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/dal/OldBookmarkPublicFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/old/dal/OldBookmarkPublicFeedViewModel.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.old.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel @Stable class OldBookmarkPublicFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/browser/BrowserScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/browser/BrowserScreen.kt index cfac4dccb1..725fd312a9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/browser/BrowserScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/browser/BrowserScreen.kt @@ -86,6 +86,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.icons.symbols.rememberMaterialSymbolPainter import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.browser_clear @@ -102,14 +103,14 @@ import com.vitorpamplona.amethyst.commons.resources.favorite_app_remove import com.vitorpamplona.amethyst.commons.resources.favorite_app_still_loading import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.nsites.datasource.NsitesFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.favorites.FavoriteAppLauncher import com.vitorpamplona.amethyst.favorites.PreloadFavoriteNostrApps import com.vitorpamplona.amethyst.favorites.rememberNappletIconModel -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.favorites.favoriteAppItems import com.vitorpamplona.amethyst.ui.screen.loggedIn.napplets.datasource.NappletsFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.nsites.datasource.NsitesFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip5aStaticWebsites.NamedSiteEvent @@ -199,10 +200,10 @@ private fun BrowserLauncher( NappletsFilterAssemblerSubscription(accountViewModel) val nsiteNotes by remember { - Amethyst.instance.cache.observeNotes(Filter(kinds = listOf(RootSiteEvent.KIND, NamedSiteEvent.KIND))) + LocalCache.observeNotes(Filter(kinds = listOf(RootSiteEvent.KIND, NamedSiteEvent.KIND))) }.collectAsStateWithLifecycle(emptyList()) val nappletNotes by remember { - Amethyst.instance.cache.observeNotes(Filter(kinds = listOf(RootNappletEvent.KIND, NamedNappletEvent.KIND))) + LocalCache.observeNotes(Filter(kinds = listOf(RootNappletEvent.KIND, NamedNappletEvent.KIND))) }.collectAsStateWithLifecycle(emptyList()) val nsiteFollows by accountViewModel.account.liveNsitesFollowLists.collectAsStateWithLifecycle() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/browser/WebAppScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/browser/WebAppScreen.kt index 946c2c9a40..7a50ebb6f3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/browser/WebAppScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/browser/WebAppScreen.kt @@ -75,14 +75,14 @@ import com.vitorpamplona.amethyst.commons.model.navigation.favoriteIds import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.browser_unsupported import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.favorites.FavoriteAppLauncher import com.vitorpamplona.amethyst.favorites.WebShortcuts import com.vitorpamplona.amethyst.napplet.WebAppNetworkRegistry import com.vitorpamplona.amethyst.napplet.WebSitePermissionRegistry import com.vitorpamplona.amethyst.napplethost.BrowserWebTools -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.EmbeddedTabChrome import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.EmbeddedTabFactory import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.EmbeddedTabHost diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentAttestationScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentAttestationScreen.kt index 273f518dd9..b235b71514 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentAttestationScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentAttestationScreen.kt @@ -66,6 +66,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.buzz.BuzzHeldAttestations import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserName import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.buzz_attest_after_label import com.vitorpamplona.amethyst.commons.resources.buzz_attest_agent_label @@ -93,10 +94,9 @@ import com.vitorpamplona.amethyst.commons.resources.buzz_attest_warning import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.buzz.oaOwnerAttestation.AttestationConditions import com.vitorpamplona.quartz.buzz.oaOwnerAttestation.OwnerAttestation import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentConsoleScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentConsoleScreen.kt index 4035ef5a1f..cb4940267a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentConsoleScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentConsoleScreen.kt @@ -64,7 +64,7 @@ import com.vitorpamplona.amethyst.commons.model.buzz.TokenTotals import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * The workspace owner's agent-owner console — a dashboard over the fleet of AI agents diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentConsoleViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentConsoleViewModel.kt index 11c9d91d79..bf21ff22b3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentConsoleViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentConsoleViewModel.kt @@ -23,13 +23,13 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.buzz.AgentFleetAggregator import com.vitorpamplona.amethyst.commons.model.buzz.AgentFleetMetrics import com.vitorpamplona.amethyst.commons.model.buzz.BuzzRelayDialect import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filter import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthDecision -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.buzz.amTurnMetrics.AgentTurnMetricEvent import com.vitorpamplona.quartz.buzz.amTurnMetrics.AgentTurnMetricPayload import com.vitorpamplona.quartz.buzz.aoObserver.ObserverFrameEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentWorkBoardScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentWorkBoardScreen.kt index 93bda944b7..b519809b21 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentWorkBoardScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentWorkBoardScreen.kt @@ -93,13 +93,13 @@ import com.vitorpamplona.amethyst.commons.model.buzz.AgentWorkKind import com.vitorpamplona.amethyst.commons.model.buzz.AgentWorkState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgo import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgoStyle import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentWorkBoardViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentWorkBoardViewModel.kt index 49ab04252a..99e32dec23 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentWorkBoardViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentWorkBoardViewModel.kt @@ -22,11 +22,11 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.buzz.AgentWorkBoard import com.vitorpamplona.amethyst.commons.model.buzz.AgentWorkItem import com.vitorpamplona.amethyst.commons.model.buzz.BuzzJobAggregator import com.vitorpamplona.amethyst.commons.model.buzz.WorkflowRunAggregator -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.buzz.workflow.ApprovalDenyEvent import com.vitorpamplona.quartz.buzz.workflow.ApprovalGrantEvent import com.vitorpamplona.quartz.buzz.workflow.WorkflowApprovalRequestedEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzAddPeopleDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzAddPeopleDialog.kt index b568a20083..f3dda59a9a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzAddPeopleDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzAddPeopleDialog.kt @@ -41,7 +41,6 @@ import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.resources.Res @@ -50,11 +49,11 @@ import com.vitorpamplona.amethyst.commons.resources.buzz_add_people_hint import com.vitorpamplona.amethyst.commons.resources.buzz_import_added import com.vitorpamplona.amethyst.commons.resources.cancel import com.vitorpamplona.amethyst.commons.resources.relay_group_add_member +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightChat -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import androidx.compose.runtime.LaunchedEffect as ComposeLaunchedEffect @@ -84,7 +83,7 @@ fun BuzzAddPeopleDialog( var query by remember { mutableStateOf("") } val userSuggestions = remember(accountViewModel) { - UserSuggestionState(accountViewModel.account, Amethyst.instance.nip05Client) + UserSuggestionState(accountViewModel.account, accountViewModel.nip05ClientBuilder()) } val focusRequester = remember { FocusRequester() } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzCanvasScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzCanvasScreen.kt index 33e46e4d59..ccf9e302cc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzCanvasScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzCanvasScreen.kt @@ -63,11 +63,11 @@ import com.vitorpamplona.amethyst.commons.resources.buzz_canvas_empty import com.vitorpamplona.amethyst.commons.resources.buzz_canvas_save import com.vitorpamplona.amethyst.commons.resources.buzz_canvas_title import com.vitorpamplona.amethyst.commons.resources.cancel +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.buzz.stream.CanvasEvent import com.vitorpamplona.quartz.buzz.workspace.isBuzzDm import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzDmDiscovery.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzDmDiscovery.kt index 36eb1dfd56..f0835ff2e2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzDmDiscovery.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzDmDiscovery.kt @@ -22,17 +22,17 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.buzz.BuzzChannelInvites import com.vitorpamplona.amethyst.commons.model.buzz.BuzzDmChannels import com.vitorpamplona.amethyst.commons.model.buzz.ChannelClassification +import com.vitorpamplona.amethyst.commons.model.buzz.buzzChannelTypes +import com.vitorpamplona.amethyst.commons.model.buzz.classifyBuzzChannel +import com.vitorpamplona.amethyst.commons.model.buzz.membershipNoticeFilter +import com.vitorpamplona.amethyst.commons.model.buzz.membershipNotices import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relayClient.channel.relayGroup.RELAY_GROUP_METADATA_KINDS -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.buzz.buzzChannelTypes -import com.vitorpamplona.amethyst.model.buzz.classifyBuzzChannel -import com.vitorpamplona.amethyst.model.buzz.membershipNoticeFilter -import com.vitorpamplona.amethyst.model.buzz.membershipNotices -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.fetchAllWithHooks import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @@ -48,7 +48,7 @@ import kotlinx.coroutines.flow.map * * The deployed relay does not expose a queryable DM list; it addresses each member a kind-44100 * member-added notification (`#p` = me). Those arrive through the ordinary subscription pipeline — - * [com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.buzz.BuzzMembershipEoseManager] + * [com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.buzz.BuzzMembershipEoseManager] * owns the one `#p=me` REQ per workspace relay — so this reads them back out of [LocalCache], fetches * each discovered channel's 39000-39003 directory (so its `t`=dm marker + participants land), and * records the ones that turn out to be DMs into [BuzzDmChannels]. The companion @@ -58,7 +58,7 @@ import kotlinx.coroutines.flow.map * * Everything else somebody added the viewer to is a named channel; it must NOT be silently subscribed, * so it stays out of [BuzzDmChannels] and surfaces as a prompt instead — see - * [com.vitorpamplona.amethyst.model.buzz.ChannelInvitesState], which projects the + * [com.vitorpamplona.amethyst.commons.model.buzz.ChannelInvitesState], which projects the * same cached notices. * * ### Recompute, don't accumulate diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzDmListScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzDmListScreen.kt index bac94781ee..5267f16fa3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzDmListScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzDmListScreen.kt @@ -68,6 +68,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserName import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.add_to_messages import com.vitorpamplona.amethyst.commons.resources.buzz_dm_add_hint @@ -86,13 +87,12 @@ import com.vitorpamplona.amethyst.commons.resources.remove_from_messages import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.note.TimeAgoLabels +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.note.rememberTimeAgoLabels import com.vitorpamplona.amethyst.commons.ui.note.timeAgoShort import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.isValid import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzDmListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzDmListViewModel.kt index 50eadb9aa2..1a0c63157f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzDmListViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzDmListViewModel.kt @@ -23,17 +23,17 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.buzz.BuzzChannelInvites import com.vitorpamplona.amethyst.commons.model.buzz.BuzzDmChannels import com.vitorpamplona.amethyst.commons.model.buzz.BuzzDmRegistry import com.vitorpamplona.amethyst.commons.model.buzz.BuzzRelayDialect +import com.vitorpamplona.amethyst.commons.model.buzz.membershipNoticeFilter +import com.vitorpamplona.amethyst.commons.model.buzz.membershipNotices import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filter import com.vitorpamplona.amethyst.commons.relayClient.channel.relayGroup.RELAY_GROUP_METADATA_KINDS import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthDecision -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.buzz.membershipNoticeFilter -import com.vitorpamplona.amethyst.model.buzz.membershipNotices import com.vitorpamplona.quartz.buzz.dvDmVisibility.DmVisibilityEvent import com.vitorpamplona.quartz.buzz.notifications.MemberAddedNotificationEvent import com.vitorpamplona.quartz.buzz.stream.StreamMessageV2Event @@ -296,7 +296,7 @@ class BuzzDmListViewModel : ViewModel() { * * The 44100/30622 stream itself is **not** subscribed here. `bind` marks this community's relay a * joined workspace, which is exactly what - * [com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.buzz.BuzzMembershipEoseManager] + * [com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.buzz.BuzzMembershipEoseManager] * keys its always-on `#p=me` subscription on — so opening this screen used to put a second, identical * REQ on the same relay. Observing [LocalCache] instead means the screen sees the same events at the * same time for free, and the relay sees one subscription. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzForumThreadScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzForumThreadScreen.kt index db6158135c..c75688b1cf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzForumThreadScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzForumThreadScreen.kt @@ -51,15 +51,15 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.buzz_forum_no_replies import com.vitorpamplona.amethyst.commons.resources.buzz_forum_thread_title import com.vitorpamplona.amethyst.commons.resources.chat_minichat_reply_count +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.send.EditFieldRow import com.vitorpamplona.quartz.buzz.forum.ForumCommentEvent import com.vitorpamplona.quartz.buzz.forum.ForumPostEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzImportRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzImportRow.kt index 53fd592704..528deed877 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzImportRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzImportRow.kt @@ -45,25 +45,25 @@ 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.chats.publicChannels.relayGroup.newestTimelineNote +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.relayGroupChannelUnreadCountFlow import com.vitorpamplona.amethyst.commons.concord.ui.ConcordUnreadBadge import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannel +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserName import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.relay_group_member_count import com.vitorpamplona.amethyst.commons.resources.relay_group_no_messages_yet import com.vitorpamplona.amethyst.commons.ui.note.timeAgo import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.buzzTimelinePreviewSummary -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.newestTimelineNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.relayGroupChannelUnreadCountFlow import com.vitorpamplona.quartz.nip29RelayGroups.GroupId /** A first screen's worth of recent messages to prefetch per visible card, so previews fill in. */ diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzInviteScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzInviteScreen.kt index 596bd5d7f8..2d77460d81 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzInviteScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzInviteScreen.kt @@ -70,8 +70,8 @@ import com.vitorpamplona.amethyst.commons.resources.buzz_invite_workspace import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.favorites.FavoriteAppLauncher -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.buzz.invite.BuzzInviteLink import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzRelayImportViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzRelayImportViewModel.kt index 40b883d263..0a7f5e0893 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzRelayImportViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzRelayImportViewModel.kt @@ -22,11 +22,11 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupDeletions import com.vitorpamplona.amethyst.commons.relayClient.channel.relayGroup.RELAY_GROUP_METADATA_KINDS import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthDecision -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.buzz.notifications.MemberAddedNotificationEvent import com.vitorpamplona.quartz.buzz.stream.SystemMessageEvent import com.vitorpamplona.quartz.buzz.workspace.isBuzzDm diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzWorkspaceOverflowMenu.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzWorkspaceOverflowMenu.kt index 5a78eea7a3..cd03b8f84b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzWorkspaceOverflowMenu.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzWorkspaceOverflowMenu.kt @@ -41,7 +41,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp -import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.actions.BuzzInviteMinter import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -58,7 +57,7 @@ import com.vitorpamplona.amethyst.commons.resources.buzz_invite_share import com.vitorpamplona.amethyst.commons.resources.more_options import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.CancellationException import kotlinx.coroutines.launch @@ -153,7 +152,7 @@ fun BuzzWorkspaceOverflowMenu( BuzzInviteMinter.mint( relay = relay, ttlSecs = null, - okHttpClient = Amethyst.instance.roleBasedHttpClientBuilder::okHttpClientForPushRegistration, + okHttpClient = accountViewModel.httpClientBuilder::okHttpClientForPushRegistration, httpAuth = accountViewModel.account::createHTTPAuthorization, ) } catch (e: Exception) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/JobBoardScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/JobBoardScreen.kt index aed7f61cfb..e7a6992928 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/JobBoardScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/JobBoardScreen.kt @@ -88,14 +88,14 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.buzz_job_board_title import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgo import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgoStyle import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/JobBoardViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/JobBoardViewModel.kt index 1f60812ea3..c2fd829cb3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/JobBoardViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/JobBoardViewModel.kt @@ -22,9 +22,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.buzz.BuzzJobAggregator import com.vitorpamplona.amethyst.commons.model.buzz.JobView -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.subscribeAsFlow import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/RelayStatusBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/RelayStatusBar.kt index 29bc160630..53371635cb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/RelayStatusBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/RelayStatusBar.kt @@ -60,10 +60,10 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.buzz.BuzzRelayDialect +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor import com.vitorpamplona.amethyst.commons.ui.theme.warningColor -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.client.auth.RelayAuthSnapshot import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @@ -96,7 +96,7 @@ fun RelayStatusBar( val isConnected by remember(relay) { derivedStateOf { relay in connectedState.value } } val phase by remember(relay) { derivedStateOf { authState.value[relay]?.phase ?: RelayAuthSnapshot.Phase.IDLE } } val isBuzz by remember(relay) { derivedStateOf { relay in buzzState.value } } - val stat = remember(relay, isConnected) { Amethyst.instance.relayStats.get(relay) } + val stat = remember(relay, isConnected) { accountViewModel.host.relayStats.get(relay) } val (dotColor, statusLabel) = health(isConnected, phase) var expanded by remember { mutableStateOf(false) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/WorkflowRunBoardScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/WorkflowRunBoardScreen.kt index 48e3bdf00b..9084414321 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/WorkflowRunBoardScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/WorkflowRunBoardScreen.kt @@ -160,14 +160,14 @@ import com.vitorpamplona.amethyst.commons.resources.buzz_workflow_waiting_for_ap import com.vitorpamplona.amethyst.commons.resources.buzz_workflow_waiting_on import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgo import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgoStyle import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import kotlinx.coroutines.launch import org.jetbrains.compose.resources.StringResource diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/WorkflowRunBoardViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/WorkflowRunBoardViewModel.kt index 10982c18d5..1839c82f2c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/WorkflowRunBoardViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/WorkflowRunBoardViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.buzz.WorkflowRun import com.vitorpamplona.amethyst.commons.model.buzz.WorkflowRunAggregator -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.buzz.workflow.ApprovalDenyEvent import com.vitorpamplona.quartz.buzz.workflow.ApprovalGrantEvent import com.vitorpamplona.quartz.buzz.workflow.WorkflowApprovalRequestedEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarCollectionsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarCollectionsScreen.kt index f84dee3e2a..294dd1f135 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarCollectionsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarCollectionsScreen.kt @@ -28,11 +28,11 @@ import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.nip52Calendar.ui.NewCalendarButton import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.datasource.CalendarsFilterAssemblerSubscription /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarCollectionsTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarCollectionsTopBar.kt index c5c54cff10..380ea64ce6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarCollectionsTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarCollectionsTopBar.kt @@ -24,18 +24,18 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip52Calendar.calendar.CalendarCollectionEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarCollectionsView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarCollectionsView.kt index c284b41922..1b05e7275d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarCollectionsView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarCollectionsView.kt @@ -71,7 +71,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.UserCardHeader import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip52Calendar.appt.day.CalendarDateSlotEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarDayView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarDayView.kt index 8e4021316e..aa4f0a7981 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarDayView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarDayView.kt @@ -66,7 +66,7 @@ import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import java.time.LocalDate import java.time.ZoneId diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarEventListCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarEventListCard.kt index 16366ee7b2..7c874b1323 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarEventListCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarEventListCard.kt @@ -51,9 +51,9 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip52Calendar.CalendarAppointmentView import com.vitorpamplona.amethyst.commons.model.nip52Calendar.appointmentView +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.UserCardHeader import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import java.time.Instant diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarFeedView.kt index 0d62fc715b..dc1d7733a6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarFeedView.kt @@ -52,7 +52,7 @@ import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.utils.TimeUtils @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarFollowsGoingView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarFollowsGoingView.kt index 8e643aeb96..fb2224065d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarFollowsGoingView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarFollowsGoingView.kt @@ -43,20 +43,20 @@ import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip52Calendar.AppointmentAttendance import com.vitorpamplona.amethyst.commons.nip52Calendar.ui.CalendarEmptyState +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.calendar_follows_going_count import com.vitorpamplona.amethyst.commons.resources.calendar_follows_going_empty_subtitle import com.vitorpamplona.amethyst.commons.resources.calendar_follows_going_empty_title import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.types.UserGallery import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.types.UserGallery -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** Faces drawn on a row before the rest collapse into "+N". */ private const val ATTENDEE_FACES = 6 diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarMonthView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarMonthView.kt index 0e6452e4ab..d07e649d06 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarMonthView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarMonthView.kt @@ -63,7 +63,7 @@ import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import java.time.LocalDate import java.time.YearMonth import java.time.ZoneId diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarWeekView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarWeekView.kt index e4a325fccb..4b504f1c73 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarWeekView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarWeekView.kt @@ -63,7 +63,7 @@ import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import java.time.LocalDate import java.time.ZoneId diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarsScreen.kt index 1936c6e600..0403996741 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarsScreen.kt @@ -35,11 +35,11 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.nip52Calendar.ui.CalendarsViewMode import com.vitorpamplona.amethyst.commons.nip52Calendar.ui.NewCalendarButton import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.datasource.CalendarsFilterAssemblerSubscription import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarsTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarsTopBar.kt index 99c31d4e52..04151d7545 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarsTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarsTopBar.kt @@ -37,6 +37,8 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.nip52Calendar.ui.CalendarsViewMode import com.vitorpamplona.amethyst.commons.resources.Res @@ -44,12 +46,10 @@ import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip52Calendar.appt.day.CalendarDateSlotEvent import com.vitorpamplona.quartz.nip52Calendar.appt.time.CalendarTimeSlotEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/create/NewCalendarCollectionScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/create/NewCalendarCollectionScreen.kt index c3b0524447..d98058b5f3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/create/NewCalendarCollectionScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/create/NewCalendarCollectionScreen.kt @@ -72,7 +72,7 @@ import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SavingTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.formatLongDate @OptIn(ExperimentalMaterial3Api::class) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/create/NewCalendarCollectionViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/create/NewCalendarCollectionViewModel.kt index 24dace858c..8cf614ea2b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/create/NewCalendarCollectionViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/create/NewCalendarCollectionViewModel.kt @@ -25,9 +25,9 @@ import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.aTag.aTags diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/create/NewCalendarEventScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/create/NewCalendarEventScreen.kt index e9b7f684a2..450b025c40 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/create/NewCalendarEventScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/create/NewCalendarEventScreen.kt @@ -81,15 +81,15 @@ import com.vitorpamplona.amethyst.commons.resources.new_calendar_event import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SavingTopBar +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size30dp import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightChat -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/create/NewCalendarEventViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/create/NewCalendarEventViewModel.kt index 06186eaed6..b8f4d1fe12 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/create/NewCalendarEventViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/create/NewCalendarEventViewModel.kt @@ -24,13 +24,13 @@ import android.content.Context import android.net.Uri import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip52Calendar.parseIsoDateToUnixSeconds -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadingState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags import com.vitorpamplona.quartz.nip01Core.tags.people.PTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/datasource/CalendarsFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/datasource/CalendarsFilterAssemblerSubscription.kt index 7346b33ca6..4066159581 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/datasource/CalendarsFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/datasource/CalendarsFilterAssemblerSubscription.kt @@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.calendars.CalendarsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun CalendarsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/detail/AddToCalendarSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/detail/AddToCalendarSheet.kt index 6d878afb92..e686b5cbfb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/detail/AddToCalendarSheet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/detail/AddToCalendarSheet.kt @@ -49,7 +49,7 @@ import com.vitorpamplona.amethyst.commons.resources.calendar_add_to_calendar_non import com.vitorpamplona.amethyst.commons.resources.calendar_add_to_calendar_title import com.vitorpamplona.amethyst.commons.resources.calendar_untitled import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.aTag.aTags diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/detail/CalendarEventDetailScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/detail/CalendarEventDetailScreen.kt index 3072750bd7..bce0ec65b3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/detail/CalendarEventDetailScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/detail/CalendarEventDetailScreen.kt @@ -65,6 +65,7 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip52Calendar.IcsExport import com.vitorpamplona.amethyst.commons.model.nip52Calendar.appointmentView +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back import com.vitorpamplona.amethyst.commons.resources.calendar_add_to_calendar_action @@ -89,26 +90,25 @@ import com.vitorpamplona.amethyst.commons.resources.calendar_share_nostr_title import com.vitorpamplona.amethyst.commons.resources.calendar_untitled import com.vitorpamplona.amethyst.commons.resources.edit_calendar_event import com.vitorpamplona.amethyst.commons.resources.route_calendar_event_detail +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.types.CalendarRsvpRow import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size30dp import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.ReactionsRow -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.types.CalendarRsvpRow -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.addToPhoneCalendar import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.datasource.CalendarsFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.formatCalendarRange import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.formatLongDate import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.rememberRelativeTimeLabel import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.shareIcs -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.tags.people.PTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnComposer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnComposer.kt index a09a212e37..12bc6d3266 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnComposer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnComposer.kt @@ -49,6 +49,9 @@ import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiSuggestio import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.ShowEmojiSuggestionList import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.cordn_composer_hint +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState +import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.text.MentionPreservingInputTransformation import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord @@ -57,16 +60,13 @@ import com.vitorpamplona.amethyst.commons.ui.theme.EditFieldModifier import com.vitorpamplona.amethyst.commons.ui.theme.EditFieldTrailingIconModifier import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightChat import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation import com.vitorpamplona.amethyst.ui.actions.uploads.RecordingResult import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery import com.vitorpamplona.amethyst.ui.actions.uploads.VoiceMessagePreview import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.nipA0VoiceMessages.AudioMeta /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnCreateGroupScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnCreateGroupScreen.kt index d1d0f28e89..d6e91be25d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnCreateGroupScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnCreateGroupScreen.kt @@ -64,6 +64,8 @@ import com.vitorpamplona.amethyst.commons.cordn.GroupExposure import com.vitorpamplona.amethyst.commons.cordn.ui.CordnExposureCard import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.cordn.CordnCoverage +import com.vitorpamplona.amethyst.commons.model.cordn.CordnGroupCreation import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back @@ -118,16 +120,14 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable_deta import com.vitorpamplona.amethyst.commons.resources.cordn_member_count import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.note.timeAgoNoDot -import com.vitorpamplona.amethyst.model.cordn.CordnCoverage -import com.vitorpamplona.amethyst.model.cordn.CordnGroupCreation -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.pluralStringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex -import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.CoordinatorIdentityRow -import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.coordinatorDisplayName -import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings.cordn.CoordinatorIdentityRow +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings.cordn.coordinatorDisplayName +import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.cordn.spec01GroupMetadata.CordnGroupMetadata import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnCreateMembersScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnCreateMembersScreen.kt index 1a09a1c890..a184abec97 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnCreateMembersScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnCreateMembersScreen.kt @@ -54,6 +54,8 @@ import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.model.cordn.CordnCoverage +import com.vitorpamplona.amethyst.commons.model.cordn.CordnRuntime import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.cordn_create_add_member import com.vitorpamplona.amethyst.commons.resources.cordn_create_admin @@ -75,17 +77,15 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_member_count import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState +import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex +import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightChat +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.CordnGroupDraft -import com.vitorpamplona.amethyst.model.cordn.CordnCoverage -import com.vitorpamplona.amethyst.model.cordn.CordnRuntime -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.pluralStringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex -import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.nip01Core.core.HexKey /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupChatScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupChatScreen.kt index f51173a565..fba0c1263d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupChatScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupChatScreen.kt @@ -68,7 +68,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.audio.WaveformData import com.vitorpamplona.amethyst.commons.chats.ui.AutoScrollToNewest import com.vitorpamplona.amethyst.commons.cordn.CordnGroupManager import com.vitorpamplona.amethyst.commons.icons.symbols.Icon @@ -104,28 +104,27 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_voice_stop import com.vitorpamplona.amethyst.commons.richtext.EncryptedMediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.EncryptedMediaUrlVideo import com.vitorpamplona.amethyst.commons.ui.components.EmptyState +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NonClickableUserPictures +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex +import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.model.cordn.CordnMediaService -import com.vitorpamplona.amethyst.service.playback.composable.WaveformData import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.MetadataStripper import com.vitorpamplona.amethyst.ui.actions.uploads.RecordingResult import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.VoiceMessageRecorder import com.vitorpamplona.amethyst.ui.components.ZoomableContentView -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.note.NonClickableUserPictures -import com.vitorpamplona.amethyst.ui.note.UserPicture import com.vitorpamplona.amethyst.ui.note.types.RenderAudioWaveformPlayer -import com.vitorpamplona.amethyst.ui.pluralStringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadState -import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.cordn.appEncryptedMedia.CordnBlobUpload import com.vitorpamplona.quartz.cordn.appEncryptedMedia.CordnMediaAttachment import com.vitorpamplona.quartz.cordn.appEncryptedMedia.CordnMediaCipher @@ -1170,7 +1169,7 @@ internal fun CordnAttachment( } val cipher = remember(attachment, mediaKey) { CordnMediaCipher(mediaKey, attachment) } - Amethyst.instance.keyCache.add(attachment.url, cipher, attachment.mimeType) + accountViewModel.account.encryptionKeyCache.add(attachment.url, cipher, attachment.mimeType) // A voice note is audio, and audio has no picture: sent down the video // branch below it plays on a blank video surface. The Note-free player is diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupInfoScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupInfoScreen.kt index e134442396..fae0dec2d3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupInfoScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupInfoScreen.kt @@ -68,6 +68,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.cordn.CordnRuntime import com.vitorpamplona.amethyst.commons.model.cordnGroups.CordnGroupChatroom import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back @@ -126,20 +127,19 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_share_title import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState +import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings.cordn.CoordinatorIdentityRow +import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightChat import com.vitorpamplona.amethyst.commons.util.toShortDisplay -import com.vitorpamplona.amethyst.model.cordn.CordnRuntime -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.pluralStringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.QrCodeDrawer import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SectionCollapse import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SectionExpand -import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.CoordinatorIdentityRow -import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.cordn.spec00Coordinator.JoinRequest import com.vitorpamplona.quartz.cordn.spec01GroupMetadata.CordnGroupMetadata import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupListScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupListScreen.kt index d29ffb280a..68c10c0a45 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupListScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupListScreen.kt @@ -47,6 +47,7 @@ import com.vitorpamplona.amethyst.commons.cordn.CoordinatorHealth import com.vitorpamplona.amethyst.commons.cordn.ui.CoordinatorHealthRow import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.cordn.CordnRuntime import com.vitorpamplona.amethyst.commons.model.cordnGroups.CordnGroupChatroom import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res @@ -62,14 +63,13 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_groups_title import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings.cordn.CoordinatorIdentityRow +import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness -import com.vitorpamplona.amethyst.model.cordn.CordnRuntime -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.pluralStringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.CordnGroupRoomCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.CoordinatorIdentityRow -import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.nip01Core.core.HexKey import kotlinx.coroutines.flow.MutableStateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnMessageRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnMessageRow.kt index 7c5696ca0d..b789cd5a8e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnMessageRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnMessageRow.kt @@ -92,20 +92,23 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_reactions_title import com.vitorpamplona.amethyst.commons.resources.quick_action_share import com.vitorpamplona.amethyst.commons.resources.today import com.vitorpamplona.amethyst.commons.ui.components.ClickableBox +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.QuickActionAlertDialog +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgoStyle import com.vitorpamplona.amethyst.commons.ui.note.elements.ToggleableTimeAgoText +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings.cordn.coordinatorDisplayName +import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Font12SP import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor import com.vitorpamplona.amethyst.commons.ui.theme.isLight import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.note.QuickActionAlertDialog -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.ActionTile import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.ChatChipFlowRow import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.MoreActionsToggle @@ -114,9 +117,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.ReactionChipView import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.SectionDivider import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.TileRow import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.authorNameColorFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex -import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.coordinatorDisplayName -import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.cordn.appEncryptedMedia.CordnMediaTag import com.vitorpamplona.quartz.cordn.spec02Envelopes.CordnAnnotationIndex import com.vitorpamplona.quartz.cordn.spec02Envelopes.CordnDeliveredMessage diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatDeliveryTicks.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatDeliveryTicks.kt index 3457109346..f2f0000f73 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatDeliveryTicks.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatDeliveryTicks.kt @@ -69,6 +69,9 @@ import com.vitorpamplona.amethyst.commons.resources.chat_delivery_sending import com.vitorpamplona.amethyst.commons.resources.close import com.vitorpamplona.amethyst.commons.ui.components.ClickableBox import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.note.timeAbsolute import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Font12SP @@ -76,10 +79,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import org.jetbrains.compose.resources.StringResource diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatEngagementDetailSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatEngagementDetailSheet.kt index 0ac2efbfa8..e856d62f1a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatEngagementDetailSheet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatEngagementDetailSheet.kt @@ -46,18 +46,18 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.model.ZapAmountCommentNotification import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteReactions import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.commons.ui.theme.Font12SP import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteReactions -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.ZapAmountCommentNotification -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatFeedView.kt index 69b60bc6ff..4ce029ed54 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatFeedView.kt @@ -48,9 +48,9 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.FeedEmpty import com.vitorpamplona.amethyst.commons.ui.feeds.FeedError import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.screen.SaveableFeedState import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.screen.SaveableFeedState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip37Drafts.DraftWrapEvent import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatInlineQuoteRenderer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatInlineQuoteRenderer.kt index 1796e4b562..7578d88e8a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatInlineQuoteRenderer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatInlineQuoteRenderer.kt @@ -21,9 +21,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.ui.components.InlineQuoteRenderer +import com.vitorpamplona.amethyst.commons.ui.note.WatchNoteEvent import com.vitorpamplona.amethyst.ui.components.DefaultInlineQuoteRenderer -import com.vitorpamplona.amethyst.ui.components.InlineQuoteRenderer -import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatMessageActionSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatMessageActionSheet.kt index 85cdabb4ba..889d177e43 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatMessageActionSheet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatMessageActionSheet.kt @@ -63,6 +63,7 @@ import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.concord.ConcordChannel import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.buzz_edit_message import com.vitorpamplona.amethyst.commons.resources.chat_delivery_details_title @@ -77,9 +78,22 @@ import com.vitorpamplona.amethyst.commons.resources.relay_group_pin_message import com.vitorpamplona.amethyst.commons.resources.relay_group_unpin_message import com.vitorpamplona.amethyst.commons.resources.reply_description import com.vitorpamplona.amethyst.commons.resources.show_less +import com.vitorpamplona.amethyst.commons.service.ZapPaymentHandler import com.vitorpamplona.amethyst.commons.ui.components.ClickableBox import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.ChangeReactionIcon +import com.vitorpamplona.amethyst.commons.ui.note.QuickActionAlertDialog +import com.vitorpamplona.amethyst.commons.ui.note.RenderReaction +import com.vitorpamplona.amethyst.commons.ui.note.deletionRequestBody +import com.vitorpamplona.amethyst.commons.ui.note.elements.AddHashtagLabelDialog +import com.vitorpamplona.amethyst.commons.ui.note.elements.ConcordBanConfirmationDialog +import com.vitorpamplona.amethyst.commons.ui.note.elements.DropDownParams +import com.vitorpamplona.amethyst.commons.ui.note.elements.NoteActionHandlers +import com.vitorpamplona.amethyst.commons.ui.note.elements.ShareOptionsBottomSheet +import com.vitorpamplona.amethyst.commons.ui.note.elements.noteActionSections +import com.vitorpamplona.amethyst.commons.ui.note.elements.observeBookmarksFollowsAndAccount +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.report.ReportNoteDialog +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.navigateToReloadMint import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.Size28Modifier @@ -87,26 +101,12 @@ import com.vitorpamplona.amethyst.commons.ui.theme.SmallishBorder import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.reactionBox import com.vitorpamplona.amethyst.commons.ui.theme.selectedReactionBoxModifier -import com.vitorpamplona.amethyst.service.ZapPaymentHandler -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.EditPostView -import com.vitorpamplona.amethyst.ui.note.QuickActionAlertDialog -import com.vitorpamplona.amethyst.ui.note.RenderReaction import com.vitorpamplona.amethyst.ui.note.ZapAmountChoiceGrid -import com.vitorpamplona.amethyst.ui.note.deletionRequestBody -import com.vitorpamplona.amethyst.ui.note.elements.AddHashtagLabelDialog -import com.vitorpamplona.amethyst.ui.note.elements.ConcordBanConfirmationDialog -import com.vitorpamplona.amethyst.ui.note.elements.DropDownParams -import com.vitorpamplona.amethyst.ui.note.elements.NoteActionHandlers -import com.vitorpamplona.amethyst.ui.note.elements.ShareOptionsBottomSheet -import com.vitorpamplona.amethyst.ui.note.elements.noteActionSections -import com.vitorpamplona.amethyst.ui.note.elements.observeBookmarksFollowsAndAccount import com.vitorpamplona.amethyst.ui.note.observeZapRailCapability import com.vitorpamplona.amethyst.ui.note.payViaIntentOrManualSplit -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.report.ReportNoteDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.OnchainZapSendDialog -import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.navigateToReloadMint import com.vitorpamplona.quartz.buzz.stream.StreamMessageV2Event import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nipC7Chats.ChatEvent @@ -670,7 +670,6 @@ private fun QuickZapAmountRow( amountInSats * 1000, null, "", - context, true, onError, { }, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatMessageCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatMessageCompose.kt index 3d180334b9..70cd0a46a2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatMessageCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatMessageCompose.kt @@ -53,28 +53,28 @@ import com.vitorpamplona.amethyst.commons.model.latestBuzzEdit import com.vitorpamplona.amethyst.commons.model.latestConcordEdit import com.vitorpamplona.amethyst.commons.model.latestMarmotEdit import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.ui.components.LocalInlineQuoteRenderer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.WatchBlockAndReport +import com.vitorpamplona.amethyst.commons.ui.note.WatchNoteEvent +import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.DisplayZapSplits +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.RenderBuzzSystemMessage +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.RenderChatClip +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.RenderEncryptedFile import com.vitorpamplona.amethyst.commons.ui.theme.ReactionRowZapraiser import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer -import com.vitorpamplona.amethyst.ui.components.LocalInlineQuoteRenderer -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.RenderZapRaiser -import com.vitorpamplona.amethyst.ui.note.WatchBlockAndReport -import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent -import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.DisplayZapSplits -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderBuzzActivityRow import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderBuzzDiff import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderBuzzEditedNote import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderBuzzForumVote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderBuzzSystemMessage import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderChannelAdminSystemMessage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderChatClip import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderChatRaid import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderChatZap import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderDraftEvent import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderEditedNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderEncryptedFile import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderEncryptedMediaV2 import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderMarmotEncryptedMedia import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderRegularTextNote diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatReactionChips.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatReactionChips.kt index cee05e166e..9ffea11b26 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatReactionChips.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatReactionChips.kt @@ -58,6 +58,9 @@ import com.vitorpamplona.amethyst.commons.model.concord.ConcordChannel import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteMinichatReplyCount +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteReactions +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteZaps import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.chat_minichat_reply_count import com.vitorpamplona.amethyst.commons.ui.components.AnimatedBorderTextCornerRadius @@ -72,11 +75,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size14Modifier import com.vitorpamplona.amethyst.commons.ui.theme.bitcoinColor import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.subtleBorder -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteMinichatReplyCount -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteReactions -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteZaps +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.ObserveZapAmountText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip30CustomEmoji.CustomEmoji import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatTimeAgo.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatTimeAgo.kt index a870d61657..246d683152 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatTimeAgo.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatTimeAgo.kt @@ -40,6 +40,8 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.expiration_date_label import com.vitorpamplona.amethyst.commons.resources.relay_group_pinned_content_description import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayLocation +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayPoW import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgoStyle import com.vitorpamplona.amethyst.commons.ui.note.elements.ToggleableTimeAgoText import com.vitorpamplona.amethyst.commons.ui.note.timeAheadNoDot @@ -47,9 +49,7 @@ import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Font12SP import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.note.elements.DisplayLocation -import com.vitorpamplona.amethyst.ui.note.elements.DisplayPoW -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.geohash.geoHashOrScope import com.vitorpamplona.quartz.nip04Dm.messages.EncryptedDmEvent import com.vitorpamplona.quartz.nip13Pow.strongPoWOrNull diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/DrawAuthorInfo.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/DrawAuthorInfo.kt index ddbc9a2cba..12efb2524c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/DrawAuthorInfo.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/DrawAuthorInfo.kt @@ -32,18 +32,18 @@ import com.vitorpamplona.amethyst.commons.chats.ui.UserDisplayNameLayout import com.vitorpamplona.amethyst.commons.model.EmptyTagList import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserDisplayNickname +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.FollowingIcon +import com.vitorpamplona.amethyst.commons.ui.note.InnerUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.ObserveAndRenderUserCards +import com.vitorpamplona.amethyst.commons.ui.note.WatchUserFollows import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.Size5Modifier import com.vitorpamplona.amethyst.commons.ui.theme.isLight -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserDisplayNickname -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.ui.note.InnerUserPicture -import com.vitorpamplona.amethyst.ui.note.ObserveAndRenderUserCards -import com.vitorpamplona.amethyst.ui.note.WatchUserFollows -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun DrawAuthorInfo( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/LoadingReplyNote.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/LoadingReplyNote.kt index bcf67f43bc..836da6cfc3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/LoadingReplyNote.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/LoadingReplyNote.kt @@ -58,7 +58,7 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.DmHistoryRelayDialog import com.vitorpamplona.amethyst.commons.ui.feeds.historySubtitle import com.vitorpamplona.amethyst.commons.ui.feeds.incompleteSubtitle import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine @@ -78,12 +78,12 @@ enum class DmReplyProtocol { /** * The inner-quote placeholder for a reply whose target message has not been paged in yet — used in - * place of the generic [com.vitorpamplona.amethyst.ui.note.BlankNote] ("post not found") that the main + * place of the generic [com.vitorpamplona.amethyst.commons.ui.note.BlankNote] ("post not found") that the main * feeds show. A reply target inside a conversation isn't *missing*, it's simply older than the window * loaded so far; for gift wraps it can't even be fetched by id. So instead of declaring it lost, this * card actively walks the conversation's history backward — kicking the protocol's `loadMore` each time * the previous page settles — until either the target decrypts (the surrounding - * [com.vitorpamplona.amethyst.ui.note.WatchNoteEvent] crossfades the real message in and disposes this) + * [com.vitorpamplona.amethyst.commons.ui.note.WatchNoteEvent] crossfades the real message in and disposes this) * or that protocol's history runs dry, at which point it settles into the terminal "not found" text. * * It runs regardless of scroll position (no oldest-end gate like the scroll-driven loader) precisely so diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderBuzzNotes.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderBuzzNotes.kt index 3d69eb83af..c8285ca31f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderBuzzNotes.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderBuzzNotes.kt @@ -56,10 +56,12 @@ import com.vitorpamplona.amethyst.commons.resources.buzz_job_progress import com.vitorpamplona.amethyst.commons.resources.buzz_job_requested import com.vitorpamplona.amethyst.commons.resources.buzz_job_result import com.vitorpamplona.amethyst.commons.resources.buzz_message_edited +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.buzzSystemMessageText +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.buzz.forum.ForumVoteEvent import com.vitorpamplona.quartz.buzz.huddles.HuddleEndedEvent import com.vitorpamplona.quartz.buzz.huddles.HuddleParticipantJoinedEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChannelAdminNote.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChannelAdminNote.kt index 0cb635f4f0..9d076d82e9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChannelAdminNote.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChannelAdminNote.kt @@ -26,14 +26,14 @@ import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.chats.ui.ChatSystemMessage import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.chat_system_created_channel import com.vitorpamplona.amethyst.commons.resources.chat_system_created_channel_unnamed import com.vitorpamplona.amethyst.commons.resources.chat_system_updated_channel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelMetadataEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChatRaid.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChatRaid.kt index 2d42798e9c..36295d5eac 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChatRaid.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChatRaid.kt @@ -42,15 +42,15 @@ import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.StreamSystemCar import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.chat_raid_is_raiding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.CrossfadeToDisplayComment +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer -import com.vitorpamplona.amethyst.ui.note.CrossfadeToDisplayComment -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip53LiveActivities.raid.LiveActivitiesRaidEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChatZap.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChatZap.kt index b3d0c85a11..eb9dc3f248 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChatZap.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChatZap.kt @@ -36,12 +36,17 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.model.ZapAmountCommentNotification import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.StreamSystemCard import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.chat_zap_amount_suffix import com.vitorpamplona.amethyst.commons.resources.chat_zap_anonymous import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.CrossfadeToDisplayComment +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.note.ZapIcon import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange @@ -49,12 +54,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.Size24Modifier import com.vitorpamplona.amethyst.commons.util.showAmountInteger -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.CrossfadeToDisplayComment -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.ZapAmountCommentNotification -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent private const val BIG_ZAP_THRESHOLD_SATS = 50_000L diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderDraftEvent.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderDraftEvent.kt index 3c2fe1185c..746c729d19 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderDraftEvent.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderDraftEvent.kt @@ -26,9 +26,9 @@ import androidx.compose.runtime.MutableState import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.ObserveDraftEvent import com.vitorpamplona.amethyst.commons.ui.theme.RowColSpacing5dp -import com.vitorpamplona.amethyst.ui.note.ObserveDraftEvent -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.NoteRow import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.RenderReplyRow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderEditedNote.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderEditedNote.kt index 94aeada6e8..867c082f6b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderEditedNote.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderEditedNote.kt @@ -34,10 +34,10 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.message_edited +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * A chat message whose content has been superseded by an edit: renders the diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderMarmotEncryptedMedia.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderMarmotEncryptedMedia.kt index a084b2d178..95b955f564 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderMarmotEncryptedMedia.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderMarmotEncryptedMedia.kt @@ -28,7 +28,6 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.model.EmptyTagList import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.resources.Res @@ -37,12 +36,12 @@ import com.vitorpamplona.amethyst.commons.richtext.BaseMediaContent import com.vitorpamplona.amethyst.commons.richtext.EncryptedMediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.EncryptedMediaUrlVideo import com.vitorpamplona.amethyst.commons.richtext.RichTextParser +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.ZoomableContentView import com.vitorpamplona.amethyst.ui.note.types.RenderAudioWithWaveform -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.marmot.appComponents.EncryptedMediaPolicyV2 import com.vitorpamplona.quartz.marmot.appComponents.EncryptedMediaReferenceV2 import com.vitorpamplona.quartz.marmot.appComponents.EncryptedMediaV2 @@ -128,7 +127,7 @@ fun RenderEncryptedMediaV2( } val cipher = remember(reference, mediaSecret) { EncryptedMediaV2Cipher(mediaSecret, reference) } - Amethyst.instance.keyCache.add(url, cipher, reference.mediaType) + accountViewModel.account.encryptionKeyCache.add(url, cipher, reference.mediaType) val description = event.alt() @@ -252,7 +251,7 @@ private fun RenderMip04Content( filename = meta.filename, ) } - Amethyst.instance.keyCache.add(meta.url, cipher, meta.mimeType) + accountViewModel.account.encryptionKeyCache.add(meta.url, cipher, meta.mimeType) val description = note.event?.alt() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderRegularTextNote.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderRegularTextNote.kt index b28fd4501d..27dad4cdbe 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderRegularTextNote.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderRegularTextNote.kt @@ -34,14 +34,14 @@ import com.vitorpamplona.amethyst.commons.model.nip92IMeta.appendMissingImetaUrl import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.could_not_decrypt_the_message +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadDecryptedContentOrNull +import com.vitorpamplona.amethyst.commons.ui.note.types.getAudioMetaWithWaveform import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.note.LoadDecryptedContentOrNull +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.types.RenderAudioFromIMeta -import com.vitorpamplona.amethyst.ui.note.types.getAudioMetaWithWaveform -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @Composable fun RenderRegularTextNote( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/GeohashChatScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/GeohashChatScreen.kt index 1cb5d049aa..b1da5855ba 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/GeohashChatScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/GeohashChatScreen.kt @@ -63,19 +63,19 @@ import com.google.accompanist.permissions.rememberPermissionState import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.geohashChat.GeohashChatChannel +import com.vitorpamplona.amethyst.commons.model.location.LocationResult +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserPicture import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SearchTopBarAction import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings -import com.vitorpamplona.amethyst.service.location.LocationState -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserPicture -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.topbars.SearchTopBarAction +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.LocalChatActingIdentities import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.LocalChatDisplayNameResolver import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.LocalChatReactOverride @@ -170,7 +170,7 @@ private fun GeohashChatRoom( val isTeleported = remember(deviceLocation, geohash, teleported) { when (val loc = deviceLocation) { - is LocationState.LocationResult.Success -> { + is LocationResult.Success -> { // Compare on the common prefix: the device fix is fixed-precision (8 chars), so a // finer (longer) cell can never be a prefix of it — treat a shared prefix as "here". val device = loc.geoHash.toString() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/GeohashChatViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/GeohashChatViewModel.kt index 7a40654504..6f26ea4fdc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/GeohashChatViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/GeohashChatViewModel.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.geohashChat import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.service.geohash.GeohashRelays -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.service.georelay.GeohashRelays +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/GeohashChatsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/GeohashChatsScreen.kt index c453d4cfb4..3e53546877 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/GeohashChatsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/GeohashChatsScreen.kt @@ -65,14 +65,14 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.location_channels +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.experimental.bitchat.geohash.GeohashChannelLevel import com.vitorpamplona.amethyst.commons.icons.symbols.Icon as SymbolIcon diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/LoadGeohashChannel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/LoadGeohashChannel.kt index e6aac28ec9..61988db27d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/LoadGeohashChannel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/LoadGeohashChannel.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.geohashChat import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.geohashChat.GeohashChatChannel -import com.vitorpamplona.amethyst.ui.note.produceStateIfNotNull +import com.vitorpamplona.amethyst.commons.ui.note.produceStateIfNotNull /** * Resolves the [GeohashChatChannel] for [geohash] from LocalCache, creating an diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/NewGeohashChatScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/NewGeohashChatScreen.kt index 2cb3ed0a5e..eb54b6aac2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/NewGeohashChatScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/NewGeohashChatScreen.kt @@ -62,13 +62,13 @@ import com.google.accompanist.permissions.rememberPermissionState import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton -import com.vitorpamplona.amethyst.service.location.LocationState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.experimental.bitchat.geohash.GeohashChannelLevel import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeoHash import com.vitorpamplona.amethyst.commons.icons.symbols.Icon as SymbolIcon @@ -309,7 +309,7 @@ private fun NearMeSection(onOpen: (String) -> Unit) { val location by Amethyst.instance.locationManager.preciseGeohashStateFlow .collectAsStateWithLifecycle() when (val loc = location) { - is LocationState.LocationResult.Success -> { + is LocationResult.Success -> { val fix = loc.geoHash.toString() Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { GeohashChannelLevel.ordered.forEach { level -> @@ -324,10 +324,10 @@ private fun NearMeSection(onOpen: (String) -> Unit) { } } - LocationState.LocationResult.Loading -> + LocationResult.Loading -> Text("Locating…", style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) - LocationState.LocationResult.LackPermission -> + LocationResult.LackPermission -> Text("Location unavailable.", style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/CreateGroupScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/CreateGroupScreen.kt index cae9a3f162..016a0a22fb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/CreateGroupScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/CreateGroupScreen.kt @@ -44,6 +44,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp +import com.vitorpamplona.amethyst.commons.marmot.MarmotGroupIconChange import com.vitorpamplona.amethyst.commons.marmot.ui.MarmotRetentionChoice import com.vitorpamplona.amethyst.commons.marmot.ui.MarmotRetentionPicker import com.vitorpamplona.amethyst.commons.model.navigation.Route @@ -63,9 +64,9 @@ import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.CreatingTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.send.MarmotGroupIconChange +import com.vitorpamplona.amethyst.ui.screen.loggedIn.uploadMarmotGroupIcon import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.RandomInstance diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/EditGroupInfoScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/EditGroupInfoScreen.kt index ca0964fcbb..9143123543 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/EditGroupInfoScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/EditGroupInfoScreen.kt @@ -43,6 +43,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.marmot.MarmotGroupIconChange import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.description import com.vitorpamplona.amethyst.commons.resources.marmot_avatar_url @@ -61,9 +62,9 @@ import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ActionTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.send.MarmotGroupIconChange +import com.vitorpamplona.amethyst.ui.screen.loggedIn.uploadMarmotGroupIcon import com.vitorpamplona.quartz.nip01Core.core.HexKey import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupChatScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupChatScreen.kt index 8a90a9ee79..fa57d7efda 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupChatScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupChatScreen.kt @@ -46,13 +46,13 @@ import com.vitorpamplona.amethyst.commons.resources.back import com.vitorpamplona.amethyst.commons.resources.marmot_add_member_action import com.vitorpamplona.amethyst.commons.resources.marmot_group_default_name import com.vitorpamplona.amethyst.commons.resources.marmot_member_count +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NonClickableUserPictures import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.privateDM.header.DisplayUserSetAsSubject import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.note.NonClickableUserPictures -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.header.DisplayUserSetAsSubject +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey @OptIn(ExperimentalMaterial3Api::class) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupChatView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupChatView.kt index f31fc28a75..405682ed35 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupChatView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupChatView.kt @@ -70,6 +70,7 @@ import com.vitorpamplona.amethyst.commons.resources.reply_here import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.text.MentionPreservingInputTransformation import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer @@ -78,12 +79,11 @@ import com.vitorpamplona.amethyst.commons.ui.theme.EditFieldModifier import com.vitorpamplona.amethyst.commons.ui.theme.EditFieldTrailingIconModifier import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightChat import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.LocalChatIsOneOnOne import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.RefreshingChatroomFeedView import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.send.MarmotFileSender diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupFeedViewModel.kt index e5d2b4f79d..8db68d763e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupFeedViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import com.vitorpamplona.amethyst.commons.feeds.MarmotGroupFeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.viewmodels.ListChangeFeedViewModel -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.HexKey class MarmotGroupFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupIconDisplay.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupIconDisplay.kt index 8132972932..7707996ad9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupIconDisplay.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupIconDisplay.kt @@ -26,8 +26,8 @@ import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.model.marmotGroups.MarmotGroupImage -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.marmot.appComponents.GroupAvatarUrlV1 import com.vitorpamplona.quartz.marmot.appComponents.MarmotWebUrl import com.vitorpamplona.quartz.marmot.mip01Groups.MarmotGroupImageCipher @@ -87,7 +87,7 @@ fun rememberMarmotGroupIconUrl( // and synchronously during composition so the interceptor can decrypt before Coil fetches. // The plaintext MIME isn't stored (MIP-01 v2), so Coil sniffs the format from the bytes. remember(url, cipher) { - Amethyst.instance.keyCache.add(url, cipher, null) + accountViewModel.account.encryptionKeyCache.add(url, cipher, null) url } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupIconEditor.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupIconEditor.kt index 06b8f8649c..2a7cbd75ae 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupIconEditor.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupIconEditor.kt @@ -47,8 +47,8 @@ import com.vitorpamplona.amethyst.commons.resources.marmot_remove_photo import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey /** @@ -58,7 +58,7 @@ import com.vitorpamplona.quartz.nip01Core.core.HexKey * icon is [removeRequested], or the group's current (decrypted) avatar. Tapping the * avatar opens the system photo picker; a text button below removes the current icon. * All selection state is hoisted so the parent screen can turn it into a - * [com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.send.MarmotGroupIconChange] + * [com.vitorpamplona.amethyst.commons.marmot.MarmotGroupIconChange] * at save time. */ @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupInfoScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupInfoScreen.kt index a0779f5df5..26bc045929 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupInfoScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupInfoScreen.kt @@ -71,6 +71,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.marmot.GroupMemberInfo import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back import com.vitorpamplona.amethyst.commons.resources.cancel @@ -130,6 +131,11 @@ import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.RenderRelayIcon +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.note.timeAgo import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings @@ -139,13 +145,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightCh import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.ripple24dp -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo -import com.vitorpamplona.amethyst.ui.note.RenderRelayIcon -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.normalizeRelayUrlOrNull diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupListScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupListScreen.kt index 7adda762bf..6fae96011f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupListScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupListScreen.kt @@ -79,15 +79,15 @@ import com.vitorpamplona.amethyst.commons.resources.marmot_tab_new_requests_coun import com.vitorpamplona.amethyst.commons.resources.marmot_unread_messages import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NonClickableUserPictures import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgoStyle import com.vitorpamplona.amethyst.commons.ui.note.elements.ToggleableTimeAgoText +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.privateDM.header.DisplayUserSetAsSubject import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.note.NonClickableUserPictures -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.header.DisplayUserSetAsSubject +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey @OptIn(ExperimentalMaterial3Api::class) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupPreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupPreview.kt index 4130dc30d5..69445c053b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupPreview.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupPreview.kt @@ -25,6 +25,7 @@ import androidx.compose.runtime.key import com.vitorpamplona.amethyst.commons.marmot.GroupMemberInfo import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.marmot_group_fallback_name import com.vitorpamplona.amethyst.commons.resources.marmot_no_messages_yet @@ -32,13 +33,12 @@ import com.vitorpamplona.amethyst.commons.resources.marmot_preview_group_updated import com.vitorpamplona.amethyst.commons.resources.marmot_preview_media import com.vitorpamplona.amethyst.commons.resources.marmot_preview_no_text import com.vitorpamplona.amethyst.commons.resources.marmot_preview_with_sender +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.observeChatEdit import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.hasEncryptedMediaV2 import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.hasMip04Media -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex import com.vitorpamplona.quartz.marmot.foundation.appEvents.MarmotAppEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotInviteDeviceBanner.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotInviteDeviceBanner.kt index d01672b1da..d8655ff66b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotInviteDeviceBanner.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotInviteDeviceBanner.kt @@ -49,6 +49,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.LatestKeyPackageOwner import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.marmot_invite_device_banner import com.vitorpamplona.amethyst.commons.resources.marmot_invite_device_banner_dismiss @@ -58,8 +59,7 @@ import com.vitorpamplona.amethyst.commons.resources.marmot_invite_device_rejecte import com.vitorpamplona.amethyst.commons.resources.marmot_invite_device_success import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.model.LatestKeyPackageOwner -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotSystemRowRenderer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotSystemRowRenderer.kt index 6f7a2c9adf..ea5571d5a4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotSystemRowRenderer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotSystemRowRenderer.kt @@ -51,7 +51,7 @@ import com.vitorpamplona.amethyst.commons.resources.marmot_system_member_left import com.vitorpamplona.amethyst.commons.resources.marmot_system_member_removed import com.vitorpamplona.amethyst.commons.resources.marmot_system_member_removed_passive import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.ChatFeedRowRenderer import com.vitorpamplona.quartz.marmot.foundation.appEvents.MarmotAppEvent import com.vitorpamplona.quartz.marmot.foundation.appEvents.MarmotSystemEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotFileSender.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotFileSender.kt index 1ad5e8eb9e..1309eb280b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotFileSender.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotFileSender.kt @@ -20,7 +20,7 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.send -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.marmot.mip04EncryptedMedia.buildMip04IMetaTag import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotFileUploader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotFileUploader.kt index 51a3ff7a77..3ac1b82a62 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotFileUploader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotFileUploader.kt @@ -22,10 +22,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.send import android.content.Context import android.net.Uri +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.failed_to_upload_media_no_details import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadingState diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotGroupIconUploader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotGroupIconUploader.kt index e37e720044..c96b1a3cf2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotGroupIconUploader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotGroupIconUploader.kt @@ -22,62 +22,21 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.send import android.content.Context import android.net.Uri +import com.vitorpamplona.amethyst.commons.marmot.MarmotGroupIconUpload +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadingState import com.vitorpamplona.quartz.marmot.mip01Groups.MarmotGroupImageCipher import com.vitorpamplona.quartz.marmot.mip01Groups.MarmotGroupImageEncryption -import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.utils.Log import java.io.File -/** - * The parameters produced by encrypting + uploading a new Marmot group avatar, - * ready to be folded into a [com.vitorpamplona.quartz.marmot.mip01Groups.MarmotGroupData] - * via [com.vitorpamplona.quartz.marmot.mip01Groups.MarmotGroupData.withImage]. - */ -class MarmotGroupIconUpload( - /** SHA-256 (hex) of the encrypted blob = its Blossom content hash. */ - val imageHash: HexKey, - /** 32-byte HKDF seed for the image AEAD key (MIP-01 v2). */ - val imageKey: ByteArray, - /** 12-byte nonce. */ - val imageNonce: ByteArray, - /** 32-byte HKDF seed for the Blossom-auth keypair (MIP-01 v2). */ - val imageUploadKey: ByteArray, - /** - * Media type of the DECRYPTED image. - * - * MIP-01's blob never carried one, but the current profile's `0x8002` - * component requires it on a present image — and it is bound into the - * AEAD's AAD there, so a receiver cannot be steered into decoding the - * plaintext as a different type than the uploader meant. - */ - val mediaType: String, -) - -/** - * How a metadata update should treat the group icon. - */ -sealed class MarmotGroupIconChange { - /** Leave the existing icon (if any) untouched. */ - data object Keep : MarmotGroupIconChange() - - /** Remove the current icon. */ - data object Clear : MarmotGroupIconChange() - - /** Replace the icon with a freshly-uploaded one. */ - class Set( - val upload: MarmotGroupIconUpload, - ) : MarmotGroupIconChange() -} - /** * Encrypts a picked image with the MIP-01 v2 scheme (see [MarmotGroupImageEncryption]) * and uploads the ciphertext to Blossom, signing the upload authorization with the diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotNewMessageViewModel.kt index ac02ee25e1..0d5e197d51 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotNewMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotNewMessageViewModel.kt @@ -28,16 +28,16 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.latestMarmotEdit import com.vitorpamplona.amethyst.commons.model.marmotGroups.MarmotGroupChatroom +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.onUiThread -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadState import com.vitorpamplona.quartz.nip01Core.core.HexKey import kotlinx.collections.immutable.ImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/minichat/MinichatFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/minichat/MinichatFeedViewModel.kt index 4d26fdc2fd..99a108d88f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/minichat/MinichatFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/minichat/MinichatFeedViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.minichat import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.chats.isMinichatReply -import com.vitorpamplona.amethyst.model.Account import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.SharingStarted diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/minichat/MinichatScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/minichat/MinichatScreen.kt index 4d2d19e7c8..a35ffee77e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/minichat/MinichatScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/minichat/MinichatScreen.kt @@ -53,12 +53,14 @@ 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.chats.publicChannels.concord.datasource.ConcordChannelHistorySubAssembler import com.vitorpamplona.amethyst.commons.chats.ui.ThinSendButton import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.concord.ConcordChannel import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back import com.vitorpamplona.amethyst.commons.resources.chat_minichat_title @@ -67,22 +69,20 @@ import com.vitorpamplona.amethyst.commons.resources.concord_open_channel import com.vitorpamplona.amethyst.commons.resources.reply_here import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.EditFieldBorder import com.vitorpamplona.amethyst.commons.ui.theme.EditFieldModifier import com.vitorpamplona.amethyst.commons.ui.theme.EditFieldTrailingIconModifier import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.ChatroomMessageCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.LocalSuppressReplyToNoteId import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.upload.ChatFileUploader -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelHistorySubAssembler import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelHistorySubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadState import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.toConcordImeta diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomByAuthorScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomByAuthorScreen.kt index bb3992b403..5b707cb16e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomByAuthorScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomByAuthorScreen.kt @@ -28,10 +28,10 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.BottomTopHeight -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.header.RenderRoomTopBar import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey import kotlinx.collections.immutable.persistentSetOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomScreen.kt index c5d3549828..76540a7d80 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomScreen.kt @@ -27,11 +27,11 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.call.CallActivity import com.vitorpamplona.amethyst.ui.call.rememberCallWithPermission -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.header.RenderRoomTopBar import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomView.kt index 611bf714b2..b12fe8797e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomView.kt @@ -43,6 +43,7 @@ import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.chats.formatHistoryReachDate import com.vitorpamplona.amethyst.commons.model.privateChatLastReadRoute +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription 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 @@ -54,13 +55,12 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachSentinels import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachState import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.resolveSharedMedia -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.ui.note.elements.ObserveRelayListForDMsAndDisplayIfNotFound -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.RefreshingChatroomFeedView import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.dal.ChatroomFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.datasource.ChatroomFilterAssemblerSubscription diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/dal/ChatroomFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/dal/ChatroomFeedViewModel.kt index 476dc17068..71187b8101 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/dal/ChatroomFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/dal/ChatroomFeedViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.dal import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import com.vitorpamplona.amethyst.commons.feeds.ChatroomFeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.viewmodels.ListChangeFeedViewModel -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey class ChatroomFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomFilterAssemblerSubscription.kt index c666272fc4..09aa97fc9a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomFilterAssemblerSubscription.kt @@ -22,8 +22,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.chats.privateDM.datasource.ChatroomFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.privateDM.datasource.ChatroomQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/DmReportWarningCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/DmReportWarningCard.kt index a84f4d0f17..25ad963b7f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/DmReportWarningCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/DmReportWarningCard.kt @@ -67,15 +67,15 @@ import com.vitorpamplona.amethyst.commons.resources.dm_sender_reported_more_coun import com.vitorpamplona.amethyst.commons.resources.dm_sender_reported_subtitle import com.vitorpamplona.amethyst.commons.resources.dm_sender_reported_who import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.NoteAuthorPicture import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.Size30dp import com.vitorpamplona.amethyst.commons.ui.theme.Size36dp -import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey /** Reporter avatars shown before the row collapses into a "+N" overflow chip. */ diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/NewChatroomSubjectDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/NewChatroomSubjectDialog.kt index dd881133d9..0314a3d947 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/NewChatroomSubjectDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/NewChatroomSubjectDialog.kt @@ -24,7 +24,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.nip17Dm.ui.ChatroomSubjectDialog -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey import com.vitorpamplona.quartz.nip17Dm.messages.ChatMessageEvent import com.vitorpamplona.quartz.nip17Dm.messages.changeSubject diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/RenderRoomTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/RenderRoomTopBar.kt index e9c636c095..1d39484d2a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/RenderRoomTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/RenderRoomTopBar.kt @@ -55,18 +55,19 @@ import com.vitorpamplona.amethyst.commons.resources.edits_the_channel_metadata import com.vitorpamplona.amethyst.commons.resources.messages_group_descriptor import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.NonClickableUserPictures +import com.vitorpamplona.amethyst.commons.ui.note.UserCompose +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.privateDM.header.RoomNameOnlyDisplay import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.Size34dp import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding import com.vitorpamplona.amethyst.commons.ui.theme.ZeroPadding -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.NonClickableUserPictures -import com.vitorpamplona.amethyst.ui.note.UserCompose -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey import kotlinx.collections.immutable.toPersistentList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt index 889e7ded8a..5eee33b981 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt @@ -32,6 +32,7 @@ import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User @@ -43,21 +44,21 @@ import com.vitorpamplona.amethyst.commons.model.composer.NewMessageTagger import com.vitorpamplona.amethyst.commons.model.composer.PreviewState import com.vitorpamplona.amethyst.commons.model.composer.SplitBuilder import com.vitorpamplona.amethyst.commons.model.composer.toZapSplitSetup +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiPackState import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiSuggestionState import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation import com.vitorpamplona.amethyst.commons.ui.note.creators.messagefield.IMessageField +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.IZapField import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.ui.text.onUiThread import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.location.LocationState import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.note.creators.location.ILocationGrabber -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.upload.ChatFileSender import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.upload.ChatFileUploader import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.upload.SuccessfulUploads @@ -253,7 +254,7 @@ class ChatNewMessageViewModel : // GeoHash var wantsToAddGeoHash by mutableStateOf(false) override var pickedGeoHash by mutableStateOf(null) - var location: StateFlow? = null + var location: StateFlow? = null // ZapRaiser var canAddZapRaiser by mutableStateOf(false) @@ -462,7 +463,7 @@ class ChatNewMessageViewModel : uploadState?.load(list) } - override fun locationFlow(): StateFlow { + override fun locationFlow(): StateFlow { if (location == null) { location = locationManager().geohashStateFlow } @@ -600,7 +601,7 @@ class ChatNewMessageViewModel : val urls = findURLs(messageText) val usedAttachments = iMetaAttachments.filterIsIn(urls.toSet()) val emojis = accountViewModel.account.emoji.findEmojiTags(messageText) - val geoHash = if (wantsToAddGeoHash) (pickedGeoHash ?: (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString()) else null + val geoHash = if (wantsToAddGeoHash) (pickedGeoHash ?: (location?.value as? LocationResult.Success)?.geoHash?.toString()) else null val message = messageText val contentWarningReason = if (wantsToMarkAsSensitive) contentWarningDescription else null @@ -792,7 +793,7 @@ class ChatNewMessageViewModel : viewModelScope.launch(Dispatchers.IO) { iMetaAttachments.downloadAndPrepare(item.link) { - Amethyst.instance.roleBasedHttpClientBuilder.okHttpClientForImage(item.link) + accountViewModel.httpClientBuilder.okHttpClientForImage(item.link) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/IMetaAttachments.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/IMetaAttachments.kt index b8ff848e4d..8497a8b240 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/IMetaAttachments.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/IMetaAttachments.kt @@ -24,8 +24,9 @@ import android.webkit.MimeTypeMap import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue -import com.vitorpamplona.amethyst.service.uploads.FileHeader +import com.vitorpamplona.amethyst.commons.service.upload.FileHeader import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator +import com.vitorpamplona.amethyst.service.uploads.prepare import com.vitorpamplona.quartz.nip92IMeta.IMetaTag import com.vitorpamplona.quartz.nip92IMeta.IMetaTagBuilder import com.vitorpamplona.quartz.nip92IMeta.imetaTagBuilder diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/NewGroupDMScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/NewGroupDMScreen.kt index 38c55eadf4..f5a15641f7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/NewGroupDMScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/NewGroupDMScreen.kt @@ -66,7 +66,6 @@ import androidx.compose.ui.unit.dp import androidx.core.net.toUri import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel -import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.ShowEmojiSuggestionList @@ -91,7 +90,9 @@ import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeToMessage import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.PostingTopBar +import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.ContentSensitivityExplainer import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.MarkAsSensitiveButton import com.vitorpamplona.amethyst.commons.ui.note.creators.expiration.ExpirationDateButton @@ -100,6 +101,7 @@ import com.vitorpamplona.amethyst.commons.ui.note.creators.location.AddGeoHashBu import com.vitorpamplona.amethyst.commons.ui.note.creators.messagefield.IMessageField import com.vitorpamplona.amethyst.commons.ui.note.creators.secretEmoji.AddSecretEmojiButton import com.vitorpamplona.amethyst.commons.ui.note.creators.secretEmoji.SecretEmojiRequest +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList import com.vitorpamplona.amethyst.commons.ui.note.creators.zapraiser.AddZapraiserButton import com.vitorpamplona.amethyst.commons.ui.note.creators.zapraiser.ZapRaiserRequest import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.ForwardZapToButton @@ -114,6 +116,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightPage import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery @@ -123,8 +126,6 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideoButton import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField import com.vitorpamplona.amethyst.ui.components.ZoomableContentView import com.vitorpamplona.amethyst.ui.navigation.navs.Nav -import com.vitorpamplona.amethyst.ui.navigation.routes.routeToMessage -import com.vitorpamplona.amethyst.ui.note.BaseUserPicture import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker import com.vitorpamplona.amethyst.ui.note.creators.invoice.NewPostInvoiceRequest @@ -132,9 +133,7 @@ import com.vitorpamplona.amethyst.ui.note.creators.location.GeoHashPostSection import com.vitorpamplona.amethyst.ui.note.creators.messagefield.MessageField import com.vitorpamplona.amethyst.ui.note.creators.previews.PreviewUrl import com.vitorpamplona.amethyst.ui.note.creators.uploads.ImageVideoDescription -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.ForwardZapTo -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.upload.SuccessfulUploads import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.Dispatchers @@ -626,7 +625,7 @@ fun ShowImageUploadGallery( val isImage = data.result.mimeTypeBeforeEncryption?.startsWith("image/") == true || RichTextParser.isImageUrl(data.result.url) if (data.cipher != null) { - Amethyst.instance.keyCache.add(data.result.url, data.cipher, data.result.mimeTypeBeforeEncryption) + accountViewModel.account.encryptionKeyCache.add(data.result.url, data.cipher, data.result.mimeTypeBeforeEncryption) } val content by remember(data) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/PrivateMessageEditFieldRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/PrivateMessageEditFieldRow.kt index 11b011c810..ac480c057f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/PrivateMessageEditFieldRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/PrivateMessageEditFieldRow.kt @@ -65,6 +65,9 @@ import com.vitorpamplona.amethyst.commons.resources.upload_without_encryption_wa import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDialog import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList import com.vitorpamplona.amethyst.commons.ui.note.timeAheadNoDot import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.text.MentionPreservingInputTransformation @@ -79,18 +82,15 @@ import com.vitorpamplona.amethyst.commons.ui.theme.SpacedBy10dp import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightChat import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.util.showCount +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.showCount -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.upload.RoomChatFileUploadDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.DisplayReplyingToNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileSender.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileSender.kt index f72733a80d..c34f038e26 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileSender.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileSender.kt @@ -20,8 +20,8 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.upload +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.IMetaAttachments import com.vitorpamplona.quartz.nip01Core.tags.references.references diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileUploadDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileUploadDialog.kt index 7a9fec165b..14cebf331d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileUploadDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileUploadDialog.kt @@ -30,10 +30,10 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NonClickableUserPictures +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.privateDM.header.RoomNameOnlyDisplay import com.vitorpamplona.amethyst.commons.ui.theme.Size34dp -import com.vitorpamplona.amethyst.ui.note.NonClickableUserPictures -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.header.RoomNameOnlyDisplay +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.ChatNewMessageViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadState diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileUploader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileUploader.kt index 7cfa676036..98eaf8e91d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileUploader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileUploader.kt @@ -21,13 +21,13 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.upload import android.content.Context +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.avif_metadata_strip_failed import com.vitorpamplona.amethyst.commons.resources.failed_to_upload_encrypted_media_message import com.vitorpamplona.amethyst.commons.resources.failed_to_upload_encrypted_media_title import com.vitorpamplona.amethyst.commons.resources.failed_to_upload_media_no_details import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadState diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordChannelListScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordChannelListScreen.kt index 8e12603fd3..fcb92a4a6a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordChannelListScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordChannelListScreen.kt @@ -63,6 +63,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.chats.publicChannels.concord.concordChannelUnreadCountFlow +import com.vitorpamplona.amethyst.commons.chats.publicChannels.concord.newestTimelineNote import com.vitorpamplona.amethyst.commons.concord.ui.ConcordUnreadBadge import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -70,6 +72,7 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.concord.ConcordCommunitySession import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserName import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_name import com.vitorpamplona.amethyst.commons.resources.back @@ -104,12 +107,11 @@ import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar import com.vitorpamplona.amethyst.commons.ui.note.timeAgo +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelPreviewLoader +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelPreviewLoader -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.QrCodeDrawer import com.vitorpamplona.quartz.concord.cord03Channels.ConcordChannelId import com.vitorpamplona.quartz.concord.cord04Roles.ConcordPermissions diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordChannelScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordChannelScreen.kt index 47838e144b..d79851774f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordChannelScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordChannelScreen.kt @@ -53,6 +53,7 @@ import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel +import com.vitorpamplona.amethyst.commons.chats.publicChannels.concord.datasource.ConcordChannelHistorySubAssembler import com.vitorpamplona.amethyst.commons.chats.ui.ReplyModeToggle import com.vitorpamplona.amethyst.commons.chats.ui.ThinSendButton import com.vitorpamplona.amethyst.commons.feeds.FeedContentState @@ -63,6 +64,7 @@ import com.vitorpamplona.amethyst.commons.model.chats.formatHistoryReachDate import com.vitorpamplona.amethyst.commons.model.concord.ConcordCommunitySession import com.vitorpamplona.amethyst.commons.model.concordChannelLastReadRoute import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.ShowEmojiSuggestionList +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back import com.vitorpamplona.amethyst.commons.resources.concord_dissolved_read_only @@ -79,6 +81,8 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachState import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.text.MentionPreservingInputTransformation import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer @@ -87,20 +91,16 @@ import com.vitorpamplona.amethyst.commons.ui.theme.EditFieldModifier import com.vitorpamplona.amethyst.commons.ui.theme.EditFieldTrailingIconModifier import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightChat import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.RefreshingChatroomFeedView import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.upload.ChatFileUploader import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.upload.SuccessfulUploads -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelHistorySubAssembler import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelHistorySubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.send.ConcordNewMessageViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.dal.ChannelFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadDialog diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordCommunityImage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordCommunityImage.kt index 83f337834c..2edfb1473a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordCommunityImage.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordCommunityImage.kt @@ -24,7 +24,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.produceState import androidx.compose.ui.platform.LocalContext -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.concord.cord02Community.ImagePointer import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordCreateScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordCreateScreen.kt index c866cdc039..5f7549b8fe 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordCreateScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordCreateScreen.kt @@ -54,7 +54,7 @@ import com.vitorpamplona.amethyst.commons.resources.concord_create_relays_desc import com.vitorpamplona.amethyst.commons.resources.concord_create_title import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.concord.cord02Community.ImagePointer import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordEditScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordEditScreen.kt index c75feed5ad..ddf048bd2a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordEditScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordEditScreen.kt @@ -55,9 +55,9 @@ import com.vitorpamplona.amethyst.commons.resources.concord_edit_relays_desc import com.vitorpamplona.amethyst.commons.resources.concord_edit_save import com.vitorpamplona.amethyst.commons.resources.concord_edit_title import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.concord.cord02Community.ImagePointer import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer @@ -68,7 +68,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon as SymbolIcon /** * Edit a Concord community's metadata (name / description / icon). Reuses the shared * [ConcordMetadataFields] hero + fields, prefilled from the folded Control Plane, and - * saves a new metadata edition via [com.vitorpamplona.amethyst.model.Account.editConcordMetadata] + * saves a new metadata edition via [com.vitorpamplona.amethyst.commons.model.Account.editConcordMetadata] * — honored on fold only when this account holds MANAGE_METADATA (or is the owner). */ @OptIn(ExperimentalMaterial3Api::class) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordHomeScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordHomeScreen.kt index 5852cb0061..01c517f2b3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordHomeScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordHomeScreen.kt @@ -54,11 +54,15 @@ 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.chats.publicChannels.concord.concordChannelUnreadCountFlow +import com.vitorpamplona.amethyst.commons.chats.publicChannels.concord.newestTimelineNote import com.vitorpamplona.amethyst.commons.concord.ui.ConcordUnreadBadge import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserName import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back import com.vitorpamplona.amethyst.commons.resources.concord_channel_count @@ -72,14 +76,12 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarP import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar import com.vitorpamplona.amethyst.commons.ui.note.timeAgo +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.concord.cord02Community.ImagePointer import com.vitorpamplona.quartz.concord.cord03Channels.ConcordChannelId import kotlinx.coroutines.flow.combine diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordImageUploader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordImageUploader.kt index 43ef3dedca..9c3c5470ac 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordImageUploader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordImageUploader.kt @@ -22,11 +22,11 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.conco import android.content.Context import android.net.Uri +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.DEFAULT_MEDIA_SERVERS import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadingState diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordInviteLinksScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordInviteLinksScreen.kt index 27f4f2205d..9b03cc9e9f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordInviteLinksScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordInviteLinksScreen.kt @@ -75,7 +75,7 @@ import com.vitorpamplona.amethyst.commons.resources.more_options import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.concord.cord05Invites.ConcordInviteListEntry import kotlinx.coroutines.launch import java.text.DateFormat diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordMetadataForm.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordMetadataForm.kt index 476a3b0bf7..d715b3089e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordMetadataForm.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordMetadataForm.kt @@ -66,6 +66,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil3.compose.AsyncImage import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.concord_create_about import com.vitorpamplona.amethyst.commons.resources.concord_create_icon_hint @@ -78,12 +79,11 @@ import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncIma import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.RenderRelayIcon import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.MediumRelayIconModifier -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo -import com.vitorpamplona.amethyst.ui.note.RenderRelayIcon -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField import com.vitorpamplona.quartz.concord.cord02Community.ImagePointer import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelHistorySubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelHistorySubscription.kt index 409d157e4b..c836316b36 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelHistorySubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelHistorySubscription.kt @@ -25,8 +25,11 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.chats.publicChannels.concord.datasource.ConcordChannelHistoryFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.concord.datasource.ConcordChannelHistoryQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Mount on the open Concord Channel screen to keep its backward-history pager bound and armed. The diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/send/ConcordNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/send/ConcordNewMessageViewModel.kt index 0361980ecb..ea1c2768ab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/send/ConcordNewMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/send/ConcordNewMessageViewModel.kt @@ -28,18 +28,18 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiPackState import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiSuggestionState +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.onUiThread +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.ReplyMode -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadState import com.vitorpamplona.quartz.concord.cord03Channels.ConcordChannelId import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/dal/ChannelFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/dal/ChannelFeedFilter.kt index f656839204..e057199a37 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/dal/ChannelFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/dal/ChannelFeedFilter.kt @@ -22,11 +22,11 @@ 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.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Channel import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.chats.isMinichatReply -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder class ChannelFeedFilter( val channel: Channel, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/dal/ChannelFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/dal/ChannelFeedViewModel.kt index ce9fc17080..ccf3ffec0c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/dal/ChannelFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/dal/ChannelFeedViewModel.kt @@ -22,10 +22,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.dal import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Channel import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.viewmodels.ListChangeFeedViewModel -import com.vitorpamplona.amethyst.model.Account class ChannelFeedViewModel( val channel: Channel, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/ChannelFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/ChannelFilterAssemblerSubscription.kt index 13b127cec4..6cac602664 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/ChannelFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/ChannelFilterAssemblerSubscription.kt @@ -31,7 +31,7 @@ import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActiviti import com.vitorpamplona.amethyst.commons.relayClient.channel.ChannelFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.channel.ChannelQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun ChannelFilterAssemblerSubscription( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/ChannelView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/ChannelView.kt index 6692e456ba..98b236ba66 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/ChannelView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/ChannelView.kt @@ -35,7 +35,7 @@ import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.RefreshingChatroomFeedView import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.dal.ChannelFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.datasource.ChannelFilterAssemblerSubscription diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/EphemeralChatScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/EphemeralChatScreen.kt index 37080d9668..1613bbfec7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/EphemeralChatScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/EphemeralChatScreen.kt @@ -26,9 +26,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.ephemChat.header.EphemeralChatTopBar import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/LoadEphemeralChatChannel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/LoadEphemeralChatChannel.kt index df81acc0fa..8673f99314 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/LoadEphemeralChatChannel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/LoadEphemeralChatChannel.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.ephem import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel -import com.vitorpamplona.amethyst.ui.note.produceStateIfNotNull +import com.vitorpamplona.amethyst.commons.ui.note.produceStateIfNotNull import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/header/EphemeralChatChannelHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/header/EphemeralChatChannelHeader.kt index f3b1fead68..607b791ad4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/header/EphemeralChatChannelHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/header/EphemeralChatChannelHeader.kt @@ -29,9 +29,9 @@ import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun EphemeralChatChannelHeader( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/header/EphemeralChatTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/header/EphemeralChatTopBar.kt index 3a597bfb62..eb8e58b8ec 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/header/EphemeralChatTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/header/EphemeralChatTopBar.kt @@ -24,7 +24,7 @@ import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun EphemeralChatTopBar( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/header/ShortEphemeralChatChannelHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/header/ShortEphemeralChatChannelHeader.kt index 357f3576cf..b34632879d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/header/ShortEphemeralChatChannelHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/header/ShortEphemeralChatChannelHeader.kt @@ -38,6 +38,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.chats.ui.JoinChannelButton import com.vitorpamplona.amethyst.commons.chats.ui.LeaveChannelButton import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannel +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserIsFollowingChannel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.profile_image import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage @@ -46,10 +49,7 @@ import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.HeaderPictureModifier import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsFollowingChannel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun ShortEphemeralChatChannelHeader( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/metadata/NewEphemeralChatMetaViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/metadata/NewEphemeralChatMetaViewModel.kt index 5090b14109..c5f8910f74 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/metadata/NewEphemeralChatMetaViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/metadata/NewEphemeralChatMetaViewModel.kt @@ -25,7 +25,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.ViewModel -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/metadata/NewEphemeralChatScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/metadata/NewEphemeralChatScreen.kt index 52c4b36170..1650680780 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/metadata/NewEphemeralChatScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/ephemChat/metadata/NewEphemeralChatScreen.kt @@ -51,15 +51,15 @@ import com.vitorpamplona.amethyst.commons.resources.relay_chat_title import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.PostingTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.SettingsCategoryFirstModifier import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.SettingsCategory @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/ChannelView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/ChannelView.kt index b1721b7f7a..9b19514b26 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/ChannelView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/ChannelView.kt @@ -34,9 +34,9 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadPublicChatChannel import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer -import com.vitorpamplona.amethyst.ui.note.LoadPublicChatChannel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.RefreshingChatroomFeedView import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.dal.ChannelFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.datasource.ChannelFilterAssemblerSubscription diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/PublicChatChannelScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/PublicChatChannelScreen.kt index 10e544030b..6f0133c242 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/PublicChatChannelScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/PublicChatChannelScreen.kt @@ -27,11 +27,11 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.note.LoadPublicChatChannel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.note.LoadPublicChatChannel +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.PublicChatTopBar import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/PublicChatTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/PublicChatTopBar.kt index 105b3b5108..95534cbd1e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/PublicChatTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/PublicChatTopBar.kt @@ -24,7 +24,9 @@ import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.LongPublicChatChannelHeader +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.ShortPublicChatChannelHeader +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun PublicChatTopBar( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/metadata/ChannelMetadataScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/metadata/ChannelMetadataScreen.kt index e809b75853..b40634d951 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/metadata/ChannelMetadataScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/metadata/ChannelMetadataScreen.kt @@ -45,7 +45,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.commons.resources.Res @@ -64,8 +64,10 @@ import com.vitorpamplona.amethyst.commons.resources.read_only_user import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.CreatingTopBar import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SavingTopBar +import com.vitorpamplona.amethyst.commons.ui.note.LoadPublicChatChannel import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding @@ -73,11 +75,9 @@ import com.vitorpamplona.amethyst.commons.ui.theme.SettingsCategoryFirstModifier import com.vitorpamplona.amethyst.commons.ui.theme.SettingsCategorySpacingModifier import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectSingleFromGallery -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.LoadPublicChatChannel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.SettingsCategory import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField @@ -238,7 +238,7 @@ private fun ChannelMetadataScaffold( BasicRelaySetupInfoDialog( item, onDelete = { postViewModel.deleteHomeRelay(item) }, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = HorzHalfVertPadding, accountViewModel = accountViewModel, nav = nav, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/metadata/ChannelMetadataViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/metadata/ChannelMetadataViewModel.kt index f949da6185..286b7f2a6a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/metadata/ChannelMetadataViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/metadata/ChannelMetadataViewModel.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel @@ -41,7 +41,7 @@ import com.vitorpamplona.amethyst.commons.resources.metadata_strip_failed_title import com.vitorpamplona.amethyst.commons.resources.metadata_strip_failed_upload_cancelled import com.vitorpamplona.amethyst.commons.resources.server_did_not_provide_a_url_after_uploading import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.AvifMetadataNotVerifiableException import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.MediaCompressor @@ -49,7 +49,6 @@ import com.vitorpamplona.amethyst.service.uploads.MetadataStripper import com.vitorpamplona.amethyst.service.uploads.blossom.BlossomUploader import com.vitorpamplona.amethyst.service.uploads.nip96.Nip96Uploader import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle @@ -251,7 +250,7 @@ class ChannelMetadataViewModel : ViewModel() { alt = null, sensitiveContent = null, serverBaseUrl = account.settings.defaultFileServer.baseUrl, - okHttpClient = Amethyst.instance.roleBasedHttpClientBuilder::okHttpClientForUploads, + okHttpClient = accountViewModel.httpClientBuilder::okHttpClientForUploads, onProgress = {}, httpAuth = account::createHTTPAuthorization, context = context, @@ -264,7 +263,7 @@ class ChannelMetadataViewModel : ViewModel() { alt = null, sensitiveContent = null, serverBaseUrl = account.settings.defaultFileServer.baseUrl, - okHttpClient = Amethyst.instance.roleBasedHttpClientBuilder::okHttpClientForUploads, + okHttpClient = accountViewModel.httpClientBuilder::okHttpClientForUploads, httpAuth = account::createBlossomUploadAuth, context = context, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/ChannelView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/ChannelView.kt index 640a432263..0c469c4510 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/ChannelView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/ChannelView.kt @@ -33,9 +33,11 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadLiveActivityChannel +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.ShowVideoStreaming +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.nests.room.lobby.NestJoinCard import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer -import com.vitorpamplona.amethyst.ui.note.LoadLiveActivityChannel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.RefreshingChatroomFeedView import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.dal.ChannelFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.datasource.ChannelFilterAssemblerSubscription @@ -43,7 +45,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53L import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header.LiveStreamTopZappers import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.send.ChannelNewMessageViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.send.EditFieldRow -import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.lobby.NestJoinCard import com.vitorpamplona.quartz.nip01Core.core.Address @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/LiveActivityChannelScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/LiveActivityChannelScreen.kt index bf3b19c433..98e6975828 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/LiveActivityChannelScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/LiveActivityChannelScreen.kt @@ -28,10 +28,10 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.service.OnlineChecker +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.note.LoadLiveActivityChannel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.note.LoadLiveActivityChannel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header.LiveActivityTopBar import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveActivityTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveActivityTopBar.kt index 3c9f484278..573eca0086 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveActivityTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveActivityTopBar.kt @@ -24,7 +24,9 @@ import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header.LongLiveActivityChannelHeader +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header.ShortLiveActivityChannelHeader +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun LiveActivityTopBar( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveStreamGoalHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveStreamGoalHeader.kt index c8f2739522..615928c14a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveStreamGoalHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveStreamGoalHeader.kt @@ -39,15 +39,15 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.types.GoalProgressBar import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.ZapReaction -import com.vitorpamplona.amethyst.ui.note.types.GoalProgressBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip75ZapGoals.ZapGoalEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveStreamTopZappers.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveStreamTopZappers.kt index 7d31a80b08..4d588255fc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveStreamTopZappers.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveStreamTopZappers.kt @@ -55,15 +55,15 @@ import com.vitorpamplona.amethyst.commons.nip53LiveActivities.TopZapperEntry import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.chat_zap_anonymous import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.note.ZapIcon import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.commons.ui.theme.Size16Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size24dp import com.vitorpamplona.amethyst.commons.util.showAmountInteger +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.LiveStreamTopZappersViewModel -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import java.math.BigDecimal /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/BuzzTypingIndicator.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/BuzzTypingIndicator.kt index 9e5dc3bd1e..d5b02fa0ef 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/BuzzTypingIndicator.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/BuzzTypingIndicator.kt @@ -57,14 +57,14 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.buzz.BuzzTypingState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.buzz_typing_many import com.vitorpamplona.amethyst.commons.resources.buzz_typing_one import com.vitorpamplona.amethyst.commons.resources.buzz_typing_two import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.delay diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/InviteRelayGroupDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/InviteRelayGroupDialog.kt index eac28755b3..b46ce30b80 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/InviteRelayGroupDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/InviteRelayGroupDialog.kt @@ -45,7 +45,7 @@ import com.vitorpamplona.amethyst.commons.resources.relay_group_invite_preparing import com.vitorpamplona.amethyst.commons.resources.relay_group_invite_title import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.utils.RandomInstance import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/JoinRelayGroupDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/JoinRelayGroupDialog.kt index 197323b319..9e4fe9deb4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/JoinRelayGroupDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/JoinRelayGroupDialog.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relay import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.nip29RelayGroups.ui.RelayGroupInviteCodeDialog -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Ask for an invite code before joining a closed (invite-only) NIP-29 group, then diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupBrowseScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupBrowseScreen.kt index 041e7caf05..0f7899954d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupBrowseScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupBrowseScreen.kt @@ -47,7 +47,7 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.relay_group_browse_description @@ -62,7 +62,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensible import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.HalfHorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.PopupUpEffect -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelaySuggestionState import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.ShowRelaySuggestionList import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer @@ -170,7 +170,7 @@ fun RelayGroupBrowseScreen( relaySuggestions = relaySuggestions, onSelect = { relay -> open(relay.url) }, modifier = HalfHorzPadding, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, accountViewModel = accountViewModel, nav = nav, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupChannelListScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupChannelListScreen.kt index 0bd74d7ba7..fcc4e5b605 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupChannelListScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupChannelListScreen.kt @@ -64,6 +64,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.buzz.ui.PresenceDot +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.newestTimelineNote import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note @@ -74,6 +75,7 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupDeletions +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserName import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.isRelaySignedRelayGroup import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.looksLikeNonNip29Relay import com.vitorpamplona.amethyst.commons.resources.Res @@ -98,20 +100,20 @@ import com.vitorpamplona.amethyst.commons.resources.relay_tor_clearnet_body import com.vitorpamplona.amethyst.commons.resources.relay_tor_clearnet_title import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton import com.vitorpamplona.amethyst.commons.ui.note.TimeAgoLabels +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.note.rememberTimeAgoLabels import com.vitorpamplona.amethyst.commons.ui.note.timeAgoShort +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.warningColor import com.vitorpamplona.amethyst.commons.util.sortedBySnapshot -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.BuzzAddPeopleDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.BuzzDmListViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.BuzzImportRow @@ -119,7 +121,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.BuzzRelayImportViewMod import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.BuzzWorkspaceOverflowMenu import com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz.HiddenDmHeader import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.buzzTimelinePreviewSummary -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupsOnRelaySubscription import com.vitorpamplona.quartz.buzz.workspace.BUZZ_CHANNEL_TYPE_DM import com.vitorpamplona.quartz.buzz.workspace.BUZZ_CHANNEL_TYPE_FORUM @@ -200,7 +201,7 @@ fun RelayGroupChannelListScreen( // Warm the relay's NIP-11 so we can tell its genuine (relay-signed) groups from stray // user-published 39000s that a non-NIP-29 relay may also be storing. Re-keyed on trust so a move // to clearnet re-fetches over the new transport instead of serving the cached over-Tor failure. - val nip11Cache = Amethyst.instance.nip11Cache + val nip11Cache = LocalCache.appHost.nip11Cache val relayInfo by produceState(nip11Cache.getFromCache(relay), relay, isTrusted) { if (isTrusted) nip11Cache.invalidate(relay) nip11Cache.loadRelayInfo(relay, onInfo = { value = it }, onError = { _, _, _ -> }) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupChannelView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupChannelView.kt index bc9bb08e2e..1b2cb77630 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupChannelView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupChannelView.kt @@ -39,6 +39,7 @@ 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.chats.publicChannels.relayGroup.datasource.RelayGroupOpenChatHistorySubAssembler import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.commons.model.Note @@ -56,13 +57,13 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachSentinels import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachState import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.LoadRelayGroupChannel import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.RefreshingChatroomFeedView import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.dal.ChannelFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.datasource.ChannelFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupOpenChatHistorySubAssembler import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupOpenChatHistorySubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupOpenChatTailSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.send.ChannelNewMessageViewModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupChatScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupChatScreen.kt index e938259b76..3ff4589c70 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupChatScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupChatScreen.kt @@ -27,10 +27,11 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.LoadRelayGroupChannel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip29RelayGroups.GroupId diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMetadataScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMetadataScreen.kt index 1cbb3cdd66..55720bc405 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMetadataScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMetadataScreen.kt @@ -66,9 +66,9 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import coil3.compose.AsyncImage -import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.resources.Res @@ -108,13 +108,14 @@ import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.CreatingTopBar import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SavingTopBar +import com.vitorpamplona.amethyst.commons.ui.platform.GeohashLocationPickerDialog +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.LoadRelayGroupChannel +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelectSingle -import com.vitorpamplona.amethyst.ui.note.creators.location.GeohashLocationPickerDialog import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName import com.vitorpamplona.amethyst.ui.note.creators.location.LocationPreviewMap -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupSubscription import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeoHash import com.vitorpamplona.quartz.nip29RelayGroups.GroupId @@ -144,7 +145,7 @@ fun RelayGroupCreateScreen( // on the relay advertising NIP-29 in its NIP-11 `supported_nips`. Tri-state: null = still checking, // false = confirmed unsupported (or unreachable), true = advertised. val nip29Support by produceState(initialValue = null, relay) { - Amethyst.instance.nip11Cache.loadRelayInfo( + LocalCache.appHost.nip11Cache.loadRelayInfo( relay = relay, onInfo = { info -> value = info.supported_nips?.any { it == "29" } ?: false }, onError = { _, _, _ -> value = false }, @@ -216,7 +217,7 @@ private fun RelayGroupMetadataScaffold( // NIP-29 §Subgroups relay support detection: `"nip29": { "subgroups": true }` in the NIP-11. val subgroupsSupported by produceState(initialValue = false, viewModel.relay) { val relay = viewModel.relay ?: return@produceState - Amethyst.instance.nip11Cache.loadRelayInfo( + LocalCache.appHost.nip11Cache.loadRelayInfo( relay = relay, onInfo = { info -> value = info.nip29?.subgroups == true }, onError = { _, _, _ -> value = false }, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMetadataViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMetadataViewModel.kt index 06273e016a..17cb7d0c4c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMetadataViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMetadataViewModel.kt @@ -30,6 +30,7 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.buzz.BuzzRelayDialect import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel @@ -43,7 +44,7 @@ import com.vitorpamplona.amethyst.commons.resources.metadata_strip_failed_upload import com.vitorpamplona.amethyst.commons.resources.read_only_user import com.vitorpamplona.amethyst.commons.resources.server_did_not_provide_a_url_after_uploading import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.AvifMetadataNotVerifiableException import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.MediaCompressor @@ -51,7 +52,6 @@ import com.vitorpamplona.amethyst.service.uploads.MetadataStripper import com.vitorpamplona.amethyst.service.uploads.blossom.BlossomUploader import com.vitorpamplona.amethyst.service.uploads.nip96.Nip96Uploader import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.buzz.workspace.BUZZ_CHANNEL_TYPE_FORUM import com.vitorpamplona.quartz.buzz.workspace.BUZZ_CHANNEL_TYPE_STREAM import com.vitorpamplona.quartz.buzz.workspace.newBuzzChannelId diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMigrationBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMigrationBar.kt index 315adef376..506393d4d8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMigrationBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMigrationBar.kt @@ -51,6 +51,7 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupAdminCache import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupMigrationDetector +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.relay_group_migration_by_admins import com.vitorpamplona.amethyst.commons.resources.relay_group_migration_by_friends @@ -62,8 +63,7 @@ import com.vitorpamplona.amethyst.commons.resources.relay_group_migration_open import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import com.vitorpamplona.quartz.nip51Lists.simpleGroupList.SimpleGroupListEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupParentPicker.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupParentPicker.kt index d0da74a4c0..dceeb4485d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupParentPicker.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupParentPicker.kt @@ -63,6 +63,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.isRelaySignedRelayGroup import com.vitorpamplona.amethyst.commons.resources.Res @@ -79,11 +80,10 @@ import com.vitorpamplona.amethyst.commons.resources.relay_group_section_structur import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.util.sortedBySnapshot -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupsOnRelaySubscription import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupPinnedBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupPinnedBar.kt index 71f21dc2a2..055e627de8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupPinnedBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupPinnedBar.kt @@ -47,13 +47,13 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.relay_group_pinned_content_description import com.vitorpamplona.amethyst.commons.resources.relay_group_pinned_label import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip29RelayGroups.tags.AddressPin import com.vitorpamplona.quartz.nip29RelayGroups.tags.EventPin diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupServerList.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupServerList.kt index 8489a8e868..f8d30ed04d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupServerList.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupServerList.kt @@ -37,16 +37,16 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.looksLikeNonNip29Relay import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.relay_group_relay_not_nip29 +import com.vitorpamplona.amethyst.commons.ui.note.RenderRelayIcon import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.LargeRelayIconModifier import com.vitorpamplona.amethyst.commons.ui.theme.warningColor -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo -import com.vitorpamplona.amethyst.ui.note.RenderRelayIcon -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupSubgroupsBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupSubgroupsBar.kt index 0010259629..cded118fbb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupSubgroupsBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupSubgroupsBar.kt @@ -48,8 +48,9 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.LoadRelayGroupChannel import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupsOnRelaySubscription import com.vitorpamplona.quartz.nip29RelayGroups.GroupId diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupTopBar.kt index 56f21f5ff1..a70e5755f4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupTopBar.kt @@ -59,6 +59,8 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupMembership +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannel +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserName import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.add_to_messages import com.vitorpamplona.amethyst.commons.resources.buzz_agent_work_title @@ -85,13 +87,12 @@ import com.vitorpamplona.amethyst.commons.resources.relay_group_threads_title import com.vitorpamplona.amethyst.commons.resources.remove_from_messages import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SearchTopBarAction import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.BuzzPinDropdownItem import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.util.njumpLink -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.navigation.topbars.SearchTopBarAction -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.buzz.workspace.buzzParticipants import com.vitorpamplona.quartz.buzz.workspace.isBuzzDm import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/WarmJoinedRelayGroupNip11.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/WarmJoinedRelayGroupNip11.kt index 364aeba052..7178a4c90d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/WarmJoinedRelayGroupNip11.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/WarmJoinedRelayGroupNip11.kt @@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.model.nip11RelayInfo.WarmNip11 -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.WarmNip11 +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupChatSubscriptions.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupChatSubscriptions.kt index f137c02d54..d334e18e90 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupChatSubscriptions.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupChatSubscriptions.kt @@ -26,13 +26,20 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.key import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.BuzzDmJoinedChatTailQueryState +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupJoinedChatTailQueryState +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupJoinedStateQueryState +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupOpenChatHistoryFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupOpenChatHistoryQueryState +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupOpenChatTailFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupOpenChatTailQueryState import com.vitorpamplona.amethyst.commons.model.buzz.BuzzDmChannels import com.vitorpamplona.amethyst.commons.model.buzz.BuzzDmRegistry import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType import com.vitorpamplona.amethyst.commons.relayClient.channel.relayGroup.buildRelayGroupJoinedChatTailFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip29RelayGroups.GroupId diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsOnRelaySubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsOnRelaySubscription.kt index f97122929f..c93a040021 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsOnRelaySubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsOnRelaySubscription.kt @@ -22,8 +22,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relay import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupsOnRelayFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupsOnRelayQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelFileUploadDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelFileUploadDialog.kt index 467917ee63..6ae466e4a3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelFileUploadDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelFileUploadDialog.kt @@ -40,12 +40,12 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.profile_image import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.HeaderPictureModifier import com.vitorpamplona.amethyst.commons.ui.theme.Size34dp -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadState diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt index cd4edf2318..4c61d9a10d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt @@ -32,6 +32,7 @@ import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Channel import com.vitorpamplona.amethyst.commons.model.Note @@ -44,6 +45,7 @@ import com.vitorpamplona.amethyst.commons.model.composer.NewMessageTagger import com.vitorpamplona.amethyst.commons.model.composer.SplitBuilder import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel import com.vitorpamplona.amethyst.commons.model.geohashChat.GeohashChatChannel +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupMembership @@ -58,19 +60,18 @@ import com.vitorpamplona.amethyst.commons.richtext.UrlParser import com.vitorpamplona.amethyst.commons.service.pow.PoWReplay import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation import com.vitorpamplona.amethyst.commons.ui.loadStringRes +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.ui.text.onUiThread import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.ReplyMode -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.location.LocationState import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.note.creators.location.ILocationGrabber -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.IMetaAttachments import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadState import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.UserSuggestionAnchor @@ -222,7 +223,7 @@ open class ChannelNewMessageViewModel : // GeoHash var wantsToAddGeoHash by mutableStateOf(false) override var pickedGeoHash by mutableStateOf(null) - var location: StateFlow? = null + var location: StateFlow? = null // Geohash location chat (Bitchat interop): messages are signed with an anonymous per-cell // identity (unless posting as self) and carry a small NIP-13 PoW + the n/t tags. @@ -625,7 +626,7 @@ open class ChannelNewMessageViewModel : val emojis = accountViewModel.account.emoji.findEmojiTags(messageText) val channelRelays = channel.relays() - val geoHash = if (wantsToAddGeoHash) (pickedGeoHash ?: (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString()) else null + val geoHash = if (wantsToAddGeoHash) (pickedGeoHash ?: (location?.value as? LocationResult.Success)?.geoHash?.toString()) else null val contentWarningReason = if (wantsToMarkAsSensitive) contentWarningDescription else null val localExpirationDate = if (wantsExpirationDate) expirationDate else null @@ -1013,7 +1014,7 @@ open class ChannelNewMessageViewModel : viewModelScope.launch(Dispatchers.IO) { iMetaAttachments.downloadAndPrepare(item.link) { - Amethyst.instance.roleBasedHttpClientBuilder.okHttpClientForImage(item.link) + accountViewModel.httpClientBuilder.okHttpClientForImage(item.link) } } @@ -1039,7 +1040,7 @@ open class ChannelNewMessageViewModel : override fun locationManager(): LocationState = Amethyst.instance.locationManager - override fun locationFlow(): StateFlow { + override fun locationFlow(): StateFlow { if (location == null) { location = locationManager().geohashStateFlow } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/EditFieldRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/EditFieldRow.kt index a1093b684d..6cb3e598d1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/EditFieldRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/EditFieldRow.kt @@ -55,6 +55,7 @@ import com.vitorpamplona.amethyst.commons.resources.cancel import com.vitorpamplona.amethyst.commons.resources.reply_here import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDialog import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.text.MentionPreservingInputTransformation import com.vitorpamplona.amethyst.commons.ui.text.onUiThread @@ -63,12 +64,11 @@ import com.vitorpamplona.amethyst.commons.ui.theme.EditFieldModifier import com.vitorpamplona.amethyst.commons.ui.theme.EditFieldTrailingIconModifier import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightChat import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.DisplayReplyingToNote import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChatroomHeaderCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChatroomHeaderCompose.kt index d782720627..bf4d44624d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChatroomHeaderCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChatroomHeaderCompose.kt @@ -33,7 +33,6 @@ import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -45,6 +44,9 @@ import androidx.compose.ui.text.style.TextDirection import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.chats.publicChannels.concord.concordCommunityHasUnreadFlow +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.relayGroupServerHasUnreadFlow +import com.vitorpamplona.amethyst.commons.chats.rooms.rowHasUnread import com.vitorpamplona.amethyst.commons.concord.ui.ConcordCommunityPill import com.vitorpamplona.amethyst.commons.cordn.CoordinatorConfig import com.vitorpamplona.amethyst.commons.icons.symbols.Icon @@ -52,6 +54,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.model.buzz.toMembershipNotice import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.chatMessageMarksRoomAsRead import com.vitorpamplona.amethyst.commons.model.chats.ConcordServerRoomNote @@ -65,6 +68,7 @@ import com.vitorpamplona.amethyst.commons.model.marmotGroupLastReadRoute import com.vitorpamplona.amethyst.commons.model.marmotGroups.MarmotGroupChatroom import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.model.privateChatLastReadRoute @@ -72,6 +76,10 @@ import com.vitorpamplona.amethyst.commons.model.privateChats.ChatPreview import com.vitorpamplona.amethyst.commons.model.privateChats.chatPreviewOf import com.vitorpamplona.amethyst.commons.model.relayGroupChannelLastReadRoute import com.vitorpamplona.amethyst.commons.nip29RelayGroups.ui.RelayNameChip +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteHasEvent +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannel +import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderByParentFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserName import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.add_to_messages import com.vitorpamplona.amethyst.commons.resources.channel_created @@ -114,10 +122,20 @@ import com.vitorpamplona.amethyst.commons.ui.components.NewItemsBubble import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.layouts.ChatHeaderLayout import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.BlankNote import com.vitorpamplona.amethyst.commons.ui.note.HeaderPill +import com.vitorpamplona.amethyst.commons.ui.note.LoadDecryptedContentOrNull +import com.vitorpamplona.amethyst.commons.ui.note.LoadPublicChatChannel +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.NonClickableUserPictures +import com.vitorpamplona.amethyst.commons.ui.note.ObserveDraftEvent import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgoStyle import com.vitorpamplona.amethyst.commons.ui.note.elements.ToggleableTimeAgoText import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.privateDM.header.RoomNameDisplay +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings.cordn.coordinatorDisplayName import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.AccountPictureModifier import com.vitorpamplona.amethyst.commons.ui.theme.ChatLabelMaxWidth @@ -127,34 +145,17 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.model.buzz.toMembershipNotice -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteHasEvent -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.UserFinderByParentFilterAssemblerSubscription -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.BlankNote -import com.vitorpamplona.amethyst.ui.note.LoadDecryptedContentOrNull -import com.vitorpamplona.amethyst.ui.note.LoadPublicChatChannel -import com.vitorpamplona.amethyst.ui.note.NonClickableUserPictures -import com.vitorpamplona.amethyst.ui.note.ObserveDraftEvent -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.buzzTimelinePreviewSummary -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.loadMarmotRelayIcon import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.marmotGroupPreviewText import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.marmotGroupTitle import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.marmotOtherMembers import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.rememberMarmotGroupAvatarUrl -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.header.RoomNameDisplay import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.header.reportWarningContentDescription import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.ConcordLeaveDialog -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.concordCommunityHasUnreadFlow import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.rememberConcordImageModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.ephemChat.LoadEphemeralChatChannel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.relayGroupServerHasUnreadFlow -import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.coordinatorDisplayName import com.vitorpamplona.quartz.buzz.notifications.MemberAddedNotificationEvent import com.vitorpamplona.quartz.cordn.appEncryptedMedia.CordnMediaTag import com.vitorpamplona.quartz.experimental.bitchat.geohash.GeohashChatEvent @@ -1282,23 +1283,6 @@ private fun RowScope.LastMessagePreview( } } -@Composable -fun LoadUser( - baseUserHex: String, - content: @Composable (User?) -> Unit, -) { - var user by - remember(baseUserHex) { mutableStateOf(LocalCache.getUserIfExists(baseUserHex)) } - - if (user == null) { - LaunchedEffect(key1 = baseUserHex) { - user = LocalCache.checkGetOrCreateUser(baseUserHex) - } - } - - content(user) -} - @Composable fun ChannelName( channelIdHex: String, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/MessagesScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/MessagesScreen.kt index 91d1273aad..e954e46c47 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/MessagesScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/MessagesScreen.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.DpSize import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.singlepane.MessagesSinglePane import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.twopane.MessagesTwoPane diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/ChatroomListFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/ChatroomListFilterAssemblerSubscription.kt index dc778c521e..38981a48ad 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/ChatroomListFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/ChatroomListFilterAssemblerSubscription.kt @@ -22,8 +22,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.chats.rooms.datasource.ChatroomListFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.rooms.datasource.ChatroomListState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun ChatroomListFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/feed/ChatroomListFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/feed/ChatroomListFeedView.kt index f17261abee..4e269a3929 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/feed/ChatroomListFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/feed/ChatroomListFeedView.kt @@ -58,13 +58,13 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachDetailDialog import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachMarkers import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachSentinels import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.ChatroomHeaderCompose import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/feed/ChatroomListTabs.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/feed/ChatroomListTabs.kt index 33361c03d4..1f5b5d2314 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/feed/ChatroomListTabs.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/feed/ChatroomListTabs.kt @@ -57,7 +57,7 @@ import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size40dp import com.vitorpamplona.amethyst.commons.ui.theme.TabRowHeight import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.launch import org.jetbrains.compose.resources.StringResource diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/singlepane/MessagesSinglePane.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/singlepane/MessagesSinglePane.kt index ff1e19cd00..e959234874 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/singlepane/MessagesSinglePane.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/singlepane/MessagesSinglePane.kt @@ -36,13 +36,13 @@ import com.vitorpamplona.amethyst.commons.resources.known import com.vitorpamplona.amethyst.commons.resources.new_requests import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.topbars.AmethystClickableIcon -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.WarmJoinedRelayGroupNip11 import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource.ChatroomListFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.feed.MessagesPager diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/ChatroomListPane.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/ChatroomListPane.kt index 55b7bb97f3..402cebae47 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/ChatroomListPane.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/ChatroomListPane.kt @@ -33,7 +33,7 @@ import com.vitorpamplona.amethyst.commons.resources.new_requests import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource.ChatroomListFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.feed.MessagesPager import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.feed.MessagesTabHeader diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/MessagesTwoPane.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/MessagesTwoPane.kt index 21776a66c7..4a6e0a8ddb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/MessagesTwoPane.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/MessagesTwoPane.kt @@ -41,12 +41,12 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.TwoPaneNav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.getActivity -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar import com.vitorpamplona.amethyst.ui.navigation.topbars.AmethystClickableIcon -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.ChatroomView import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.PublicChatChannelView import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.WarmJoinedRelayGroupNip11 diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/share/ShareDMRoomsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/share/ShareDMRoomsFeedFilter.kt index 17260fb9d1..734cd2d143 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/share/ShareDMRoomsFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/share/ShareDMRoomsFeedFilter.kt @@ -21,9 +21,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.share import com.vitorpamplona.amethyst.commons.feeds.FeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder /** * Recent private-DM conversations only (no public channels, ephemeral chats, or diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/share/ShareToDMScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/share/ShareToDMScreen.kt index 6be8af6f4d..dc72134862 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/share/ShareToDMScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/share/ShareToDMScreen.kt @@ -47,7 +47,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.ShareToDMNav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.feed.ChatroomListFeedView @OptIn(ExperimentalMaterial3Api::class) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/utils/ChatFileUploadDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/utils/ChatFileUploadDialog.kt index 637f91bb53..8b52378ae7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/utils/ChatFileUploadDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/utils/ChatFileUploadDialog.kt @@ -83,9 +83,9 @@ import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.Settin import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.ShowImageUploadGallery import com.vitorpamplona.amethyst.ui.components.SetDialogToEdgeToEdge -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsRow import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/utils/DisplayReplyingToNote.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/utils/DisplayReplyingToNote.kt index 64f9d3209c..129fb8df84 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/utils/DisplayReplyingToNote.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/utils/DisplayReplyingToNote.kt @@ -38,7 +38,7 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.ChatroomMessageCompose @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/AndroidChessAdapter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/AndroidChessAdapter.kt index 80b6a7ec27..5e39b89c07 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/AndroidChessAdapter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/AndroidChessAdapter.kt @@ -20,6 +20,7 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chess +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.nip64Chess.ChessConfig import com.vitorpamplona.amethyst.commons.nip64Chess.ChessEventBroadcaster @@ -30,7 +31,6 @@ import com.vitorpamplona.amethyst.commons.nip64Chess.IUserMetadataProvider import com.vitorpamplona.amethyst.commons.nip64Chess.RelayFetchProgress import com.vitorpamplona.amethyst.commons.nip64Chess.RelayGameSummary import com.vitorpamplona.amethyst.commons.nip64Chess.subscription.ChessFilterBuilder -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip64Chess.ChessGameEnd import com.vitorpamplona.quartz.nip64Chess.ChessMoveEvent import com.vitorpamplona.quartz.nip64Chess.Color diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessGameScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessGameScreen.kt index 2e15512276..183dfb2e18 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessGameScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessGameScreen.kt @@ -78,7 +78,7 @@ import com.vitorpamplona.amethyst.commons.resources.relay_settings import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Height4dpModifier -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chess.datasource.ChessSubscription import com.vitorpamplona.quartz.nip64Chess.ChessGameNameGenerator diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessLobbyScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessLobbyScreen.kt index ca57f5d7c3..a41afb483a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessLobbyScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessLobbyScreen.kt @@ -83,7 +83,7 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chess.datasource.ChessSubscription import com.vitorpamplona.quartz.nip64Chess.Color as ChessColor diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessRelaySettingsSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessRelaySettingsSheet.kt index faa4bff105..10e0639223 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessRelaySettingsSheet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessRelaySettingsSheet.kt @@ -50,7 +50,7 @@ import com.vitorpamplona.amethyst.commons.nip64Chess.ChessViewModel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.connected import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import kotlinx.coroutines.flow.map diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessViewModelFactory.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessViewModelFactory.kt index 3d69227fd1..a785dc80d5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessViewModelFactory.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessViewModelFactory.kt @@ -22,10 +22,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chess import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.nip64Chess.ChessDismissedGamesStore import com.vitorpamplona.amethyst.commons.nip64Chess.ChessPollingDefaults import com.vitorpamplona.amethyst.commons.nip64Chess.ChessViewModel -import com.vitorpamplona.amethyst.model.Account /** * Factory for the shared [ChessViewModel], wired with the Android adapters. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/dal/ChessFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/dal/ChessFeedFilter.kt index 8380fc7400..af6f8e2fee 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/dal/ChessFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/dal/ChessFeedFilter.kt @@ -22,10 +22,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chess.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip64Chess.game.ChessGameEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/datasource/ChessSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/datasource/ChessSubscription.kt index a9522ae2e9..c5a072a0fc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/datasource/ChessSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/datasource/ChessSubscription.kt @@ -28,7 +28,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.nip64Chess.ChessViewModel import com.vitorpamplona.amethyst.commons.relayClient.chess.ChessQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Subscribe to chess events when the Chess screen is active. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/CommunitiesScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/CommunitiesScreen.kt index 776dffceff..56636c4501 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/CommunitiesScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/CommunitiesScreen.kt @@ -41,17 +41,17 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.FeedEmpty import com.vitorpamplona.amethyst.commons.ui.feeds.FeedError import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.list.datasource.CommunitiesListFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.ChannelCardCompose import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/CommunitiesTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/CommunitiesTopBar.kt index 7ad14f7c77..3dfeaa1535 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/CommunitiesTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/CommunitiesTopBar.kt @@ -24,18 +24,18 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/datasource/CommunitiesListFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/datasource/CommunitiesListFilterAssemblerSubscription.kt index 3fe66d5843..ecd20288d1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/datasource/CommunitiesListFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/datasource/CommunitiesListFilterAssemblerSubscription.kt @@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.communities.list.CommunitiesListFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun CommunitiesListFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/CommunityRulesEditor.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/CommunityRulesEditor.kt index 1039ed6592..cb020b11d7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/CommunityRulesEditor.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/CommunityRulesEditor.kt @@ -82,12 +82,12 @@ import com.vitorpamplona.amethyst.commons.resources.new_community_rules_wot_sect import com.vitorpamplona.amethyst.commons.resources.remove import com.vitorpamplona.amethyst.commons.ui.components.Nip05OrPubkeyLine import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightPage -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip19Bech32.Nip19Parser import com.vitorpamplona.quartz.nip19Bech32.entities.NPub diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityModel.kt index 981d691248..8fe84605f6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityModel.kt @@ -30,6 +30,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.mediaServers.DEFAULT_MEDIA_SERVERS import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName @@ -39,7 +40,6 @@ import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_ import com.vitorpamplona.amethyst.commons.resources.read_only_user import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityScreen.kt index eac78f2eb4..105360e64f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityScreen.kt @@ -66,7 +66,6 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import coil3.compose.AsyncImage -import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.User @@ -99,15 +98,15 @@ import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ActionTopBar import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.CreatingTopBar +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightPage +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelect import com.vitorpamplona.amethyst.ui.actions.uploads.ShowImageUploadGallery -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoClickableRow import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder @@ -578,7 +577,7 @@ private fun RelaysSection( loadRobohash = LocalDisplaySettings.current.loadRobohash, onClick = {}, onDelete = { model.removeRelay(entry) }, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, accountViewModel = accountViewModel, nav = nav, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/ChannelCardCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/ChannelCardCompose.kt index f4e4212c37..0c396b5399 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/ChannelCardCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/ChannelCardCompose.kt @@ -26,19 +26,19 @@ import androidx.compose.runtime.MutableState import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.CheckHiddenFeedWatchBlockAndReport +import com.vitorpamplona.amethyst.commons.ui.note.ClickableNote +import com.vitorpamplona.amethyst.commons.ui.note.LongPressToQuickAction +import com.vitorpamplona.amethyst.commons.ui.note.WatchNoteEvent +import com.vitorpamplona.amethyst.commons.ui.note.calculateBackgroundColor +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.discover.nip51FollowSets.RenderFollowSetThumb import com.vitorpamplona.amethyst.commons.ui.theme.HalfPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.note.CheckHiddenFeedWatchBlockAndReport -import com.vitorpamplona.amethyst.ui.note.ClickableNote -import com.vitorpamplona.amethyst.ui.note.LongPressToQuickAction -import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent -import com.vitorpamplona.amethyst.ui.note.calculateBackgroundColor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip23LongForm.RenderLongFormThumb import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip28Chats.RenderPublicChatChannelThumb -import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip51FollowSets.RenderFollowSetThumb import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip53LiveActivities.RenderLiveActivityThumb import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip72Communities.RenderCommunitiesThumb import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip90DVMs.RenderContentDVMThumb diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/DiscoverScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/DiscoverScreen.kt index f85d225362..c32b75daab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/DiscoverScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/DiscoverScreen.kt @@ -67,23 +67,23 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.FeedEmpty import com.vitorpamplona.amethyst.commons.ui.feeds.FeedError import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.commons.ui.feeds.PagerStateKeys +import com.vitorpamplona.amethyst.commons.ui.feeds.PrefetchLoadedFeedMedia import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableGridFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverPagerState +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.TabRowHeight -import com.vitorpamplona.amethyst.ui.feeds.PrefetchLoadedFeedMedia -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableGridFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.datasource.DiscoveryFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.TabItem import com.vitorpamplona.quartz.nip23LongContent.LongFormContentEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/DiscoveryTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/DiscoveryTopBar.kt index 3e99933f2a..9035ab5fae 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/DiscoveryTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/DiscoveryTopBar.kt @@ -24,17 +24,17 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun DiscoveryTopBar( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/datasource/DiscoveryFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/datasource/DiscoveryFilterAssemblerSubscription.kt index be668aaa61..37d199ccb7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/datasource/DiscoveryFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/datasource/DiscoveryFilterAssemblerSubscription.kt @@ -26,7 +26,7 @@ import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.commons.relayClient.discover.DiscoveryFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.discover.DiscoveryQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun DiscoveryFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormCard.kt index e780927f4a..5f8625bc94 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormCard.kt @@ -23,10 +23,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip23LongForm import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.note.types.LongFormHeader -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.note.types.LongFormHeader +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip23LongContent.LongFormContentEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostScreen.kt index bc4b838b8e..9759574d1a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostScreen.kt @@ -102,6 +102,7 @@ import com.vitorpamplona.amethyst.commons.resources.url_slug_placeholder import com.vitorpamplona.amethyst.commons.resources.your_article_title import com.vitorpamplona.amethyst.commons.resources.zapraiser import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDialog +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.PostingTopBar import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.ContentSensitivityExplainer @@ -111,6 +112,7 @@ import com.vitorpamplona.amethyst.commons.ui.note.creators.invoice.AddLnInvoiceB import com.vitorpamplona.amethyst.commons.ui.note.creators.location.AddGeoHashButton import com.vitorpamplona.amethyst.commons.ui.note.creators.secretEmoji.AddSecretEmojiButton import com.vitorpamplona.amethyst.commons.ui.note.creators.secretEmoji.SecretEmojiRequest +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList import com.vitorpamplona.amethyst.commons.ui.note.creators.zapraiser.AddZapraiserButton import com.vitorpamplona.amethyst.commons.ui.note.creators.zapraiser.ZapRaiserRequest import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.ForwardZapToButton @@ -121,6 +123,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightPage import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelectSingle import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles @@ -128,7 +131,6 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.TakePictureButton import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideoButton -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField import com.vitorpamplona.amethyst.ui.components.markdown.RenderContentAsMarkdown import com.vitorpamplona.amethyst.ui.navigation.navs.Nav @@ -137,9 +139,7 @@ import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePick import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest import com.vitorpamplona.amethyst.ui.note.creators.location.GeoHashPostSection import com.vitorpamplona.amethyst.ui.note.creators.uploads.ImageVideoDescription -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.ForwardZapTo -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.ObserveInboxRelayListAndDisplayIfNotFound import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsRow import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostViewModel.kt index de2ed7b234..470e776a6e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostViewModel.kt @@ -33,6 +33,7 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User @@ -43,6 +44,7 @@ import com.vitorpamplona.amethyst.commons.model.composer.IZapRaiser import com.vitorpamplona.amethyst.commons.model.composer.NewMessageTagger import com.vitorpamplona.amethyst.commons.model.composer.SplitBuilder import com.vitorpamplona.amethyst.commons.model.composer.toZapSplitSetup +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiPackState.EmojiMedia @@ -57,13 +59,14 @@ import com.vitorpamplona.amethyst.commons.service.upload.MediaUploadTracker import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.note.creators.messagefield.IMessageField +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.IZapField import com.vitorpamplona.amethyst.commons.ui.text.appendSignature import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.ui.text.onUiThread import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.location.LocationState import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.MediaCompressor @@ -74,8 +77,6 @@ import com.vitorpamplona.amethyst.service.uploads.nip96.Nip96Uploader import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMediaProcessing import com.vitorpamplona.amethyst.ui.note.creators.location.ILocationGrabber -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.IMetaAttachments import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.UserSuggestionAnchor import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent @@ -215,7 +216,7 @@ class LongFormPostViewModel : // GeoHash var wantsToAddGeoHash by mutableStateOf(false) override var pickedGeoHash by mutableStateOf(null) - var location: StateFlow? = null + var location: StateFlow? = null var wantsExclusiveGeoPost by mutableStateOf(false) // ZapRaiser @@ -431,7 +432,7 @@ class LongFormPostViewModel : val zapReceiver = if (wantsForwardZapTo) forwardZapTo.value.toZapSplitSetup() else null - val geoHash = if (wantsToAddGeoHash) (pickedGeoHash ?: (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString()) else null + val geoHash = if (wantsToAddGeoHash) (pickedGeoHash ?: (location?.value as? LocationResult.Success)?.geoHash?.toString()) else null val localZapRaiserAmount = if (wantsZapRaiser) zapRaiserAmount.value else null val emojis = account.emoji.findEmojiTags(tagger.message) @@ -502,7 +503,7 @@ class LongFormPostViewModel : alt = null, sensitiveContent = null, serverBaseUrl = account.settings.defaultFileServer.baseUrl, - okHttpClient = Amethyst.instance.roleBasedHttpClientBuilder::okHttpClientForUploads, + okHttpClient = accountViewModel.httpClientBuilder::okHttpClientForUploads, onProgress = {}, httpAuth = account::createHTTPAuthorization, context = context, @@ -515,7 +516,7 @@ class LongFormPostViewModel : alt = null, sensitiveContent = null, serverBaseUrl = account.settings.defaultFileServer.baseUrl, - okHttpClient = Amethyst.instance.roleBasedHttpClientBuilder::okHttpClientForUploads, + okHttpClient = accountViewModel.httpClientBuilder::okHttpClientForUploads, httpAuth = account::createBlossomUploadAuth, context = context, ) @@ -729,7 +730,7 @@ class LongFormPostViewModel : viewModelScope.launch(Dispatchers.IO) { iMetaAttachments.downloadAndPrepare(item.link) { - Amethyst.instance.roleBasedHttpClientBuilder.okHttpClientForImage(item.link) + accountViewModel.httpClientBuilder.okHttpClientForImage(item.link) } } @@ -754,7 +755,7 @@ class LongFormPostViewModel : multiOrchestrator = MultiOrchestrator(uris) } - override fun locationFlow(): StateFlow { + override fun locationFlow(): StateFlow { if (location == null) { location = locationManager().geohashStateFlow } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip28Chats/RenderPublicChatChannelThumb.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip28Chats/RenderPublicChatChannelThumb.kt index 481db912e5..c4314574a4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip28Chats/RenderPublicChatChannelThumb.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip28Chats/RenderPublicChatChannelThumb.kt @@ -51,10 +51,14 @@ 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.relayClient.reqCommand.channel.observeChannel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.chat_about_topic import com.vitorpamplona.amethyst.commons.ui.layouts.LeftPictureLayout import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.DisplayAuthorBanner +import com.vitorpamplona.amethyst.commons.ui.note.Gallery +import com.vitorpamplona.amethyst.commons.ui.note.LoadPublicChatChannel import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.HalfTopPadding import com.vitorpamplona.amethyst.commons.ui.theme.QuoteBorder @@ -62,13 +66,9 @@ import com.vitorpamplona.amethyst.commons.ui.theme.RowColSpacing import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.util.equalImmutableLists -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.ui.note.DisplayAuthorBanner -import com.vitorpamplona.amethyst.ui.note.Gallery +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.LikeReaction -import com.vitorpamplona.amethyst.ui.note.LoadPublicChatChannel import com.vitorpamplona.amethyst.ui.note.ZapReaction -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/LiveActivityCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/LiveActivityCard.kt index d66acadf03..24ac29e322 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/LiveActivityCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/LiveActivityCard.kt @@ -56,18 +56,18 @@ import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.EndedFlag import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.LiveFlag import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.OfflineFlag import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.ScheduledFlag +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteAndMap +import com.vitorpamplona.amethyst.commons.ui.components.CheckIfVideoIsOnline import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.DisplayAuthorBanner +import com.vitorpamplona.amethyst.commons.ui.note.Gallery +import com.vitorpamplona.amethyst.commons.ui.note.LoadLiveActivityChannel +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header.LiveActivitiesChannelHeader import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.commons.util.equalImmutableLists -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteAndMap -import com.vitorpamplona.amethyst.ui.note.DisplayAuthorBanner -import com.vitorpamplona.amethyst.ui.note.Gallery -import com.vitorpamplona.amethyst.ui.note.LoadLiveActivityChannel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header.LiveActivitiesChannelHeader -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CheckIfVideoIsOnline +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip53LiveActivities.LiveStreamLike diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/CommunityCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/CommunityCard.kt index f99364c6a9..bfc457075a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/CommunityCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/CommunityCard.kt @@ -53,10 +53,13 @@ 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.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.community_about_topic import com.vitorpamplona.amethyst.commons.ui.layouts.LeftPictureLayout import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.DisplayAuthorBanner +import com.vitorpamplona.amethyst.commons.ui.note.Gallery import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.HalfTopPadding import com.vitorpamplona.amethyst.commons.ui.theme.QuoteBorder @@ -64,12 +67,9 @@ import com.vitorpamplona.amethyst.commons.ui.theme.RowColSpacing import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.util.equalImmutableLists -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.note.DisplayAuthorBanner -import com.vitorpamplona.amethyst.ui.note.Gallery +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.LikeReaction import com.vitorpamplona.amethyst.ui.note.ZapReaction -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent import kotlinx.collections.immutable.ImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DVMCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DVMCard.kt index 89efcd5e61..14ff0c3b40 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DVMCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DVMCard.kt @@ -41,8 +41,11 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.layouts.LeftPictureLayout import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.elements.BannerImage import com.vitorpamplona.amethyst.commons.ui.theme.HalfTopPadding import com.vitorpamplona.amethyst.commons.ui.theme.RowColSpacing5dp import com.vitorpamplona.amethyst.commons.ui.theme.SimpleImageBorder @@ -50,12 +53,9 @@ import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.bitcoinColor import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.nip05 -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.UserFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.LikeReaction import com.vitorpamplona.amethyst.ui.note.ZapReaction -import com.vitorpamplona.amethyst.ui.note.elements.BannerImage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.FavoriteAlgoFeedToggle import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.observeAppDefinition diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/ClassifiedsThumb.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/ClassifiedsThumb.kt index 8b71b86826..cd518375cc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/ClassifiedsThumb.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/ClassifiedsThumb.kt @@ -45,13 +45,13 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteAndMap import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.DisplayAuthorBanner import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.util.showAmountInteger -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteAndMap -import com.vitorpamplona.amethyst.ui.note.DisplayAuthorBanner -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent import com.vitorpamplona.quartz.nip99Classifieds.tags.PriceTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductScreen.kt index 8814d25bbb..0d283ddfb9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductScreen.kt @@ -56,6 +56,7 @@ import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDial import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.PostingTopBar +import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.ContentSensitivityExplainer import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.MarkAsSensitiveButton import com.vitorpamplona.amethyst.commons.ui.note.creators.expiration.ExpirationDateButton @@ -63,6 +64,7 @@ import com.vitorpamplona.amethyst.commons.ui.note.creators.invoice.AddLnInvoiceB import com.vitorpamplona.amethyst.commons.ui.note.creators.location.AddGeoHashButton import com.vitorpamplona.amethyst.commons.ui.note.creators.secretEmoji.AddSecretEmojiButton import com.vitorpamplona.amethyst.commons.ui.note.creators.secretEmoji.SecretEmojiRequest +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList import com.vitorpamplona.amethyst.commons.ui.note.creators.zapraiser.AddZapraiserButton import com.vitorpamplona.amethyst.commons.ui.note.creators.zapraiser.ZapRaiserRequest import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.ForwardZapToButton @@ -72,13 +74,13 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightPage +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.TakePictureButton import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideoButton import com.vitorpamplona.amethyst.ui.navigation.navs.Nav -import com.vitorpamplona.amethyst.ui.note.BaseUserPicture import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest @@ -86,9 +88,7 @@ import com.vitorpamplona.amethyst.ui.note.creators.location.GeoHashPostSection import com.vitorpamplona.amethyst.ui.note.creators.messagefield.MessageField import com.vitorpamplona.amethyst.ui.note.creators.previews.DisplayPreviews import com.vitorpamplona.amethyst.ui.note.creators.uploads.ImageVideoDescription -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.ForwardZapTo -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt index 3d9a0f574d..c73f4fbe0a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt @@ -32,6 +32,7 @@ import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User @@ -43,6 +44,7 @@ import com.vitorpamplona.amethyst.commons.model.composer.NewMessageTagger import com.vitorpamplona.amethyst.commons.model.composer.PreviewState import com.vitorpamplona.amethyst.commons.model.composer.SplitBuilder import com.vitorpamplona.amethyst.commons.model.composer.toZapSplitSetup +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiPackState import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiSuggestionState @@ -52,12 +54,13 @@ import com.vitorpamplona.amethyst.commons.service.upload.MediaUploadTracker import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.note.creators.messagefield.IMessageField +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.IZapField import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.ui.text.onUiThread import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.location.LocationState import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator @@ -65,8 +68,6 @@ import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMediaProcessing import com.vitorpamplona.amethyst.ui.note.creators.location.ILocationGrabber -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.IMetaAttachments import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.UserSuggestionAnchor import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent @@ -188,7 +189,7 @@ open class NewProductViewModel : // GeoHash var wantsToAddGeoHash by mutableStateOf(false) override var pickedGeoHash by mutableStateOf(null) - var location: StateFlow? = null + var location: StateFlow? = null // ZapRaiser var canAddZapRaiser by mutableStateOf(false) @@ -357,7 +358,7 @@ open class NewProductViewModel : val urls = findURLs(tagger.message) val usedAttachments = iMetaDescription.filterIsIn(urls.toSet()) + productImages.map { it.toIMeta() } - val geoHash = if (wantsToAddGeoHash) (pickedGeoHash ?: (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString()) else null + val geoHash = if (wantsToAddGeoHash) (pickedGeoHash ?: (location?.value as? LocationResult.Success)?.geoHash?.toString()) else null val zapReceiver = if (wantsForwardZapTo) forwardZapTo.value.toZapSplitSetup() else null val localZapRaiserAmount = if (wantsZapraiser) zapRaiserAmount.value else null @@ -577,7 +578,7 @@ open class NewProductViewModel : viewModelScope.launch(Dispatchers.IO) { iMetaDescription.downloadAndPrepare(item.link) { - Amethyst.instance.roleBasedHttpClientBuilder.okHttpClientForImage(item.link) + accountViewModel.httpClientBuilder.okHttpClientForImage(item.link) } } @@ -607,7 +608,7 @@ open class NewProductViewModel : multiOrchestrator = MultiOrchestrator(uris) } - override fun locationFlow(): StateFlow { + override fun locationFlow(): StateFlow { if (location == null) { location = locationManager().geohashStateFlow } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/SellProduct.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/SellProduct.kt index 065426107c..dae7daa668 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/SellProduct.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/SellProduct.kt @@ -91,9 +91,9 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.SquaredQuoteBorderModifier import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.quartz.nip99Classifieds.tags.ConditionTag import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmContentDiscoveryScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmContentDiscoveryScreen.kt index a0f559056c..c33d41a4f6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmContentDiscoveryScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmContentDiscoveryScreen.kt @@ -52,6 +52,8 @@ 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.model.payments.PaymentSource +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteAndMap +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.clink_debit_no_response import com.vitorpamplona.amethyst.commons.resources.dvm_looking_for_app @@ -63,29 +65,29 @@ import com.vitorpamplona.amethyst.commons.resources.dvm_waiting_to_confirm_payme import com.vitorpamplona.amethyst.commons.resources.no_wallet_found import com.vitorpamplona.amethyst.commons.resources.nwc_payment_request import com.vitorpamplona.amethyst.commons.resources.wallet_connect_pay_invoice_error_error +import com.vitorpamplona.amethyst.commons.service.nwc.nwcFailureDetail +import com.vitorpamplona.amethyst.commons.service.nwc.nwcTimeoutMessage +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.feeds.FeedEmpty import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.WatchNoteEvent +import com.vitorpamplona.amethyst.commons.ui.note.elements.BannerImage +import com.vitorpamplona.amethyst.commons.ui.screen.RenderFeedState +import com.vitorpamplona.amethyst.commons.ui.screen.SaveableFeedState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.dvms.DvmOfflineBanner +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.dvms.rememberDvmHeartbeatFresh import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.SimpleImage75Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteAndMap -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.ReusableZapButton import com.vitorpamplona.amethyst.ui.components.ZapButtonConfig -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent -import com.vitorpamplona.amethyst.ui.note.elements.BannerImage import com.vitorpamplona.amethyst.ui.note.payViaIntent -import com.vitorpamplona.amethyst.ui.nwc.nwcFailureDetail -import com.vitorpamplona.amethyst.ui.nwc.nwcTimeoutMessage -import com.vitorpamplona.amethyst.ui.screen.RenderFeedState -import com.vitorpamplona.amethyst.ui.screen.SaveableFeedState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip90DVMs.DVMCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.dal.DvmContentDiscoveryFeedViewModel import com.vitorpamplona.quartz.lightning.LnInvoiceUtil diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmTopBar.kt index fb4fff3272..3dc424bd2c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmTopBar.kt @@ -29,16 +29,16 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.style.TextOverflow import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteAndMap +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.MyExtensibleTopAppBar import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon +import com.vitorpamplona.amethyst.commons.ui.note.elements.BannerImage import com.vitorpamplona.amethyst.commons.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.SimpleImage35Modifier -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteAndMap -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.note.elements.BannerImage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/FavoriteAlgoFeedToggle.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/FavoriteAlgoFeedToggle.kt index 2eb0e01e0b..226f2b0240 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/FavoriteAlgoFeedToggle.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/FavoriteAlgoFeedToggle.kt @@ -28,14 +28,14 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.AddressableNote +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteAndMap import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.add_dvm_to_favorites import com.vitorpamplona.amethyst.commons.resources.remove_dvm_from_favorites import com.vitorpamplona.amethyst.commons.ui.components.ClickableBox import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteAndMap -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.AddressBookmark import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent import com.vitorpamplona.quartz.nip90Dvms.contentDiscoveryRequest.DvmContentDiscoveryRequestEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/dal/DvmContentDiscoveryFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/dal/DvmContentDiscoveryFeedViewModel.kt index 6e16027d13..d27acc98da 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/dal/DvmContentDiscoveryFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/dal/DvmContentDiscoveryFeedViewModel.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel @Stable class DvmContentDiscoveryFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/dal/DvmContentDiscoveryResponseFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/dal/DvmContentDiscoveryResponseFilter.kt index 5ba64e8d5f..c438c3ea8c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/dal/DvmContentDiscoveryResponseFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/dal/DvmContentDiscoveryResponseFilter.kt @@ -22,10 +22,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.observables.CreatedAtComparator -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.tags.events.isTaggedEvent import com.vitorpamplona.quartz.nip90Dvms.contentDiscoveryResponse.DvmContentDiscoveryResponseEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/favorites/FavoriteAlgoFeedsListScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/favorites/FavoriteAlgoFeedsListScreen.kt index 14723050ed..6a6b8a143e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/favorites/FavoriteAlgoFeedsListScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/favorites/FavoriteAlgoFeedsListScreen.kt @@ -78,21 +78,21 @@ import com.vitorpamplona.amethyst.commons.resources.favorite_dvms_empty_step2 import com.vitorpamplona.amethyst.commons.resources.favorite_dvms_explainer import com.vitorpamplona.amethyst.commons.resources.favorite_dvms_title import com.vitorpamplona.amethyst.commons.resources.remove_dvm_from_favorites +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.elements.BannerImage +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.dvms.rememberDvmHeartbeatFresh import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.SimpleImage35Modifier import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.note.elements.BannerImage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.observeAppDefinition -import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.rememberDvmHeartbeatFresh import kotlinx.coroutines.launch private const val STAR_INLINE_ID = "star" diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/embed/EmbeddedTabPreloader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/embed/EmbeddedTabPreloader.kt index 11b4372751..8138d93e01 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/embed/EmbeddedTabPreloader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/embed/EmbeddedTabPreloader.kt @@ -34,7 +34,7 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.navigation.favoriteIds -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Warms every bottom-bar favorite at startup so the first tap is instant — the surfaces are built, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/embed/FavoriteAppManifestPreloader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/embed/FavoriteAppManifestPreloader.kt index 9edabf3bdb..b7ff45a8e0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/embed/FavoriteAppManifestPreloader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/embed/FavoriteAppManifestPreloader.kt @@ -29,8 +29,8 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.favorites.FavoriteApp import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/display/AddEmojiDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/display/AddEmojiDialog.kt index 5ea0608e1f..51c417b32e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/display/AddEmojiDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/display/AddEmojiDialog.kt @@ -58,8 +58,8 @@ import com.vitorpamplona.amethyst.commons.resources.emoji_shortcode_label import com.vitorpamplona.amethyst.commons.resources.emoji_url_label import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectSingleFromGallery -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip30CustomEmoji.EmojiUrlTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/display/EmojiPackScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/display/EmojiPackScreen.kt index 02a30a5ea5..9fb240fd82 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/display/EmojiPackScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/display/EmojiPackScreen.kt @@ -74,7 +74,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size35Modifier -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip30CustomEmoji.EmojiUrlTag @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/display/EmojiPackViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/display/EmojiPackViewModel.kt index 03341b294b..25c362c7bf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/display/EmojiPackViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/display/EmojiPackViewModel.kt @@ -29,6 +29,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.avif_metadata_strip_failed @@ -38,7 +39,6 @@ import com.vitorpamplona.amethyst.commons.resources.metadata_strip_failed_title import com.vitorpamplona.amethyst.commons.resources.metadata_strip_failed_upload_cancelled import com.vitorpamplona.amethyst.commons.resources.server_did_not_provide_a_url_after_uploading import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.uploads.AvifMetadataNotVerifiableException import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.MediaCompressor diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/list/metadata/EmojiPackMetadataScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/list/metadata/EmojiPackMetadataScreen.kt index ca70ddd248..6c6bdcfa5b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/list/metadata/EmojiPackMetadataScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/list/metadata/EmojiPackMetadataScreen.kt @@ -77,8 +77,8 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.CreatingTopBar import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SavingTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelectSingle -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @Composable fun EmojiPackMetadataScreen( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/list/metadata/EmojiPackMetadataViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/list/metadata/EmojiPackMetadataViewModel.kt index 31a9e14dc2..10a94b3a97 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/list/metadata/EmojiPackMetadataViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/list/metadata/EmojiPackMetadataViewModel.kt @@ -30,6 +30,7 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.OwnedEmojiPack import com.vitorpamplona.amethyst.commons.resources.Res @@ -42,7 +43,7 @@ import com.vitorpamplona.amethyst.commons.resources.metadata_strip_failed_upload import com.vitorpamplona.amethyst.commons.resources.read_only_user import com.vitorpamplona.amethyst.commons.resources.server_did_not_provide_a_url_after_uploading import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.AvifMetadataNotVerifiableException import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.MediaCompressor @@ -50,7 +51,6 @@ import com.vitorpamplona.amethyst.service.uploads.MetadataStripper import com.vitorpamplona.amethyst.service.uploads.blossom.BlossomUploader import com.vitorpamplona.amethyst.service.uploads.nip96.Nip96Uploader import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/favorites/FavoriteAppsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/favorites/FavoriteAppsScreen.kt index f3e9e9f896..a4c51199df 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/favorites/FavoriteAppsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/favorites/FavoriteAppsScreen.kt @@ -72,12 +72,12 @@ import com.vitorpamplona.amethyst.commons.resources.favorite_app_still_loading import com.vitorpamplona.amethyst.commons.resources.favorite_apps import com.vitorpamplona.amethyst.commons.resources.favorite_apps_empty import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.favorites.FavoriteAppLauncher import com.vitorpamplona.amethyst.favorites.PreloadFavoriteNostrApps import com.vitorpamplona.amethyst.favorites.rememberNappletIconModel -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel /** * The Favorite Apps grid: the user's pinned web clients / nsites / napplets as big launch buttons. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/favorites/NostrAppScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/favorites/NostrAppScreen.kt index 953adc5305..5dccbbf0dc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/favorites/NostrAppScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/favorites/NostrAppScreen.kt @@ -75,17 +75,17 @@ import com.vitorpamplona.amethyst.commons.resources.favorite_notice_published import com.vitorpamplona.amethyst.commons.resources.favorite_notice_uploaded import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.favorites.FavoriteAppLauncher import com.vitorpamplona.amethyst.napplet.NappletNetworkRegistry import com.vitorpamplona.amethyst.napplethost.HostProfile import com.vitorpamplona.amethyst.napplethost.NappletEmbedContract import com.vitorpamplona.amethyst.napplethost.NappletHostContract -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.EmbeddedTabChrome import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.EmbeddedTabFactory import com.vitorpamplona.amethyst.ui.screen.loggedIn.embed.EmbeddedTabHost -import com.vitorpamplona.amethyst.ui.stringRes import kotlinx.coroutines.launch import org.jetbrains.compose.resources.StringResource diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/FollowPackFeedScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/FollowPackFeedScreen.kt index cad3be3193..bc55ce3516 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/FollowPackFeedScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/FollowPackFeedScreen.kt @@ -54,6 +54,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back import com.vitorpamplona.amethyst.commons.resources.conversations @@ -62,24 +63,23 @@ import com.vitorpamplona.amethyst.commons.resources.new_threads import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverPagerState +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TitleIconModifier import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarSize +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.HalfHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.Size18Modifier import com.vitorpamplona.amethyst.commons.ui.theme.SpacedBy2dp import com.vitorpamplona.amethyst.commons.ui.theme.TabRowHeight -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.LikeReaction -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.ui.note.ReplyReaction import com.vitorpamplona.amethyst.ui.note.ZapReaction -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView import com.vitorpamplona.amethyst.ui.screen.UserFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.dal.FollowPackFeedConversationsFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.dal.FollowPackFeedNewThreadFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.dal.FollowPackMembersUserFeedViewModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackFeedConversationsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackFeedConversationsFeedFilter.kt index c56e60de18..b5090fbdfa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackFeedConversationsFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackFeedConversationsFeedFilter.kt @@ -22,6 +22,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -29,8 +31,6 @@ import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows.AllUs 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.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackFeedConversationsFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackFeedConversationsFeedViewModel.kt index c9ea145fb4..87dce9b1ad 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackFeedConversationsFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackFeedConversationsFeedViewModel.kt @@ -22,9 +22,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.dal import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel class FollowPackFeedConversationsFeedViewModel( val note: AddressableNote, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackFeedNewThreadFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackFeedNewThreadFeedFilter.kt index 5de1c944b7..a9b0b68d9b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackFeedNewThreadFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackFeedNewThreadFeedFilter.kt @@ -23,14 +23,14 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams import com.vitorpamplona.amethyst.commons.feeds.isRenderableRepost +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache 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.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.agora.FundraiserEvent import com.vitorpamplona.quartz.experimental.audio.header.AudioHeaderEvent import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackFeedNewThreadFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackFeedNewThreadFeedViewModel.kt index 42b0acef3a..9914d03646 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackFeedNewThreadFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackFeedNewThreadFeedViewModel.kt @@ -22,9 +22,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.dal import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel class FollowPackFeedNewThreadFeedViewModel( val note: AddressableNote, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackMembersFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackMembersFeedFilter.kt index 0e6b1ee160..72cd2143e8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackMembersFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackMembersFeedFilter.kt @@ -21,10 +21,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.dal import com.vitorpamplona.amethyst.commons.feeds.FeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache.checkGetOrCreateUser -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip51Lists.starterPack.StarterPackEvent class FollowPackMembersFeedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackMembersUserFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackMembersUserFeedViewModel.kt index 4e7ac69cf3..83b6356ff3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackMembersUserFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/dal/FollowPackMembersUserFeedViewModel.kt @@ -22,8 +22,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.dal import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.ui.screen.UserFeedViewModel class FollowPackMembersUserFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/datasource/FollowPackFeedFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/datasource/FollowPackFeedFilterAssemblerSubscription.kt index de0e3d671c..638fd3825b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/datasource/FollowPackFeedFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/datasource/FollowPackFeedFilterAssemblerSubscription.kt @@ -22,9 +22,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.datasourc import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.followPacks.feed.datasource.FollowPackFeedQueryState import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun FollowPackFeedFilterAssemblerSubscription( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/FollowPacksFeedLoaded.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/FollowPacksFeedLoaded.kt index 5937c2290a..13090f0708 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/FollowPacksFeedLoaded.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/FollowPacksFeedLoaded.kt @@ -36,7 +36,7 @@ import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.ChannelCardCompose import com.vitorpamplona.quartz.nip51Lists.starterPack.StarterPackEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/FollowPacksScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/FollowPacksScreen.kt index 711ecf9007..0043f6c6a7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/FollowPacksScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/FollowPacksScreen.kt @@ -27,14 +27,14 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.list.datasource.FollowPacksFilterAssemblerSubscription @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/FollowPacksTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/FollowPacksTopBar.kt index 644b0e02b0..d50031d6a7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/FollowPacksTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/FollowPacksTopBar.kt @@ -24,18 +24,18 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip51Lists.starterPack.StarterPackEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/datasource/FollowPacksFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/datasource/FollowPacksFilterAssemblerSubscription.kt index 04be70b8f8..882b723143 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/datasource/FollowPacksFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/datasource/FollowPacksFilterAssemblerSubscription.kt @@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.followPacks.FollowPacksFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun FollowPacksFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocacheFeedLoaded.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocacheFeedLoaded.kt index 8038175f52..2572ecc6b3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocacheFeedLoaded.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocacheFeedLoaded.kt @@ -50,6 +50,7 @@ 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.location.LocationResult import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.geocache_empty_finds @@ -66,13 +67,12 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.geocachePoint +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderGeocache +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderGeocacheFoundLog import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.service.location.LocationState -import com.vitorpamplona.amethyst.ui.note.types.RenderGeocache -import com.vitorpamplona.amethyst.ui.note.types.RenderGeocacheFoundLog -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nipCCGeocaching.curation.GeocacheCurationListEvent import com.vitorpamplona.quartz.nipCCGeocaching.foundLog.GeocacheFoundLogEvent import com.vitorpamplona.quartz.nipCCGeocaching.listing.GeocacheListingEvent @@ -135,7 +135,7 @@ private fun GeocacheFeedColumn( val here = if (kind == GeocacheListKind.NEARBY && useLocation) { val fix by accountViewModel.account.geolocationFlow().collectAsStateWithLifecycle(null) - (fix as? LocationState.LocationResult.Success)?.geoHash + (fix as? LocationResult.Success)?.geoHash } else { null } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocacheHuntRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocacheHuntRow.kt index 6bb8654ded..9b97ed7ba0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocacheHuntRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocacheHuntRow.kt @@ -43,12 +43,13 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.geocache_hunt_caches import com.vitorpamplona.amethyst.commons.resources.geocache_hunt_progress +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.rememberGeocachePalette import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.geocaches.rememberMyFoundCacheIds import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nipCCGeocaching.curation.GeocacheCurationListEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocachesScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocachesScreen.kt index fb41b9f2e1..da6f1f9b9b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocachesScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocachesScreen.kt @@ -48,17 +48,17 @@ import com.vitorpamplona.amethyst.commons.resources.geocache_tab_mine import com.vitorpamplona.amethyst.commons.resources.geocache_tab_nearby import com.vitorpamplona.amethyst.commons.ui.feeds.PagerStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverPagerState +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.geocaches.datasource.GeocachesFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.theme.TabRowHeight -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.datasource.GeocachesFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.map.GeocacheMapTab import kotlinx.coroutines.launch import org.jetbrains.compose.resources.stringResource diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocachesTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocachesTopBar.kt index a1b5f52224..afe0991bda 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocachesTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocachesTopBar.kt @@ -24,18 +24,18 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nipCCGeocaching.listing.GeocacheListingEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/create/NewGeocacheScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/create/NewGeocacheScreen.kt index 6d09488f1e..45f447610e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/create/NewGeocacheScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/create/NewGeocacheScreen.kt @@ -100,15 +100,15 @@ import com.vitorpamplona.amethyst.commons.resources.geocache_owner_qr_warning import com.vitorpamplona.amethyst.commons.resources.geocache_photo_remove import com.vitorpamplona.amethyst.commons.resources.route_edit_geocache import com.vitorpamplona.amethyst.commons.resources.route_new_geocache +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.geocacheEmoji import com.vitorpamplona.amethyst.commons.ui.note.geocacheLabelRes +import com.vitorpamplona.amethyst.commons.ui.platform.GeohashLocationPickerDialog import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.note.creators.location.GeohashLocationPickerDialog +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.creators.location.LocationPreviewMap -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.QrCodeDrawer import com.vitorpamplona.quartz.nip01Core.tags.geohash.toGeoHash import com.vitorpamplona.quartz.nipCCGeocaching.listing.GeocacheGeohash diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/create/NewGeocacheViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/create/NewGeocacheViewModel.kt index 578db796a3..e1dfe1e218 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/create/NewGeocacheViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/create/NewGeocacheViewModel.kt @@ -25,12 +25,12 @@ import android.net.Uri import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadingState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.toHexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocachesHereFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocachesHereFeedFilter.kt index 0713842aca..eb4c2505b5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocachesHereFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocachesHereFeedFilter.kt @@ -21,11 +21,12 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.geocaches.dal.GeocachesFeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.relayClient.geocaches.GeocacheListingKinds -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nipCCGeocaching.listing.GeocacheListingEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocachesHereFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocachesHereFeedViewModel.kt index 67de4d1083..c97d568fc3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocachesHereFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocachesHereFeedViewModel.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel /** * Drives the "N caches here" chip on a geohash screen. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheAddToHuntSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheAddToHuntSheet.kt index 7028c9f23f..8ab7b184f9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheAddToHuntSheet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheAddToHuntSheet.kt @@ -58,7 +58,7 @@ import com.vitorpamplona.amethyst.commons.resources.geocache_hunt_new import com.vitorpamplona.amethyst.commons.resources.geocache_hunt_none_yet import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nipCCGeocaching.curation.GeocacheCurationListEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheDetailParts.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheDetailParts.kt index 4bcf6e1d24..52e05596e9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheDetailParts.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheDetailParts.kt @@ -47,6 +47,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserName import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.geocache_archived import com.vitorpamplona.amethyst.commons.resources.geocache_found_it @@ -57,15 +58,14 @@ import com.vitorpamplona.amethyst.commons.resources.geocache_log_type_maintenanc import com.vitorpamplona.amethyst.commons.resources.geocache_log_type_note import com.vitorpamplona.amethyst.commons.resources.geocache_verified_find import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture import com.vitorpamplona.amethyst.commons.ui.note.GeocacheChip +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.note.rememberGeocachePalette import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip19Bech32.entities.NAddress import com.vitorpamplona.quartz.nip22Comments.CommentEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheDetailScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheDetailScreen.kt index ac35a14fe3..5cb6948c20 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheDetailScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheDetailScreen.kt @@ -72,6 +72,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back import com.vitorpamplona.amethyst.commons.resources.geocache_add_note @@ -88,6 +89,7 @@ import com.vitorpamplona.amethyst.commons.resources.geocache_needs_maintenance import com.vitorpamplona.amethyst.commons.resources.geocache_no_logs import com.vitorpamplona.amethyst.commons.resources.geocache_photos_section import com.vitorpamplona.amethyst.commons.resources.route_geocache_detail +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.GeocacheChips @@ -98,13 +100,11 @@ import com.vitorpamplona.amethyst.commons.ui.note.geocacheEmoji import com.vitorpamplona.amethyst.commons.ui.note.geocachePoint import com.vitorpamplona.amethyst.commons.ui.note.rememberGeocachePalette import com.vitorpamplona.amethyst.commons.ui.note.specSummary +import com.vitorpamplona.amethyst.commons.ui.note.types.distanceToCache +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.geocaches.datasource.GeocachesFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.creators.location.LocationPreviewMap -import com.vitorpamplona.amethyst.ui.note.types.distanceToCache -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.datasource.GeocachesFilterAssemblerSubscription import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nipCCGeocaching.listing.GeocacheListingEvent import com.vitorpamplona.quartz.nipCCGeocaching.listing.tags.TypeModifier diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheLogSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheLogSheet.kt index 6300ff7260..87f4ab5b18 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheLogSheet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheLogSheet.kt @@ -52,7 +52,7 @@ import com.vitorpamplona.amethyst.commons.resources.geocache_log_type_dnf import com.vitorpamplona.amethyst.commons.resources.geocache_log_type_maintenance import com.vitorpamplona.amethyst.commons.resources.geocache_log_type_note import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nipCCGeocaching.comment.GeocacheLogComment import com.vitorpamplona.quartz.nipCCGeocaching.listing.GeocacheListingEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheOwnerActions.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheOwnerActions.kt index a5edbd271b..11d10a89a2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheOwnerActions.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/detail/GeocacheOwnerActions.kt @@ -61,7 +61,7 @@ import com.vitorpamplona.amethyst.commons.resources.geocache_owner_qr_warning import com.vitorpamplona.amethyst.commons.resources.geocache_owner_show_qr import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.QrCodeDrawer import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nipCCGeocaching.firstToFind.FirstToFindResolver diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/log/LogGeocacheFindScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/log/LogGeocacheFindScreen.kt index 9322d6ce86..12f69392be 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/log/LogGeocacheFindScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/log/LogGeocacheFindScreen.kt @@ -91,9 +91,9 @@ import com.vitorpamplona.amethyst.commons.resources.route_log_geocache_find import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.rememberGeocachePalette +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.geocaches.datasource.GeocachesFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.datasource.GeocachesFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.SimpleQrCodeScanner import com.vitorpamplona.quartz.nip01Core.core.Address import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/log/LogGeocacheFindViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/log/LogGeocacheFindViewModel.kt index ca4e965933..56711ae236 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/log/LogGeocacheFindViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/log/LogGeocacheFindViewModel.kt @@ -25,12 +25,12 @@ import android.net.Uri import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadingState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/map/GeocacheMapTab.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/map/GeocacheMapTab.kt index 63ef5409a0..58c4c595e0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/map/GeocacheMapTab.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/map/GeocacheMapTab.kt @@ -65,10 +65,10 @@ import com.vitorpamplona.amethyst.commons.ui.note.GeocacheSpecLine import com.vitorpamplona.amethyst.commons.ui.note.geocacheEmoji import com.vitorpamplona.amethyst.commons.ui.note.geocachePoint import com.vitorpamplona.amethyst.commons.ui.note.rememberGeocachePalette +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.geocaches.rememberMyFoundCacheIds import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.creators.location.roadEventPinBitmap -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.rememberMyFoundCacheIds import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeoHash import com.vitorpamplona.quartz.nipCCGeocaching.listing.GeocacheGeohash import com.vitorpamplona.quartz.nipCCGeocaching.listing.GeocacheListingEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/GeoHashPostScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/GeoHashPostScreen.kt index 2b0eaf0089..4422ea12d1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/GeoHashPostScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/GeoHashPostScreen.kt @@ -27,11 +27,11 @@ import androidx.compose.ui.platform.LocalContext import androidx.core.net.toUri import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.navigation.navs.Nav import com.vitorpamplona.amethyst.ui.note.nip22Comments.CommentPostViewModel import com.vitorpamplona.amethyst.ui.note.nip22Comments.GenericCommentPostScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip73ExternalIds.location.GeohashId import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/GeoHashScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/GeoHashScreen.kt index fcbd83e541..1c42247bbd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/GeoHashScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/GeoHashScreen.kt @@ -32,6 +32,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.profile.ui.FollowButton import com.vitorpamplona.amethyst.commons.profile.ui.UnfollowButton +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserIsFollowingGeohash import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.geohash_chat_open import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_be_able_to_follow @@ -39,16 +40,15 @@ import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_ import com.vitorpamplona.amethyst.commons.resources.read_only_user import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SearchTopBarAction import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsFollowingGeohash -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.topbars.SearchTopBarAction +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.geohash.dal.GeoHashFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.geohash.datasource.GeoHashFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.icons.symbols.Icon as SymbolIcon diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/GeocachesHereChip.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/GeocachesHereChip.kt index a279748574..2bf49a987c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/GeocachesHereChip.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/GeocachesHereChip.kt @@ -49,9 +49,9 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.rememberGeocachePalette import com.vitorpamplona.amethyst.commons.ui.pluralStringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.geocaches.datasource.GeocachesFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.dal.GeocachesHereFeedViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.datasource.GeocachesFilterAssemblerSubscription /** * "N caches here", shown on a geohash feed when there are any. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/NewGeoNoteButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/NewGeoNoteButton.kt index b4729826d1..8fa7a5f5e8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/NewGeoNoteButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/NewGeoNoteButton.kt @@ -25,16 +25,16 @@ import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.ic_compose import com.vitorpamplona.amethyst.commons.resources.new_community_note import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun NewGeoPostButton( @@ -51,7 +51,7 @@ fun NewGeoPostButton( containerColor = MaterialTheme.colorScheme.primary, ) { Icon( - painter = painterRes(R.drawable.ic_compose, 1), + painter = painterRes(Res.drawable.ic_compose, 1), contentDescription = stringRes(id = Res.string.new_community_note), modifier = Size26Modifier, tint = MaterialTheme.colorScheme.onPrimary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/dal/GeoHashFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/dal/GeoHashFeedFilter.kt index 3322db8e7d..88a241678f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/dal/GeoHashFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/dal/GeoHashFeedFilter.kt @@ -21,10 +21,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.geohash.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.audio.header.AudioHeaderEvent import com.vitorpamplona.quartz.experimental.music.playlist.MusicPlaylistEvent import com.vitorpamplona.quartz.experimental.music.track.MusicTrackEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/dal/GeoHashFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/dal/GeoHashFeedViewModel.kt index 3e9421f981..4fd0ea3b81 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/dal/GeoHashFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/dal/GeoHashFeedViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.geohash.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @Stable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/datasource/GeoHashFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/datasource/GeoHashFilterAssemblerSubscription.kt index c95626e87d..18aa1cea55 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/datasource/GeoHashFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/datasource/GeoHashFilterAssemblerSubscription.kt @@ -26,7 +26,7 @@ import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.relayClient.geohash.GeohashQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @SuppressLint("StateFlowValueCalledInComposition") @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitItemListRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitItemListRow.kt index abf6b78359..e80e4ca7f8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitItemListRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitItemListRow.kt @@ -57,22 +57,22 @@ import com.vitorpamplona.amethyst.commons.resources.git_pr_revised import com.vitorpamplona.amethyst.commons.resources.git_untitled import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.CheckHiddenFeedWatchBlockAndReport +import com.vitorpamplona.amethyst.commons.ui.note.LongPressToQuickAction +import com.vitorpamplona.amethyst.commons.ui.note.NoteUsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.ObserveDisplayNip05Status import com.vitorpamplona.amethyst.commons.ui.note.StatusKind +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.WatchAuthor +import com.vitorpamplona.amethyst.commons.ui.note.WatchNoteEvent +import com.vitorpamplona.amethyst.commons.ui.note.clickableNoteModifier +import com.vitorpamplona.amethyst.commons.ui.note.elements.MoreOptionsButton import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgo import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.Size40dp -import com.vitorpamplona.amethyst.ui.note.CheckHiddenFeedWatchBlockAndReport -import com.vitorpamplona.amethyst.ui.note.LongPressToQuickAction -import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay -import com.vitorpamplona.amethyst.ui.note.ObserveDisplayNip05Status -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.WatchAuthor -import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent -import com.vitorpamplona.amethyst.ui.note.clickableNoteModifier -import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent import com.vitorpamplona.quartz.nip34Git.patch.GitPatchEvent @@ -81,7 +81,7 @@ import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestEvent /** * Compact feed renderer for the repository screen's Issues and Patches & PRs tabs. * - * Unlike the generic [com.vitorpamplona.amethyst.ui.note.NoteCompose], which is tuned + * Unlike the generic [com.vitorpamplona.amethyst.commons.ui.note.NoteCompose], which is tuned * for items appearing inside a regular feed, this shows a simple one-line-per-item list: * author picture, name, NIP-05, subject, time and the shared 3-dot options. It still * layers the same gating NoteCompose applies — event loading ([WatchNoteEvent]), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitNewIssue.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitNewIssue.kt index 4142c962af..6ccac20698 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitNewIssue.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitNewIssue.kt @@ -49,15 +49,15 @@ import com.vitorpamplona.amethyst.commons.resources.git_new_issue_labels import com.vitorpamplona.amethyst.commons.resources.git_new_issue_labels_hint import com.vitorpamplona.amethyst.commons.resources.git_new_issue_subject import com.vitorpamplona.amethyst.commons.resources.git_new_issue_title +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.layouts.LocalDisappearingScaffoldPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TitleIconModifier import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitRepoSettings.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitRepoSettings.kt index 001b3fad8f..335d849c74 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitRepoSettings.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitRepoSettings.kt @@ -46,7 +46,7 @@ import com.vitorpamplona.amethyst.commons.resources.git_repo_settings_title import com.vitorpamplona.amethyst.commons.resources.git_repo_settings_topics import com.vitorpamplona.amethyst.commons.resources.git_repo_settings_web_urls import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitRepositoryHomeUi.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitRepositoryHomeUi.kt index 6e86a1266f..fdb89b6ed8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitRepositoryHomeUi.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitRepositoryHomeUi.kt @@ -65,16 +65,16 @@ import com.vitorpamplona.amethyst.commons.resources.git_repo_stat_files import com.vitorpamplona.amethyst.commons.resources.git_repo_stat_tags import com.vitorpamplona.amethyst.commons.resources.git_repo_stat_updated import com.vitorpamplona.amethyst.commons.resources.git_untitled +import com.vitorpamplona.amethyst.commons.ui.components.ClickableUrlOrBlossom import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgo import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.ui.components.ClickableUrl -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.ReactionsRow -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip34Git.git.GitCommit import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent @@ -382,7 +382,7 @@ fun RepoExternalNotice(event: GitRepositoryEvent) { color = MaterialTheme.colorScheme.grayText, ) if (web != null) { - ClickableUrl(url = web, urlText = stringRes(Res.string.git_repo_open_in_browser)) + ClickableUrlOrBlossom(url = web, urlText = stringRes(Res.string.git_repo_open_in_browser)) } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitRepositoryScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitRepositoryScreen.kt index f6859edce3..e99465db38 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitRepositoryScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/GitRepositoryScreen.kt @@ -68,6 +68,7 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.nip34Git.GitBrowseState import com.vitorpamplona.amethyst.commons.nip34Git.GitRepoSnapshotCache import com.vitorpamplona.amethyst.commons.nip34Git.GitRepositoryBrowserViewModel +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.relayClient.gitRepo.RepositoryFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.git_new_issue_button @@ -81,19 +82,18 @@ import com.vitorpamplona.amethyst.commons.resources.git_repo_tab_issues import com.vitorpamplona.amethyst.commons.resources.git_repo_tab_patches import com.vitorpamplona.amethyst.commons.resources.loading_feed import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.layouts.LocalDisappearingScaffoldPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TitleIconModifier import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.elements.MoreOptionsButton +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.FeedViewModel -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.code.GitCodeTab import com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.code.GitReadmeSection import com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.dal.RepositoryIssuesFeedViewModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitCodeTab.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitCodeTab.kt index bd6f58933f..7926d67b00 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitCodeTab.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitCodeTab.kt @@ -78,7 +78,7 @@ import com.vitorpamplona.amethyst.commons.ui.layouts.LocalDisappearingScaffoldPa import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip34Git.git.GitRepoSnapshot import com.vitorpamplona.quartz.nip34Git.git.GitTreeEntry diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitFileViewer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitFileViewer.kt index 3c7741fc13..204d228e21 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitFileViewer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitFileViewer.kt @@ -70,12 +70,12 @@ import com.vitorpamplona.amethyst.commons.resources.git_repo_code_loading import com.vitorpamplona.amethyst.commons.resources.git_repo_copy_file import com.vitorpamplona.amethyst.commons.resources.git_repo_file_load_error import com.vitorpamplona.amethyst.commons.resources.git_repo_plain_text +import com.vitorpamplona.amethyst.commons.ui.components.RichTextViewer import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.components.RichTextViewer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip34Git.git.GitRepoSnapshot import com.vitorpamplona.quartz.nip34Git.git.GitTreeEntry import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitReadmeTab.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitReadmeTab.kt index ce4e4535e4..30ec3d6466 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitReadmeTab.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitReadmeTab.kt @@ -40,10 +40,10 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.git_repo_code_loading import com.vitorpamplona.amethyst.commons.resources.git_repo_file_load_error import com.vitorpamplona.amethyst.commons.resources.git_repo_readme_missing +import com.vitorpamplona.amethyst.commons.ui.components.RichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.components.RichTextViewer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip34Git.git.GitRepoSnapshot import com.vitorpamplona.quartz.nip34Git.git.GitTreeEntry import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/dal/RepositoryIssuesFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/dal/RepositoryIssuesFeedFilter.kt index b16534784f..b5519f2077 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/dal/RepositoryIssuesFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/dal/RepositoryIssuesFeedFilter.kt @@ -21,12 +21,12 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.GitStatusIndex import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent class RepositoryIssuesFeedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/dal/RepositoryIssuesFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/dal/RepositoryIssuesFeedViewModel.kt index 63f76dde28..c80883fc1f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/dal/RepositoryIssuesFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/dal/RepositoryIssuesFeedViewModel.kt @@ -23,10 +23,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.dal import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.GitStatusIndex -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/dal/RepositoryPatchesFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/dal/RepositoryPatchesFeedFilter.kt index abeb3f1e7b..98460903e6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/dal/RepositoryPatchesFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/dal/RepositoryPatchesFeedFilter.kt @@ -21,12 +21,12 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.GitStatusIndex import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip34Git.patch.GitPatchEvent import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/dal/RepositoryPatchesFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/dal/RepositoryPatchesFeedViewModel.kt index 1326bb415a..405a9604df 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/dal/RepositoryPatchesFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/dal/RepositoryPatchesFeedViewModel.kt @@ -23,10 +23,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.dal import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.GitStatusIndex -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/HashtagFeedLoaded.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/HashtagFeedLoaded.kt index 3504801065..ced407187e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/HashtagFeedLoaded.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/HashtagFeedLoaded.kt @@ -43,8 +43,11 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.hashtag_label_added_by +import com.vitorpamplona.amethyst.commons.ui.feeds.PrefetchLoadedFeedMedia import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding @@ -52,10 +55,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HalfStartPadding import com.vitorpamplona.amethyst.commons.ui.theme.Size16Modifier import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.feeds.PrefetchLoadedFeedMedia -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.hashtags.isTaggedHash /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/HashtagPostScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/HashtagPostScreen.kt index b1eb0e449b..d43a6bc4ca 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/HashtagPostScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/HashtagPostScreen.kt @@ -27,11 +27,11 @@ import androidx.compose.ui.platform.LocalContext import androidx.core.net.toUri import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.navigation.navs.Nav import com.vitorpamplona.amethyst.ui.note.nip22Comments.CommentPostViewModel import com.vitorpamplona.amethyst.ui.note.nip22Comments.GenericCommentPostScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip73ExternalIds.topics.HashtagId import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/HashtagScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/HashtagScreen.kt index b3add349ab..9832596f06 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/HashtagScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/HashtagScreen.kt @@ -45,6 +45,8 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.profile.ui.FollowButton import com.vitorpamplona.amethyst.commons.profile.ui.UnfollowButton +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserIsFollowingHashtag +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserIsMutingHashtag import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_be_able_to_follow import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_be_able_to_hide_word @@ -56,17 +58,15 @@ import com.vitorpamplona.amethyst.commons.resources.read_only_user import com.vitorpamplona.amethyst.commons.resources.unmute_hashtag import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SearchTopBarAction import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsFollowingHashtag -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsMutingHashtag -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.topbars.SearchTopBarAction -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.dal.HashtagFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.datasource.HashtagFilterAssemblerSubscription diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/NewHashtagNoteButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/NewHashtagNoteButton.kt index 157cde87bf..97f7b7320a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/NewHashtagNoteButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/NewHashtagNoteButton.kt @@ -25,16 +25,16 @@ import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.ic_compose import com.vitorpamplona.amethyst.commons.resources.new_community_note import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun NewHashtagPostButton( @@ -51,7 +51,7 @@ fun NewHashtagPostButton( containerColor = MaterialTheme.colorScheme.primary, ) { Icon( - painter = painterRes(R.drawable.ic_compose, 3), + painter = painterRes(Res.drawable.ic_compose, 3), contentDescription = stringRes(id = Res.string.new_community_note), modifier = Size26Modifier, tint = MaterialTheme.colorScheme.onPrimary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/dal/HashtagFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/dal/HashtagFeedFilter.kt index 0c7d4f80cc..3ecbdcc74f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/dal/HashtagFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/dal/HashtagFeedFilter.kt @@ -22,10 +22,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.isRenderableRepost +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.audio.header.AudioHeaderEvent import com.vitorpamplona.quartz.experimental.music.playlist.MusicPlaylistEvent import com.vitorpamplona.quartz.experimental.music.track.MusicTrackEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/dal/HashtagFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/dal/HashtagFeedViewModel.kt index 4164d69bf8..ddb32f8d8f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/dal/HashtagFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/dal/HashtagFeedViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @Stable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/datasource/HashtagFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/datasource/HashtagFilterAssemblerSubscription.kt index f4f81978ad..02660106a7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/datasource/HashtagFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/datasource/HashtagFilterAssemblerSubscription.kt @@ -22,9 +22,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.hashtag.datasource.HashtagQueryState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun HashtagFilterAssemblerSubscription( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/NewHighlightPostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/NewHighlightPostViewModel.kt index 14f8152590..4866a544e4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/NewHighlightPostViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/NewHighlightPostViewModel.kt @@ -27,6 +27,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -34,11 +35,10 @@ import com.vitorpamplona.amethyst.commons.model.composer.NewMessageTagger import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiPackState.EmojiMedia import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiSuggestionState import com.vitorpamplona.amethyst.commons.ui.note.creators.messagefield.IMessageField +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags import com.vitorpamplona.quartz.nip01Core.tags.people.pTags diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/NewHighlightScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/NewHighlightScreen.kt index a5d403d1d0..8358b47b80 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/NewHighlightScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/NewHighlightScreen.kt @@ -73,16 +73,16 @@ import com.vitorpamplona.amethyst.commons.resources.new_highlight_source_label import com.vitorpamplona.amethyst.commons.resources.new_highlight_title import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.PostingTopBar +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.types.ReplyRenderType import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightPage import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.Nav -import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList import com.vitorpamplona.amethyst.ui.note.creators.messagefield.MessageField -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.types.ReplyRenderType -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel /** A warm highlighter amber — the highlight metaphor reads as yellow regardless of theme. */ private val MarkerAccent = Color(0xFFF5C518) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/AddOutboxRelayCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/AddOutboxRelayCard.kt index 3a113fb5f2..acc89b1249 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/AddOutboxRelayCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/AddOutboxRelayCard.kt @@ -50,8 +50,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.AddInboxRelayCard @Preview diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/AddOutboxRelayListDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/AddOutboxRelayListDialog.kt index 6aeedc26f6..374ab4452a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/AddOutboxRelayListDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/AddOutboxRelayListDialog.kt @@ -45,8 +45,8 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SavingTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.SetDialogToEdgeToEdge -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.nip65.Nip65OutboxRelayList import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.nip65.Nip65RelayListViewModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/AlgoFeedStatusBanner.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/AlgoFeedStatusBanner.kt index ac92ec3436..3d2372b282 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/AlgoFeedStatusBanner.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/AlgoFeedStatusBanner.kt @@ -40,7 +40,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.model.algoFeeds.FavoriteAlgoFeedsSnapshot import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteAndMap import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.dvm_home_retry import com.vitorpamplona.amethyst.commons.resources.dvm_home_status_error @@ -49,17 +51,15 @@ import com.vitorpamplona.amethyst.commons.resources.dvm_home_status_processing import com.vitorpamplona.amethyst.commons.resources.dvm_home_status_requesting import com.vitorpamplona.amethyst.commons.resources.dvm_home_status_requesting_all import com.vitorpamplona.amethyst.commons.resources.dvm_offline_banner +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.dvms.rememberDvmHeartbeatFresh import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer -import com.vitorpamplona.amethyst.model.algoFeeds.FavoriteAlgoFeedsSnapshot -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteAndMap -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.DvmPaymentActions -import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.rememberDvmHeartbeatFresh import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeScreen.kt index 14b4ff9783..bc4a6b369b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeScreen.kt @@ -52,7 +52,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment @@ -67,6 +66,7 @@ import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel import com.vitorpamplona.amethyst.commons.model.geohashChat.GeohashChatChannel +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter @@ -76,19 +76,22 @@ import com.vitorpamplona.amethyst.commons.resources.feed_is_empty import com.vitorpamplona.amethyst.commons.resources.home_tab_everything import com.vitorpamplona.amethyst.commons.resources.new_threads import com.vitorpamplona.amethyst.commons.resources.refresh -import com.vitorpamplona.amethyst.commons.service.OnlineChecker -import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled import com.vitorpamplona.amethyst.commons.ui.feeds.FeedError import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.commons.ui.feeds.PagerStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverPagerState +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.zonedDrawerSwipeIfModal +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding @@ -97,13 +100,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.TabRowHeight import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow -import com.vitorpamplona.amethyst.service.location.LocationState -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.backups.BackupConflictCards import com.vitorpamplona.amethyst.ui.screen.loggedIn.geohash.NewGeoPostButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.NewHashtagPostButton @@ -341,13 +338,13 @@ fun HomeScreenFloatingButton( .collectAsStateWithLifecycle() when (val myLocation = location) { - is LocationState.LocationResult.Success -> { + is LocationResult.Success -> { NewGeoPostButton(myLocation.geoHash.toString(), accountViewModel, nav) } - is LocationState.LocationResult.LackPermission -> { } + is LocationResult.LackPermission -> { } - is LocationState.LocationResult.Loading -> { } + is LocationResult.Loading -> { } } } @@ -593,51 +590,6 @@ fun HomeFeedEmpty(onRefresh: () -> Unit) { } } -@Composable -fun CheckIfVideoIsOnline( - url: String, - accountViewModel: AccountViewModel, - whenOnline: @Composable (Boolean) -> Unit, -) { - val online by produceState( - initialValue = OnlineChecker.isOnlineCached(url), - key1 = url, - ) { - val isOnline = accountViewModel.checkVideoIsOnline(url) - if (value != isOnline) { - value = isOnline - } - } - - whenOnline(online) -} - -@Composable -fun CrossfadeCheckIfVideoIsOnline( - url: String, - accountViewModel: AccountViewModel, - whenOnline: @Composable () -> Unit, -) { - val online by produceState( - initialValue = OnlineChecker.isOnlineCached(url), - key1 = url, - ) { - val isOnline = accountViewModel.checkVideoIsOnline(url) - if (value != isOnline) { - value = isOnline - } - } - - CrossfadeIfEnabled( - targetState = online, - label = "CheckIfUrlIsOnline", - ) { - if (it) { - whenOnline() - } - } -} - @Composable fun WatchAccountForHomeScreen( liveFeedState: ChannelFeedContentState, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeTopBar.kt index a5581e4223..0f7d0f8077 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeTopBar.kt @@ -24,17 +24,17 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun HomeTopBar( @@ -56,8 +56,9 @@ fun HomeTopBar( listName = list, accountViewModel = accountViewModel, ) { listName -> - if (listName.route != null) { - nav.nav(listName.route) + val route = listName.route + if (route != null) { + nav.nav(route) } else { accountViewModel.account.settings.changeDefaultHomeFollowList(listName.code) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/NewChessGameButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/NewChessGameButton.kt index df0959e00b..22c74905d0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/NewChessGameButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/NewChessGameButton.kt @@ -39,7 +39,7 @@ import com.vitorpamplona.amethyst.commons.resources.new_chess_game import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chess.ChessViewModelFactory /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/NewNoteButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/NewNoteButton.kt index adf442c8de..0a3cf4bb8d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/NewNoteButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/NewNoteButton.kt @@ -31,17 +31,17 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.ic_compose import com.vitorpamplona.amethyst.commons.resources.new_post import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow -import com.vitorpamplona.amethyst.ui.painterRes @Preview @Composable @@ -64,7 +64,7 @@ fun NewNoteButton(nav: INav) { containerColor = MaterialTheme.colorScheme.primary, ) { Icon( - painter = painterRes(R.drawable.ic_compose, 4), + painter = painterRes(Res.drawable.ic_compose, 4), contentDescription = stringRes(Res.string.new_post), modifier = Size26Modifier, tint = MaterialTheme.colorScheme.onPrimary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostScreen.kt index 031fc4226f..5823df6c8b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostScreen.kt @@ -113,6 +113,8 @@ import com.vitorpamplona.amethyst.commons.resources.zapraiser import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDialog import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.PostingTopBar +import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.note.creators.aihelp.AiWritingHelpPanel import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.ContentSensitivityExplainer import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.MarkAsSensitiveButton @@ -122,9 +124,11 @@ import com.vitorpamplona.amethyst.commons.ui.note.creators.location.AddGeoHashBu import com.vitorpamplona.amethyst.commons.ui.note.creators.scheduling.ScheduleAtButton import com.vitorpamplona.amethyst.commons.ui.note.creators.secretEmoji.AddSecretEmojiButton import com.vitorpamplona.amethyst.commons.ui.note.creators.secretEmoji.SecretEmojiRequest +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList import com.vitorpamplona.amethyst.commons.ui.note.creators.zapraiser.AddZapraiserButton import com.vitorpamplona.amethyst.commons.ui.note.creators.zapraiser.ZapRaiserRequest import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.ForwardZapToButton +import com.vitorpamplona.amethyst.commons.ui.note.types.ReplyRenderType import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.text.onUiThread import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness @@ -138,6 +142,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightPa import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.mediaServers.FileServerSelectionRow import com.vitorpamplona.amethyst.ui.actions.uploads.MAX_VOICE_RECORD_SECONDS import com.vitorpamplona.amethyst.ui.actions.uploads.RecordVoiceButton @@ -152,8 +157,6 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.VoiceMessagePreview import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField import com.vitorpamplona.amethyst.ui.components.getActivity import com.vitorpamplona.amethyst.ui.navigation.navs.Nav -import com.vitorpamplona.amethyst.ui.note.BaseUserPicture -import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest @@ -168,11 +171,8 @@ import com.vitorpamplona.amethyst.ui.note.creators.previews.DisplayPreviews import com.vitorpamplona.amethyst.ui.note.creators.scheduling.ScheduleAtPicker import com.vitorpamplona.amethyst.ui.note.creators.scheduling.roundUpToNextQuarterHour import com.vitorpamplona.amethyst.ui.note.creators.uploads.ImageVideoDescription -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList import com.vitorpamplona.amethyst.ui.note.creators.zappolls.ZapPollField import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.ForwardZapTo -import com.vitorpamplona.amethyst.ui.note.types.ReplyRenderType -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsRow import com.vitorpamplona.quartz.nip01Core.core.HexKey import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt index fe72a2233d..3ddf7c7f8a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt @@ -35,6 +35,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.audio.VoicePreset +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.BooleanType import com.vitorpamplona.amethyst.commons.model.Note @@ -47,6 +48,7 @@ import com.vitorpamplona.amethyst.commons.model.composer.NewMessageTagger import com.vitorpamplona.amethyst.commons.model.composer.PreviewState import com.vitorpamplona.amethyst.commons.model.composer.SplitBuilder import com.vitorpamplona.amethyst.commons.model.composer.toZapSplitSetup +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiPackState.EmojiMedia import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiSuggestionState @@ -70,6 +72,7 @@ import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.note.creators.messagefield.IMessageField import com.vitorpamplona.amethyst.commons.ui.note.creators.notify.IAudience +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.IZapField import com.vitorpamplona.amethyst.commons.ui.text.appendSignature import com.vitorpamplona.amethyst.commons.ui.text.currentWord @@ -77,7 +80,7 @@ import com.vitorpamplona.amethyst.commons.ui.text.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.ui.text.onUiThread import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord import com.vitorpamplona.amethyst.commons.ui.text.setTextAndPlaceCursorAtBeginning -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.model.accountsCache.AccountCacheState import com.vitorpamplona.amethyst.service.ai.WritingAssistantFactory import com.vitorpamplona.amethyst.service.location.LocationState @@ -91,8 +94,6 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMediaProcessing import com.vitorpamplona.amethyst.ui.actions.uploads.VoiceAnonymizationController import com.vitorpamplona.amethyst.ui.note.creators.location.ILocationGrabber -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.IMetaAttachments import com.vitorpamplona.quartz.experimental.nip95.data.FileStorageEvent import com.vitorpamplona.quartz.experimental.nip95.header.FileStorageHeaderEvent @@ -365,7 +366,7 @@ open class ShortNotePostViewModel : // GeoHash var wantsToAddGeoHash by mutableStateOf(false) - var location: StateFlow? = null + var location: StateFlow? = null override var pickedGeoHash by mutableStateOf(null) var wantsExclusiveGeoPost by mutableStateOf(false) @@ -1382,7 +1383,7 @@ open class ShortNotePostViewModel : val geoHash = if (wantsToAddGeoHash) { // A map-picked geohash wins over the live GPS fix. - pickedGeoHash ?: (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString() + pickedGeoHash ?: (location?.value as? LocationResult.Success)?.geoHash?.toString() } else { null } @@ -1820,7 +1821,7 @@ open class ShortNotePostViewModel : viewModelScope.launch(Dispatchers.IO) { iMetaAttachments.downloadAndPrepare(item.link) { - Amethyst.instance.roleBasedHttpClientBuilder.okHttpClientForImage(item.link) + accountViewModel.httpClientBuilder.okHttpClientForImage(item.link) } } @@ -2004,7 +2005,7 @@ open class ShortNotePostViewModel : } } - override fun locationFlow(): StateFlow { + override fun locationFlow(): StateFlow { if (location == null) { location = locationManager().geohashStateFlow } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/VoiceReplyScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/VoiceReplyScreen.kt index a7522a9111..6eb9f05f9d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/VoiceReplyScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/VoiceReplyScreen.kt @@ -41,17 +41,17 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.PostingTopBar +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.note.types.ReplyRenderType import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.mediaServers.FileServerSelectionRow import com.vitorpamplona.amethyst.ui.actions.uploads.UploadProgressIndicator import com.vitorpamplona.amethyst.ui.actions.uploads.VoiceAnonymizationSection import com.vitorpamplona.amethyst.ui.actions.uploads.VoiceMessagePreview import com.vitorpamplona.amethyst.ui.navigation.navs.Nav -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.note.types.ReplyRenderType -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/VoiceReplyViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/VoiceReplyViewModel.kt index 2ae2f26bf4..0dfff06e30 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/VoiceReplyViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/VoiceReplyViewModel.kt @@ -40,12 +40,12 @@ import com.vitorpamplona.amethyst.commons.resources.upload_error_voice_message_n import com.vitorpamplona.amethyst.commons.service.pow.PoWReplay import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.util.deleteOrWarn +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadingState import com.vitorpamplona.amethyst.ui.actions.uploads.RecordingResult import com.vitorpamplona.amethyst.ui.actions.uploads.VoiceAnonymizationController -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.people.toPTag import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip10Notes.tags.markedETags diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/HomeFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/HomeFilterAssemblerSubscription.kt index 6911d05e39..06e836f313 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/HomeFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/datasource/HomeFilterAssemblerSubscription.kt @@ -26,7 +26,7 @@ import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.commons.relayClient.home.HomeFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.home.HomeQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun HomeFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/live/LiveStatusIndicator.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/live/LiveStatusIndicator.kt index 69679d2ea5..69badc6e51 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/live/LiveStatusIndicator.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/live/LiveStatusIndicator.kt @@ -33,7 +33,8 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel import com.vitorpamplona.amethyst.commons.service.OnlineChecker -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.ui.screen.loggedIn.checkVideoIsOnline import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/live/RenderEphemeralBubble.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/live/RenderEphemeralBubble.kt index 552d98c52f..7c3cdf9c29 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/live/RenderEphemeralBubble.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/live/RenderEphemeralBubble.kt @@ -31,12 +31,12 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannelNoteAuthors import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.Gallery import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannelNoteAuthors -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.Gallery -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun RenderEphemeralBubble( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/live/RenderGeohashBubble.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/live/RenderGeohashBubble.kt index 57738f7a8b..1d3aa3d9fa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/live/RenderGeohashBubble.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/live/RenderGeohashBubble.kt @@ -35,8 +35,8 @@ import com.vitorpamplona.amethyst.commons.model.geohashChat.GeohashChatChannel import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.commons.icons.symbols.Icon as SymbolIcon /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/live/RenderLiveActivityBubble.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/live/RenderLiveActivityBubble.kt index 2ecf69a51e..50ea9a4b59 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/live/RenderLiveActivityBubble.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/live/RenderLiveActivityBubble.kt @@ -34,14 +34,14 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel +import com.vitorpamplona.amethyst.commons.nests.room.activity.NestBridge +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannelNoteAuthors import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.Gallery import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannelNoteAuthors -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.Gallery -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.activity.NestActivity -import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.activity.NestBridge import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/nip75Goals/NewGoalScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/nip75Goals/NewGoalScreen.kt index 17492a9013..a8fc08fab7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/nip75Goals/NewGoalScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/nip75Goals/NewGoalScreen.kt @@ -63,8 +63,8 @@ import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.PostingTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.Nav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/nip75Goals/NewGoalViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/nip75Goals/NewGoalViewModel.kt index 1696cdae66..04b437e14c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/nip75Goals/NewGoalViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/nip75Goals/NewGoalViewModel.kt @@ -27,9 +27,9 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.ViewModel +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.ui.text.onUiThread -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate import com.vitorpamplona.quartz.nip75ZapGoals.ZapGoalEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/keyBackup/AccountBackupScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/keyBackup/AccountBackupScreen.kt index 35791070c2..804ce0e0ef 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/keyBackup/AccountBackupScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/keyBackup/AccountBackupScreen.kt @@ -138,10 +138,10 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackBu import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.note.authenticate import com.vitorpamplona.amethyst.ui.note.rememberAuthPromptLabels -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.BackButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.QrCodeDrawer import com.vitorpamplona.quartz.nip19Bech32.toNsec diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/keyBackup/BackupKeysNudge.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/keyBackup/BackupKeysNudge.kt index 9ddd74bece..7dd5fce323 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/keyBackup/BackupKeysNudge.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/keyBackup/BackupKeysNudge.kt @@ -55,7 +55,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip19Bech32.toNpub import kotlinx.coroutines.flow.MutableStateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/PeopleListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/PeopleListView.kt index 05196b1570..ea29830159 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/PeopleListView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/PeopleListView.kt @@ -37,13 +37,13 @@ import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.remove_user_from_the_list import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserComposeNoAction import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.HalfHalfHorzModifier import com.vitorpamplona.amethyst.commons.ui.theme.HalfPadding -import com.vitorpamplona.amethyst.ui.note.UserComposeNoAction -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.collections.immutable.ImmutableList @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/ShowUserSuggestions.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/ShowUserSuggestions.kt index 5362ff77f6..585ec8d72b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/ShowUserSuggestions.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/ShowUserSuggestions.kt @@ -63,11 +63,17 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.relayClient.searchCommand.UserSearchDataSourceSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.in_the_list import com.vitorpamplona.amethyst.commons.resources.remove import com.vitorpamplona.amethyst.commons.resources.search_and_add_a_user +import com.vitorpamplona.amethyst.commons.ui.note.AboutDisplay import com.vitorpamplona.amethyst.commons.ui.note.ClearTextIcon +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.AnimateOnNewSearch +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.HalfVertSpacer @@ -77,13 +83,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.SmallBorder import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer -import com.vitorpamplona.amethyst.service.relayClient.searchCommand.UserSearchDataSourceSubscription -import com.vitorpamplona.amethyst.ui.note.AboutDisplay -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.AnimateOnNewSearch -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/lists/PeopleListScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/lists/PeopleListScreen.kt index 074ca3547a..6dcb4548ed 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/lists/PeopleListScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/lists/PeopleListScreen.kt @@ -93,6 +93,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon import com.vitorpamplona.amethyst.commons.ui.note.ClearTextIcon import com.vitorpamplona.amethyst.commons.ui.note.VerticalDotsIcon +import com.vitorpamplona.amethyst.commons.ui.note.externalLinkForNote import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness @@ -102,12 +103,11 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding import com.vitorpamplona.amethyst.commons.ui.theme.TabRowHeight import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow -import com.vitorpamplona.amethyst.ui.note.externalLinkForNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.display.DrawUser import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.display.PeopleListView import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.display.RenderAddUserFieldAndSuggestions -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/lists/PeopleListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/lists/PeopleListViewModel.kt index dcc16a37a9..15ed464437 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/lists/PeopleListViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/lists/PeopleListViewModel.kt @@ -26,11 +26,11 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip51Lists.followSet.FollowSetEvent import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/packs/FollowPackScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/packs/FollowPackScreen.kt index cf121ecf3e..633661c400 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/packs/FollowPackScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/packs/FollowPackScreen.kt @@ -82,6 +82,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon import com.vitorpamplona.amethyst.commons.ui.note.ClearTextIcon import com.vitorpamplona.amethyst.commons.ui.note.VerticalDotsIcon +import com.vitorpamplona.amethyst.commons.ui.note.externalLinkForNote import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness @@ -90,12 +91,11 @@ import com.vitorpamplona.amethyst.commons.ui.theme.PopupUpEffect import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow -import com.vitorpamplona.amethyst.ui.note.externalLinkForNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.display.DrawUser import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.display.PeopleListView import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.display.RenderAddUserFieldAndSuggestions -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.MutableStateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/packs/FollowPackViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/packs/FollowPackViewModel.kt index 002eb5f4a6..cf7e4f725b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/packs/FollowPackViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/display/packs/FollowPackViewModel.kt @@ -26,11 +26,11 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip51Lists.starterPack.StarterPackEvent import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/metadata/FollowPackMetadataScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/metadata/FollowPackMetadataScreen.kt index 332f2e9754..82bf221d7f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/metadata/FollowPackMetadataScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/metadata/FollowPackMetadataScreen.kt @@ -64,9 +64,9 @@ import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.SettingsCategoryFirstModifier import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectSingleFromGallery -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.SettingsCategory import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/metadata/FollowPackMetadataViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/metadata/FollowPackMetadataViewModel.kt index 89c0ab56f6..9429e26f05 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/metadata/FollowPackMetadataViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/metadata/FollowPackMetadataViewModel.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType import com.vitorpamplona.amethyst.commons.model.nip51Lists.followSets.PeopleList import com.vitorpamplona.amethyst.commons.resources.Res @@ -40,7 +40,7 @@ import com.vitorpamplona.amethyst.commons.resources.metadata_strip_failed_title import com.vitorpamplona.amethyst.commons.resources.metadata_strip_failed_upload_cancelled import com.vitorpamplona.amethyst.commons.resources.server_did_not_provide_a_url_after_uploading import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.AvifMetadataNotVerifiableException import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.MediaCompressor @@ -48,7 +48,6 @@ import com.vitorpamplona.amethyst.service.uploads.MetadataStripper import com.vitorpamplona.amethyst.service.uploads.blossom.BlossomUploader import com.vitorpamplona.amethyst.service.uploads.nip96.Nip96Uploader import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -182,7 +181,7 @@ class FollowPackMetadataViewModel : ViewModel() { alt = null, sensitiveContent = null, serverBaseUrl = account.settings.defaultFileServer.baseUrl, - okHttpClient = Amethyst.instance.roleBasedHttpClientBuilder::okHttpClientForUploads, + okHttpClient = accountViewModel.httpClientBuilder::okHttpClientForUploads, onProgress = {}, httpAuth = account::createHTTPAuthorization, context = context, @@ -195,7 +194,7 @@ class FollowPackMetadataViewModel : ViewModel() { alt = null, sensitiveContent = null, serverBaseUrl = account.settings.defaultFileServer.baseUrl, - okHttpClient = Amethyst.instance.roleBasedHttpClientBuilder::okHttpClientForUploads, + okHttpClient = accountViewModel.httpClientBuilder::okHttpClientForUploads, httpAuth = account::createBlossomUploadAuth, context = context, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/metadata/PeopleListMetadataScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/metadata/PeopleListMetadataScreen.kt index f36cbc71b9..34d71f6a98 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/metadata/PeopleListMetadataScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/metadata/PeopleListMetadataScreen.kt @@ -64,9 +64,9 @@ import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.SettingsCategoryFirstModifier import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectSingleFromGallery -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.SettingsCategory import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/metadata/PeopleListMetadataViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/metadata/PeopleListMetadataViewModel.kt index 70a193bb50..f015379575 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/metadata/PeopleListMetadataViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/metadata/PeopleListMetadataViewModel.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType import com.vitorpamplona.amethyst.commons.model.nip51Lists.followSets.PeopleList import com.vitorpamplona.amethyst.commons.resources.Res @@ -40,7 +40,7 @@ import com.vitorpamplona.amethyst.commons.resources.metadata_strip_failed_title import com.vitorpamplona.amethyst.commons.resources.metadata_strip_failed_upload_cancelled import com.vitorpamplona.amethyst.commons.resources.server_did_not_provide_a_url_after_uploading import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.AvifMetadataNotVerifiableException import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.MediaCompressor @@ -48,7 +48,6 @@ import com.vitorpamplona.amethyst.service.uploads.MetadataStripper import com.vitorpamplona.amethyst.service.uploads.blossom.BlossomUploader import com.vitorpamplona.amethyst.service.uploads.nip96.Nip96Uploader import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -182,7 +181,7 @@ class PeopleListMetadataViewModel : ViewModel() { alt = null, sensitiveContent = null, serverBaseUrl = account.settings.defaultFileServer.baseUrl, - okHttpClient = Amethyst.instance.roleBasedHttpClientBuilder::okHttpClientForUploads, + okHttpClient = accountViewModel.httpClientBuilder::okHttpClientForUploads, onProgress = {}, httpAuth = account::createHTTPAuthorization, context = context, @@ -195,7 +194,7 @@ class PeopleListMetadataViewModel : ViewModel() { alt = null, sensitiveContent = null, serverBaseUrl = account.settings.defaultFileServer.baseUrl, - okHttpClient = Amethyst.instance.roleBasedHttpClientBuilder::okHttpClientForUploads, + okHttpClient = accountViewModel.httpClientBuilder::okHttpClientForUploads, httpAuth = account::createBlossomUploadAuth, context = context, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/LiveStreamsFeedLoaded.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/LiveStreamsFeedLoaded.kt index 65318e29a1..3d9f4368ff 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/LiveStreamsFeedLoaded.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/LiveStreamsFeedLoaded.kt @@ -36,7 +36,7 @@ import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.ChannelCardCompose import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/LiveStreamsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/LiveStreamsScreen.kt index 394a02b2f5..370f855c61 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/LiveStreamsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/LiveStreamsScreen.kt @@ -27,14 +27,14 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.livestreams.datasource.LiveStreamsFilterAssemblerSubscription @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/LiveStreamsTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/LiveStreamsTopBar.kt index d3ea9cbedf..c0254eb04b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/LiveStreamsTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/LiveStreamsTopBar.kt @@ -24,18 +24,18 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingRoomEvent import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/datasource/LiveStreamsFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/datasource/LiveStreamsFilterAssemblerSubscription.kt index 8def1ff279..0b8870df4c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/datasource/LiveStreamsFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/datasource/LiveStreamsFilterAssemblerSubscription.kt @@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.livestreams.LiveStreamsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun LiveStreamsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/LongsFeedLoaded.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/LongsFeedLoaded.kt index 9633a4189c..d52cd64a1d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/LongsFeedLoaded.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/LongsFeedLoaded.kt @@ -36,7 +36,7 @@ import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.shorts.VideoCardCompose import com.vitorpamplona.quartz.nip71Video.VideoEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/LongsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/LongsScreen.kt index 107a3508e2..62afa18f9d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/LongsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/LongsScreen.kt @@ -27,15 +27,15 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.longs.datasource.LongsFilterAssemblerSubscription @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/LongsTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/LongsTopBar.kt index 898057185a..61640fe87f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/LongsTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/LongsTopBar.kt @@ -24,18 +24,18 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip71Video.AddressableNormalVideoEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/NewLongVideoButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/NewLongVideoButton.kt index 540cdfef1f..23f91913bc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/NewLongVideoButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/NewLongVideoButton.kt @@ -42,25 +42,25 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp 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.model.VideoPostKind import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.ic_compose import com.vitorpamplona.amethyst.commons.resources.new_long_video import com.vitorpamplona.amethyst.commons.resources.record_a_video import com.vitorpamplona.amethyst.commons.resources.upload_image import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.NewMediaModel import com.vitorpamplona.amethyst.ui.actions.NewMediaView import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelect import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideo -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.Dispatchers @@ -193,7 +193,7 @@ fun NewLongVideoButton( exit = fadeOut(), ) { Icon( - painter = painterRes(R.drawable.ic_compose, 5), + painter = painterRes(Res.drawable.ic_compose, 5), contentDescription = stringRes(id = Res.string.new_long_video), modifier = Size26Modifier, tint = MaterialTheme.colorScheme.onPrimary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/datasource/LongsFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/datasource/LongsFilterAssemblerSubscription.kt index 86c19b40b0..fedefdccc7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/datasource/LongsFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/datasource/LongsFilterAssemblerSubscription.kt @@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.longs.LongsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun LongsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/AddToMusicPlaylistSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/AddToMusicPlaylistSheet.kt index 43da52b5bb..320ffd6830 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/AddToMusicPlaylistSheet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/AddToMusicPlaylistSheet.kt @@ -77,8 +77,8 @@ import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel /** * Modal-style picker that lets a user toggle the visible track in/out of any of their own diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/AddToMusicPlaylistViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/AddToMusicPlaylistViewModel.kt index 20d9328279..14f02c9df7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/AddToMusicPlaylistViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/AddToMusicPlaylistViewModel.kt @@ -24,10 +24,10 @@ import androidx.compose.runtime.Immutable import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.music.playlist.MusicPlaylistEvent import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.AddressSerializer diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicComposerUploadUi.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicComposerUploadUi.kt index 425ae83c1a..7894e15e7e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicComposerUploadUi.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicComposerUploadUi.kt @@ -51,9 +51,9 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator import com.vitorpamplona.amethyst.ui.actions.uploads.ShowImageUploadGallery -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import org.jetbrains.compose.resources.StringResource /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicPlaylistScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicPlaylistScreen.kt index c185009a62..b5b837f382 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicPlaylistScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicPlaylistScreen.kt @@ -68,6 +68,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.AddressableNote +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.cancel import com.vitorpamplona.amethyst.commons.resources.edit_music_playlist @@ -93,19 +94,18 @@ import com.vitorpamplona.amethyst.commons.resources.music_playlist_unknown_track import com.vitorpamplona.amethyst.commons.resources.music_playlist_uploading_banner import com.vitorpamplona.amethyst.commons.resources.new_music_playlist import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDialog +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SendingTopBar +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelectSingle -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.quartz.experimental.music.track.MusicTrackEvent import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicPlaylistViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicPlaylistViewModel.kt index 9b1d06e1fa..179566e82a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicPlaylistViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicPlaylistViewModel.kt @@ -23,18 +23,18 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.music import android.content.Context import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadingState import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.experimental.music.playlist.MusicPlaylistEvent import com.vitorpamplona.quartz.nip01Core.core.Address import kotlinx.collections.immutable.ImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicTrackScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicTrackScreen.kt index 53f6016435..4c130e5156 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicTrackScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicTrackScreen.kt @@ -90,10 +90,10 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SendingTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelectSingle import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import kotlinx.collections.immutable.persistentListOf @OptIn(ExperimentalMaterial3Api::class) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicTrackViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicTrackViewModel.kt index 936a63a29a..602f125695 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicTrackViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/NewMusicTrackViewModel.kt @@ -26,17 +26,17 @@ import android.net.Uri import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.experimental.music.track.MusicTrackEvent import com.vitorpamplona.quartz.nip01Core.core.Address import kotlinx.collections.immutable.ImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/ConnectedAppDetailScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/ConnectedAppDetailScreen.kt index bf71ccce1c..6a6b38d0c7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/ConnectedAppDetailScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/ConnectedAppDetailScreen.kt @@ -114,6 +114,7 @@ import com.vitorpamplona.amethyst.commons.resources.nip46_signer_reconnecting import com.vitorpamplona.amethyst.commons.resources.nip46_signer_remote_app import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.favorites.rememberManifestIconModel import com.vitorpamplona.amethyst.favorites.rememberWebAppIconModel import com.vitorpamplona.amethyst.napplet.NappletBrokerService @@ -122,7 +123,6 @@ import com.vitorpamplona.amethyst.napplet.counterpartyLabel import com.vitorpamplona.amethyst.napplet.descriptionRes import com.vitorpamplona.amethyst.napplet.labelRes import com.vitorpamplona.amethyst.napplet.resolveNappletMeta -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.nip46.Nip46AppIcon import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.nip46.Nip46LiveStatus import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.nip46.Nip46ReconnectPill diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/ConnectedAppsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/ConnectedAppsScreen.kt index a33c540ae3..25c7625df0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/ConnectedAppsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/ConnectedAppsScreen.kt @@ -71,9 +71,9 @@ import com.vitorpamplona.amethyst.commons.resources.napplet_policy_paranoid import com.vitorpamplona.amethyst.commons.resources.napplet_policy_reasonable import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.favorites.rememberManifestIconModel import com.vitorpamplona.amethyst.favorites.rememberWebAppIconModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.napplets.datasource.ConnectedAppsFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.nip01Core.core.Event diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/NappletsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/NappletsScreen.kt index bea2b1ae8f..f28fc919f6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/NappletsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/NappletsScreen.kt @@ -36,16 +36,16 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.napplet_none_found import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.napplet.NappletLauncher -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.napplets.datasource.NappletsFilterAssemblerSubscription import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip5dNapplets.NamedNappletEvent @@ -72,7 +72,7 @@ fun NappletsScreen( NappletsFilterAssemblerSubscription(accountViewModel) val napplets by remember { - Amethyst.instance.cache.observeNotes( + LocalCache.observeNotes( Filter(kinds = listOf(RootNappletEvent.KIND, NamedNappletEvent.KIND)), ) }.collectAsStateWithLifecycle(emptyList()) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/NappletsTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/NappletsTopBar.kt index a1d748266f..62ddcd717e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/NappletsTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/NappletsTopBar.kt @@ -31,6 +31,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.navigation.Route @@ -40,16 +41,15 @@ import com.vitorpamplona.amethyst.commons.resources.napplet_manage_permissions import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarNavigationIcon +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.searchRouteFor import com.vitorpamplona.amethyst.commons.ui.note.SearchIcon import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size22Modifier import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarNavigationIcon -import com.vitorpamplona.amethyst.ui.navigation.topbars.searchRouteFor -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip5dNapplets.NamedNappletEvent import com.vitorpamplona.quartz.nip5dNapplets.RootNappletEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/ConnectedAppsFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/ConnectedAppsFilterAssemblerSubscription.kt index 63d6000dce..c6a357b9a5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/ConnectedAppsFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/ConnectedAppsFilterAssemblerSubscription.kt @@ -24,7 +24,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.napplets.ConnectedAppsQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/NappletsFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/NappletsFilterAssemblerSubscription.kt index a42615c872..f2af75c0db 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/NappletsFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/napplets/datasource/NappletsFilterAssemblerSubscription.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.napplets.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun NappletsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/NestsFeedLoaded.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/NestsFeedLoaded.kt index f3bd69a5bd..86d189d6b6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/NestsFeedLoaded.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/NestsFeedLoaded.kt @@ -64,10 +64,15 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.nests.dal.NestsFeedFilter +import com.vitorpamplona.amethyst.commons.nests.dal.NestsFeedFilter.NestBucket +import com.vitorpamplona.amethyst.commons.nests.datasource.NestRoomLivenessProbeSubscription +import com.vitorpamplona.amethyst.commons.nests.room.activity.NestBridge import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.EndedFlag import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.LiveFlag import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.PrivateFlag import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.ScheduledFlag +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteAndMap import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.live_stream_ended_tag import com.vitorpamplona.amethyst.commons.resources.nests_ended_ago @@ -76,8 +81,16 @@ import com.vitorpamplona.amethyst.commons.resources.nests_section_recently_ended import com.vitorpamplona.amethyst.commons.resources.nests_section_scheduled import com.vitorpamplona.amethyst.commons.resources.wallet_loading import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.DisplayAuthorBanner +import com.vitorpamplona.amethyst.commons.ui.note.Gallery +import com.vitorpamplona.amethyst.commons.ui.note.LongPressToQuickAction +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.elements.MoreOptionsButton import com.vitorpamplona.amethyst.commons.ui.note.timeAgoNoDot import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness @@ -91,24 +104,11 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteAndMap -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.DisplayAuthorBanner -import com.vitorpamplona.amethyst.ui.note.Gallery +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.LikeReaction -import com.vitorpamplona.amethyst.ui.note.LongPressToQuickAction -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.ui.note.ZapReaction -import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip53LiveActivities.LoadParticipants -import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.dal.NestsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.dal.NestsFeedFilter.NestBucket -import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.datasource.NestRoomLivenessProbeSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.activity.NestActivity -import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.activity.NestBridge import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/NestsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/NestsScreen.kt index 6e7bb87122..8a12264822 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/NestsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/NestsScreen.kt @@ -45,16 +45,16 @@ import com.vitorpamplona.amethyst.commons.resources.nest_no_server_title import com.vitorpamplona.amethyst.commons.resources.nest_no_server_use_default import com.vitorpamplona.amethyst.commons.resources.nests import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.create.CreateNestSheet import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.create.CreateNestViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.datasource.NestsFilterAssemblerSubscription diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/NestsTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/NestsTopBar.kt index 32febb02ab..28bb4aa6db 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/NestsTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/NestsTopBar.kt @@ -23,17 +23,17 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.nests import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingRoomEvent import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/create/CreateNestSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/create/CreateNestSheet.kt index 7c8991961c..c062d737cc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/create/CreateNestSheet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/create/CreateNestSheet.kt @@ -55,6 +55,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel +import com.vitorpamplona.amethyst.commons.nests.room.activity.NestBridge import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.nest_create_cancel import com.vitorpamplona.amethyst.commons.resources.nest_create_field_endpoint @@ -71,11 +72,10 @@ import com.vitorpamplona.amethyst.commons.resources.nest_create_when import com.vitorpamplona.amethyst.commons.resources.next import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectSingleFromGallery -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.NestsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.activity.NestActivity -import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.activity.NestBridge import kotlinx.coroutines.launch import android.text.format.DateFormat as AndroidDateFormat diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/create/CreateNestViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/create/CreateNestViewModel.kt index 8fdaec1ab4..314f882a8a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/create/CreateNestViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/create/CreateNestViewModel.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.create import android.content.Context import androidx.lifecycle.ViewModel import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.avif_metadata_strip_failed @@ -31,7 +32,7 @@ import com.vitorpamplona.amethyst.commons.resources.metadata_strip_failed_title import com.vitorpamplona.amethyst.commons.resources.metadata_strip_failed_upload_cancelled import com.vitorpamplona.amethyst.commons.resources.server_did_not_provide_a_url_after_uploading import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.AvifMetadataNotVerifiableException import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.MediaCompressor @@ -39,7 +40,6 @@ import com.vitorpamplona.amethyst.service.uploads.MetadataStripper import com.vitorpamplona.amethyst.service.uploads.blossom.BlossomUploader import com.vitorpamplona.amethyst.service.uploads.nip96.Nip96Uploader import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.activity.NestActivity import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.endpoint diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/datasource/NestsFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/datasource/NestsFilterAssemblerSubscription.kt index 6e8bb35dd1..e32c5b698b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/datasource/NestsFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/datasource/NestsFilterAssemblerSubscription.kt @@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.nests.NestsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun NestsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/activity/NestActivity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/activity/NestActivity.kt index f2ca0061d1..f1dbaa2bab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/activity/NestActivity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/activity/NestActivity.kt @@ -36,6 +36,7 @@ import androidx.activity.compose.setContent import androidx.appcompat.app.AppCompatActivity import androidx.compose.runtime.mutableStateOf import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.commons.nests.room.activity.NestBridge import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.service.relayClient.authCommand.compose.RelayAuthSubscription import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountFilterAssemblerSubscription @@ -51,7 +52,7 @@ import kotlinx.coroutines.flow.asSharedFlow /** * Standalone activity that owns the lifetime of an audio-room session. The - * lobby ([com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.lobby.NestJoinCard]) + * lobby ([com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.nests.room.lobby.NestJoinCard]) * launches this activity when the user taps "Join audio room"; finishing it * tears down the MoQ session, the broadcaster (if any), and the foreground * notification. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/activity/NestActivityContent.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/activity/NestActivityContent.kt index b6d187044f..959c747bce 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/activity/NestActivityContent.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/activity/NestActivityContent.kt @@ -45,21 +45,21 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.AddressableNote +import com.vitorpamplona.amethyst.commons.nests.datasource.NestRoomFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.nest_loading_room import com.vitorpamplona.amethyst.commons.resources.nest_unjoinable_back import com.vitorpamplona.amethyst.commons.resources.nest_unjoinable_body import com.vitorpamplona.amethyst.commons.resources.nest_unjoinable_title +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.BroadcastUiState import com.vitorpamplona.amethyst.commons.viewmodels.ConnectionUiState import com.vitorpamplona.amethyst.commons.viewmodels.NestViewModel import com.vitorpamplona.amethyst.commons.viewmodels.buildParticipantGrid -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent import com.vitorpamplona.amethyst.ui.call.KeepScreenOn -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.datasource.NestRoomFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.lifecycle.AutoConnectAndTrackSpeakers import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.lifecycle.LeaveOnKick import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.lifecycle.LeaveOnRoomClosed diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestChatPanel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestChatPanel.kt index 2a057cde96..33273adf90 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestChatPanel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestChatPanel.kt @@ -49,9 +49,9 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.nest_chat_empty import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.NestViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.BouncingIntentNav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.ChatroomMessageCompose import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent import kotlinx.coroutines.delay diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestEditFieldRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestEditFieldRow.kt index 72a702b616..11b20b6327 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestEditFieldRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestEditFieldRow.kt @@ -41,6 +41,7 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.reply_here import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDialog import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.text.MentionPreservingInputTransformation import com.vitorpamplona.amethyst.commons.ui.theme.EditFieldBorder @@ -48,12 +49,11 @@ import com.vitorpamplona.amethyst.commons.ui.theme.EditFieldModifier import com.vitorpamplona.amethyst.commons.ui.theme.EditFieldTrailingIconModifier import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightChat import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.DisplayReplyingToNote import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.FlowPreview diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestFileUploadDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestFileUploadDialog.kt index f28f17978f..8c8c0e6afc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestFileUploadDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestFileUploadDialog.kt @@ -33,9 +33,9 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.theme.Size34dp -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadState import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestNewMessageViewModel.kt index 1dded94988..cb1dd4ce5c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestNewMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestNewMessageViewModel.kt @@ -32,6 +32,7 @@ import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User @@ -40,6 +41,7 @@ import com.vitorpamplona.amethyst.commons.model.composer.DraftTagState import com.vitorpamplona.amethyst.commons.model.composer.IExpiration import com.vitorpamplona.amethyst.commons.model.composer.NewMessageTagger import com.vitorpamplona.amethyst.commons.model.composer.SplitBuilder +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiPackState import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiSuggestionState import com.vitorpamplona.amethyst.commons.resources.Res @@ -49,18 +51,17 @@ import com.vitorpamplona.amethyst.commons.resources.read_only_user import com.vitorpamplona.amethyst.commons.richtext.UrlParser import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation import com.vitorpamplona.amethyst.commons.ui.loadStringRes +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.ui.text.onUiThread import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.location.LocationState import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.note.creators.location.ILocationGrabber -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.IMetaAttachments import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadState import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.UserSuggestionAnchor @@ -183,7 +184,7 @@ open class NestNewMessageViewModel : // GeoHash var wantsToAddGeoHash by mutableStateOf(false) override var pickedGeoHash by mutableStateOf(null) - var location: StateFlow? = null + var location: StateFlow? = null // ZapRaiser var canAddZapRaiser by mutableStateOf(false) @@ -437,7 +438,7 @@ open class NestNewMessageViewModel : val usedAttachments = iMetaAttachments.filterIsIn(urls.toSet()) val emojis = accountViewModel.account.emoji.findEmojiTags(messageText) - val geoHash = if (wantsToAddGeoHash) (pickedGeoHash ?: (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString()) else null + val geoHash = if (wantsToAddGeoHash) (pickedGeoHash ?: (location?.value as? LocationResult.Success)?.geoHash?.toString()) else null val contentWarningReason = if (wantsToMarkAsSensitive) contentWarningDescription else null val localExpirationDate = if (wantsExpirationDate) expirationDate else null @@ -569,7 +570,7 @@ open class NestNewMessageViewModel : viewModelScope.launch(Dispatchers.IO) { iMetaAttachments.downloadAndPrepare(item.link) { - Amethyst.instance.roleBasedHttpClientBuilder.okHttpClientForImage(item.link) + accountViewModel.httpClientBuilder.okHttpClientForImage(item.link) } } @@ -595,7 +596,7 @@ open class NestNewMessageViewModel : override fun locationManager(): LocationState = Amethyst.instance.locationManager - override fun locationFlow(): StateFlow { + override fun locationFlow(): StateFlow { if (location == null) { location = locationManager().geohashStateFlow } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/edit/EditNestSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/edit/EditNestSheet.kt index 9db1f21bc5..af8455e65e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/edit/EditNestSheet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/edit/EditNestSheet.kt @@ -67,7 +67,7 @@ import com.vitorpamplona.amethyst.commons.resources.nest_edit_save import com.vitorpamplona.amethyst.commons.resources.nest_edit_title import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/edit/EditNestViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/edit/EditNestViewModel.kt index faedda3910..f2fe76aa60 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/edit/EditNestViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/edit/EditNestViewModel.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.edit import androidx.lifecycle.ViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.endpoint import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.image diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lifecycle/NestRoomEventCollectors.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lifecycle/NestRoomEventCollectors.kt index a18200cfdd..e7ce7e4bc3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lifecycle/NestRoomEventCollectors.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lifecycle/NestRoomEventCollectors.kt @@ -47,7 +47,7 @@ import kotlinx.coroutines.isActive * VM through six LaunchedEffects. * * The wire subscription that populates LocalCache is - * [com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.datasource.NestRoomFilterAssemblerSubscription]; + * [com.vitorpamplona.amethyst.commons.nests.datasource.NestRoomFilterAssemblerSubscription]; * this composable is purely the read side — observing what's * already in cache, not opening relay REQs of its own. */ diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lifecycle/NestRoomPresencePublisher.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lifecycle/NestRoomPresencePublisher.kt index e148e3d0bd..43be606541 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lifecycle/NestRoomPresencePublisher.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lifecycle/NestRoomPresencePublisher.kt @@ -25,9 +25,9 @@ import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberUpdatedState +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.viewmodels.BroadcastUiState import com.vitorpamplona.amethyst.commons.viewmodels.NestUiState -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent import com.vitorpamplona.quartz.nip53LiveActivities.presence.MeetingRoomPresenceEvent import kotlinx.coroutines.DelicateCoroutinesApi diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lobby/NestLobbyScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lobby/NestLobbyScreen.kt index cbbcac7877..dbdf4cdf2d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lobby/NestLobbyScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lobby/NestLobbyScreen.kt @@ -65,6 +65,8 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.nests.datasource.NestRoomFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.nests.room.activity.NestBridge import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.nest_chat_empty import com.vitorpamplona.amethyst.commons.resources.nest_lobby_host_label @@ -73,23 +75,21 @@ import com.vitorpamplona.amethyst.commons.resources.nest_lobby_no_listeners import com.vitorpamplona.amethyst.commons.resources.nest_lobby_open_action import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.types.MeetingSpaceClosedFlag +import com.vitorpamplona.amethyst.commons.ui.note.types.MeetingSpaceOpenFlag +import com.vitorpamplona.amethyst.commons.ui.note.types.MeetingSpacePlannedFlag +import com.vitorpamplona.amethyst.commons.ui.note.types.MeetingSpacePrivateFlag import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.types.MeetingSpaceClosedFlag -import com.vitorpamplona.amethyst.ui.note.types.MeetingSpaceOpenFlag -import com.vitorpamplona.amethyst.ui.note.types.MeetingSpacePlannedFlag -import com.vitorpamplona.amethyst.ui.note.types.MeetingSpacePrivateFlag -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.ChatroomMessageCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.datasource.NestRoomFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.activity.NestActivity -import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.activity.NestBridge import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.chat.NestEditFieldRow import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.chat.NestNewMessageViewModel import com.vitorpamplona.quartz.nip01Core.core.Address diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/participants/ParticipantHostActionsSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/participants/ParticipantHostActionsSheet.kt index 8714898475..1a371c87b1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/participants/ParticipantHostActionsSheet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/participants/ParticipantHostActionsSheet.kt @@ -53,6 +53,7 @@ import androidx.core.net.toUri import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.error_dialog_zap_error import com.vitorpamplona.amethyst.commons.resources.nest_chat_send_failed_title @@ -83,15 +84,14 @@ import com.vitorpamplona.amethyst.commons.resources.nest_toast_host_action_faile import com.vitorpamplona.amethyst.commons.resources.nest_toast_host_action_failed_title import com.vitorpamplona.amethyst.commons.resources.no_wallet_found import com.vitorpamplona.amethyst.commons.ui.components.toasts.multiline.UserBasedErrorMessage +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.NestViewModel import com.vitorpamplona.amethyst.commons.viewmodels.RoomSpeakerCatalog -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo import com.vitorpamplona.amethyst.ui.MainActivity -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.ui.note.ZapCustomDialog import com.vitorpamplona.amethyst.ui.note.payViaIntent -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.experimental.nests.admin.AdminCommandEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/reactions/RoomReactionPopup.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/reactions/RoomReactionPopup.kt index 4e89d9e10b..2b96f58fc8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/reactions/RoomReactionPopup.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/reactions/RoomReactionPopup.kt @@ -31,11 +31,11 @@ import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.window.Popup import androidx.compose.ui.window.PopupProperties import com.vitorpamplona.amethyst.commons.model.AddressableNote +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.ReactionChoicePopupContent import com.vitorpamplona.amethyst.ui.note.popupAnimationEnter import com.vitorpamplona.amethyst.ui.note.popupAnimationExit import com.vitorpamplona.amethyst.ui.note.rememberVisibilityState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent import com.vitorpamplona.quartz.nip30CustomEmoji.EmojiUrlTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/screen/NestActionBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/screen/NestActionBar.kt index f01f0b7500..9f55ac0cd0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/screen/NestActionBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/screen/NestActionBar.kt @@ -92,7 +92,9 @@ import com.vitorpamplona.amethyst.commons.resources.no_wallet_found import com.vitorpamplona.amethyst.commons.resources.zap_description import com.vitorpamplona.amethyst.commons.ui.components.toasts.multiline.UserBasedErrorMessage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.navigateToReloadMint import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.BroadcastUiState import com.vitorpamplona.amethyst.commons.viewmodels.ConnectionUiState import com.vitorpamplona.amethyst.commons.viewmodels.NestUiState @@ -101,9 +103,7 @@ import com.vitorpamplona.amethyst.ui.note.ZapAmountChoicePopup import com.vitorpamplona.amethyst.ui.note.ZapCustomDialog import com.vitorpamplona.amethyst.ui.note.payViaIntent import com.vitorpamplona.amethyst.ui.note.zapClick -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.reactions.RoomReactionPopup -import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.navigateToReloadMint import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlin.uuid.ExperimentalUuidApi @@ -492,7 +492,6 @@ private fun NestZapButton( zapClick( baseNote = roomNote, accountViewModel = accountViewModel, - context = context, onZapStarts = {}, onZappingProgress = { progress -> scope.launch { zappingProgress = progress } }, onMultipleChoices = { scope.launch { wantsToZap = true } }, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/screen/NestFullScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/screen/NestFullScreen.kt index 0968b8d0ea..23fbed8670 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/screen/NestFullScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/screen/NestFullScreen.kt @@ -77,11 +77,11 @@ import com.vitorpamplona.amethyst.commons.resources.nests import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.NestUiState import com.vitorpamplona.amethyst.commons.viewmodels.NestViewModel import com.vitorpamplona.amethyst.commons.viewmodels.ParticipantGrid import com.vitorpamplona.amethyst.ui.navigation.navs.BouncingIntentNav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.chat.NestChatPanel import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.edit.EditNestSheet import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.edit.EditNestViewModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/screen/NestPipScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/screen/NestPipScreen.kt index 5b81547f5b..340748d1ef 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/screen/NestPipScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/screen/NestPipScreen.kt @@ -54,14 +54,14 @@ import com.vitorpamplona.amethyst.commons.resources.nest_lower_hand import com.vitorpamplona.amethyst.commons.resources.nest_mic_mute import com.vitorpamplona.amethyst.commons.resources.nest_mic_unmute import com.vitorpamplona.amethyst.commons.resources.nest_reconnecting +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.BroadcastUiState import com.vitorpamplona.amethyst.commons.viewmodels.ConnectionUiState import com.vitorpamplona.amethyst.commons.viewmodels.NestUiState import com.vitorpamplona.amethyst.commons.viewmodels.NestViewModel import com.vitorpamplona.amethyst.commons.viewmodels.RoomMember -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel /** * Compact PIP layout. Renders three things, in priority order: diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/stage/HandRaiseQueueSection.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/stage/HandRaiseQueueSection.kt index 615b4137c3..363379ac39 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/stage/HandRaiseQueueSection.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/stage/HandRaiseQueueSection.kt @@ -44,13 +44,13 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.nest_hand_raise_approve import com.vitorpamplona.amethyst.commons.resources.nest_hand_raise_queue_title +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.NestViewModel import com.vitorpamplona.amethyst.commons.viewmodels.RoomPresence -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.participants.RoomParticipantActions import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.ROLE diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/stage/ParticipantsGrid.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/stage/ParticipantsGrid.kt index 1e189e34c9..45a1533454 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/stage/ParticipantsGrid.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/stage/ParticipantsGrid.kt @@ -79,14 +79,14 @@ import com.vitorpamplona.amethyst.commons.resources.nest_stage_empty import com.vitorpamplona.amethyst.commons.resources.nest_state_mic_open import com.vitorpamplona.amethyst.commons.resources.nest_state_muted import com.vitorpamplona.amethyst.commons.resources.nest_state_speaking +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.RoomMember import com.vitorpamplona.amethyst.commons.viewmodels.RoomReaction import com.vitorpamplona.amethyst.commons.viewmodels.RoomZap -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.ROLE import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.persistentSetOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/theme/NestThemedScope.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/theme/NestThemedScope.kt index ea5de86706..e8a46d181a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/theme/NestThemedScope.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/theme/NestThemedScope.kt @@ -39,8 +39,8 @@ import androidx.compose.ui.text.font.FontFamily import coil3.asDrawable import coil3.compose.AsyncImage import coil3.imageLoader +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.RoomTheme -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/AddInboxRelayCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/AddInboxRelayCard.kt index caee674457..55fc8e2b05 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/AddInboxRelayCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/AddInboxRelayCard.kt @@ -50,8 +50,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel @Preview @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/AddInboxRelayListDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/AddInboxRelayListDialog.kt index 2c06cd4757..95b78161eb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/AddInboxRelayListDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/AddInboxRelayListDialog.kt @@ -45,8 +45,8 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SavingTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.SetDialogToEdgeToEdge -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.nip65.Nip65InboxRelayList import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.nip65.Nip65RelayListViewModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedView.kt index 9a64c999a6..96d8811bec 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedView.kt @@ -52,7 +52,19 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.Card +import com.vitorpamplona.amethyst.commons.feeds.CardFeedState import com.vitorpamplona.amethyst.commons.model.chats.formatHistoryReachDate +import com.vitorpamplona.amethyst.commons.notifications.BadgeCard +import com.vitorpamplona.amethyst.commons.notifications.CardFeedContentState +import com.vitorpamplona.amethyst.commons.notifications.ChannelInviteCard +import com.vitorpamplona.amethyst.commons.notifications.MessageSetCard +import com.vitorpamplona.amethyst.commons.notifications.MultiSetCard +import com.vitorpamplona.amethyst.commons.notifications.NoteCard +import com.vitorpamplona.amethyst.commons.notifications.NutzapUserSetCard +import com.vitorpamplona.amethyst.commons.notifications.OpenPollsState +import com.vitorpamplona.amethyst.commons.notifications.ZapUserSetCard +import com.vitorpamplona.amethyst.commons.notifications.containsEventId import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.notification_feed_is_empty import com.vitorpamplona.amethyst.commons.resources.refresh @@ -65,8 +77,9 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.StickToTopOnPrepend import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.CloseIcon -import com.vitorpamplona.amethyst.commons.ui.notifications.Card -import com.vitorpamplona.amethyst.commons.ui.notifications.CardFeedState +import com.vitorpamplona.amethyst.commons.ui.note.MultiSetCompose +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.note.types.ReplyRenderType import com.vitorpamplona.amethyst.commons.ui.notifications.OpenPollsSectionHeader import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness @@ -74,15 +87,12 @@ import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier -import com.vitorpamplona.amethyst.logTime +import com.vitorpamplona.amethyst.commons.util.logTime +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.BadgeCompose import com.vitorpamplona.amethyst.ui.note.MessageSetCompose -import com.vitorpamplona.amethyst.ui.note.MultiSetCompose -import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.note.NutzapUserSetCompose import com.vitorpamplona.amethyst.ui.note.ZapUserSetCompose -import com.vitorpamplona.amethyst.ui.note.types.ReplyRenderType -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.donations.ShowDonationCard import kotlinx.coroutines.delay diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationHistoryPaging.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationHistoryPaging.kt index 4dee72c0ab..db95124d95 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationHistoryPaging.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationHistoryPaging.kt @@ -30,10 +30,10 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.relayClient.paging.PagingStatus +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip01Notifications.AccountNotificationsHistoryEoseManager import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachCursor import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachSentinels import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachState -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip01Notifications.AccountNotificationsHistoryEoseManager import com.vitorpamplona.quartz.nip01Core.relay.client.paging.RelayPagingProgress import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.delay diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationScreen.kt index cd772a90de..784402841a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationScreen.kt @@ -32,8 +32,12 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.model.NOTIFICATION_LAST_READ_KEY import com.vitorpamplona.amethyst.commons.model.UiSettingsFlow import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.notifications.CardFeedContentState +import com.vitorpamplona.amethyst.commons.notifications.NotificationSummaryState +import com.vitorpamplona.amethyst.commons.notifications.OpenPollsState import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.notification_tab_everyone import com.vitorpamplona.amethyst.commons.resources.notification_tab_following @@ -42,18 +46,16 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverLazyListState import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverPagerState +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.TabRowHeight +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.SelectNotificationProvider import com.vitorpamplona.amethyst.ui.feeds.WatchScrollToTop -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.launch -const val NOTIFICATION_LAST_READ_KEY = "Notification" - @Composable fun NotificationScreen( scrollToEventId: String? = null, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSidePanel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSidePanel.kt index 2ca840ae1e..89edb5756f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSidePanel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSidePanel.kt @@ -57,7 +57,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size12dp import com.vitorpamplona.amethyst.commons.ui.theme.Size16dp import com.vitorpamplona.amethyst.commons.ui.theme.Size22Modifier import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * The docked notification feed shown on very wide windows, to the right of the center pane. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSummaryView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSummaryView.kt index 04ed75de78..379de16c0c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSummaryView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSummaryView.kt @@ -40,6 +40,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.patrykandpatrick.vico.compose.common.ProvideVicoTheme +import com.vitorpamplona.amethyst.commons.notifications.NotificationSummaryState import com.vitorpamplona.amethyst.ui.note.UserReactionsRow import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.chart.ShowChart import com.vitorpamplona.amethyst.ui.theme.chartStyle diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationTopBar.kt index 356ac10591..83a8a55e49 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationTopBar.kt @@ -25,6 +25,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.route_notifications @@ -33,12 +35,10 @@ import com.vitorpamplona.amethyst.commons.search.SearchQuery import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.collections.immutable.persistentListOf @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/chart/AmountValueFormatter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/chart/AmountValueFormatter.kt index 71359a8851..31936e8ba7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/chart/AmountValueFormatter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/chart/AmountValueFormatter.kt @@ -24,9 +24,9 @@ import androidx.compose.runtime.Stable import com.patrykandpatrick.vico.compose.cartesian.CartesianMeasuringContext import com.patrykandpatrick.vico.compose.cartesian.axis.Axis import com.patrykandpatrick.vico.compose.cartesian.data.CartesianValueFormatter +import com.vitorpamplona.amethyst.commons.notifications.ShowDecimals import com.vitorpamplona.amethyst.commons.util.showAmountIntegerWithZero import com.vitorpamplona.amethyst.commons.util.showAmountWithZero -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.ShowDecimals @Stable class AmountValueFormatter : CartesianValueFormatter { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/donations/ShowDonationCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/donations/ShowDonationCard.kt index 75a287d35e..2903ef7c3d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/donations/ShowDonationCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/donations/ShowDonationCard.kt @@ -24,9 +24,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.BuildConfig +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun ShowDonationCard( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/donations/ZapTheDevsCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/donations/ZapTheDevsCard.kt index 94ec7a0b5c..b0484b9cce 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/donations/ZapTheDevsCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/donations/ZapTheDevsCard.kt @@ -58,6 +58,7 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.brought_to_you_by import com.vitorpamplona.amethyst.commons.resources.cancel @@ -65,23 +66,22 @@ import com.vitorpamplona.amethyst.commons.resources.this_version_brought_to_you_ import com.vitorpamplona.amethyst.commons.resources.version_name import com.vitorpamplona.amethyst.commons.resources.zap_the_devs_description import com.vitorpamplona.amethyst.commons.resources.zap_the_devs_title +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.components.appendLink import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.note.ZapIcon +import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.DisplayZapSplits import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.components.ReusableZapButton import com.vitorpamplona.amethyst.ui.components.ZapButtonConfig -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.DisplayZapSplits -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageScreen.kt index f48d6ef95e..724e63e4c6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageScreen.kt @@ -64,6 +64,7 @@ import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDial import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.PostingTopBar +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.ContentSensitivityExplainer import com.vitorpamplona.amethyst.commons.ui.note.creators.contentWarning.MarkAsSensitiveButton import com.vitorpamplona.amethyst.commons.ui.note.creators.expiration.ExpirationDateButton @@ -71,9 +72,11 @@ import com.vitorpamplona.amethyst.commons.ui.note.creators.invoice.AddLnInvoiceB import com.vitorpamplona.amethyst.commons.ui.note.creators.location.AddGeoHashButton import com.vitorpamplona.amethyst.commons.ui.note.creators.secretEmoji.AddSecretEmojiButton import com.vitorpamplona.amethyst.commons.ui.note.creators.secretEmoji.SecretEmojiRequest +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList import com.vitorpamplona.amethyst.commons.ui.note.creators.zapraiser.AddZapraiserButton import com.vitorpamplona.amethyst.commons.ui.note.creators.zapraiser.ZapRaiserRequest import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.ForwardZapToButton +import com.vitorpamplona.amethyst.commons.ui.note.types.ReplyRenderType import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.text.MentionPreservingInputTransformation import com.vitorpamplona.amethyst.commons.ui.text.onUiThread @@ -84,6 +87,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightPage import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery @@ -92,17 +96,13 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.TakePictureButton import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideoButton import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField import com.vitorpamplona.amethyst.ui.navigation.navs.Nav -import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList import com.vitorpamplona.amethyst.ui.note.creators.expiration.ExpirationDatePicker import com.vitorpamplona.amethyst.ui.note.creators.invoice.NewPostInvoiceRequest import com.vitorpamplona.amethyst.ui.note.creators.location.GeoHashPostSection import com.vitorpamplona.amethyst.ui.note.creators.previews.DisplayPreviews import com.vitorpamplona.amethyst.ui.note.creators.uploads.ImageVideoDescription -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.ForwardZapTo -import com.vitorpamplona.amethyst.ui.note.types.ReplyRenderType -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.MessageFieldRow import com.vitorpamplona.quartz.nip01Core.core.HexKey import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageViewModel.kt index b33f4b1daa..b28456d3db 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageViewModel.kt @@ -32,6 +32,7 @@ import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User @@ -43,6 +44,7 @@ import com.vitorpamplona.amethyst.commons.model.composer.NewMessageTagger import com.vitorpamplona.amethyst.commons.model.composer.PreviewState import com.vitorpamplona.amethyst.commons.model.composer.SplitBuilder import com.vitorpamplona.amethyst.commons.model.composer.toZapSplitSetup +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiPackState import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiSuggestionState @@ -54,12 +56,13 @@ import com.vitorpamplona.amethyst.commons.service.upload.MediaUploadTracker import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.note.creators.messagefield.IMessageField +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.IZapField import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.ui.text.onUiThread import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.location.LocationState import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator @@ -67,8 +70,6 @@ import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMediaProcessing import com.vitorpamplona.amethyst.ui.note.creators.location.ILocationGrabber -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.IMetaAttachments import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.UserSuggestionAnchor import com.vitorpamplona.quartz.experimental.nip95.data.FileStorageEvent @@ -202,7 +203,7 @@ class NewPublicMessageViewModel : // GeoHash var wantsToAddGeoHash by mutableStateOf(false) override var pickedGeoHash by mutableStateOf(null) - var location: StateFlow? = null + var location: StateFlow? = null // ZapRaiser var canAddZapRaiser by mutableStateOf(false) @@ -330,7 +331,7 @@ class NewPublicMessageViewModel : iMetaAttachments.addAll(draftEvent.imetas()) } - override fun locationFlow(): StateFlow { + override fun locationFlow(): StateFlow { if (location == null) { location = locationManager().geohashStateFlow } @@ -394,7 +395,7 @@ class NewPublicMessageViewModel : val zapReceiver = if (wantsForwardZapTo) forwardZapTo.value.toZapSplitSetup() else null - val geoHash = (if (wantsToAddGeoHash) pickedGeoHash else null) ?: (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString() + val geoHash = (if (wantsToAddGeoHash) pickedGeoHash else null) ?: (location?.value as? LocationResult.Success)?.geoHash?.toString() val localZapRaiserAmount = if (wantsZapraiser) zapRaiserAmount.value else null val emojis = account.emoji.findEmojiTags(tagger.message) @@ -641,7 +642,7 @@ class NewPublicMessageViewModel : viewModelScope.launch(Dispatchers.IO) { iMetaAttachments.downloadAndPrepare(item.link) { - Amethyst.instance.roleBasedHttpClientBuilder.okHttpClientForImage(item.link) + accountViewModel.httpClientBuilder.okHttpClientForImage(item.link) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/NewPictureButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/NewPictureButton.kt index 8d7195308d..29e9486023 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/NewPictureButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/NewPictureButton.kt @@ -44,25 +44,25 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp 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.resources.Res +import com.vitorpamplona.amethyst.commons.resources.ic_compose import com.vitorpamplona.amethyst.commons.resources.new_picture import com.vitorpamplona.amethyst.commons.resources.take_a_picture import com.vitorpamplona.amethyst.commons.resources.upload_image import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.NewMediaModel import com.vitorpamplona.amethyst.ui.actions.NewMediaView import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelect import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.TakePicture import com.vitorpamplona.amethyst.ui.actions.uploads.resolveSharedMedia -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.Dispatchers @@ -206,7 +206,7 @@ fun NewPictureButton( exit = fadeOut(), ) { Icon( - painter = painterRes(R.drawable.ic_compose, 5), + painter = painterRes(Res.drawable.ic_compose, 5), contentDescription = stringRes(id = Res.string.new_picture), modifier = Size26Modifier, tint = MaterialTheme.colorScheme.onPrimary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PictureCardCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PictureCardCompose.kt index f4d58d1f36..ccd21a2374 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PictureCardCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PictureCardCompose.kt @@ -39,19 +39,19 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage +import com.vitorpamplona.amethyst.commons.ui.components.AutoNonlazyGrid +import com.vitorpamplona.amethyst.commons.ui.components.BlurhashBackdrop +import com.vitorpamplona.amethyst.commons.ui.components.BlurhashGridBackdrop +import com.vitorpamplona.amethyst.commons.ui.components.ContentWarningGate +import com.vitorpamplona.amethyst.commons.ui.components.collectContentWarningReasons +import com.vitorpamplona.amethyst.commons.ui.components.mediaSizingModifier import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.model.MediaAspectRatioCache -import com.vitorpamplona.amethyst.ui.components.AutoNonlazyGrid -import com.vitorpamplona.amethyst.ui.components.BlurhashBackdrop -import com.vitorpamplona.amethyst.ui.components.BlurhashGridBackdrop -import com.vitorpamplona.amethyst.ui.components.ContentWarningGate +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.ZoomableContentView -import com.vitorpamplona.amethyst.ui.components.collectContentWarningReasons -import com.vitorpamplona.amethyst.ui.components.mediaSizingModifier import com.vitorpamplona.amethyst.ui.note.ReactionsRow -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.UserCardHeader import com.vitorpamplona.quartz.nip36SensitiveContent.isSensitiveOrNSFW import com.vitorpamplona.quartz.nip68Picture.PictureEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PictureCardComposePreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PictureCardComposePreview.kt index f07f651977..eda5b2b6e6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PictureCardComposePreview.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PictureCardComposePreview.kt @@ -34,10 +34,10 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip68Picture.PictureEvent import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PictureFeedLoaded.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PictureFeedLoaded.kt index 7be8109c8c..42e436f495 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PictureFeedLoaded.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PictureFeedLoaded.kt @@ -36,7 +36,7 @@ import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip68Picture.PictureEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PicturesScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PicturesScreen.kt index ed7d680d4b..5814aabfaa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PicturesScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PicturesScreen.kt @@ -27,15 +27,15 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.pictures.datasource.PicturesFilterAssemblerSubscription @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PicturesTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PicturesTopBar.kt index 3f1036ee3b..27d7412c65 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PicturesTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PicturesTopBar.kt @@ -24,18 +24,18 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip68Picture.PictureEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/datasource/PicturesFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/datasource/PicturesFilterAssemblerSubscription.kt index 20a05f69a1..a17d0a403d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/datasource/PicturesFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/datasource/PicturesFilterAssemblerSubscription.kt @@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.pictures.PicturesFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun PicturesFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastAuthors.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastAuthors.kt index 65b4ceb89f..4eaace58e1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastAuthors.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastAuthors.kt @@ -42,20 +42,20 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.podcast_author_verified import com.vitorpamplona.amethyst.commons.resources.podcast_role_cohost import com.vitorpamplona.amethyst.commons.resources.podcast_role_editor import com.vitorpamplona.amethyst.commons.resources.podcast_role_host import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nipF4Podcasts.authored.AuthoredPodcastsEvent import com.vitorpamplona.quartz.nipF4Podcasts.metadata.tags.AuthorTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastEpisodeListItem.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastEpisodeListItem.kt index 2f36698470..3d74d3d04d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastEpisodeListItem.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastEpisodeListItem.kt @@ -43,15 +43,15 @@ import com.vitorpamplona.amethyst.commons.resources.podcast_episode_number import com.vitorpamplona.amethyst.commons.resources.podcast_season import com.vitorpamplona.amethyst.commons.resources.podcast_season_episode import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.note.rememberTimeAgoLabels import com.vitorpamplona.amethyst.commons.ui.note.timeAgoWith import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.ReactionsRow import com.vitorpamplona.amethyst.ui.note.types.PodcastEpisodeAudioPlayer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.podcasts.PodcastEpisode private val PLAYER_SHAPE = Modifier.clip(RoundedCornerShape(12.dp)) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastHeader.kt index 212eaeed98..1d92d618ce 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastHeader.kt @@ -42,16 +42,16 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.podcast_episode_count +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.types.PodcastCoverCard +import com.vitorpamplona.amethyst.commons.ui.note.types.PodcastPeople import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.ReactionsRow -import com.vitorpamplona.amethyst.ui.note.types.PodcastCoverCard -import com.vitorpamplona.amethyst.ui.note.types.PodcastPeople -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nipF4Podcasts.metadata.PodcastMetadataEvent import com.vitorpamplona.quartz.podcasts.PodcastShow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastScreen.kt index 047752d739..83e79a7e3e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastScreen.kt @@ -46,26 +46,27 @@ import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.podcast_no_episodes import com.vitorpamplona.amethyst.commons.resources.route_podcasts import com.vitorpamplona.amethyst.commons.ui.feeds.FeedError import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.elements.MoreOptionsButton +import com.vitorpamplona.amethyst.commons.ui.note.types.PodcastBookmarkButton +import com.vitorpamplona.amethyst.commons.ui.screen.SaveableFeedState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts.PodcastTrailerListItem import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton -import com.vitorpamplona.amethyst.ui.note.types.PodcastBookmarkButton -import com.vitorpamplona.amethyst.ui.screen.SaveableFeedState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.dal.OnePodcastFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.datasource.OnePodcastFilterAssemblerSubscription import com.vitorpamplona.quartz.nip01Core.core.Address diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastTopSupporters.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastTopSupporters.kt index 88abf9fe0a..2ab7bcab5f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastTopSupporters.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastTopSupporters.kt @@ -44,10 +44,15 @@ import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.nip53LiveActivities.LiveActivityTopZappersAggregator import com.vitorpamplona.amethyst.commons.nip53LiveActivities.TopZapperEntry import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ZapContribution +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteZaps import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.chat_zap_anonymous import com.vitorpamplona.amethyst.commons.resources.podcast_top_supporters import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.note.ZapIcon import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange @@ -55,12 +60,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size16Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.util.showAmountInteger -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteZaps -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent import java.math.BigDecimal diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/EditPodcastShowScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/EditPodcastShowScreen.kt index ee7b75f2ff..47aefaed52 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/EditPodcastShowScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/EditPodcastShowScreen.kt @@ -77,8 +77,8 @@ import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDial import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SendingTopBar +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelectSingle -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.CoverImagePicker import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.UploadInProgressBanner import com.vitorpamplona.amethyst.ui.stringRes diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/EditPodcastShowViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/EditPodcastShowViewModel.kt index ad55093d4a..d5f77f1e98 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/EditPodcastShowViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/EditPodcastShowViewModel.kt @@ -23,15 +23,15 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.authoring import android.content.Context import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.podcasts.V4VSplitEditorState import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip78AppData.AppSpecificDataEvent import com.vitorpamplona.quartz.nipXXPodcasting20.metadata.Podcasting20PodcastMetadata diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/NewPodcastEpisodeScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/NewPodcastEpisodeScreen.kt index 3022b3717c..c21e4a2857 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/NewPodcastEpisodeScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/NewPodcastEpisodeScreen.kt @@ -94,9 +94,9 @@ import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SendingTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelectSingle import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.CoverImagePicker import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.UploadInProgressBanner import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.UploadPlaceholder diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/NewPodcastEpisodeViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/NewPodcastEpisodeViewModel.kt index 35090b62f9..a43c37fa88 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/NewPodcastEpisodeViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/NewPodcastEpisodeViewModel.kt @@ -24,15 +24,15 @@ import android.content.Context import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.podcasts.V4VSplitEditorState import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nipXXPodcasting20.episode.Podcasting20EpisodeEvent import com.vitorpamplona.quartz.podcasts.PodcastAudio diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/NewPodcastTrailerScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/NewPodcastTrailerScreen.kt index 8492d0c385..81f617a207 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/NewPodcastTrailerScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/NewPodcastTrailerScreen.kt @@ -75,8 +75,8 @@ import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SendingTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.UploadInProgressBanner import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.UploadPlaceholder diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/NewPodcastTrailerViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/NewPodcastTrailerViewModel.kt index 304b497cb3..19ad47e7cf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/NewPodcastTrailerViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/NewPodcastTrailerViewModel.kt @@ -23,13 +23,13 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.authoring import android.content.Context import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.service.upload.SuspendableConfirmation -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nipXXPodcasting20.trailer.Podcasting20TrailerEvent import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/PodcastComposerMedia.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/PodcastComposerMedia.kt index f23c18d762..5198d8b943 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/PodcastComposerMedia.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/PodcastComposerMedia.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.authoring import android.content.Context import android.media.MediaMetadataRetriever import android.net.Uri +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/V4VSplitEditor.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/V4VSplitEditor.kt index 7f0d1e3ac2..13be6b657e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/V4VSplitEditor.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/V4VSplitEditor.kt @@ -71,15 +71,15 @@ import com.vitorpamplona.amethyst.commons.resources.podcast_value_type_lnaddress import com.vitorpamplona.amethyst.commons.resources.podcast_value_type_node import com.vitorpamplona.amethyst.commons.resources.podcast_value_user_no_lnaddress import com.vitorpamplona.amethyst.commons.resources.podcast_value_weight +import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size40dp import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightPage import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.ui.note.BaseUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Editor for a Podcasting-2.0 value-for-value split. Recipients are added the Amethyst-native way — diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/dal/OnePodcastEpisodesFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/dal/OnePodcastEpisodesFeedFilter.kt index 5275645f6e..dbe4d2c532 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/dal/OnePodcastEpisodesFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/dal/OnePodcastEpisodesFeedFilter.kt @@ -21,11 +21,11 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nipXXPodcasting20.episode.Podcasting20EpisodeEvent import com.vitorpamplona.quartz.nipXXPodcasting20.trailer.Podcasting20TrailerEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/dal/OnePodcastFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/dal/OnePodcastFeedViewModel.kt index 824cc69c3b..14f1ead528 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/dal/OnePodcastFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/dal/OnePodcastFeedViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey @Stable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/datasource/OnePodcastFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/datasource/OnePodcastFilterAssemblerSubscription.kt index aab62d65aa..c60c68521b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/datasource/OnePodcastFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/datasource/OnePodcastFilterAssemblerSubscription.kt @@ -25,7 +25,7 @@ import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.relayClient.podcasts.OnePodcastQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun OnePodcastFilterAssemblerSubscription( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/PollPostScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/PollPostScreen.kt index 38eacaafdc..40f7184fbc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/PollPostScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/PollPostScreen.kt @@ -26,8 +26,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.Nav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.NewPostScreenInner import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.ShortNotePostViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/ProductsFeedLoaded.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/ProductsFeedLoaded.kt index 92baf2422b..c8c8f0d7d8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/ProductsFeedLoaded.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/ProductsFeedLoaded.kt @@ -39,12 +39,12 @@ import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled import com.vitorpamplona.amethyst.commons.ui.feeds.FeedEmpty import com.vitorpamplona.amethyst.commons.ui.feeds.FeedError import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed +import com.vitorpamplona.amethyst.commons.ui.feeds.PrefetchLoadedFeedMedia import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.feeds.PrefetchLoadedFeedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.ChannelCardCompose import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/ProductsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/ProductsScreen.kt index cc0f69bb77..83a312fd5f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/ProductsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/ProductsScreen.kt @@ -28,14 +28,14 @@ import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.nip99Classifieds.ui.NewProductButton import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableGridFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.feeds.SaveableGridFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.products.datasource.ProductsFilterAssemblerSubscription @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/ProductsTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/ProductsTopBar.kt index 656161f30e..6e7ff0a6d9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/ProductsTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/ProductsTopBar.kt @@ -24,18 +24,18 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/datasource/ProductsFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/datasource/ProductsFilterAssemblerSubscription.kt index cf4b391b6a..f5c0c2b7f5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/datasource/ProductsFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/datasource/ProductsFilterAssemblerSubscription.kt @@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.products.ProductsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun ProductsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/ProfileScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/ProfileScreen.kt index 861d97c490..e318fed286 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/ProfileScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/ProfileScreen.kt @@ -69,6 +69,7 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.profile.ui.RelaysTabHeader import com.vitorpamplona.amethyst.commons.relayClient.profile.UserProfileFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.observeAccountIsHiddenUser import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.gallery import com.vitorpamplona.amethyst.commons.resources.mutual @@ -78,13 +79,12 @@ import com.vitorpamplona.amethyst.commons.resources.replies import com.vitorpamplona.amethyst.commons.ui.feeds.UserBlockedFeed import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.Size8dp +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.UserExternalIdentitiesViewModel -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.observeAccountIsHiddenUser -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.apps.TabApps import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.apps.dal.UserProfileAppsFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.bookmarks.BookmarkTabHeader diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/apps/TabApps.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/apps/TabApps.kt index c473d1aa98..b4fb0f1c65 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/apps/TabApps.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/apps/TabApps.kt @@ -28,8 +28,8 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.apps.dal.UserProfileAppsFeedViewModel /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/apps/dal/UserProfileAppsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/apps/dal/UserProfileAppsFeedFilter.kt index 3264316f1b..0dc7eb64e0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/apps/dal/UserProfileAppsFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/apps/dal/UserProfileAppsFeedFilter.kt @@ -22,12 +22,12 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.apps.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip5aStaticWebsites.NamedSiteEvent import com.vitorpamplona.quartz.nip5aStaticWebsites.RootSiteEvent import com.vitorpamplona.quartz.nip5dNapplets.NamedNappletEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/apps/dal/UserProfileAppsFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/apps/dal/UserProfileAppsFeedViewModel.kt index a64719a406..1f1c2c4ff0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/apps/dal/UserProfileAppsFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/apps/dal/UserProfileAppsFeedViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.apps.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel @Stable class UserProfileAppsFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/BookmarkTabHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/BookmarkTabHeader.kt index a5a096d9eb..a57e2a42c0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/BookmarkTabHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/BookmarkTabHeader.kt @@ -24,11 +24,11 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserBookmarkCount import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.bookmarks_title import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserBookmarkCount -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun BookmarkTabHeader( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/TabBookmarks.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/TabBookmarks.kt index 757537885b..3307c80418 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/TabBookmarks.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/TabBookmarks.kt @@ -28,8 +28,8 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.bookmarks.dal.UserProfileBookmarksFeedViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/dal/UserProfileBookmarksFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/dal/UserProfileBookmarksFeedFilter.kt index ddc089dfe1..b31eb14984 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/dal/UserProfileBookmarksFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/dal/UserProfileBookmarksFeedFilter.kt @@ -21,10 +21,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.bookmarks.dal import com.vitorpamplona.amethyst.commons.feeds.FeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip51Lists.bookmarkList.BookmarkListEvent import com.vitorpamplona.quartz.nip51Lists.bookmarkList.OldBookmarkListEvent import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.AddressBookmark diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/dal/UserProfileBookmarksFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/dal/UserProfileBookmarksFeedViewModel.kt index be0597072c..fc7dc200df 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/dal/UserProfileBookmarksFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/dal/UserProfileBookmarksFeedViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.bookmarks.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel @Stable class UserProfileBookmarksFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/conversations/TabNotesConversations.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/conversations/TabNotesConversations.kt index 96adcd190b..bc7451de42 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/conversations/TabNotesConversations.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/conversations/TabNotesConversations.kt @@ -25,8 +25,8 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.conversations.dal.UserProfileConversationsFeedViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/conversations/dal/UserProfileConversationsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/conversations/dal/UserProfileConversationsFeedFilter.kt index 9d0d1be771..5390218eea 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/conversations/dal/UserProfileConversationsFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/conversations/dal/UserProfileConversationsFeedFilter.kt @@ -23,11 +23,11 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.conversations.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip22Comments.CommentEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/conversations/dal/UserProfileConversationsFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/conversations/dal/UserProfileConversationsFeedViewModel.kt index 759953378c..41ebb0f777 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/conversations/dal/UserProfileConversationsFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/conversations/dal/UserProfileConversationsFeedViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.conversations.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel @Stable class UserProfileConversationsFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/followers/FollowersTabHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/followers/FollowersTabHeader.kt index ce6c0e9dc2..55f17dedb4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/followers/FollowersTabHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/followers/FollowersTabHeader.kt @@ -25,11 +25,11 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserAssertionsFollowerCount import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.number_followers import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserAssertionsFollowerCount -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.followers.dal.UserProfileFollowersUserFeedViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/followers/TabFollowers.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/followers/TabFollowers.kt index 25ab77a42d..43b2a11a4b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/followers/TabFollowers.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/followers/TabFollowers.kt @@ -32,10 +32,10 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserCompose import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.note.UserCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.followers.dal.UserProfileFollowersUserFeedViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/followers/dal/UserProfileFollowersUserFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/followers/dal/UserProfileFollowersUserFeedViewModel.kt index 637d20122c..78a45c1a61 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/followers/dal/UserProfileFollowersUserFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/followers/dal/UserProfileFollowersUserFeedViewModel.kt @@ -24,8 +24,8 @@ import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/follows/FollowTabHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/follows/FollowTabHeader.kt index f984dd38a0..6d07f2ece2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/follows/FollowTabHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/follows/FollowTabHeader.kt @@ -27,7 +27,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.number_following import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.follows.dal.UserProfileFollowsUserFeedViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/follows/TabFollows.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/follows/TabFollows.kt index 03f717429d..62993d5ae3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/follows/TabFollows.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/follows/TabFollows.kt @@ -32,10 +32,10 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserCompose import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.note.UserCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.follows.dal.UserProfileFollowsUserFeedViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/follows/dal/UserProfileFollowsUserFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/follows/dal/UserProfileFollowsUserFeedViewModel.kt index 038c9c118a..7d14f5fdc4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/follows/dal/UserProfileFollowsUserFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/follows/dal/UserProfileFollowsUserFeedViewModel.kt @@ -24,9 +24,9 @@ import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharingStarted diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/GalleryCardCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/GalleryCardCompose.kt index ab7322b1a8..6807e8465a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/GalleryCardCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/GalleryCardCompose.kt @@ -29,15 +29,15 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.CheckHiddenFeedWatchBlockAndReport -import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.CheckHiddenFeedWatchBlockAndReport +import com.vitorpamplona.amethyst.commons.ui.note.WatchNoteEvent +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.profileGallery.ProfileGalleryEntryEvent import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent import com.vitorpamplona.quartz.nip18Reposts.RepostEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/GalleryThumb.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/GalleryThumb.kt index 45e7ab52b9..934fc14e28 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/GalleryThumb.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/GalleryThumb.kt @@ -42,6 +42,7 @@ import coil3.compose.SubcomposeAsyncImageContent import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.play import com.vitorpamplona.amethyst.commons.richtext.MediaUrlContent @@ -49,20 +50,19 @@ import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo import com.vitorpamplona.amethyst.commons.richtext.RichTextParser.Companion.isHlsMimeType import com.vitorpamplona.amethyst.commons.richtext.RichTextParser.Companion.isVideoUrl +import com.vitorpamplona.amethyst.commons.ui.components.AutoNonlazyGrid import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.components.DisplayBlurHash import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.WatchAuthor +import com.vitorpamplona.amethyst.commons.ui.note.elements.BannerImage import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.commons.ui.theme.Size50Modifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.isHlsMedia -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.components.AutoNonlazyGrid -import com.vitorpamplona.amethyst.ui.components.DisplayBlurHash -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.note.WatchAuthor -import com.vitorpamplona.amethyst.ui.note.elements.BannerImage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.experimental.profileGallery.ProfileGalleryEntryEvent import com.vitorpamplona.quartz.nip53LiveActivities.clip.LiveActivitiesClipEvent import com.vitorpamplona.quartz.nip68Picture.PictureEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/ProfileGalleryFeed.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/ProfileGalleryFeed.kt index 3e6a73c0e3..8407656f48 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/ProfileGalleryFeed.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/ProfileGalleryFeed.kt @@ -38,11 +38,11 @@ import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled import com.vitorpamplona.amethyst.commons.ui.feeds.FeedEmpty import com.vitorpamplona.amethyst.commons.ui.feeds.FeedError import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed +import com.vitorpamplona.amethyst.commons.ui.feeds.PrefetchLoadedFeedMedia import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.FeedViewModel -import com.vitorpamplona.amethyst.ui.feeds.PrefetchLoadedFeedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @Composable fun RenderGalleryFeed( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/QuickActionGallery.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/QuickActionGallery.kt index 704a0abd3c..b8df4039c4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/QuickActionGallery.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/QuickActionGallery.kt @@ -29,9 +29,9 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.quick_action_delete_dialog_btn import com.vitorpamplona.amethyst.commons.resources.quick_action_request_deletion_gallery_alert_body_v2 import com.vitorpamplona.amethyst.commons.resources.quick_action_request_deletion_gallery_title +import com.vitorpamplona.amethyst.commons.ui.note.QuickActionAlertDialogOneButton import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.note.QuickActionAlertDialogOneButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun QuickActionGallery( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/TabGallery.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/TabGallery.kt index 7c933aa12c..8912863c06 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/TabGallery.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/TabGallery.kt @@ -27,8 +27,8 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.SaveableGridFeedState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.SaveableGridFeedState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.gallery.dal.UserProfileGalleryFeedViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/dal/UserProfileGalleryFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/dal/UserProfileGalleryFeedFilter.kt index 05cf74f316..c9b7901193 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/dal/UserProfileGalleryFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/dal/UserProfileGalleryFeedFilter.kt @@ -22,13 +22,13 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.gallery.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.profileGallery.ProfileGalleryEntryEvent import com.vitorpamplona.quartz.nip53LiveActivities.clip.LiveActivitiesClipEvent import com.vitorpamplona.quartz.nip68Picture.PictureEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/dal/UserProfileGalleryFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/dal/UserProfileGalleryFeedViewModel.kt index 050f7ffbef..ed760a427e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/dal/UserProfileGalleryFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/dal/UserProfileGalleryFeedViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.gallery.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel @Stable class UserProfileGalleryFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/hashtags/FollowedTagsTabHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/hashtags/FollowedTagsTabHeader.kt index 4de47108b8..7be9af6d15 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/hashtags/FollowedTagsTabHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/hashtags/FollowedTagsTabHeader.kt @@ -24,11 +24,11 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserTagFollowCount import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.followed_tags import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserTagFollowCount -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun FollowedTagsTabHeader( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/hashtags/TabFollowedTags.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/hashtags/TabFollowedTags.kt index c79de9489e..fcd6571a7a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/hashtags/TabFollowedTags.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/hashtags/TabFollowedTags.kt @@ -33,10 +33,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserTagFollows import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserTagFollows -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.HashtagHeader @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/Bolt12OffersDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/Bolt12OffersDialog.kt index d425f7f03e..0c89d5d432 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/Bolt12OffersDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/Bolt12OffersDialog.kt @@ -67,8 +67,8 @@ import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.payViaBolt12Intent -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.launch @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DisplayFollowUnfollowButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DisplayFollowUnfollowButton.kt index 73eb00e41a..ee238b69fd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DisplayFollowUnfollowButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DisplayFollowUnfollowButton.kt @@ -25,14 +25,14 @@ import androidx.compose.runtime.getValue import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.profile.ui.FollowButton import com.vitorpamplona.amethyst.commons.profile.ui.UnfollowButton +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserIsFollowing import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.follow import com.vitorpamplona.amethyst.commons.resources.follow_back import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_be_able_to_follow import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_be_able_to_unfollow import com.vitorpamplona.amethyst.commons.resources.read_only_user -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsFollowing -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun DisplayFollowUnfollowButton( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DisplayPaymentTargets.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DisplayPaymentTargets.kt index 4f65d19674..7a8d0a6936 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DisplayPaymentTargets.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DisplayPaymentTargets.kt @@ -37,7 +37,7 @@ import com.vitorpamplona.amethyst.commons.resources.no_payment_app_found_for_typ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.commons.ui.theme.Size16Modifier -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.payment.ProfilePaymentMethod import com.vitorpamplona.quartz.nipA3PaymentTargets.PaymentTarget import com.vitorpamplona.quartz.nipBCOnchainZaps.taproot.SegwitAddress diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DrawAdditionalInfo.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DrawAdditionalInfo.kt index ee6838f0a2..bcd53937ec 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DrawAdditionalInfo.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DrawAdditionalInfo.kt @@ -55,17 +55,22 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip05DnsIdentifiers.Nip05State +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.copy_nprofile_to_clipboard import com.vitorpamplona.amethyst.commons.resources.copy_npub_to_clipboard import com.vitorpamplona.amethyst.commons.resources.github +import com.vitorpamplona.amethyst.commons.resources.ic_qrcode import com.vitorpamplona.amethyst.commons.resources.mastodon import com.vitorpamplona.amethyst.commons.resources.show_nprofile_as_a_qr_code import com.vitorpamplona.amethyst.commons.resources.telegram import com.vitorpamplona.amethyst.commons.resources.twitter import com.vitorpamplona.amethyst.commons.resources.website +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.ObserveAndRenderNIP05VerifiedSymbol import com.vitorpamplona.amethyst.commons.ui.note.lastSeenSentence +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size15Modifier @@ -74,14 +79,11 @@ import com.vitorpamplona.amethyst.commons.ui.theme.SpacedBy5dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.util.toShortDisplay +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.UserExternalIdentitiesViewModel -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.components.util.LongPressCopyText import com.vitorpamplona.amethyst.ui.note.DrawPlayName -import com.vitorpamplona.amethyst.ui.note.ObserveAndRenderNIP05VerifiedSymbol import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header.apps.DisplayAppRecommendations import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header.apps.UserAppRecommendationsFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header.badges.DisplayBadges @@ -213,7 +215,7 @@ fun DrawAdditionalInfo( onClick = { nav.nav(Route.QRDisplay(baseUser.pubkeyHex)) }, ) { Icon( - painter = painterRes(R.drawable.ic_qrcode, 1), + painter = painterRes(Res.drawable.ic_qrcode, 1), contentDescription = stringRes(id = Res.string.show_nprofile_as_a_qr_code), modifier = Size15Modifier, tint = MaterialTheme.colorScheme.placeholderText, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DrawBanner.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DrawBanner.kt index 4e49948fa6..647bbdfc7c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DrawBanner.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DrawBanner.kt @@ -39,18 +39,17 @@ import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserBanner import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.profile_banner import com.vitorpamplona.amethyst.commons.resources.profile_image import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.commons.ui.components.util.setText +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserBanner +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.ZoomableImageDialog -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.launch @OptIn(ExperimentalFoundationApi::class) @@ -80,8 +79,8 @@ fun DrawBanner( model = banner, contentDescription = stringRes(id = Res.string.profile_image), contentScale = ContentScale.Crop, - placeholder = painterRes(R.drawable.profile_banner, 1), - error = painterRes(R.drawable.profile_banner, 1), + placeholder = painterRes(Res.drawable.profile_banner, 1), + error = painterRes(Res.drawable.profile_banner, 1), modifier = Modifier .fillMaxWidth() @@ -107,7 +106,7 @@ fun DrawBanner( } } else { Image( - painter = painterRes(R.drawable.profile_banner, 2), + painter = painterRes(Res.drawable.profile_banner, 2), contentDescription = stringRes(id = Res.string.profile_banner), contentScale = ContentScale.FillWidth, modifier = diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/MessageButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/MessageButton.kt index 28e5280263..61f0404f45 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/MessageButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/MessageButton.kt @@ -27,17 +27,17 @@ import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.ic_dm import com.vitorpamplona.amethyst.commons.resources.send_a_direct_message import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeToMessage +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.ZeroPadding -import com.vitorpamplona.amethyst.ui.navigation.routes.routeToMessage -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey @Composable @@ -62,7 +62,7 @@ fun MessageButton( contentPadding = ZeroPadding, ) { Icon( - painter = painterRes(R.drawable.ic_dm, 1), + painter = painterRes(Res.drawable.ic_dm, 1), stringRes(Res.string.send_a_direct_message), modifier = Size20Modifier, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/PaymentTargetsDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/PaymentTargetsDialog.kt index d1ed9b394a..d878498609 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/PaymentTargetsDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/PaymentTargetsDialog.kt @@ -65,9 +65,9 @@ import com.vitorpamplona.amethyst.commons.ui.components.M3ActionRow import com.vitorpamplona.amethyst.commons.ui.components.M3ActionSection import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.loadStringRes +import com.vitorpamplona.amethyst.commons.ui.note.ErrorMessageDialog import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier -import com.vitorpamplona.amethyst.ui.note.ErrorMessageDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.QrCodeDrawer import com.vitorpamplona.quartz.nipA3PaymentTargets.PaymentTarget import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfileActions.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfileActions.kt index a6ab23d442..1dda2b37e8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfileActions.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfileActions.kt @@ -28,10 +28,10 @@ import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.profile.ui.EditButton import com.vitorpamplona.amethyst.commons.profile.ui.ListButton +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.observeAccountIsHiddenUser import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.ShowUserButton -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.observeAccountIsHiddenUser -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun ProfileActions( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfileHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfileHeader.kt index 01cc8fc5b6..49f43cad99 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfileHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfileHeader.kt @@ -56,22 +56,22 @@ import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserPicture import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.upload_image import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size100dp import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp import com.vitorpamplona.amethyst.commons.ui.theme.userProfileBorderModifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.UserExternalIdentitiesViewModel -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserPicture import com.vitorpamplona.amethyst.ui.actions.NewUserMetadataViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelectSingle import com.vitorpamplona.amethyst.ui.components.ZoomableImageDialog -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header.apps.UserAppRecommendationsFeedViewModel import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfilePaymentRailChips.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfilePaymentRailChips.kt index 6ee12c1654..fef65c0796 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfilePaymentRailChips.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfilePaymentRailChips.kt @@ -58,6 +58,8 @@ import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip01Core.UserInfo +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.bolt12_lightning_offer import com.vitorpamplona.amethyst.commons.resources.clink_lightning_offer @@ -68,13 +70,11 @@ import com.vitorpamplona.amethyst.commons.resources.send_payment_method_lightnin import com.vitorpamplona.amethyst.commons.resources.send_payment_method_onchain import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.commons.ui.theme.Size16Modifier -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.payment.ProfilePaymentMethod import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.payment.rememberProfileClinkOffer import com.vitorpamplona.quartz.experimental.clink.pointers.NOffer diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfileTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfileTopBar.kt index 45b4e2785f..cd8ba6b90d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfileTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/ProfileTopBar.kt @@ -44,13 +44,13 @@ import com.vitorpamplona.amethyst.commons.resources.search_button import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.searchRouteFor import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.commons.ui.theme.ZeroPadding import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.navigation.topbars.searchRouteFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/UserNicknameCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/UserNicknameCard.kt index 5e666661c5..0ad2717538 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/UserNicknameCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/UserNicknameCard.kt @@ -42,15 +42,15 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.nip85TrustedAssertions.ui.EditNicknameDialog +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserNickname import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.nickname_private import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserNickname +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel /** * The nickname (petname) and private note the account keeps for [baseUser], diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/UserProfileDropDownMenu.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/UserProfileDropDownMenu.kt index 78f5d38f66..91bb215d53 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/UserProfileDropDownMenu.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/UserProfileDropDownMenu.kt @@ -48,10 +48,10 @@ import com.vitorpamplona.amethyst.commons.ui.components.M3ActionDialog import com.vitorpamplona.amethyst.commons.ui.components.M3ActionRow import com.vitorpamplona.amethyst.commons.ui.components.M3ActionSection import com.vitorpamplona.amethyst.commons.ui.components.util.setText +import com.vitorpamplona.amethyst.commons.ui.note.externalLinkForUser import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.creators.emojiSuggestions.WatchAndLoadMyEmojiList -import com.vitorpamplona.amethyst.ui.note.externalLinkForUser -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip56Reports.ReportType import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/apps/DisplayAppRecommendations.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/apps/DisplayAppRecommendations.kt index 8b15cee0da..f3d9f04abf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/apps/DisplayAppRecommendations.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/apps/DisplayAppRecommendations.kt @@ -52,8 +52,9 @@ import com.vitorpamplona.amethyst.commons.resources.profile_apps_header import com.vitorpamplona.amethyst.commons.resources.profile_apps_header_empty import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.profile.header.apps.AppRecommendationChip import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun DisplayAppRecommendations( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/apps/UserAppRecommendationsFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/apps/UserAppRecommendationsFeedViewModel.kt index a3210caed7..ea92ae0860 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/apps/UserAppRecommendationsFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/apps/UserAppRecommendationsFeedViewModel.kt @@ -24,7 +24,7 @@ import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel @Stable class UserAppRecommendationsFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/apps/UserProfileAppRecommendationsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/apps/UserProfileAppRecommendationsFeedFilter.kt index 2f9e87e4c6..0d096b6ad3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/apps/UserProfileAppRecommendationsFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/apps/UserProfileAppRecommendationsFeedFilter.kt @@ -21,10 +21,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header.apps import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip89AppHandlers.recommendation.AppRecommendationEvent import com.vitorpamplona.quartz.utils.flattenToSet diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/badges/DisplayBadges.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/badges/DisplayBadges.kt index ddb814058a..97eca91396 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/badges/DisplayBadges.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/badges/DisplayBadges.kt @@ -65,6 +65,8 @@ import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.badge_award_image import com.vitorpamplona.amethyst.commons.resources.badge_award_image_for @@ -74,13 +76,11 @@ import com.vitorpamplona.amethyst.commons.resources.profile_badges_title import com.vitorpamplona.amethyst.commons.ui.components.RobohashAsyncImage import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip58Badges.accepted.AcceptedBadgeSetEvent import com.vitorpamplona.quartz.nip58Badges.award.BadgeAwardEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/mutual/TabMutualConversations.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/mutual/TabMutualConversations.kt index 5ebd3fd3cd..6f7ee2d539 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/mutual/TabMutualConversations.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/mutual/TabMutualConversations.kt @@ -25,8 +25,8 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.mutual.dal.UserProfileMutualFeedViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/mutual/dal/UserProfileMutualFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/mutual/dal/UserProfileMutualFeedFilter.kt index 1af33308ff..dfbecdf667 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/mutual/dal/UserProfileMutualFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/mutual/dal/UserProfileMutualFeedFilter.kt @@ -22,12 +22,12 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.mutual.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.isRenderableRepost +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.agora.FundraiserEvent import com.vitorpamplona.quartz.experimental.audio.header.AudioHeaderEvent import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/mutual/dal/UserProfileMutualFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/mutual/dal/UserProfileMutualFeedViewModel.kt index 7863ae7525..cf1ca273b4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/mutual/dal/UserProfileMutualFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/mutual/dal/UserProfileMutualFeedViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.mutual.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel @Stable class UserProfileMutualFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/newthreads/TabNotesNewThreads.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/newthreads/TabNotesNewThreads.kt index d600bd16fd..ffa2d98cff 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/newthreads/TabNotesNewThreads.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/newthreads/TabNotesNewThreads.kt @@ -39,15 +39,15 @@ import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.commons.ui.feeds.FeedEmpty import com.vitorpamplona.amethyst.commons.ui.feeds.FeedError import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed +import com.vitorpamplona.amethyst.commons.ui.feeds.PrefetchLoadedFeedMedia import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox import com.vitorpamplona.amethyst.commons.ui.feeds.StickToTopOnPrepend import com.vitorpamplona.amethyst.commons.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.feeds.PrefetchLoadedFeedMedia -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.newthreads.dal.UserProfileNewThreadsFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.pinnedNotes.dal.UserProfilePinnedNotesFeedViewModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/newthreads/dal/UserProfileNewThreadFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/newthreads/dal/UserProfileNewThreadFeedFilter.kt index 561bc45837..e0d6330ba0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/newthreads/dal/UserProfileNewThreadFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/newthreads/dal/UserProfileNewThreadFeedFilter.kt @@ -22,12 +22,12 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.newthreads.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.isRenderableRepost +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.agora.FundraiserEvent import com.vitorpamplona.quartz.experimental.attestations.attestation.AttestationEvent import com.vitorpamplona.quartz.experimental.attestations.proficiency.AttestorProficiencyEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/newthreads/dal/UserProfileNewThreadsFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/newthreads/dal/UserProfileNewThreadsFeedViewModel.kt index 966c174a09..4ddf48e4bb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/newthreads/dal/UserProfileNewThreadsFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/newthreads/dal/UserProfileNewThreadsFeedViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.newthreads.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel @Stable class UserProfileNewThreadsFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/payment/ProfileClinkOfferResolver.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/payment/ProfileClinkOfferResolver.kt index a7f62be4e2..2709eb4916 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/payment/ProfileClinkOfferResolver.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/payment/ProfileClinkOfferResolver.kt @@ -28,7 +28,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import com.vitorpamplona.amethyst.commons.model.nip01Core.UserInfo -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.clink.pointers.ClinkPointerParser import com.vitorpamplona.quartz.experimental.clink.pointers.NOffer import com.vitorpamplona.quartz.nip05DnsIdentifiers.Nip05Id diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/payment/SendPaymentScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/payment/SendPaymentScreen.kt index 0d2c6bdd90..045e37ad70 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/payment/SendPaymentScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/payment/SendPaymentScreen.kt @@ -44,6 +44,8 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.model.DEFAULT_ONCHAIN_ZAP_SATS +import com.vitorpamplona.amethyst.commons.model.MIN_ONCHAIN_ZAP_SATS import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.payments.PaymentSource @@ -51,6 +53,8 @@ import com.vitorpamplona.amethyst.commons.model.payments.PaymentSourceResolver import com.vitorpamplona.amethyst.commons.onchain.OnchainZapSendResult import com.vitorpamplona.amethyst.commons.onchain.ui.technicalDetail import com.vitorpamplona.amethyst.commons.onchain.ui.userMessage +import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.clink_debit_no_response import com.vitorpamplona.amethyst.commons.resources.clink_offer_amount_range @@ -92,24 +96,20 @@ import com.vitorpamplona.amethyst.commons.resources.zap_type_private import com.vitorpamplona.amethyst.commons.resources.zap_type_private_explainer import com.vitorpamplona.amethyst.commons.resources.zap_type_public import com.vitorpamplona.amethyst.commons.resources.zap_type_public_explainer +import com.vitorpamplona.amethyst.commons.service.nwc.nwcFailureDetail +import com.vitorpamplona.amethyst.commons.service.nwc.nwcTimeoutMessage import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeToMessage import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.model.DEFAULT_ONCHAIN_ZAP_SATS -import com.vitorpamplona.amethyst.model.MIN_ONCHAIN_ZAP_SATS +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.ClinkOfferPayer -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.UserFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.ui.navigation.routes.routeToMessage -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.ui.note.payViaIntent -import com.vitorpamplona.amethyst.ui.nwc.nwcFailureDetail -import com.vitorpamplona.amethyst.ui.nwc.nwcTimeoutMessage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.FeeTier import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.rateFor import com.vitorpamplona.quartz.experimental.clink.common.SatRange @@ -479,7 +479,6 @@ private fun SendPaymentLoaded( onNewInvoice = { invoice -> scope.launch { payBolt11(invoice) } }, onError = { _, msg -> scope.launch { postStage(PaymentFlowStage.Failure(msg)) } }, onProgress = {}, - context = context, zapType = zapType, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/pinnedNotes/PinnedNotesTabHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/pinnedNotes/PinnedNotesTabHeader.kt index 2b5330b07a..572d863413 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/pinnedNotes/PinnedNotesTabHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/pinnedNotes/PinnedNotesTabHeader.kt @@ -24,11 +24,11 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserPinnedNotesCount import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.pinned_notes import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserPinnedNotesCount -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun PinnedNotesTabHeader( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/pinnedNotes/TabPinnedNotes.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/pinnedNotes/TabPinnedNotes.kt index 5653e4a29a..b31a6fa4ab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/pinnedNotes/TabPinnedNotes.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/pinnedNotes/TabPinnedNotes.kt @@ -28,8 +28,8 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.pinnedNotes.dal.UserProfilePinnedNotesFeedViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/pinnedNotes/dal/UserProfilePinnedNotesFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/pinnedNotes/dal/UserProfilePinnedNotesFeedFilter.kt index a6581aaa69..3e5e8ee5ff 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/pinnedNotes/dal/UserProfilePinnedNotesFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/pinnedNotes/dal/UserProfilePinnedNotesFeedFilter.kt @@ -21,10 +21,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.pinnedNotes.dal import com.vitorpamplona.amethyst.commons.feeds.FeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip51Lists.PinListEvent class UserProfilePinnedNotesFeedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/pinnedNotes/dal/UserProfilePinnedNotesFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/pinnedNotes/dal/UserProfilePinnedNotesFeedViewModel.kt index 028a33a1b1..939131cfab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/pinnedNotes/dal/UserProfilePinnedNotesFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/pinnedNotes/dal/UserProfilePinnedNotesFeedViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.pinnedNotes.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel @Stable class UserProfilePinnedNotesFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/relays/RelayFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/relays/RelayFeedView.kt index 88214cac18..9bd8dff391 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/relays/RelayFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/relays/RelayFeedView.kt @@ -43,11 +43,11 @@ import com.vitorpamplona.amethyst.commons.resources.public_notif_section import com.vitorpamplona.amethyst.commons.resources.public_notif_section_explainer_profile import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.RelayCompose import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.MyRelayInfo import com.vitorpamplona.amethyst.commons.viewmodels.RelayFeedViewModel -import com.vitorpamplona.amethyst.ui.note.RelayCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.SettingsCategory import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/relays/TabRelays.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/relays/TabRelays.kt index 94a32f6e90..e88dedd638 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/relays/TabRelays.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/relays/TabRelays.kt @@ -31,8 +31,8 @@ import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.RelayFeedViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @Composable fun TabRelays( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/reports/ReportsTabHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/reports/ReportsTabHeader.kt index 99dc841385..db54f9d6f8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/reports/ReportsTabHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/reports/ReportsTabHeader.kt @@ -29,7 +29,7 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.number_reports import com.vitorpamplona.amethyst.commons.resources.reports import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.reports.dal.UserProfileReportFeedViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/reports/TabReports.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/reports/TabReports.kt index 4f3ba3d7ee..f6aea85cf3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/reports/TabReports.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/reports/TabReports.kt @@ -35,10 +35,10 @@ import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.reports.dal.UserProfileReportFeedViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/reports/dal/UserProfileReportFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/reports/dal/UserProfileReportFeedViewModel.kt index 906e191a0a..70f1dd0a2b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/reports/dal/UserProfileReportFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/reports/dal/UserProfileReportFeedViewModel.kt @@ -24,9 +24,9 @@ import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.model.Account import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/TabReceivedZaps.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/TabReceivedZaps.kt index 1bc24ec6d5..fd714997ed 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/TabReceivedZaps.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/TabReceivedZaps.kt @@ -34,7 +34,7 @@ import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.zaps.dal.UserProfileZapsViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/ZapNoteCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/ZapNoteCompose.kt index fa36cb56dd..9eeb4f3cc1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/ZapNoteCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/ZapNoteCompose.kt @@ -38,16 +38,16 @@ import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.ui.layouts.listItem.SlimListItem import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.UserActionOptions +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.util.showAmountInteger -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.UserActionOptions -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.zaps.dal.ZapAmount import com.vitorpamplona.quartz.utils.BigDecimal diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/ZapTabHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/ZapTabHeader.kt index 186ea85888..113750a506 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/ZapTabHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/ZapTabHeader.kt @@ -28,7 +28,7 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.zaps import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.util.showAmountInteger -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.zaps.dal.UserProfileZapsViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/dal/UserProfileZapsViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/dal/UserProfileZapsViewModel.kt index db71a85712..31f5b82918 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/dal/UserProfileZapsViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/dal/UserProfileZapsViewModel.kt @@ -25,9 +25,9 @@ import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/PublicChatsFeedLoaded.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/PublicChatsFeedLoaded.kt index 53f73eac3d..9190b18848 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/PublicChatsFeedLoaded.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/PublicChatsFeedLoaded.kt @@ -47,18 +47,18 @@ 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 +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.CheckHiddenFeedWatchBlockAndReport +import com.vitorpamplona.amethyst.commons.ui.note.ClickableNote +import com.vitorpamplona.amethyst.commons.ui.note.LongPressToQuickAction +import com.vitorpamplona.amethyst.commons.ui.note.WatchNoteEvent +import com.vitorpamplona.amethyst.commons.ui.note.calculateBackgroundColor import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.note.CheckHiddenFeedWatchBlockAndReport -import com.vitorpamplona.amethyst.ui.note.ClickableNote -import com.vitorpamplona.amethyst.ui.note.LongPressToQuickAction -import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent -import com.vitorpamplona.amethyst.ui.note.calculateBackgroundColor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip28Chats.RenderPublicChatChannelThumb @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/PublicChatsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/PublicChatsScreen.kt index 54752b3e35..66bb155ece 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/PublicChatsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/PublicChatsScreen.kt @@ -28,15 +28,15 @@ import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.nip28PublicChat.ui.NewPublicChatButton import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.publicChats.datasource.PublicChatsFilterAssemblerSubscription @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/PublicChatsTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/PublicChatsTopBar.kt index 0d6cdd2a1c..423d0517c0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/PublicChatsTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/PublicChatsTopBar.kt @@ -23,17 +23,17 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.publicChats import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelMetadataEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/datasource/PublicChatsFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/datasource/PublicChatsFilterAssemblerSubscription.kt index 546a20c48c..14be5c7925 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/datasource/PublicChatsFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/datasource/PublicChatsFilterAssemblerSubscription.kt @@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.publicChats.PublicChatsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun PublicChatsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/qrcode/QrCodeScanner.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/qrcode/QrCodeScanner.kt index 4de3518bdd..f935fd2575 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/qrcode/QrCodeScanner.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/qrcode/QrCodeScanner.kt @@ -24,7 +24,7 @@ import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.qrcode.ScannedPayload import com.vitorpamplona.amethyst.commons.qrcode.classifyScannedPayload -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.scanner.QrCodeScannerDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.scanner.ScanOutcome import com.vitorpamplona.amethyst.ui.uriToRoute diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/qrcode/ScanQrImageScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/qrcode/ScanQrImageScreen.kt index 2455252811..66e4b35358 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/qrcode/ScanQrImageScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/qrcode/ScanQrImageScreen.kt @@ -56,7 +56,7 @@ import com.vitorpamplona.amethyst.commons.resources.scan_qr import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.scanner.QrImageImport import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.scanner.ZxingCppBarcodeDecoder import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.scanner.copyToClipboard diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/qrcode/ShowQRScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/qrcode/ShowQRScreen.kt index fc0f30163e..cfda159a4b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/qrcode/ShowQRScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/qrcode/ShowQRScreen.kt @@ -50,6 +50,7 @@ import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.nip05DnsIdentifiers.Nip05State +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.profile_image import com.vitorpamplona.amethyst.commons.resources.scan_qr @@ -59,6 +60,8 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.ObserveAndDisplayNIP05 import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes @@ -66,11 +69,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Font14SP import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp import com.vitorpamplona.amethyst.commons.ui.theme.largeProfilePictureModifier -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.ui.note.ObserveAndDisplayNIP05 -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent import com.vitorpamplona.quartz.nip01Core.metadata.UserMetadata diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/redirect/LoadRedirectScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/redirect/LoadRedirectScreen.kt index 02a3d3cf14..9a20f90a6d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/redirect/LoadRedirectScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/redirect/LoadRedirectScreen.kt @@ -37,20 +37,20 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteLocally import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.looking_for_event import com.vitorpamplona.amethyst.commons.resources.looking_for_event_title import com.vitorpamplona.amethyst.commons.resources.looking_for_private_event +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.Nav -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/NewRelayNoteButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/NewRelayNoteButton.kt index 10f59830eb..2597c7e193 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/NewRelayNoteButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/NewRelayNoteButton.kt @@ -25,16 +25,16 @@ import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.ic_compose import com.vitorpamplona.amethyst.commons.resources.new_community_note import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun NewRelayNoteButton( @@ -50,7 +50,7 @@ fun NewRelayNoteButton( containerColor = MaterialTheme.colorScheme.primary, ) { Icon( - painter = painterRes(R.drawable.ic_compose, 3), + painter = painterRes(Res.drawable.ic_compose, 3), contentDescription = stringRes(id = Res.string.new_community_note), modifier = Size26Modifier, tint = MaterialTheme.colorScheme.onPrimary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/RelayFeedScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/RelayFeedScreen.kt index 4d24a10b04..2ebfd0745b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/RelayFeedScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/RelayFeedScreen.kt @@ -29,18 +29,18 @@ import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.profile.ui.FollowButton import com.vitorpamplona.amethyst.commons.profile.ui.UnfollowButton +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserIsFollowingRelay import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_be_able_to_follow import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_be_able_to_unfollow import com.vitorpamplona.amethyst.commons.resources.read_only_user import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsFollowingRelay -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relay.dal.SingleRelayFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relay.datasource.RelayFeedFilterAssemblerSubscription import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/dal/RelayFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/dal/RelayFeedFilter.kt index 13e15c7c88..197a39408e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/dal/RelayFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/dal/RelayFeedFilter.kt @@ -21,10 +21,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.relay.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl class RelayFeedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/dal/SingleRelayFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/dal/SingleRelayFeedViewModel.kt index 9403ea9f3e..f4ec796d47 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/dal/SingleRelayFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/dal/SingleRelayFeedViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.relay.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @Stable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/datasource/RelayFeedFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/datasource/RelayFeedFilterAssemblerSubscription.kt index 22ae1ead78..c1bf03daa0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/datasource/RelayFeedFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relay/datasource/RelayFeedFilterAssemblerSubscription.kt @@ -25,7 +25,7 @@ import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.relayClient.relay.RelayFeedQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relayauth/RelayAuthSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relayauth/RelayAuthSettingsScreen.kt index 23d56d30ce..dffe0b19b5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relayauth/RelayAuthSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relayauth/RelayAuthSettingsScreen.kt @@ -70,6 +70,7 @@ import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo import com.vitorpamplona.amethyst.commons.relayauth.AuthPurposeKind import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthDecision import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthPermissionStore @@ -117,9 +118,8 @@ import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.MediumRelayIconModifier import com.vitorpamplona.amethyst.commons.ui.theme.RelayIconFilter -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.relayClient.authCommand.compose.relayAuthPurposeLabelRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsDivider import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsSwitchTile import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/AllRelayListScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/AllRelayListScreen.kt index 42082044f7..19d92b8115 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/AllRelayListScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/AllRelayListScreen.kt @@ -96,7 +96,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.RowColSpacing import com.vitorpamplona.amethyst.commons.ui.theme.SettingsCategoryFirstWithHorzBorderModifier import com.vitorpamplona.amethyst.commons.ui.theme.SettingsCategorySpacingWithHorzBorderModifier import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.blocked.BlockedRelayListViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.blocked.renderBlockedItems import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.broadcast.BroadcastRelayListViewModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/RelayInformationScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/RelayInformationScreen.kt index b58379d4a3..e566d7e6de 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/RelayInformationScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/RelayInformationScreen.kt @@ -72,12 +72,12 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.accepts_up_to import com.vitorpamplona.amethyst.commons.resources.access_control @@ -158,8 +158,16 @@ import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled import com.vitorpamplona.amethyst.commons.ui.components.appendLink import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.RenderRelayIcon +import com.vitorpamplona.amethyst.commons.ui.note.UserCompose +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.graspLink +import com.vitorpamplona.amethyst.commons.ui.note.nipLink import com.vitorpamplona.amethyst.commons.ui.note.timeAgoNoDot import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.KindChip import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.commons.ui.theme.Height25Modifier @@ -170,23 +178,12 @@ import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor -import com.vitorpamplona.amethyst.commons.ui.theme.bitcoinColor -import com.vitorpamplona.amethyst.commons.ui.theme.redColorOnSecondSurface import com.vitorpamplona.amethyst.commons.ui.theme.warningColor import com.vitorpamplona.amethyst.commons.util.timeDiffAgoShortish -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo -import com.vitorpamplona.amethyst.ui.note.RenderRelayIcon -import com.vitorpamplona.amethyst.ui.note.UserCompose -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.graspLink -import com.vitorpamplona.amethyst.ui.note.nipLink -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.BackButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.datasource.RelayInfoNip66FilterAssemblerSubscription -import com.vitorpamplona.quartz.kinds.KindNames import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.stats.ErrorDebugMessage import com.vitorpamplona.quartz.nip01Core.relay.client.stats.IRelayDebugMessage @@ -198,13 +195,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl -import com.vitorpamplona.quartz.nip09Deletions.DeletionRequestEvent import com.vitorpamplona.quartz.nip11RelayInfo.Nip11RelayInformation -import com.vitorpamplona.quartz.nip51Lists.muteList.MuteListEvent -import com.vitorpamplona.quartz.nip56Reports.ReportEvent -import com.vitorpamplona.quartz.nip59Giftwrap.wraps.EphemeralGiftWrapEvent -import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent -import com.vitorpamplona.quartz.nip62RequestToVanish.RequestToVanishEvent import com.vitorpamplona.quartz.nip66RelayMonitor.discovery.RelayDiscoveryEvent import com.vitorpamplona.quartz.nip86RelayManagement.Nip86Client import com.vitorpamplona.quartz.utils.TimeUtils @@ -270,7 +261,7 @@ fun RelayInformationScreen( val messages = remember(relay) { - Amethyst.instance.relayStats + accountViewModel.host.relayStats .get(url = relay) .messages .snapshot() @@ -279,7 +270,7 @@ fun RelayInformationScreen( .toImmutableList() } - RelayInformationBody(relay, relayInfo, discoveryEvents, Amethyst.instance.relayStats.get(relay), messages, pad, accountViewModel, nav) + RelayInformationBody(relay, relayInfo, discoveryEvents, accountViewModel.host.relayStats.get(relay), messages, pad, accountViewModel, nav) } } @@ -474,58 +465,6 @@ fun RelayInformationBody( // Active subscriptions + outbox display // --------------------------------------------------------------------------- -val posts = setOf(0, 1, 6, 7, 16, 30023) -val settings = setOf(3, 10002, 10000, 10001, 10003, 10004, 30000) -val dms = setOf(4, GiftWrapEvent.KIND, EphemeralGiftWrapEvent.KIND, 10050) -val zaps = setOf(9734, 9735, 9041, 17375, 23194, 23195) -val reports = setOf(ReportEvent.KIND, MuteListEvent.KIND, DeletionRequestEvent.KIND, RequestToVanishEvent.KIND) - -@Composable -fun KindChip(kind: Int) { - val nameResId = kindDisplayName(kind) - val name = if (nameResId != null) stringRes(nameResId) else (KindNames.nameFor(kind) ?: "k$kind") - val (bg, fg) = - when (kind) { - in posts -> { - MaterialTheme.colorScheme.primaryContainer to MaterialTheme.colorScheme.onPrimaryContainer - } - - // - in settings -> { - MaterialTheme.colorScheme.secondaryContainer to MaterialTheme.colorScheme.onSecondaryContainer - } - - // dms - in dms -> { - MaterialTheme.colorScheme.tertiaryContainer to MaterialTheme.colorScheme.onTertiaryContainer - } - - // zaps - in zaps -> { - MaterialTheme.colorScheme.background to MaterialTheme.colorScheme.bitcoinColor - } - - in reports -> { - MaterialTheme.colorScheme.secondaryContainer to MaterialTheme.colorScheme.redColorOnSecondSurface - } - - else -> { - MaterialTheme.colorScheme.surfaceVariant to MaterialTheme.colorScheme.onSurfaceVariant - } - } - Surface( - shape = RoundedCornerShape(50), - color = bg, - ) { - Text( - text = name, - modifier = Modifier.padding(horizontal = 8.dp, vertical = 3.dp), - style = MaterialTheme.typography.labelSmall.copy(fontFamily = FontFamily.Monospace), - color = fg, - ) - } -} - @Composable private fun FilterAttributeChip( text: String, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/blocked/BlockedRelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/blocked/BlockedRelayListView.kt index ffd826e64f..e8151d24fe 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/blocked/BlockedRelayListView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/blocked/BlockedRelayListView.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav @@ -37,8 +37,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField @@ -80,7 +80,7 @@ fun LazyListScope.renderBlockedItems( BasicRelaySetupInfoDialog( item, onDelete = { postViewModel.deleteRelay(item) }, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = HorzHalfVertPadding, index = index, dragState = dragState, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/broadcast/BroadcastRelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/broadcast/BroadcastRelayListView.kt index 496fdea25a..9c34b539c1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/broadcast/BroadcastRelayListView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/broadcast/BroadcastRelayListView.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav @@ -37,8 +37,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField @@ -80,7 +80,7 @@ fun LazyListScope.renderBroadcastItems( BasicRelaySetupInfoDialog( item, onDelete = { postViewModel.deleteRelay(item) }, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = HorzHalfVertPadding, index = index, dragState = dragState, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/BasicRelaySetupInfoClickableRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/BasicRelaySetupInfoClickableRow.kt index a9f424323e..995e4c5227 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/BasicRelaySetupInfoClickableRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/BasicRelaySetupInfoClickableRow.kt @@ -41,6 +41,7 @@ import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.Nip11CachedRetriever import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState @@ -52,6 +53,8 @@ import com.vitorpamplona.amethyst.commons.resources.and_more import com.vitorpamplona.amethyst.commons.resources.relay_reorder import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.RenderRelayIcon +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.HalfHalfVertPadding @@ -60,10 +63,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Height25Modifier import com.vitorpamplona.amethyst.commons.ui.theme.LargeRelayIconModifier import com.vitorpamplona.amethyst.commons.ui.theme.ReactionRowHeightChatMaxWidth import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo -import com.vitorpamplona.amethyst.ui.note.RenderRelayIcon -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/BasicRelaySetupInfoDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/BasicRelaySetupInfoDialog.kt index 85fe0a2ad8..1f440f217f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/BasicRelaySetupInfoDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/BasicRelaySetupInfoDialog.kt @@ -28,7 +28,7 @@ import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun BasicRelaySetupInfoDialog( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/BasicRelaySetupInfoModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/BasicRelaySetupInfoModel.kt index 03513f549a..7d565eef51 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/BasicRelaySetupInfoModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/BasicRelaySetupInfoModel.kt @@ -23,11 +23,12 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.ui.CountFilter import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult import com.vitorpamplona.amethyst.commons.util.replace -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.count import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.Dispatchers @@ -77,7 +78,7 @@ abstract class BasicRelaySetupInfoModel : ViewModel() { fun loadRelayDocuments() { viewModelScope.launch(Dispatchers.IO) { _relays.value.forEach { item -> - Amethyst.instance.nip11Cache.loadRelayInfo( + LocalCache.appHost.nip11Cache.loadRelayInfo( relay = item.relay, onInfo = { togglePaidRelay(item, it.limitation?.payment_required ?: false) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/RelayNameAndRemoveButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/RelayNameAndRemoveButton.kt index 0689224066..c4b8f3205f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/RelayNameAndRemoveButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/RelayNameAndRemoveButton.kt @@ -36,18 +36,18 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -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.resources.Res +import com.vitorpamplona.amethyst.commons.resources.ic_tor import com.vitorpamplona.amethyst.commons.resources.paid_relay import com.vitorpamplona.amethyst.commons.resources.remove import com.vitorpamplona.amethyst.commons.resources.tor_relay import com.vitorpamplona.amethyst.commons.ui.components.util.setText +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.LightRedColor import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor -import com.vitorpamplona.amethyst.ui.painterRes import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import kotlinx.coroutines.launch @@ -92,7 +92,7 @@ fun RelayNameAndRemoveButton( if (item.forcesTor) { Icon( - painter = painterRes(R.drawable.ic_tor, 2), + painter = painterRes(Res.drawable.ic_tor, 2), contentDescription = stringRes(id = Res.string.tor_relay), modifier = Modifier diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/RelayStatusRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/RelayStatusRow.kt index d9c55f6e90..c239545f84 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/RelayStatusRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/RelayStatusRow.kt @@ -54,8 +54,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.redColorOnSecondSurface import com.vitorpamplona.amethyst.commons.ui.theme.warningColor import com.vitorpamplona.amethyst.commons.util.countToHumanReadable import com.vitorpamplona.amethyst.commons.util.countToHumanReadableBytes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStat import com.vitorpamplona.quartz.nip01Core.relay.normalizer.normalizeRelayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/RelayUrlEditField.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/RelayUrlEditField.kt index c069ff51dd..bc35ac9fcc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/RelayUrlEditField.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/RelayUrlEditField.kt @@ -44,7 +44,7 @@ import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.Nip11CachedRetriever import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.add @@ -59,8 +59,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.PopupUpEffect import com.vitorpamplona.amethyst.commons.ui.theme.StdEndPadding import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStat import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer @@ -137,7 +137,7 @@ fun RelayUrlEditField( ) { RelayUrlEditField( onNewRelay = onNewRelay, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = modifier, accountViewModel = accountViewModel, nav = nav, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/ShowRelaySuggestionList.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/ShowRelaySuggestionList.kt index 3c9c6771c1..81d2290cb7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/ShowRelaySuggestionList.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/ShowRelaySuggestionList.kt @@ -31,7 +31,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.HalfVertPadding -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/connected/ConnectedRelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/connected/ConnectedRelayListView.kt index 74ba69fdf2..062c3c4b3c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/connected/ConnectedRelayListView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/connected/ConnectedRelayListView.kt @@ -36,7 +36,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.active_subs_title @@ -44,8 +44,8 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog @@ -98,7 +98,7 @@ fun LazyListScope.renderConnectedItems( BasicRelaySetupInfoDialog( item, onDelete = null, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = HorzHalfVertPadding, accountViewModel = accountViewModel, nav = nav, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/datasource/RelayInfoNip66FilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/datasource/RelayInfoNip66FilterAssemblerSubscription.kt index 15c6e42d7a..67a4f6789e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/datasource/RelayInfoNip66FilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/datasource/RelayInfoNip66FilterAssemblerSubscription.kt @@ -24,7 +24,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.relays.RelayInfoNip66QueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/dm/AddDMRelayListDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/dm/AddDMRelayListDialog.kt index 4161841e8a..0da5a916ab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/dm/AddDMRelayListDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/dm/AddDMRelayListDialog.kt @@ -48,8 +48,8 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SavingTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.SetDialogToEdgeToEdge -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder @OptIn(ExperimentalMaterial3Api::class) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/dm/DMRelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/dm/DMRelayListView.kt index 08edc9168a..33f942ae34 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/dm/DMRelayListView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/dm/DMRelayListView.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState @@ -38,8 +38,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField @@ -83,7 +83,7 @@ fun LazyListScope.renderDMItems( BasicRelaySetupInfoDialog( item, onDelete = { postViewModel.deleteRelay(item) }, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = HorzHalfVertPadding, countResult = countResults[item.relay], index = index, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/feeds/RelayFeedsListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/feeds/RelayFeedsListView.kt index cf07d2053d..31e185a97d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/feeds/RelayFeedsListView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/feeds/RelayFeedsListView.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav @@ -37,8 +37,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField @@ -80,7 +80,7 @@ fun LazyListScope.renderRelayFeedsItems( BasicRelaySetupInfoDialog( item, onDelete = { postViewModel.deleteRelay(item) }, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = HorzHalfVertPadding, index = index, dragState = dragState, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/indexer/IndexerRelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/indexer/IndexerRelayListView.kt index 08f3df803a..cee70e71e7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/indexer/IndexerRelayListView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/indexer/IndexerRelayListView.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState @@ -38,8 +38,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField @@ -83,7 +83,7 @@ fun LazyListScope.renderIndexerItems( BasicRelaySetupInfoDialog( item, onDelete = { postViewModel.deleteRelay(item) }, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = HorzHalfVertPadding, countResult = countResults[item.relay], index = index, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/keyPackage/KeyPackageRelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/keyPackage/KeyPackageRelayListView.kt index eb9fcc46a4..2ab30391a2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/keyPackage/KeyPackageRelayListView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/keyPackage/KeyPackageRelayListView.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState @@ -38,8 +38,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField @@ -83,7 +83,7 @@ fun LazyListScope.renderKeyPackageItems( BasicRelaySetupInfoDialog( item, onDelete = { postViewModel.deleteRelay(item) }, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = HorzHalfVertPadding, countResult = countResults[item.relay], index = index, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/local/LocalRelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/local/LocalRelayListView.kt index 364bb70e4b..e2237a6b2c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/local/LocalRelayListView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/local/LocalRelayListView.kt @@ -30,7 +30,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState import com.vitorpamplona.amethyst.commons.resources.Res @@ -42,8 +42,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.SettingsCategorySpacingWithHorzBorderModifier import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField @@ -86,7 +86,7 @@ fun LazyListScope.renderLocalItems( BasicRelaySetupInfoDialog( item, onDelete = { postViewModel.deleteRelay(item) }, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = HorzHalfVertPadding, index = index, dragState = dragState, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip37/PrivateOutboxRelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip37/PrivateOutboxRelayListView.kt index dccf00cc76..9dd50e8875 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip37/PrivateOutboxRelayListView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip37/PrivateOutboxRelayListView.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState @@ -38,8 +38,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField @@ -83,7 +83,7 @@ fun LazyListScope.renderPrivateOutboxItems( BasicRelaySetupInfoDialog( item, onDelete = { postViewModel.deleteRelay(item) }, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = HorzHalfVertPadding, countResult = countResults[item.relay], index = index, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip65/Nip65RelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip65/Nip65RelayListView.kt index c94344097f..11942cfbca 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip65/Nip65RelayListView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip65/Nip65RelayListView.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState @@ -38,8 +38,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField @@ -142,7 +142,7 @@ fun LazyListScope.renderNip65HomeItems( BasicRelaySetupInfoDialog( item, onDelete = { postViewModel.deleteHomeRelay(item) }, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = HorzHalfVertPadding, countResult = countResults[item.relay], index = index, @@ -175,7 +175,7 @@ fun LazyListScope.renderNip65NotifItems( BasicRelaySetupInfoDialog( item, onDelete = { postViewModel.deleteNotifRelay(item) }, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = HorzHalfVertPadding, countResult = countResults[item.relay], index = index, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip65/Nip65RelayListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip65/Nip65RelayListViewModel.kt index ae648c9a07..fa8c1450ca 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip65/Nip65RelayListViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip65/Nip65RelayListViewModel.kt @@ -23,14 +23,14 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.nip65 import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.events_from_you import com.vitorpamplona.amethyst.commons.resources.events_to_you import com.vitorpamplona.amethyst.commons.util.replace -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.count @@ -104,7 +104,7 @@ class Nip65RelayListViewModel : ViewModel() { fun loadRelayDocuments() { viewModelScope.launch(Dispatchers.IO) { _homeRelays.value.forEach { item -> - Amethyst.instance.nip11Cache.loadRelayInfo( + LocalCache.appHost.nip11Cache.loadRelayInfo( relay = item.relay, onInfo = { toggleHomePaidRelay(item, it.limitation?.payment_required ?: false) @@ -114,7 +114,7 @@ class Nip65RelayListViewModel : ViewModel() { } _notificationRelays.value.forEach { item -> - Amethyst.instance.nip11Cache.loadRelayInfo( + LocalCache.appHost.nip11Cache.loadRelayInfo( relay = item.relay, onInfo = { toggleNotifPaidRelay(item, it.limitation?.payment_required ?: false) @@ -129,7 +129,7 @@ class Nip65RelayListViewModel : ViewModel() { _homeCountResults.value = emptyMap() _notifCountResults.value = emptyMap() - val client = Amethyst.instance.client + val client = accountViewModel.account.client _homeRelays.value.forEach { item -> viewModelScope.launch(Dispatchers.IO) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip86/RelayManagementScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip86/RelayManagementScreen.kt index 0ad8237f2f..7b69acfd25 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip86/RelayManagementScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip86/RelayManagementScreen.kt @@ -78,6 +78,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip05DnsIdentifiers.Nip05State +import com.vitorpamplona.amethyst.commons.relayClient.searchCommand.UserSearchDataSourceSubscription import com.vitorpamplona.amethyst.commons.relayManagement.Nip86Retriever import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.relay_management_add @@ -129,7 +130,14 @@ import com.vitorpamplona.amethyst.commons.resources.relay_management_title import com.vitorpamplona.amethyst.commons.resources.search_and_add_a_user import com.vitorpamplona.amethyst.commons.ui.layouts.listItem.SlimListItem import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.AboutDisplay import com.vitorpamplona.amethyst.commons.ui.note.ClearTextIcon +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.ObserveAndRenderNIP05VerifiedSymbol +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.AnimateOnNewSearch +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.kindDisplayName import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.Font14SP @@ -138,16 +146,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp import com.vitorpamplona.amethyst.commons.ui.theme.SmallBorder import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.nip05 -import com.vitorpamplona.amethyst.service.relayClient.searchCommand.UserSearchDataSourceSubscription -import com.vitorpamplona.amethyst.ui.note.AboutDisplay -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.ObserveAndRenderNIP05VerifiedSymbol -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.AnimateOnNewSearch -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.BackButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.kindDisplayName import com.vitorpamplona.quartz.kinds.KindNames import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip86/RelayManagementViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip86/RelayManagementViewModel.kt index b67f9fa9c8..8e58e5c828 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip86/RelayManagementViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip86/RelayManagementViewModel.kt @@ -23,10 +23,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.nip86 import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relayManagement.Nip86Retriever -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip86RelayManagement.Nip86Client import com.vitorpamplona.quartz.nip86RelayManagement.rpc.AllowedEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/proxy/ProxyRelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/proxy/ProxyRelayListView.kt index 9e2048109d..7c1fde3709 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/proxy/ProxyRelayListView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/proxy/ProxyRelayListView.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState @@ -38,8 +38,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField @@ -83,7 +83,7 @@ fun LazyListScope.renderProxyItems( BasicRelaySetupInfoDialog( item, onDelete = { postViewModel.deleteRelay(item) }, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = HorzHalfVertPadding, countResult = countResults[item.relay], index = index, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/search/SearchRelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/search/SearchRelayListView.kt index c6555fcf87..2a3ce83c58 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/search/SearchRelayListView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/search/SearchRelayListView.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.ui.RelayCountResult import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState @@ -38,8 +38,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField @@ -83,7 +83,7 @@ fun LazyListScope.renderSearchItems( BasicRelaySetupInfoDialog( item, onDelete = { postViewModel.deleteRelay(item) }, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = HorzHalfVertPadding, countResult = countResults[item.relay], index = index, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/subscriptions/ActiveSubscriptionsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/subscriptions/ActiveSubscriptionsScreen.kt index 67146fe09a..ef75453d74 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/subscriptions/ActiveSubscriptionsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/subscriptions/ActiveSubscriptionsScreen.kt @@ -60,6 +60,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedTopNavPerRelayFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allFollows.AllFollowsTopNavPerRelayFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.aroundMe.LocationTopNavPerRelayFilter @@ -96,10 +97,9 @@ import com.vitorpamplona.amethyst.commons.ui.theme.RelayIconFilter import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.warningColor -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName import com.vitorpamplona.amethyst.ui.pluralStringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.loadMarmotRelayIcon import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.rememberMarmotGroupAvatarUrl import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.rememberConcordImageModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/trusted/TrustedRelayListView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/trusted/TrustedRelayListView.kt index 14a629c678..78193498cb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/trusted/TrustedRelayListView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/trusted/TrustedRelayListView.kt @@ -29,7 +29,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.ui.RelayDragState import com.vitorpamplona.amethyst.commons.relays.ui.rememberRelayDragState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav @@ -37,8 +37,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField @@ -80,7 +80,7 @@ fun LazyListScope.renderTrustedItems( BasicRelaySetupInfoDialog( item, onDelete = { postViewModel.deleteRelay(item) }, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = HorzHalfVertPadding, index = index, dragState = dragState, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/vanish/RequestToVanishScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/vanish/RequestToVanishScreen.kt index abbb321c4c..f51e300fc1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/vanish/RequestToVanishScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/vanish/RequestToVanishScreen.kt @@ -65,9 +65,9 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.Nip11CachedRetriever import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.cancel @@ -93,13 +93,14 @@ import com.vitorpamplona.amethyst.commons.ui.components.TitleExplainer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.DateTimeStyle +import com.vitorpamplona.amethyst.commons.ui.note.formatDateTime import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.HorzHalfVertPadding import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.note.formatMediumDateTime -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder @@ -118,7 +119,7 @@ fun RequestToVanishScreen( nav: INav, ) { RequestToVanishScreen( - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, accountViewModel = accountViewModel, nav = nav, ) @@ -308,7 +309,7 @@ fun RequestToVanishScreen( ) Spacer(Modifier.width(12.dp)) Text( - text = formatMediumDateTime(vanishDate, context), + text = formatDateTime(vanishDate * 1000, DateTimeStyle.MEDIUM, DateTimeStyle.SHORT), style = MaterialTheme.typography.bodyLarge, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/scheduledposts/ScheduledPostsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/scheduledposts/ScheduledPostsScreen.kt index 097bb9282c..2fcd331e14 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/scheduledposts/ScheduledPostsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/scheduledposts/ScheduledPostsScreen.kt @@ -131,11 +131,11 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarSize import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon import com.vitorpamplona.amethyst.commons.ui.note.timeAgoNoDot import com.vitorpamplona.amethyst.commons.ui.note.timeAheadNoDot +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.scheduledposts.ScheduledPostWorker -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.delay import kotlinx.coroutines.launch import java.time.Instant diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/AddInboxRelayForSearchCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/AddInboxRelayForSearchCard.kt index 4127b85854..5adaf1521c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/AddInboxRelayForSearchCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/AddInboxRelayForSearchCard.kt @@ -50,8 +50,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel @Preview @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/AddSearchRelayListDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/AddSearchRelayListDialog.kt index e3ff016d24..b84a61e452 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/AddSearchRelayListDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/AddSearchRelayListDialog.kt @@ -48,8 +48,8 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SavingTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.SetDialogToEdgeToEdge -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.search.SearchRelayList import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.search.SearchRelayListViewModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchBarViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchBarViewModel.kt index 369946244e..91ea210353 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchBarViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchBarViewModel.kt @@ -32,6 +32,7 @@ import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.commons.actions.ConcordActions import com.vitorpamplona.amethyst.commons.feeds.InvalidatableContent +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route @@ -46,8 +47,7 @@ import com.vitorpamplona.amethyst.commons.search.SearchSortOrder import com.vitorpamplona.amethyst.commons.search.SearchSource import com.vitorpamplona.amethyst.commons.search.SearchState import com.vitorpamplona.amethyst.commons.search.wholeInputNip19 -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.userUriPrefixes +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.userUriPrefixes import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.quartz.buzz.invite.BuzzInviteLink import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchScreen.kt index a5cb13d9f5..f6ef0c23c0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchScreen.kt @@ -85,6 +85,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.ephemeral_relay_chat import com.vitorpamplona.amethyst.commons.resources.npub_hex_username @@ -117,10 +118,17 @@ import com.vitorpamplona.amethyst.commons.search.SearchScope import com.vitorpamplona.amethyst.commons.search.SearchSortOrder import com.vitorpamplona.amethyst.commons.search.SearchSource import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.note.ClearTextIcon +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.note.SearchIcon +import com.vitorpamplona.amethyst.commons.ui.note.UserCompose +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.search.GroupCandidate import com.vitorpamplona.amethyst.commons.ui.search.SEARCH_PICKER_LIMIT @@ -134,18 +142,10 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.StdTopPadding import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.location.CachedReversedGeoLocations import com.vitorpamplona.amethyst.service.relayClient.searchCommand.TextSearchDataSourceSubscription import com.vitorpamplona.amethyst.ui.components.namecoin.NamecoinResolutionRow -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.note.UserCompose -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.ChannelName import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoClickableRow import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl @@ -826,7 +826,7 @@ private fun DisplaySearchResults( loadRobohash = LocalDisplaySettings.current.loadRobohash, onClick = { nav.nav(Route.RelayInfo(relayInfo.relay.url)) }, onDelete = null, - nip11CachedRetriever = Amethyst.instance.nip11Cache, + nip11CachedRetriever = LocalCache.appHost.nip11Cache, modifier = Modifier.padding(vertical = 5.dp, horizontal = 10.dp), accountViewModel = accountViewModel, nav = nav, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AllSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AllSettingsScreen.kt index bb68210b82..ec9e073d0d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AllSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AllSettingsScreen.kt @@ -66,14 +66,14 @@ import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SettingsSearchTopBar +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.settings.SettingsCategory import com.vitorpamplona.amethyst.commons.ui.settings.SettingsEntry import com.vitorpamplona.amethyst.commons.ui.settings.SettingsIcon import com.vitorpamplona.amethyst.commons.ui.settings.filterSettings import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.stringRes import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AppSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AppSettingsScreen.kt index 2faf472a8c..f7ff0a81e3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AppSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AppSettingsScreen.kt @@ -133,7 +133,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.contentColorOnAccent import com.vitorpamplona.amethyst.commons.ui.theme.isLight import com.vitorpamplona.amethyst.commons.ui.theme.previewColor import com.vitorpamplona.amethyst.commons.ui.theme.toFontFamily -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableMap import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AudioVisualizerSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AudioVisualizerSettingsScreen.kt index b1c8524c78..dc1a974b7e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AudioVisualizerSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AudioVisualizerSettingsScreen.kt @@ -67,8 +67,8 @@ import com.vitorpamplona.amethyst.commons.resources.audio_visualizer_waves import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.playback.composable.wavefront.FakeWaveformAnimation -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.flow.Flow @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/BlockedUsersScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/BlockedUsersScreen.kt index 52afc00f16..d5c048507f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/BlockedUsersScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/BlockedUsersScreen.kt @@ -33,7 +33,7 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.blocked_users import com.vitorpamplona.amethyst.commons.resources.security_blocked_users_empty import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.dal.HiddenAccountsFeedViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/BottomBarSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/BottomBarSettingsScreen.kt index 38b405e133..8b09e9d267 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/BottomBarSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/BottomBarSettingsScreen.kt @@ -93,6 +93,8 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.theme.Size22Modifier import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.navigation.bottombars.BottomBarCategories import com.vitorpamplona.amethyst.ui.navigation.bottombars.GroupEntryAvatar import com.vitorpamplona.amethyst.ui.navigation.bottombars.GroupEntryDisplay @@ -100,8 +102,6 @@ import com.vitorpamplona.amethyst.ui.navigation.bottombars.NavBarCatalog import com.vitorpamplona.amethyst.ui.navigation.bottombars.NavBarCategory import com.vitorpamplona.amethyst.ui.navigation.bottombars.rememberFavoriteIconModel import com.vitorpamplona.amethyst.ui.navigation.bottombars.rememberGroupEntryDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.concord.cord02Community.ConcordCommunityListEntry import com.vitorpamplona.quartz.nip51Lists.simpleGroupList.GroupTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/BottomBarSettingsState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/BottomBarSettingsState.kt index 7be09ce04d..045c274f30 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/BottomBarSettingsState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/BottomBarSettingsState.kt @@ -25,8 +25,8 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import com.vitorpamplona.amethyst.commons.model.navigation.BottomBarEntry +import com.vitorpamplona.amethyst.commons.model.navigation.DefaultBottomBarEntries import com.vitorpamplona.amethyst.commons.model.navigation.stableKey -import com.vitorpamplona.amethyst.ui.navigation.bottombars.DefaultBottomBarEntries /** * Pure list transforms for the bottom-bar pinned list. Kept free of Compose/Android so the pin, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ComposeSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ComposeSettingsScreen.kt index 3f0691f2b7..38f77ce538 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ComposeSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ComposeSettingsScreen.kt @@ -45,6 +45,7 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.AccountPoWPreferences import com.vitorpamplona.amethyst.commons.model.BooleanType import com.vitorpamplona.amethyst.commons.model.UiSettingsFlow import com.vitorpamplona.amethyst.commons.resources.Res @@ -97,13 +98,12 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.model.AccountPoWPreferences +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.service.ai.WritingAssistantFactory import com.vitorpamplona.amethyst.service.pow.deviceHashesPerSecond import com.vitorpamplona.amethyst.service.pow.loadApproxDuration import com.vitorpamplona.amethyst.ui.note.creators.pow.POW_PRESETS -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import kotlinx.coroutines.flow.MutableStateFlow import org.jetbrains.compose.resources.StringResource diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/DrawerSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/DrawerSettingsScreen.kt index 51d376c0bc..43afd795ad 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/DrawerSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/DrawerSettingsScreen.kt @@ -64,12 +64,12 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackBu import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.navigation.bottombars.NavBarCatalog import com.vitorpamplona.amethyst.ui.navigation.drawer.DrawerSection import com.vitorpamplona.amethyst.ui.navigation.drawer.DrawerSectionVisibility import com.vitorpamplona.amethyst.ui.navigation.drawer.DrawerSections -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel @Composable @Preview(device = "spec:width=2100px,height=2340px,dpi=440") diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/HiddenWordsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/HiddenWordsScreen.kt index 3a2207444f..d7db6d743b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/HiddenWordsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/HiddenWordsScreen.kt @@ -79,7 +79,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.HorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.dal.HiddenWordsFeedViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/HomeTabsSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/HomeTabsSettingsScreen.kt index f81f5e9c22..1a689f57c3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/HomeTabsSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/HomeTabsSettingsScreen.kt @@ -74,8 +74,8 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import org.jetbrains.compose.resources.StringResource @Preview diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/MutedThreadsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/MutedThreadsScreen.kt index b2dc7c2772..75bf656450 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/MutedThreadsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/MutedThreadsScreen.kt @@ -63,7 +63,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.Size15dp -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.dal.MutedThreadsFeedViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt index 7d155b5587..5a62043f6c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NIP47SetupScreen.kt @@ -57,11 +57,11 @@ import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.SettingsCategorySpacingModifier import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.paymentTargets.PaymentTargetAddField import com.vitorpamplona.amethyst.ui.actions.paymentTargets.PaymentTargetsViewModel import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountContent import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.SettingsCategory import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.WalletViewModel import com.vitorpamplona.quartz.nipA3PaymentTargets.PaymentTarget diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NamecoinSettingsSection.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NamecoinSettingsSection.kt index a51b3b5c6f..629237365d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NamecoinSettingsSection.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NamecoinSettingsSection.kt @@ -86,8 +86,9 @@ import com.vitorpamplona.amethyst.commons.resources.namecoin_test_results import com.vitorpamplona.amethyst.commons.resources.namecoin_test_success import com.vitorpamplona.amethyst.commons.resources.namecoin_testing import com.vitorpamplona.amethyst.commons.resources.namecoin_tls_info +import com.vitorpamplona.amethyst.commons.ui.note.DateTimeStyle +import com.vitorpamplona.amethyst.commons.ui.note.formatDateTime import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.note.formatMediumDateTime import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.DEFAULT_ELECTRUMX_SERVERS import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.ElectrumxServer import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinBackend @@ -514,7 +515,7 @@ private fun DiagnosticCard( val context = LocalContext.current val formatted = remember(lastTestTimestamp, context) { - formatMediumDateTime(lastTestTimestamp / 1000L, context) + formatDateTime(lastTestTimestamp, DateTimeStyle.MEDIUM, DateTimeStyle.SHORT) } val successCount = testResults.count { it.success } val totalCount = testResults.size diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NavPickerUi.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NavPickerUi.kt index 9f8dcd7a97..1985b6b1cb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NavPickerUi.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NavPickerUi.kt @@ -77,7 +77,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size24dp import com.vitorpamplona.amethyst.commons.ui.theme.Size34dp import com.vitorpamplona.amethyst.commons.ui.theme.Size40dp import com.vitorpamplona.amethyst.commons.ui.theme.Size6dp -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import org.jetbrains.compose.resources.StringResource /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NotificationSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NotificationSettingsScreen.kt index 3c4e4be86f..22cdf51516 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NotificationSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/NotificationSettingsScreen.kt @@ -63,6 +63,7 @@ import androidx.lifecycle.repeatOnLifecycle import com.vitorpamplona.amethyst.AccountInfo import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.battery_optimization_description import com.vitorpamplona.amethyst.commons.resources.battery_optimization_fix_now @@ -85,20 +86,19 @@ import com.vitorpamplona.amethyst.commons.resources.split_notifications_setting_ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.util.toShortDisplay -import com.vitorpamplona.amethyst.model.AccountSettings +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.service.notifications.BatteryOptimizationHelper import com.vitorpamplona.amethyst.service.notifications.NotificationChannels import com.vitorpamplona.amethyst.ui.components.PushNotificationProviderTile import com.vitorpamplona.amethyst.ui.components.hasPushNotificationProvider -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.quartz.nip19Bech32.decodePublicKeyAsHexOrNull import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ProfileUiSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ProfileUiSettingsScreen.kt index 1ed130938a..f3f4610603 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ProfileUiSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ProfileUiSettingsScreen.kt @@ -53,8 +53,8 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel @Preview @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ResourceUsageScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ResourceUsageScreen.kt index efd3394001..84d81bfe39 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ResourceUsageScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ResourceUsageScreen.kt @@ -135,19 +135,19 @@ import com.vitorpamplona.amethyst.commons.service.crashreports.DEV_REPORT_PUBKEY import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeToMessage import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor import com.vitorpamplona.amethyst.commons.ui.theme.warningColor +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.resourceusage.ResourceUsageAccountant import com.vitorpamplona.amethyst.service.resourceusage.ResourceUsageReportAssembler import com.vitorpamplona.amethyst.service.resourceusage.ResourceUsageReportAssembler.Companion.formatBytes import com.vitorpamplona.amethyst.service.resourceusage.ResourceUsageReportAssembler.Companion.formatConnHours import com.vitorpamplona.amethyst.service.resourceusage.ResourceUsageReportAssembler.Companion.formatDurationMs import com.vitorpamplona.amethyst.service.resourceusage.UsageSummary -import com.vitorpamplona.amethyst.ui.navigation.routes.routeToMessage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SecurityFiltersScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SecurityFiltersScreen.kt index 0714583d75..8e1bfb4217 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SecurityFiltersScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SecurityFiltersScreen.kt @@ -68,8 +68,8 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel @Composable fun SecurityFiltersScreen( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SecurityListsCommon.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SecurityListsCommon.kt index 1e5368f749..495be15db8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SecurityListsCommon.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SecurityListsCommon.kt @@ -62,9 +62,12 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.note.ShowUserButton +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.note.buttons.CloseButton import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness @@ -73,11 +76,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.HalfHorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.Size15dp import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.UserFeedViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import org.jetbrains.compose.resources.StringResource /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SpammingUsersScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SpammingUsersScreen.kt index a38fecfaa8..42ff801b75 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SpammingUsersScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SpammingUsersScreen.kt @@ -33,7 +33,7 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.security_spamming_users_empty import com.vitorpamplona.amethyst.commons.resources.spamming_users import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.dal.SpammerAccountsFeedViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/StringFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/StringFeedView.kt index 96b549e38d..3851b8fd57 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/StringFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/StringFeedView.kt @@ -45,7 +45,7 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun StringFeedView( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/UpdateZapAmountScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/UpdateZapAmountScreen.kt index a36c497652..058b3f1d82 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/UpdateZapAmountScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/UpdateZapAmountScreen.kt @@ -32,9 +32,9 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.zaps import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SavingTopBar +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountContent import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @Composable fun UpdateZapAmountScreen( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/UserSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/UserSettingsScreen.kt index 5395a54170..fc09ddd1dd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/UserSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/UserSettingsScreen.kt @@ -90,8 +90,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.SpacedBy10dp import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import java.util.Locale as JavaLocale @Preview(device = "spec:width=2160px,height=2340px,dpi=440") diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/VideoPlayerSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/VideoPlayerSettingsScreen.kt index 6fd105636d..918d6e76bc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/VideoPlayerSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/VideoPlayerSettingsScreen.kt @@ -61,6 +61,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.VideoButtonLocation +import com.vitorpamplona.amethyst.commons.model.VideoPlayerAction +import com.vitorpamplona.amethyst.commons.model.VideoPlayerButtonItem import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.video_player_settings import com.vitorpamplona.amethyst.commons.resources.video_player_settings_action_captions @@ -89,11 +92,8 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackBu import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow -import com.vitorpamplona.amethyst.model.VideoButtonLocation -import com.vitorpamplona.amethyst.model.VideoPlayerAction -import com.vitorpamplona.amethyst.model.VideoPlayerButtonItem -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel @Composable @Preview(device = "spec:width=2100px,height=2340px,dpi=440") diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnBackupScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnBackupScreen.kt index 762afc71a6..8aac8ee458 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnBackupScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnBackupScreen.kt @@ -77,9 +77,9 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable_deta import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsSection -import com.vitorpamplona.amethyst.ui.stringRes import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnCoordinatorsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnCoordinatorsScreen.kt index 1527b83d77..f8659c8274 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnCoordinatorsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnCoordinatorsScreen.kt @@ -66,6 +66,7 @@ import com.vitorpamplona.amethyst.commons.cordn.ui.SettingsFormBlock import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.cordn.CordnRuntime import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.cancel import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_add_action @@ -111,15 +112,16 @@ import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.note.timeAgoNoDot +import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings.cordn.CoordinatorIdentityRow +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings.cordn.coordinatorDisplayName +import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness -import com.vitorpamplona.amethyst.model.cordn.CordnRuntime -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.pluralStringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.cordnGroup.CopyableKeyRow import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsSection -import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.cordn.spec00Coordinator.CoordinatorServerInfo import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip19Bech32.decodePublicKeyAsHexOrNull diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnHubScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnHubScreen.kt index 776bde38f8..0c820afc23 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnHubScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnHubScreen.kt @@ -55,13 +55,13 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_hub_title import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsControlRow import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsDivider import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsSection -import com.vitorpamplona.amethyst.ui.stringRes import org.jetbrains.compose.resources.StringResource /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnKeyPackagesScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnKeyPackagesScreen.kt index 7d01ae4159..4ba0e5df10 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnKeyPackagesScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnKeyPackagesScreen.kt @@ -51,6 +51,8 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.cordn.CoordinatorConfig import com.vitorpamplona.amethyst.commons.cordn.ui.SettingsFormBlock +import com.vitorpamplona.amethyst.commons.model.cordn.CordnKeyPackageRow +import com.vitorpamplona.amethyst.commons.model.cordn.CordnRuntime import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_none import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable @@ -73,12 +75,11 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_withdraw_o import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton -import com.vitorpamplona.amethyst.model.cordn.CordnKeyPackageRow -import com.vitorpamplona.amethyst.model.cordn.CordnRuntime -import com.vitorpamplona.amethyst.ui.pluralStringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings.cordn.CoordinatorIdentityRow +import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsSection -import com.vitorpamplona.amethyst.ui.stringRes import kotlinx.coroutines.launch /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnLinkScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnLinkScreen.kt index 2f793891ad..41f3e13cd8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnLinkScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnLinkScreen.kt @@ -69,10 +69,11 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_link_section_input import com.vitorpamplona.amethyst.commons.resources.cordn_link_title import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings.cordn.CoordinatorIdentityRow +import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.SimpleQrCodeScanner import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsSection -import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.nip01Core.core.HexKey import kotlinx.coroutines.launch import org.jetbrains.compose.resources.stringResource diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnMigrateScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnMigrateScreen.kt index 5794fab94e..c2bf67e6fb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnMigrateScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnMigrateScreen.kt @@ -50,6 +50,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.cordn.CordnMigration import com.vitorpamplona.amethyst.commons.cordn.ui.BusyLabel import com.vitorpamplona.amethyst.commons.cordn.ui.SettingsFormBlock +import com.vitorpamplona.amethyst.commons.model.cordn.CordnRuntime import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable_detail @@ -80,14 +81,13 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_migrate_title import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.model.cordn.AndroidCordnBlobStore -import com.vitorpamplona.amethyst.model.cordn.CordnRuntime -import com.vitorpamplona.amethyst.ui.pluralStringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.QrCodeDrawer import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.SimpleQrCodeScanner import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsSection -import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.cordn.appMultiDevice.CordnHandoffCode import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenAccountsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenAccountsFeedFilter.kt index 782e3a60f3..7cc9eb83c4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenAccountsFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenAccountsFeedFilter.kt @@ -21,9 +21,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.dal import com.vitorpamplona.amethyst.commons.feeds.FeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenAccountsFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenAccountsFeedViewModel.kt index 054ff922b4..f572ce2a48 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenAccountsFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenAccountsFeedViewModel.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.dal import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.ui.screen.UserFeedViewModel class HiddenAccountsFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenWordsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenWordsFeedFilter.kt index cca71c4d6e..9c3b992610 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenWordsFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenWordsFeedFilter.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.dal import com.vitorpamplona.amethyst.commons.feeds.FeedFilter -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account class HiddenWordsFeedFilter( val account: Account, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenWordsFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenWordsFeedViewModel.kt index 70c64552ac..1c752650c4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenWordsFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenWordsFeedViewModel.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.dal import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.StringFeedViewModel class HiddenWordsFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/MutedThreadsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/MutedThreadsFeedFilter.kt index bc2ff4f20e..2d85c61b14 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/MutedThreadsFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/MutedThreadsFeedFilter.kt @@ -21,9 +21,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.dal import com.vitorpamplona.amethyst.commons.feeds.FeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account class MutedThreadsFeedFilter( val account: Account, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/MutedThreadsFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/MutedThreadsFeedViewModel.kt index fc9a365a88..4f415fa9f7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/MutedThreadsFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/MutedThreadsFeedViewModel.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel @Stable class MutedThreadsFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/SpammerAccountsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/SpammerAccountsFeedFilter.kt index 579b043143..b125a22065 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/SpammerAccountsFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/SpammerAccountsFeedFilter.kt @@ -21,9 +21,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.dal import com.vitorpamplona.amethyst.commons.feeds.FeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account class SpammerAccountsFeedFilter( val account: Account, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/SpammerAccountsFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/SpammerAccountsFeedViewModel.kt index 60e2c4359d..353bb2bd9c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/SpammerAccountsFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/SpammerAccountsFeedViewModel.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.dal import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.ui.screen.UserFeedViewModel class SpammerAccountsFeedViewModel( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/nip46/Nip46ConnectedAppsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/nip46/Nip46ConnectedAppsScreen.kt index d733f3fb92..3b21b83d8e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/nip46/Nip46ConnectedAppsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/nip46/Nip46ConnectedAppsScreen.kt @@ -89,7 +89,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackBu import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.util.toTimeAgo -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/nip46/Nip46SignerScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/nip46/Nip46SignerScreen.kt index 569c6c6ab9..37040337e7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/nip46/Nip46SignerScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/nip46/Nip46SignerScreen.kt @@ -83,6 +83,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip46Signer.Nip46ActivityEntry +import com.vitorpamplona.amethyst.commons.model.nip46Signer.Nip46SignerState import com.vitorpamplona.amethyst.commons.nip46RemoteSigner.ui.Nip46ActivityCard import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.nip46_signer_activity_title @@ -122,11 +123,10 @@ import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.model.nip46Signer.Nip46SignerState -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.QrCodeDrawer import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.SimpleQrCodeScanner import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/NewShortVideoButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/NewShortVideoButton.kt index 9453b4d980..4abf06c4dd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/NewShortVideoButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/NewShortVideoButton.kt @@ -44,26 +44,26 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp 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.model.VideoPostKind import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.ic_compose import com.vitorpamplona.amethyst.commons.resources.new_short_video import com.vitorpamplona.amethyst.commons.resources.record_a_video import com.vitorpamplona.amethyst.commons.resources.upload_image import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.NewMediaModel import com.vitorpamplona.amethyst.ui.actions.NewMediaView import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelect import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideo import com.vitorpamplona.amethyst.ui.actions.uploads.resolveSharedMedia -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.Dispatchers @@ -208,7 +208,7 @@ fun NewShortVideoButton( exit = fadeOut(), ) { Icon( - painter = painterRes(R.drawable.ic_compose, 5), + painter = painterRes(Res.drawable.ic_compose, 5), contentDescription = stringRes(id = Res.string.new_short_video), modifier = Size26Modifier, tint = MaterialTheme.colorScheme.onPrimary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/ShortsFeedLoaded.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/ShortsFeedLoaded.kt index ff796c77b4..7dd7b31049 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/ShortsFeedLoaded.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/ShortsFeedLoaded.kt @@ -36,7 +36,7 @@ import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip71Video.VideoEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/ShortsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/ShortsScreen.kt index df69d34184..377a4a52bf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/ShortsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/ShortsScreen.kt @@ -27,15 +27,15 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.shorts.datasource.ShortsFilterAssemblerSubscription @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/ShortsTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/ShortsTopBar.kt index 0d129f2eec..e07db0d8ff 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/ShortsTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/ShortsTopBar.kt @@ -24,18 +24,18 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip71Video.AddressableShortVideoEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/VideoCardCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/VideoCardCompose.kt index 03f6932ee9..3dff6d975c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/VideoCardCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/VideoCardCompose.kt @@ -38,6 +38,7 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.nip71Video.selectVideoTrack import com.vitorpamplona.amethyst.commons.richtext.BaseMediaContent @@ -45,15 +46,14 @@ import com.vitorpamplona.amethyst.commons.richtext.MediaContentKind import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo import com.vitorpamplona.amethyst.commons.richtext.RichTextParser +import com.vitorpamplona.amethyst.commons.ui.components.BlurhashBackdrop +import com.vitorpamplona.amethyst.commons.ui.components.ContentWarningGate +import com.vitorpamplona.amethyst.commons.ui.components.collectContentWarningReasons +import com.vitorpamplona.amethyst.commons.ui.components.mediaSizingModifier import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.model.MediaAspectRatioCache -import com.vitorpamplona.amethyst.ui.components.BlurhashBackdrop -import com.vitorpamplona.amethyst.ui.components.ContentWarningGate +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.ZoomableContentView -import com.vitorpamplona.amethyst.ui.components.collectContentWarningReasons -import com.vitorpamplona.amethyst.ui.components.mediaSizingModifier import com.vitorpamplona.amethyst.ui.note.ReactionsRow -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.UserCardHeader import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip31Alts.alt diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/datasource/ShortsFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/datasource/ShortsFilterAssemblerSubscription.kt index 6f70c1c077..9a907d347b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/datasource/ShortsFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/datasource/ShortsFilterAssemblerSubscription.kt @@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.shorts.ShortsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun ShortsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/SoftwareAppDetailScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/SoftwareAppDetailScreen.kt index 52869265fc..b4a2faa10d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/SoftwareAppDetailScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/SoftwareAppDetailScreen.kt @@ -56,6 +56,8 @@ import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.loading_feed import com.vitorpamplona.amethyst.commons.resources.nip82_no_comments @@ -67,9 +69,25 @@ import com.vitorpamplona.amethyst.commons.resources.nip82_section_links import com.vitorpamplona.amethyst.commons.resources.nip82_section_platforms import com.vitorpamplona.amethyst.commons.resources.nip82_section_topics import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.note.types.AppAuthorLine +import com.vitorpamplona.amethyst.commons.ui.note.types.AppIcon +import com.vitorpamplona.amethyst.commons.ui.note.types.AppLinksColumn +import com.vitorpamplona.amethyst.commons.ui.note.types.Chip +import com.vitorpamplona.amethyst.commons.ui.note.types.PlatformLicenseRow +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderSoftwareReleaseBody +import com.vitorpamplona.amethyst.commons.ui.note.types.ReplyRenderType +import com.vitorpamplona.amethyst.commons.ui.note.types.ScreenshotsStrip +import com.vitorpamplona.amethyst.commons.ui.note.types.TopicChipFlow +import com.vitorpamplona.amethyst.commons.ui.note.types.VersionChip +import com.vitorpamplona.amethyst.commons.ui.note.types.findAllNip82Releases +import com.vitorpamplona.amethyst.commons.ui.note.types.findLatestNip82Release +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.threadview.datasources.ThreadFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding @@ -80,27 +98,9 @@ import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.subtleBorder import com.vitorpamplona.amethyst.commons.ui.thread.drawReplyLevel -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.ReactionsRow -import com.vitorpamplona.amethyst.ui.note.types.AppAuthorLine -import com.vitorpamplona.amethyst.ui.note.types.AppIcon -import com.vitorpamplona.amethyst.ui.note.types.AppLinksColumn -import com.vitorpamplona.amethyst.ui.note.types.Chip -import com.vitorpamplona.amethyst.ui.note.types.PlatformLicenseRow -import com.vitorpamplona.amethyst.ui.note.types.RenderSoftwareReleaseBody -import com.vitorpamplona.amethyst.ui.note.types.ReplyRenderType -import com.vitorpamplona.amethyst.ui.note.types.ScreenshotsStrip -import com.vitorpamplona.amethyst.ui.note.types.TopicChipFlow -import com.vitorpamplona.amethyst.ui.note.types.VersionChip -import com.vitorpamplona.amethyst.ui.note.types.findAllNip82Releases -import com.vitorpamplona.amethyst.ui.note.types.findLatestNip82Release -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.dal.ThreadFeedViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.datasources.ThreadFilterAssemblerSubscription import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.application.SoftwareApplicationEvent import com.vitorpamplona.quartz.nip01Core.core.Address diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadFeedView.kt index 5bbc3dfe06..9f839d5c35 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadFeedView.kt @@ -74,7 +74,6 @@ import androidx.compose.ui.unit.em import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil3.compose.AsyncImage -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.birdstar.ui.RenderBirdDetection import com.vitorpamplona.amethyst.commons.birdstar.ui.RenderBirdex import com.vitorpamplona.amethyst.commons.chats.ui.ThinSendButton @@ -82,29 +81,162 @@ import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeCommunityApprovalNeedStatus import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.expand import com.vitorpamplona.amethyst.commons.resources.hi_seller_is_this_still_available import com.vitorpamplona.amethyst.commons.resources.hi_there_is_this_still_available +import com.vitorpamplona.amethyst.commons.resources.ic_dm import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for import com.vitorpamplona.amethyst.commons.resources.reply_here import com.vitorpamplona.amethyst.commons.resources.send_a_direct_message import com.vitorpamplona.amethyst.commons.resources.send_the_seller_a_message import com.vitorpamplona.amethyst.commons.resources.thread_collapsed_reply_count import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage +import com.vitorpamplona.amethyst.commons.ui.components.AutoNonlazyGrid import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeEditDraftTo +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeToMessage +import com.vitorpamplona.amethyst.commons.ui.note.CheckAndDisplayEditStatus +import com.vitorpamplona.amethyst.commons.ui.note.CheckHiddenFeedWatchBlockAndReport +import com.vitorpamplona.amethyst.commons.ui.note.DisplayDraft +import com.vitorpamplona.amethyst.commons.ui.note.DisplayOtsIfInOriginal import com.vitorpamplona.amethyst.commons.ui.note.ExpandMoreIcon +import com.vitorpamplona.amethyst.commons.ui.note.Expiration +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.LoadDecryptedContent +import com.vitorpamplona.amethyst.commons.ui.note.LongPressToQuickAction +import com.vitorpamplona.amethyst.commons.ui.note.NoteAuthorPicture +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.note.NoteUsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.ObserveDisplayNip05Status +import com.vitorpamplona.amethyst.commons.ui.note.ObserveDraftEvent +import com.vitorpamplona.amethyst.commons.ui.note.RenderApproveButton import com.vitorpamplona.amethyst.commons.ui.note.RenderCashuMint import com.vitorpamplona.amethyst.commons.ui.note.RenderCodeSnippetHeaderForThread +import com.vitorpamplona.amethyst.commons.ui.note.RenderDraft import com.vitorpamplona.amethyst.commons.ui.note.RenderFedimint import com.vitorpamplona.amethyst.commons.ui.note.RenderMintRecommendation +import com.vitorpamplona.amethyst.commons.ui.note.RenderRepost +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.WatchNoteEvent +import com.vitorpamplona.amethyst.commons.ui.note.calculateBackgroundColor +import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.DisplayZapSplits +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeader +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeaderBackground +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayFollowingCommunityInPost +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayFollowingHashtagsInPost +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayLocation +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayPoW +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayReward +import com.vitorpamplona.amethyst.commons.ui.note.elements.MoreOptionsButton +import com.vitorpamplona.amethyst.commons.ui.note.elements.Reward +import com.vitorpamplona.amethyst.commons.ui.note.elements.ShowForkInformation import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgo import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgoStyle +import com.vitorpamplona.amethyst.commons.ui.note.nip22Comments.DisplayCommentScope +import com.vitorpamplona.amethyst.commons.ui.note.observeEdits +import com.vitorpamplona.amethyst.commons.ui.note.types.BadgeDisplay +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayBlockedRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayBroadcastRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayContactList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayDMRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayFavoriteRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayIndexerRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayNIP65RelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayPeopleList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayProxyRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayRelaySet +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplaySearchRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayStarterPack +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayTrustedRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.EditState +import com.vitorpamplona.amethyst.commons.ui.note.types.FileMetadataDisplay +import com.vitorpamplona.amethyst.commons.ui.note.types.FileStorageHeaderDisplay +import com.vitorpamplona.amethyst.commons.ui.note.types.MAX_THREAD_SECTIONS +import com.vitorpamplona.amethyst.commons.ui.note.types.PictureDisplay +import com.vitorpamplona.amethyst.commons.ui.note.types.PublicationHeader +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderAppDefinition +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderAppRecommendation +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderAttestation +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderAttestationRequest +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderAttestorProficiency +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderAttestorRecommendation +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderBlossomPieceIndex +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderBolt12Zap +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderBookshelfDirectory +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderCalendarDateSlotEvent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderCalendarTimeSlotEvent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderChannelMessage +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderChat +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderChatMessageEncryptedFile +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderCitation +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderCyberspaceBag +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderEmojiPack +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderEntityRating +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderFhirResource +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderFundraiser +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderGeocache +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderGeocacheFoundLog +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderGoal +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderHighlight +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderInteractiveStory +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderLearningResource +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderLiveActivityChatMessage +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderMeetingRoomEvent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderMeetingSpaceEvent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderMusicPlaylist +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderNutzap +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderOnchainZap +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPinListEvent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPodcastEpisode +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPodcastMetadata +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPoll +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPostApproval +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPrivateMessage +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderProfileCard +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPs1Save +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPublicMessage +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPublicationSection +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderReaction +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRelayAddMember +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRelayDiscovery +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRelayJoinRequest +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRelayLeaveRequest +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRelayMembershipList +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRelayRemoveMember +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRelayReview +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRoadEventConfirmation +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRoadEventReport +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderSnoAvatar +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderSnoObject +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderSnoShard +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderSoftwareApplication +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderSoftwareAsset +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderSoftwareRelease +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderTextEvent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderTextModificationEvent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderTorrent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderTorrentComment +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderZapPoll +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderZapReceipt +import com.vitorpamplona.amethyst.commons.ui.note.types.ReplyRenderType +import com.vitorpamplona.amethyst.commons.ui.note.types.VideoDisplay +import com.vitorpamplona.amethyst.commons.ui.note.types.observeZapSender +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.RenderFeedState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.PublicChatChannelHeader +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts.PodcastTrailerListItem +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts.WorkoutDisplay import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer @@ -126,154 +258,22 @@ import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.selectedNote import com.vitorpamplona.amethyst.commons.ui.thread.drawReplyLevel import com.vitorpamplona.amethyst.commons.util.showAmount +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.thread.LevelFeedViewModel -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeCommunityApprovalNeedStatus -import com.vitorpamplona.amethyst.ui.components.AutoNonlazyGrid -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.ui.components.ZoomableContentView -import com.vitorpamplona.amethyst.ui.navigation.routes.routeEditDraftTo -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.navigation.routes.routeToMessage -import com.vitorpamplona.amethyst.ui.note.CheckAndDisplayEditStatus -import com.vitorpamplona.amethyst.ui.note.CheckHiddenFeedWatchBlockAndReport -import com.vitorpamplona.amethyst.ui.note.DisplayDraft -import com.vitorpamplona.amethyst.ui.note.DisplayOtsIfInOriginal -import com.vitorpamplona.amethyst.ui.note.Expiration -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.LoadDecryptedContent -import com.vitorpamplona.amethyst.ui.note.LongPressToQuickAction -import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay -import com.vitorpamplona.amethyst.ui.note.ObserveDisplayNip05Status -import com.vitorpamplona.amethyst.ui.note.ObserveDraftEvent import com.vitorpamplona.amethyst.ui.note.ReactionsRow -import com.vitorpamplona.amethyst.ui.note.RenderApproveButton -import com.vitorpamplona.amethyst.ui.note.RenderDraft -import com.vitorpamplona.amethyst.ui.note.RenderRepost -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent -import com.vitorpamplona.amethyst.ui.note.calculateBackgroundColor -import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.DisplayZapSplits -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeaderBackground -import com.vitorpamplona.amethyst.ui.note.elements.DisplayFollowingCommunityInPost -import com.vitorpamplona.amethyst.ui.note.elements.DisplayFollowingHashtagsInPost -import com.vitorpamplona.amethyst.ui.note.elements.DisplayLocation -import com.vitorpamplona.amethyst.ui.note.elements.DisplayPoW -import com.vitorpamplona.amethyst.ui.note.elements.DisplayReward -import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton -import com.vitorpamplona.amethyst.ui.note.elements.Reward -import com.vitorpamplona.amethyst.ui.note.elements.ShowForkInformation -import com.vitorpamplona.amethyst.ui.note.nip22Comments.DisplayCommentScope -import com.vitorpamplona.amethyst.ui.note.observeEdits import com.vitorpamplona.amethyst.ui.note.types.AudioHeader import com.vitorpamplona.amethyst.ui.note.types.AudioTrackHeader -import com.vitorpamplona.amethyst.ui.note.types.BadgeDisplay -import com.vitorpamplona.amethyst.ui.note.types.DisplayBlockedRelayList -import com.vitorpamplona.amethyst.ui.note.types.DisplayBroadcastRelayList -import com.vitorpamplona.amethyst.ui.note.types.DisplayContactList -import com.vitorpamplona.amethyst.ui.note.types.DisplayDMRelayList -import com.vitorpamplona.amethyst.ui.note.types.DisplayFavoriteRelayList -import com.vitorpamplona.amethyst.ui.note.types.DisplayIndexerRelayList -import com.vitorpamplona.amethyst.ui.note.types.DisplayNIP65RelayList -import com.vitorpamplona.amethyst.ui.note.types.DisplayPeopleList -import com.vitorpamplona.amethyst.ui.note.types.DisplayProxyRelayList -import com.vitorpamplona.amethyst.ui.note.types.DisplayRelaySet -import com.vitorpamplona.amethyst.ui.note.types.DisplaySearchRelayList -import com.vitorpamplona.amethyst.ui.note.types.DisplayStarterPack -import com.vitorpamplona.amethyst.ui.note.types.DisplayTrustedRelayList -import com.vitorpamplona.amethyst.ui.note.types.EditState -import com.vitorpamplona.amethyst.ui.note.types.FileMetadataDisplay -import com.vitorpamplona.amethyst.ui.note.types.FileStorageHeaderDisplay -import com.vitorpamplona.amethyst.ui.note.types.MAX_THREAD_SECTIONS -import com.vitorpamplona.amethyst.ui.note.types.PictureDisplay -import com.vitorpamplona.amethyst.ui.note.types.PublicationHeader -import com.vitorpamplona.amethyst.ui.note.types.RenderAppDefinition -import com.vitorpamplona.amethyst.ui.note.types.RenderAppRecommendation -import com.vitorpamplona.amethyst.ui.note.types.RenderAttestation -import com.vitorpamplona.amethyst.ui.note.types.RenderAttestationRequest -import com.vitorpamplona.amethyst.ui.note.types.RenderAttestorProficiency -import com.vitorpamplona.amethyst.ui.note.types.RenderAttestorRecommendation -import com.vitorpamplona.amethyst.ui.note.types.RenderBlossomPieceIndex -import com.vitorpamplona.amethyst.ui.note.types.RenderBolt12Zap -import com.vitorpamplona.amethyst.ui.note.types.RenderBookshelfDirectory -import com.vitorpamplona.amethyst.ui.note.types.RenderCalendarDateSlotEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderCalendarTimeSlotEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderChannelMessage -import com.vitorpamplona.amethyst.ui.note.types.RenderChat -import com.vitorpamplona.amethyst.ui.note.types.RenderChatMessageEncryptedFile -import com.vitorpamplona.amethyst.ui.note.types.RenderCitation -import com.vitorpamplona.amethyst.ui.note.types.RenderCyberspaceBag -import com.vitorpamplona.amethyst.ui.note.types.RenderEmojiPack -import com.vitorpamplona.amethyst.ui.note.types.RenderEntityRating -import com.vitorpamplona.amethyst.ui.note.types.RenderFhirResource -import com.vitorpamplona.amethyst.ui.note.types.RenderFundraiser -import com.vitorpamplona.amethyst.ui.note.types.RenderGeocache -import com.vitorpamplona.amethyst.ui.note.types.RenderGeocacheFoundLog import com.vitorpamplona.amethyst.ui.note.types.RenderGitIssueEvent import com.vitorpamplona.amethyst.ui.note.types.RenderGitPatchEvent import com.vitorpamplona.amethyst.ui.note.types.RenderGitPullRequestEvent import com.vitorpamplona.amethyst.ui.note.types.RenderGitPullRequestUpdateEvent import com.vitorpamplona.amethyst.ui.note.types.RenderGitRepositoryEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderGoal -import com.vitorpamplona.amethyst.ui.note.types.RenderHighlight -import com.vitorpamplona.amethyst.ui.note.types.RenderInteractiveStory -import com.vitorpamplona.amethyst.ui.note.types.RenderLearningResource -import com.vitorpamplona.amethyst.ui.note.types.RenderLiveActivityChatMessage -import com.vitorpamplona.amethyst.ui.note.types.RenderMeetingRoomEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderMeetingSpaceEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderMusicPlaylist import com.vitorpamplona.amethyst.ui.note.types.RenderMusicTrack import com.vitorpamplona.amethyst.ui.note.types.RenderNamedSiteEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderNutzap -import com.vitorpamplona.amethyst.ui.note.types.RenderOnchainZap -import com.vitorpamplona.amethyst.ui.note.types.RenderPinListEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderPodcastEpisode -import com.vitorpamplona.amethyst.ui.note.types.RenderPodcastMetadata -import com.vitorpamplona.amethyst.ui.note.types.RenderPoll -import com.vitorpamplona.amethyst.ui.note.types.RenderPostApproval -import com.vitorpamplona.amethyst.ui.note.types.RenderPrivateMessage -import com.vitorpamplona.amethyst.ui.note.types.RenderProfileCard -import com.vitorpamplona.amethyst.ui.note.types.RenderPs1Save -import com.vitorpamplona.amethyst.ui.note.types.RenderPublicMessage -import com.vitorpamplona.amethyst.ui.note.types.RenderPublicationSection -import com.vitorpamplona.amethyst.ui.note.types.RenderReaction -import com.vitorpamplona.amethyst.ui.note.types.RenderRelayAddMember -import com.vitorpamplona.amethyst.ui.note.types.RenderRelayDiscovery -import com.vitorpamplona.amethyst.ui.note.types.RenderRelayJoinRequest -import com.vitorpamplona.amethyst.ui.note.types.RenderRelayLeaveRequest -import com.vitorpamplona.amethyst.ui.note.types.RenderRelayMembershipList -import com.vitorpamplona.amethyst.ui.note.types.RenderRelayRemoveMember -import com.vitorpamplona.amethyst.ui.note.types.RenderRelayReview -import com.vitorpamplona.amethyst.ui.note.types.RenderRoadEventConfirmation -import com.vitorpamplona.amethyst.ui.note.types.RenderRoadEventReport import com.vitorpamplona.amethyst.ui.note.types.RenderRootSiteEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderSnoAvatar -import com.vitorpamplona.amethyst.ui.note.types.RenderSnoObject -import com.vitorpamplona.amethyst.ui.note.types.RenderSnoShard -import com.vitorpamplona.amethyst.ui.note.types.RenderSoftwareApplication -import com.vitorpamplona.amethyst.ui.note.types.RenderSoftwareAsset -import com.vitorpamplona.amethyst.ui.note.types.RenderSoftwareRelease -import com.vitorpamplona.amethyst.ui.note.types.RenderTextEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderTextModificationEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderTorrent -import com.vitorpamplona.amethyst.ui.note.types.RenderTorrentComment -import com.vitorpamplona.amethyst.ui.note.types.RenderZapPoll -import com.vitorpamplona.amethyst.ui.note.types.RenderZapReceipt -import com.vitorpamplona.amethyst.ui.note.types.ReplyRenderType -import com.vitorpamplona.amethyst.ui.note.types.VideoDisplay import com.vitorpamplona.amethyst.ui.note.types.VoiceHeader -import com.vitorpamplona.amethyst.ui.note.types.observeZapSender -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.RenderFeedState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.PublicChatChannelHeader -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.PodcastTrailerListItem -import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.WorkoutDisplay import com.vitorpamplona.quartz.cyberspace.CyberspaceBagEvent import com.vitorpamplona.quartz.cyberspace.deck0003Sno.SnoAvatarEvent import com.vitorpamplona.quartz.cyberspace.deck0003Sno.SnoObjectEvent @@ -1408,7 +1408,7 @@ private fun RenderClassifiedsReaderForThread( verticalAlignment = Alignment.CenterVertically, ) { Icon( - painter = painterRes(R.drawable.ic_dm, 5), + painter = painterRes(Res.drawable.ic_dm, 5), stringRes(Res.string.send_a_direct_message), modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.primary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadScreen.kt index 994eed7348..3eb6c6171f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadScreen.kt @@ -23,18 +23,18 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.lifecycle.viewmodel.compose.viewModel +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.thread_title +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.threadview.datasources.ThreadFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.dal.ThreadFeedViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.datasources.ThreadFilterAssemblerSubscription @Composable fun ThreadScreen( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/dal/ThreadFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/dal/ThreadFeedViewModel.kt index 46c2d4ff4d..ea83c6277f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/dal/ThreadFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/dal/ThreadFeedViewModel.kt @@ -22,9 +22,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.dal import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.viewmodels.thread.ThreadFeedFilter -import com.vitorpamplona.amethyst.model.Account class ThreadFeedViewModel( account: Account, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/NewUrlNoteButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/NewUrlNoteButton.kt index b66d3ce971..0b80f8cf5a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/NewUrlNoteButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/NewUrlNoteButton.kt @@ -25,16 +25,16 @@ import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.ic_compose import com.vitorpamplona.amethyst.commons.resources.new_community_note import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun NewUrlPostButton( @@ -51,7 +51,7 @@ fun NewUrlPostButton( containerColor = MaterialTheme.colorScheme.primary, ) { Icon( - painter = painterRes(R.drawable.ic_compose, 1), + painter = painterRes(Res.drawable.ic_compose, 1), contentDescription = stringRes(id = Res.string.new_community_note), modifier = Size26Modifier, tint = MaterialTheme.colorScheme.onPrimary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/UrlPostScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/UrlPostScreen.kt index cb8b3032c1..2844a3f4a2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/UrlPostScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/UrlPostScreen.kt @@ -27,11 +27,11 @@ import androidx.compose.ui.platform.LocalContext import androidx.core.net.toUri import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.navigation.navs.Nav import com.vitorpamplona.amethyst.ui.note.nip22Comments.CommentPostViewModel import com.vitorpamplona.amethyst.ui.note.nip22Comments.GenericCommentPostScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip73ExternalIds.urls.UrlId import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/UrlScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/UrlScreen.kt index e8946326b6..b6c5d6bb07 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/UrlScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/UrlScreen.kt @@ -32,18 +32,18 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.external_content_title import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewCard import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewState +import com.vitorpamplona.amethyst.commons.ui.feeds.FeedLoaded import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.nip22Comments.LocalCurrentExternalScope +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.MaxWidthWithHorzPadding +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.rememberUrlPreviewState -import com.vitorpamplona.amethyst.ui.feeds.FeedLoaded -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.note.nip22Comments.LocalCurrentExternalScope -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.url.dal.UrlFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.url.datasource.UrlFilterAssemblerSubscription import com.vitorpamplona.quartz.nip73ExternalIds.urls.UrlId diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/dal/UrlFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/dal/UrlFeedFilter.kt index e5895e1a8a..baf3b141ac 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/dal/UrlFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/dal/UrlFeedFilter.kt @@ -21,10 +21,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.url.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip22Comments.CommentEvent import com.vitorpamplona.quartz.nip73ExternalIds.urls.UrlId diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/dal/UrlFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/dal/UrlFeedViewModel.kt index 3719e8f6bb..e9890a34d8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/dal/UrlFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/dal/UrlFeedViewModel.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.url.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @Stable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/datasource/UrlFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/datasource/UrlFilterAssemblerSubscription.kt index 86365e6b4c..03aa1ae197 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/datasource/UrlFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/url/datasource/UrlFilterAssemblerSubscription.kt @@ -25,7 +25,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription import com.vitorpamplona.amethyst.commons.relayClient.url.UrlQueryState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @SuppressLint("StateFlowValueCalledInComposition") @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/FileMetadataCardCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/FileMetadataCardCompose.kt index 4b74c1ddf4..c88395ced3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/FileMetadataCardCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/FileMetadataCardCompose.kt @@ -37,19 +37,19 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage +import com.vitorpamplona.amethyst.commons.ui.components.BlurhashBackdrop +import com.vitorpamplona.amethyst.commons.ui.components.ContentWarningGate +import com.vitorpamplona.amethyst.commons.ui.components.collectContentWarningReasons +import com.vitorpamplona.amethyst.commons.ui.components.mediaSizingModifier import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.model.MediaAspectRatioCache -import com.vitorpamplona.amethyst.ui.components.BlurhashBackdrop -import com.vitorpamplona.amethyst.ui.components.ContentWarningGate +import com.vitorpamplona.amethyst.commons.ui.note.types.FileMetadataAttachmentCard +import com.vitorpamplona.amethyst.commons.ui.note.types.toMediaContent +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.ZoomableContentView -import com.vitorpamplona.amethyst.ui.components.collectContentWarningReasons -import com.vitorpamplona.amethyst.ui.components.mediaSizingModifier import com.vitorpamplona.amethyst.ui.note.ReactionsRow -import com.vitorpamplona.amethyst.ui.note.types.FileMetadataAttachmentCard -import com.vitorpamplona.amethyst.ui.note.types.toMediaContent -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip36SensitiveContent.isSensitiveOrNSFW import com.vitorpamplona.quartz.nip94FileMetadata.FileMetadataEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/NewVideoFeedButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/NewVideoFeedButton.kt index 6811ef8655..905532836c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/NewVideoFeedButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/NewVideoFeedButton.kt @@ -44,18 +44,20 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp 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.resources.Res +import com.vitorpamplona.amethyst.commons.resources.ic_compose import com.vitorpamplona.amethyst.commons.resources.new_media import com.vitorpamplona.amethyst.commons.resources.record_a_video import com.vitorpamplona.amethyst.commons.resources.take_a_picture import com.vitorpamplona.amethyst.commons.resources.upload_image import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.NewMediaModel import com.vitorpamplona.amethyst.ui.actions.NewMediaView import com.vitorpamplona.amethyst.ui.actions.uploads.GallerySelect @@ -63,8 +65,6 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.TakePicture import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideo import com.vitorpamplona.amethyst.ui.actions.uploads.resolveSharedMedia -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.Dispatchers @@ -242,7 +242,7 @@ fun NewVideoFeedButton( exit = fadeOut(), ) { Icon( - painter = painterRes(R.drawable.ic_compose, 5), + painter = painterRes(Res.drawable.ic_compose, 5), contentDescription = stringRes(id = Res.string.new_media), modifier = Size26Modifier, tint = MaterialTheme.colorScheme.onPrimary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/StoriesTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/StoriesTopBar.kt index 831ee5d806..4b17731e8e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/StoriesTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/StoriesTopBar.kt @@ -24,18 +24,18 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip71Video.AddressableNormalVideoEvent import com.vitorpamplona.quartz.nip71Video.AddressableShortVideoEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/UserCardHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/UserCardHeader.kt index a1a1076c97..7f22e04a90 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/UserCardHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/UserCardHeader.kt @@ -33,13 +33,13 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.NoteAuthorPicture +import com.vitorpamplona.amethyst.commons.ui.note.NoteUsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.elements.MoreOptionsButton import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgo import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture -import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay -import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun UserCardHeader( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/VideoScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/VideoScreen.kt index 7615245745..33fd756f72 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/VideoScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/VideoScreen.kt @@ -36,18 +36,18 @@ import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.pictures.PictureCardCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.shorts.VideoCardCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.datasource.VideoFilterAssemblerSubscription diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/datasource/VideoFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/datasource/VideoFilterAssemblerSubscription.kt index 239c759804..4d5143848c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/datasource/VideoFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/datasource/VideoFilterAssemblerSubscription.kt @@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription import com.vitorpamplona.amethyst.commons.relayClient.video.VideoFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun VideoFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/hls/HlsPublishOrchestratorFactory.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/hls/HlsPublishOrchestratorFactory.kt index 610ce5be46..dc9931e1c3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/hls/HlsPublishOrchestratorFactory.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/hls/HlsPublishOrchestratorFactory.kt @@ -26,8 +26,8 @@ import android.media.MediaMetadataRetriever import android.net.Uri import com.davotoula.lightcompressor.hls.HlsContentTypes import com.davotoula.lightcompressor.hls.HlsUploadHelper +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.service.upload.HlsPublishState -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.uploads.MediaUploadResult import com.vitorpamplona.amethyst.service.uploads.PreviewMetadataCalculator import com.vitorpamplona.amethyst.service.uploads.getThumbnail diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/hls/NewHlsVideoScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/hls/NewHlsVideoScreen.kt index 2c4cb16da7..194dde5161 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/hls/NewHlsVideoScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/hls/NewHlsVideoScreen.kt @@ -116,7 +116,7 @@ import com.vitorpamplona.amethyst.commons.ui.components.TitleExplainer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/hls/NewHlsVideoViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/hls/NewHlsVideoViewModel.kt index 4a324037c2..5b3d78150f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/hls/NewHlsVideoViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/hls/NewHlsVideoViewModel.kt @@ -31,10 +31,10 @@ import androidx.lifecycle.viewModelScope import com.davotoula.lightcompressor.VideoCodec import com.davotoula.lightcompressor.hls.HlsLadder import com.davotoula.lightcompressor.utils.CompressorUtils +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.mediaServers.DEFAULT_MEDIA_SERVERS import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.service.upload.HlsPublishState -import com.vitorpamplona.amethyst.model.Account import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/AddClinkDebitWalletScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/AddClinkDebitWalletScreen.kt index b5600fa024..c01f2fd456 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/AddClinkDebitWalletScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/AddClinkDebitWalletScreen.kt @@ -50,12 +50,12 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.unit.dp 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.resources.Res import com.vitorpamplona.amethyst.commons.resources.accessibility_scan_qr_code import com.vitorpamplona.amethyst.commons.resources.back +import com.vitorpamplona.amethyst.commons.resources.ic_qrcode import com.vitorpamplona.amethyst.commons.resources.paste_from_clipboard import com.vitorpamplona.amethyst.commons.resources.wallet_add_clink_invalid import com.vitorpamplona.amethyst.commons.resources.wallet_add_clink_title @@ -66,10 +66,10 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_save import com.vitorpamplona.amethyst.commons.ui.components.util.getText import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size24Modifier -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.SimpleQrCodeScanner import kotlinx.coroutines.launch @@ -161,7 +161,7 @@ fun AddClinkDebitWalletScreen( // QR code scanner IconButton(onClick = { qrScanning = true }) { Icon( - painter = painterRes(R.drawable.ic_qrcode, 3), + painter = painterRes(Res.drawable.ic_qrcode, 3), contentDescription = stringRes(id = Res.string.accessibility_scan_qr_code), modifier = Modifier.size(24.dp), tint = MaterialTheme.colorScheme.primary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/AddNwcWalletScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/AddNwcWalletScreen.kt index ca76d0d25e..cdb05c7e33 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/AddNwcWalletScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/AddNwcWalletScreen.kt @@ -52,7 +52,6 @@ import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.unit.dp 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.resources.Res @@ -60,6 +59,7 @@ import com.vitorpamplona.amethyst.commons.resources.accessibility_scan_qr_code import com.vitorpamplona.amethyst.commons.resources.back import com.vitorpamplona.amethyst.commons.resources.couldnt_find_nwc_wallets import com.vitorpamplona.amethyst.commons.resources.couldnt_find_nwc_wallets_description +import com.vitorpamplona.amethyst.commons.resources.ic_qrcode import com.vitorpamplona.amethyst.commons.resources.paste_from_clipboard import com.vitorpamplona.amethyst.commons.resources.wallet_add_nwc_title import com.vitorpamplona.amethyst.commons.resources.wallet_connect_connect_app @@ -70,12 +70,12 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_save import com.vitorpamplona.amethyst.commons.ui.components.util.getText import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.commons.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.Size24Modifier -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.SimpleQrCodeScanner import com.vitorpamplona.quartz.nip47WalletConnect.Nip47DeepLink import com.vitorpamplona.quartz.nip47WalletConnect.Nip47WalletConnect @@ -198,7 +198,7 @@ fun AddNwcWalletScreen( // QR code scanner IconButton(onClick = { qrScanning = true }) { Icon( - painter = painterRes(R.drawable.ic_qrcode, 3), + painter = painterRes(Res.drawable.ic_qrcode, 3), contentDescription = stringRes(id = Res.string.accessibility_scan_qr_code), modifier = Modifier.size(24.dp), tint = MaterialTheme.colorScheme.primary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuWalletScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuWalletScreen.kt index d1413d332e..c2394ff37e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuWalletScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuWalletScreen.kt @@ -85,6 +85,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip60Cashu.CashuWalletHistoryEoseManager import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back import com.vitorpamplona.amethyst.commons.resources.cancel @@ -158,13 +159,18 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_sats import com.vitorpamplona.amethyst.commons.ui.components.util.getText import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.CashuMeltFlowState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.CashuMintFlowState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.CashuRebalanceFlowState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.CashuRedeemFlowState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.CashuSendTokenFlowState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.CashuWalletViewModel import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip60Cashu.CashuWalletHistoryEoseManager -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip60Cashu.history.CashuSpendingHistoryEvent import com.vitorpamplona.quartz.nip60Cashu.history.SpendingDirection @@ -623,7 +629,7 @@ private fun CashuHistoryFooter( /** * Banner that surfaces unfinished mint quotes — tappable to resume the * receive flow with the stored invoice. Driven by - * [com.vitorpamplona.amethyst.model.nip60Cashu.CashuWalletState.pendingQuotes]. + * [com.vitorpamplona.amethyst.commons.model.nip60Cashu.CashuWalletState.pendingQuotes]. * * Replaces the earlier auto-popup behaviour which re-surfaced the Receive * dialog on every entry to the screen. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/OnchainSection.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/OnchainSection.kt index 991f6781e5..e331aa82c6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/OnchainSection.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/OnchainSection.kt @@ -77,9 +77,10 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_onchain_public_dialog import com.vitorpamplona.amethyst.commons.resources.wallet_onchain_public_dialog_title import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.sats import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.bitcoinColor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.coroutines.launch import java.text.NumberFormat diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/OnchainTransactionsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/OnchainTransactionsScreen.kt index 69554eea7c..3b7d3f2b63 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/OnchainTransactionsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/OnchainTransactionsScreen.kt @@ -78,13 +78,13 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_onchain_transactions import com.vitorpamplona.amethyst.commons.resources.wallet_outgoing import com.vitorpamplona.amethyst.commons.resources.wallet_refresh import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.bitcoinColor -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.formatMonthDayTime -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.datasource.OnchainZapsFilterAssemblerSubscription import java.text.NumberFormat import kotlin.math.absoluteValue diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/OnchainTransactionsViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/OnchainTransactionsViewModel.kt index 49f7a1e4cb..f978af2d63 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/OnchainTransactionsViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/OnchainTransactionsViewModel.kt @@ -24,7 +24,7 @@ import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nipBCOnchainZaps.chain.BitcoinAddressTx import com.vitorpamplona.quartz.nipBCOnchainZaps.chain.OnchainBackend diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/OnchainZapSendDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/OnchainZapSendDialog.kt index a2ea4d577a..216a41cca9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/OnchainZapSendDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/OnchainZapSendDialog.kt @@ -67,6 +67,8 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.DEFAULT_ONCHAIN_ZAP_SATS +import com.vitorpamplona.amethyst.commons.model.MIN_ONCHAIN_ZAP_SATS import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.onchain.DustRecipientException @@ -117,17 +119,16 @@ import com.vitorpamplona.amethyst.commons.resources.onchain_send_use_note_split import com.vitorpamplona.amethyst.commons.resources.send import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.sats import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.bitcoinColor import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.model.DEFAULT_ONCHAIN_ZAP_SATS -import com.vitorpamplona.amethyst.model.MIN_ONCHAIN_ZAP_SATS +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.namecoin.NamecoinResolutionRow -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletDetailScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletDetailScreen.kt index e73928004f..0ae375f82d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletDetailScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletDetailScreen.kt @@ -64,7 +64,7 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_send import com.vitorpamplona.amethyst.commons.resources.wallet_transactions import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import java.text.NumberFormat @OptIn(ExperimentalMaterial3Api::class) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletReceiveScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletReceiveScreen.kt index 6c62ca02dd..85f789f232 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletReceiveScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletReceiveScreen.kt @@ -75,7 +75,7 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_receive import com.vitorpamplona.amethyst.commons.resources.wallet_sats import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.QrCodeDrawer import java.text.NumberFormat diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletScreen.kt index 452a991874..1512dc514d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletScreen.kt @@ -104,10 +104,11 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_sats import com.vitorpamplona.amethyst.commons.resources.wallet_save import com.vitorpamplona.amethyst.commons.resources.wallet_set_default import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.CashuWalletViewModel import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.clink.debits.DebitFrequency import kotlinx.coroutines.launch import java.text.NumberFormat diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletSendScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletSendScreen.kt index 0f16c22048..b0d036312a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletSendScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletSendScreen.kt @@ -65,7 +65,7 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_payment_success import com.vitorpamplona.amethyst.commons.resources.wallet_send import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletTransactionsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletTransactionsScreen.kt index 1934a77dcc..f1bdad6aa6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletTransactionsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletTransactionsScreen.kt @@ -75,12 +75,12 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_transactions import com.vitorpamplona.amethyst.commons.resources.wallet_transactions_load_failed import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.formatMonthDayTime -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser import com.vitorpamplona.quartz.nip47WalletConnect.rpc.NwcTransaction import com.vitorpamplona.quartz.nip47WalletConnect.rpc.NwcTransactionType import java.text.NumberFormat diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletViewModel.kt index 40de2f46ab..317d0b09be 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/WalletViewModel.kt @@ -23,7 +23,9 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.clink.ClinkDebitWalletEntryNorm +import com.vitorpamplona.amethyst.commons.model.nip47WalletConnect.NwcSignerState import com.vitorpamplona.amethyst.commons.model.nip47WalletConnect.NwcWalletEntryNorm import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.send_payment_failed @@ -39,12 +41,11 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_request_timed_out_spo import com.vitorpamplona.amethyst.commons.resources.wallet_transactions_load_failed import com.vitorpamplona.amethyst.commons.resources.wallet_transactions_load_more_failed import com.vitorpamplona.amethyst.commons.resources.wallet_transactions_not_supported +import com.vitorpamplona.amethyst.commons.service.ClinkDebitPayer import com.vitorpamplona.amethyst.commons.ui.loadPluralStringRes import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.nip47WalletConnect.NwcSignerState -import com.vitorpamplona.amethyst.service.ClinkDebitPayer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.sats +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.clink.debits.DebitFrequency import com.vitorpamplona.quartz.experimental.clink.debits.DebitResponse import com.vitorpamplona.quartz.experimental.clink.pointers.ClinkPointerParser @@ -375,7 +376,7 @@ class WalletViewModel : ViewModel() { // treat it as "no response" so the dialog dismisses instead of hanging on a spinner. val response = try { - ClinkDebitPayer.requestBudget(acc, pointer, amountSats, frequency) + ClinkDebitPayer.requestBudget(acc, Amethyst.instance.torEvaluatorFlow, pointer, amountSats, frequency) } catch (_: IllegalArgumentException) { null } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/datasource/OnchainZapsFilterAssemblerSubscription.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/datasource/OnchainZapsFilterAssemblerSubscription.kt index efe1a1bb00..247c2fdb01 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/datasource/OnchainZapsFilterAssemblerSubscription.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/datasource/OnchainZapsFilterAssemblerSubscription.kt @@ -25,7 +25,7 @@ import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription import com.vitorpamplona.amethyst.commons.relayClient.wallet.OnchainZapsQueryState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Lifecycle-aware relay subscription for kind-8333 zaps involving [user], diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/wizard/CashuWalletWizardScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/wizard/CashuWalletWizardScreen.kt index b16fb330ee..8f3bc76fa8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/wizard/CashuWalletWizardScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/wizard/CashuWalletWizardScreen.kt @@ -101,7 +101,7 @@ import com.vitorpamplona.amethyst.commons.resources.cashu_wizard_title import com.vitorpamplona.amethyst.commons.resources.cashu_wizard_use_wallet import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import java.text.NumberFormat /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/wizard/CashuWalletWizardViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/wizard/CashuWalletWizardViewModel.kt index f8c14aae0e..37fec79deb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/wizard/CashuWalletWizardViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/wizard/CashuWalletWizardViewModel.kt @@ -24,9 +24,9 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.commons.cashu.CashuWalletDiscovery import com.vitorpamplona.amethyst.commons.cashu.ops.describeMintError -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.nip60Cashu.CashuWalletState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.model.nip60Cashu.CashuWalletState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip60Cashu.wallet.CashuWalletEvent import com.vitorpamplona.quartz.nip61Nutzaps.info.NutzapInfoEvent @@ -198,9 +198,11 @@ class CashuWalletWizardViewModel : ViewModel() { found += FoundWallet(evt, evt.createdAt, emptyList(), false, null, emptyMap(), 0L) continue } + // A local, so the null check smart-casts: the config type now lives in commons. + val privkeyHex = config.privkeyHex val recoverable = - if (config.privkeyHex != null && config.mints.isNotEmpty()) { - state.probeRecoverableFromSeed(config.privkeyHex, config.mints) + if (privkeyHex != null && config.mints.isNotEmpty()) { + state.probeRecoverableFromSeed(privkeyHex, config.mints) } else { emptyMap() } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/webBookmarks/WebBookmarksScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/webBookmarks/WebBookmarksScreen.kt index d39857b4df..ab02a59373 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/webBookmarks/WebBookmarksScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/webBookmarks/WebBookmarksScreen.kt @@ -89,24 +89,25 @@ import com.vitorpamplona.amethyst.commons.resources.web_bookmarks import com.vitorpamplona.amethyst.commons.resources.yes import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewState import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.SaveableFeedState import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.model.UrlCachedPreviewer -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.SaveableFeedState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.screen.loggedIn.urlPreview import com.vitorpamplona.quartz.nipB0WebBookmarks.WebBookmarkEvent import kotlinx.coroutines.launch @@ -322,7 +323,7 @@ private fun WebBookmarkCard( ) Text( - text = previewInfo?.verifiedUrl?.host ?: event.url(), + text = previewInfo?.verifiedHost ?: event.url(), style = MaterialTheme.typography.bodySmall, color = Color.Gray, maxLines = 1, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/NewWorkoutScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/NewWorkoutScreen.kt index 141806845b..8a168763c0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/NewWorkoutScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/NewWorkoutScreen.kt @@ -73,8 +73,10 @@ import com.vitorpamplona.amethyst.commons.resources.workout_title import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.PostingTopBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts.labelRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts.symbol import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.suggestion.DetectedWorkoutCarousel import com.vitorpamplona.quartz.experimental.fitness.workout.tags.DistanceTag import com.vitorpamplona.quartz.experimental.fitness.workout.tags.ExerciseType diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/NewWorkoutViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/NewWorkoutViewModel.kt index 6c797b83b6..af70161e48 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/NewWorkoutViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/NewWorkoutViewModel.kt @@ -25,10 +25,11 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.text.onUiThread -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.util.phonePrefersMiles +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.fitness.workout.WorkoutRecordEvent import com.vitorpamplona.quartz.experimental.fitness.workout.avgHeartRate import com.vitorpamplona.quartz.experimental.fitness.workout.calories diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/fitness/MyFitnessFormat.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/fitness/MyFitnessFormat.kt index bd9951aa34..77423c193d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/fitness/MyFitnessFormat.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/fitness/MyFitnessFormat.kt @@ -30,7 +30,7 @@ import com.vitorpamplona.amethyst.commons.resources.my_fitness_unit_km import com.vitorpamplona.amethyst.commons.resources.my_fitness_unit_m import com.vitorpamplona.amethyst.commons.resources.my_fitness_unit_mi import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.phonePrefersMiles +import com.vitorpamplona.amethyst.commons.util.phonePrefersMiles import com.vitorpamplona.quartz.experimental.fitness.workout.tags.DistanceTag import com.vitorpamplona.quartz.experimental.fitness.workout.tags.Elevation import kotlin.math.roundToInt diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/fitness/MyFitnessScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/fitness/MyFitnessScreen.kt index f176ebcc96..4263bac878 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/fitness/MyFitnessScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/fitness/MyFitnessScreen.kt @@ -94,17 +94,17 @@ import com.vitorpamplona.amethyst.commons.resources.my_fitness_window import com.vitorpamplona.amethyst.commons.resources.my_fitness_window_note import com.vitorpamplona.amethyst.commons.resources.my_fitness_workouts import com.vitorpamplona.amethyst.commons.resources.workout_suggestion_connect_details +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts.labelRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts.symbol import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.workouts.health.HealthConnectManager -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.health.HealthConnectRationaleActivity -import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.labelRes import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.suggestion.toNewWorkoutRoute -import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.symbol /** * The user's own training, summarised: how much they did this week against last, what they diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/health/HealthConnectRationaleActivity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/health/HealthConnectRationaleActivity.kt index bd3f830fca..e8814cd4ac 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/health/HealthConnectRationaleActivity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/health/HealthConnectRationaleActivity.kt @@ -26,6 +26,7 @@ import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.core.net.toUri +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts.health.HealthConnectRationaleScreen import com.vitorpamplona.amethyst.ui.theme.AmethystTheme /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/suggestion/DetectedWorkoutCarousel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/suggestion/DetectedWorkoutCarousel.kt index ffc23b3d25..8c8fca7eab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/suggestion/DetectedWorkoutCarousel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/suggestion/DetectedWorkoutCarousel.kt @@ -71,13 +71,13 @@ import com.vitorpamplona.amethyst.commons.resources.workout_suggestion_connect_m import com.vitorpamplona.amethyst.commons.resources.workout_suggestion_connect_title import com.vitorpamplona.amethyst.commons.resources.workout_suggestion_distance_km import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts.labelRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts.symbol import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.workouts.health.HealthConnectManager import com.vitorpamplona.amethyst.service.workouts.health.publishedWorkoutsOf -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.health.HealthConnectRationaleActivity -import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.labelRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.symbol import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import java.time.Duration diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/ExternalSignerButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/ExternalSignerButton.kt index d6e6c4fbc5..e7e82641c7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/ExternalSignerButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/ExternalSignerButton.kt @@ -64,9 +64,12 @@ import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size0dp import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.Size40dp -import com.vitorpamplona.amethyst.model.DefaultSignerPermissions +import com.vitorpamplona.quartz.nip37Drafts.DraftWrapEvent +import com.vitorpamplona.quartz.nip42RelayAuth.RelayAuthEvent +import com.vitorpamplona.quartz.nip55AndroidSigner.api.CommandType import com.vitorpamplona.quartz.nip55AndroidSigner.api.PubKeyResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult +import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.Permission import com.vitorpamplona.quartz.nip55AndroidSigner.client.ExternalSignerLogin import com.vitorpamplona.quartz.nip55AndroidSigner.client.getExternalSignersInstalled import com.vitorpamplona.quartz.utils.Log @@ -196,3 +199,15 @@ fun ExternalSignerButton(loginViewModel: LoginViewModel) { ) } } + +/** What Amethyst asks a NIP-55 signer app to pre-approve when the user logs in with it. */ +val DefaultSignerPermissions = + listOf( + Permission(CommandType.SIGN_EVENT, RelayAuthEvent.KIND), + Permission(CommandType.SIGN_EVENT, DraftWrapEvent.KIND), + Permission(CommandType.NIP04_ENCRYPT), + Permission(CommandType.NIP04_DECRYPT), + Permission(CommandType.NIP44_DECRYPT), + Permission(CommandType.NIP44_DECRYPT), + Permission(CommandType.DECRYPT_ZAP_EVENT), + ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/KeyTextField.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/KeyTextField.kt index a91a184f20..f29c9a28de 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/KeyTextField.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/KeyTextField.kt @@ -44,17 +44,17 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.unit.dp -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.resources.Res import com.vitorpamplona.amethyst.commons.resources.hide_password +import com.vitorpamplona.amethyst.commons.resources.ic_qrcode import com.vitorpamplona.amethyst.commons.resources.login_with_qr_code import com.vitorpamplona.amethyst.commons.resources.nsec_npub_hex_private_key import com.vitorpamplona.amethyst.commons.resources.show_password +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.painterRes import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.SimpleQrCodeScanner @Composable @@ -113,7 +113,7 @@ fun KeyTextField( } IconButton(onClick = { dialogOpen = true }) { Icon( - painter = painterRes(R.drawable.ic_qrcode, 5), + painter = painterRes(Res.drawable.ic_qrcode, 5), contentDescription = stringRes(Res.string.login_with_qr_code), modifier = Modifier.size(24.dp), tint = MaterialTheme.colorScheme.primary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt index d10655579f..2d01d2adab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.theme import android.app.Activity import androidx.compose.material3.ColorScheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember @@ -38,6 +39,11 @@ import com.vitorpamplona.amethyst.commons.model.AccentColorType import com.vitorpamplona.amethyst.commons.model.FontFamilyType import com.vitorpamplona.amethyst.commons.model.FontSizeType import com.vitorpamplona.amethyst.commons.model.ThemeType +import com.vitorpamplona.amethyst.commons.ui.components.LocalInlineQuoteRenderer +import com.vitorpamplona.amethyst.commons.ui.components.LocalTranslationPlatform +import com.vitorpamplona.amethyst.commons.ui.note.platform.LocalNotePlatform +import com.vitorpamplona.amethyst.commons.ui.platform.LocalAppPlatform +import com.vitorpamplona.amethyst.commons.ui.richtext.LocalRichTextPlatform import com.vitorpamplona.amethyst.commons.ui.screen.DisplaySettings import com.vitorpamplona.amethyst.commons.ui.screen.collectDisplaySettings import com.vitorpamplona.amethyst.commons.ui.theme.AmethystMaterialTheme @@ -46,6 +52,11 @@ import com.vitorpamplona.amethyst.commons.ui.theme.amethystLightColors import com.vitorpamplona.amethyst.commons.ui.theme.isDarkTheme import com.vitorpamplona.amethyst.commons.ui.theme.isLight import com.vitorpamplona.amethyst.commons.ui.theme.transparentBackground +import com.vitorpamplona.amethyst.ui.components.AndroidRichTextPlatform +import com.vitorpamplona.amethyst.ui.components.DefaultInlineQuoteRenderer +import com.vitorpamplona.amethyst.ui.components.FlavorTranslationPlatform +import com.vitorpamplona.amethyst.ui.note.platform.AndroidNotePlatform +import com.vitorpamplona.amethyst.ui.platform.AndroidAppPlatform val chartLightColors = VicoTheme( @@ -120,8 +131,19 @@ fun AmethystTheme( // ImageLoaderSetup registers the avatar thumbnail cache and the local Blossom bridge. profilePictureCache = true, colors = colors, - content = content, - ) + ) { + // The platform halves of the shared note and rich-text renderers: media, LaTeX, payments, + // link previews, the quoted-note card, the note types built on platform engines and the + // flavour's translator. Every Activity root goes through this theme. + CompositionLocalProvider( + LocalRichTextPlatform provides AndroidRichTextPlatform, + LocalInlineQuoteRenderer provides DefaultInlineQuoteRenderer, + LocalTranslationPlatform provides FlavorTranslationPlatform, + LocalNotePlatform provides AndroidNotePlatform, + LocalAppPlatform provides AndroidAppPlatform, + content = content, + ) + } val view = LocalView.current if (!view.isInEditMode) { diff --git a/amethyst/src/main/res/drawable-night/nip_05.xml b/amethyst/src/main/res/drawable-night/nip_05.xml deleted file mode 100644 index bc7967c176..0000000000 --- a/amethyst/src/main/res/drawable-night/nip_05.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/amethyst/src/play/java/com/vitorpamplona/amethyst/appfunctions/AmethystAppFunctions.kt b/amethyst/src/play/java/com/vitorpamplona/amethyst/appfunctions/AmethystAppFunctions.kt index c865137a76..9ad918b996 100644 --- a/amethyst/src/play/java/com/vitorpamplona/amethyst/appfunctions/AmethystAppFunctions.kt +++ b/amethyst/src/play/java/com/vitorpamplona/amethyst/appfunctions/AmethystAppFunctions.kt @@ -31,11 +31,11 @@ import com.vitorpamplona.amethyst.commons.actions.FollowActions import com.vitorpamplona.amethyst.commons.actions.SearchActions import com.vitorpamplona.amethyst.commons.actions.ZapActions import com.vitorpamplona.amethyst.commons.defaults.DefaultNIP65RelaySet +import com.vitorpamplona.amethyst.commons.home.dal.HomeNewThreadFeedFilter import com.vitorpamplona.amethyst.commons.model.payments.PaymentSource import com.vitorpamplona.amethyst.commons.relayClient.nip17Dm.unwrapAndUnsealOrNull +import com.vitorpamplona.amethyst.commons.service.ClinkDebitPayer import com.vitorpamplona.amethyst.commons.service.lnurl.LightningAddressResolver -import com.vitorpamplona.amethyst.service.ClinkDebitPayer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.dal.HomeNewThreadFeedFilter import com.vitorpamplona.quartz.experimental.clink.pointers.NDebit import com.vitorpamplona.quartz.lightning.LnInvoiceUtil import com.vitorpamplona.quartz.marmot.RecipientRelayFetcher @@ -377,7 +377,7 @@ class AmethystAppFunctions { * account, no follows, or no relays configured. */ private suspend fun fetchFollowFeed( - account: com.vitorpamplona.amethyst.model.Account, + account: com.vitorpamplona.amethyst.commons.model.Account, sinceSecs: Long?, limit: Int, ): List { @@ -1370,7 +1370,7 @@ class AmethystAppFunctions { } private suspend fun zapUserViaLightning( - account: com.vitorpamplona.amethyst.model.Account, + account: com.vitorpamplona.amethyst.commons.model.Account, recipientPub: HexKey, sats: Long, comment: String, @@ -1440,7 +1440,7 @@ class AmethystAppFunctions { } private suspend fun zapUserViaOnchain( - account: com.vitorpamplona.amethyst.model.Account, + account: com.vitorpamplona.amethyst.commons.model.Account, recipientPub: HexKey, sats: Long, comment: String, @@ -1677,7 +1677,7 @@ class AmethystAppFunctions { */ private suspend fun fetchProfileForZap( client: com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient, - account: com.vitorpamplona.amethyst.model.Account, + account: com.vitorpamplona.amethyst.commons.model.Account, pubkey: HexKey, ): String? { val relays = @@ -1715,7 +1715,7 @@ class AmethystAppFunctions { * [PayOutcome.errorMessage]) on rejection or timeout. */ private suspend fun payViaDefaultSourceOrNull( - account: com.vitorpamplona.amethyst.model.Account, + account: com.vitorpamplona.amethyst.commons.model.Account, bolt11: String, zappedNote: com.vitorpamplona.amethyst.commons.model.Note?, ): PayOutcome? = @@ -1727,11 +1727,11 @@ class AmethystAppFunctions { /** Pays [bolt11] via a CLINK debit pointer, mapping the kind-21002 reply to a [PayOutcome]. */ private suspend fun payViaClinkDebit( - account: com.vitorpamplona.amethyst.model.Account, + account: com.vitorpamplona.amethyst.commons.model.Account, pointer: NDebit, bolt11: String, ): PayOutcome { - val response = ClinkDebitPayer.payInvoice(account, pointer, bolt11) + val response = ClinkDebitPayer.payInvoice(account, Amethyst.instance.torEvaluatorFlow, pointer, bolt11) return when { response == null -> PayOutcome(false, null, "CLINK debit wallet didn't respond within ${ClinkDebitPayer.DEFAULT_TIMEOUT_MS / 1000}s") @@ -1746,7 +1746,7 @@ class AmethystAppFunctions { * seconds; bounded by [NWC_PAYMENT_TIMEOUT_MS] so a hung wallet can't stall dispatch. */ private suspend fun payViaNwc( - account: com.vitorpamplona.amethyst.model.Account, + account: com.vitorpamplona.amethyst.commons.model.Account, bolt11: String, zappedNote: com.vitorpamplona.amethyst.commons.model.Note?, ): PayOutcome { @@ -1836,7 +1836,7 @@ class AmethystAppFunctions { * a clarifying prompt to the user. */ private fun verifyExpectedRecipient( - account: com.vitorpamplona.amethyst.model.Account, + account: com.vitorpamplona.amethyst.commons.model.Account, target: HexKey, expectedDisplayName: String?, requireFollow: Boolean, diff --git a/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/CachedTranslation.kt b/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/CachedTranslation.kt index cc7229491f..d4fea19cf7 100644 --- a/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/CachedTranslation.kt +++ b/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/CachedTranslation.kt @@ -20,17 +20,17 @@ */ package com.vitorpamplona.amethyst.ui.components +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.lang.TranslationsCache -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel /** * The already-computed translation of [content] under the current language settings, or null * when no translation occurred (same language, undetected source, blocklisted) or none is * cached. Cache-only on purpose: this backs the "Copy Translated" option of the copy-text * menus, which only applies to text the user is looking at — and rendering it through - * [TranslatableRichTextViewer] is what populated the cache. + * [MlKitTranslationPlatform] is what populated the cache. */ -fun cachedTranslation( +internal fun cachedMlKitTranslation( content: String, accountViewModel: AccountViewModel, ): String? { diff --git a/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt b/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/MlKitTranslationPlatform.kt similarity index 86% rename from amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt rename to amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/MlKitTranslationPlatform.kt index 890da0e1a1..16801a66e0 100644 --- a/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt +++ b/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/MlKitTranslationPlatform.kt @@ -23,22 +23,19 @@ package com.vitorpamplona.amethyst.ui.components import androidx.compose.foundation.layout.Column import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists import com.vitorpamplona.amethyst.commons.ui.components.TranslationConfig -import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.components.TranslationPlatform import com.vitorpamplona.amethyst.commons.ui.theme.MaxWidthPaddingTop5dp +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.lang.LanguageTranslatorService import com.vitorpamplona.amethyst.service.lang.ResultOrError import com.vitorpamplona.amethyst.service.lang.TranslationsCache -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ensureActive @@ -46,46 +43,36 @@ import kotlinx.coroutines.tasks.await import kotlinx.coroutines.withContext import kotlin.coroutines.coroutineContext -@Composable -fun TranslatableRichTextViewer( - content: String, - canPreview: Boolean, - quotesLeft: Int, - modifier: Modifier = Modifier, - tags: ImmutableListOfLists, - backgroundColor: MutableState, - id: String, - callbackUri: String? = null, - authorPubKey: String? = null, - accountViewModel: AccountViewModel, - nav: INav, -) { - TranslatableRichTextViewer( - content = content, - id = id, - accountViewModel = accountViewModel, - ) { - ExpandableRichTextViewer( - it, - canPreview, - quotesLeft, - modifier, - tags, - backgroundColor, - id, - callbackUri, - authorPubKey, - accountViewModel, - nav, - ) - } +/** ML Kit's on-device translator, which only the Play build ships. */ +object MlKitTranslationPlatform : TranslationPlatform { + @Composable + override fun Translatable( + content: String, + id: String, + translationMessageModifier: Modifier, + accountViewModel: AccountViewModel, + displayText: @Composable (String) -> Unit, + ) = MlKitTranslatable(content, id, translationMessageModifier, accountViewModel, displayText) + + @Composable + override fun rememberTranslation( + content: String, + accountViewModel: AccountViewModel, + ): String = rememberMlKitTranslation(content, accountViewModel) + + override fun cachedTranslation( + content: String, + accountViewModel: AccountViewModel, + ): String? = cachedMlKitTranslation(content, accountViewModel) } +val FlavorTranslationPlatform: TranslationPlatform = MlKitTranslationPlatform + @Composable -fun TranslatableRichTextViewer( +private fun MlKitTranslatable( content: String, id: String, - translationMessageModifier: Modifier = MaxWidthPaddingTop5dp, + translationMessageModifier: Modifier, accountViewModel: AccountViewModel, displayText: @Composable (String) -> Unit, ) { @@ -131,13 +118,13 @@ fun TranslatableRichTextViewer( /** * The translation of [content] under the current language settings, or [content] unchanged when - * no translation applies. Same machinery and cache as [TranslatableRichTextViewer] but without + * no translation applies. Same machinery and cache as [MlKitTranslatable] but without * the status bar, for callers that already render one and need a second string translated in * step with it — e.g. a NIP-84 highlight, which must translate the quoted passage alongside the * context in order to keep locating the passage inside it. */ @Composable -fun rememberTranslation( +private fun rememberMlKitTranslation( content: String, accountViewModel: AccountViewModel, ): String { diff --git a/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslationStatusBar.kt b/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslationStatusBar.kt index 3bca2e4d35..965792aee0 100644 --- a/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslationStatusBar.kt +++ b/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslationStatusBar.kt @@ -56,7 +56,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.Font14SP import com.vitorpamplona.amethyst.commons.ui.theme.MaxWidthPaddingTop5dp import com.vitorpamplona.amethyst.commons.ui.theme.lessImportantLink -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import java.util.Locale /** diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/UserSuggestionPriorityRankingTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/UserSuggestionPriorityRankingTest.kt index fed8c9f63b..1bf6800661 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/UserSuggestionPriorityRankingTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/UserSuggestionPriorityRankingTest.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.UserContext -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.rankPriorityFirst +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.rankPriorityFirst import org.junit.Assert.assertEquals import org.junit.Assert.assertSame import org.junit.Test diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/CalendarAppointmentCacheIdentityTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/CalendarAppointmentCacheIdentityTest.kt index 4558af59bf..695ae7e5a2 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/CalendarAppointmentCacheIdentityTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/CalendarAppointmentCacheIdentityTest.kt @@ -20,9 +20,9 @@ */ package com.vitorpamplona.amethyst.calendar +import com.vitorpamplona.amethyst.commons.calendars.dal.CalendarAppointmentsFeedFilter import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet -import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.dal.CalendarAppointmentsFeedFilter import com.vitorpamplona.quartz.nip52Calendar.appt.time.CalendarTimeSlotEvent import org.junit.Assert.assertEquals import org.junit.Assert.assertNotEquals @@ -35,7 +35,7 @@ import org.junit.Test * A 31923 appointment lands in `LocalCache` as TWO objects: the canonical `AddressableNote` under * its address, and a version note under the event id. Only the first is handed to feeds when the * event arrives, and only the first survives the cache sweep that runs on every app switch — so a - * feed must query the addressables, which is what [com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.dal.CalendarAppointmentsFeedFilter] + * feed must query the addressables, which is what [com.vitorpamplona.amethyst.commons.calendars.dal.CalendarAppointmentsFeedFilter] * now does. Scanning `LocalCache.notes` instead gave the calendar views a second identity for the * same appointment and made them flicker events in and out around every trip to the background. * diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/CalendarTestAccount.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/CalendarTestAccount.kt index 365bc21e12..b592ec84b2 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/CalendarTestAccount.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/CalendarTestAccount.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.amethyst.calendar +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.LiveHiddenUsers +import com.vitorpamplona.amethyst.commons.model.nip51Lists.HiddenUsersState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.global.GlobalTopNavFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.nip51Lists.HiddenUsersState import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.flow.MutableStateFlow diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/CalendarsViewModelFlowTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/CalendarsViewModelFlowTest.kt index 95b7f70d16..a213d29eb7 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/CalendarsViewModelFlowTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/CalendarsViewModelFlowTest.kt @@ -23,11 +23,11 @@ package com.vitorpamplona.amethyst.calendar import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelStore import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.calendars.dal.CalendarAppointmentsFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.CalendarsViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.dal.CalendarAppointmentsFeedFilter import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip52Calendar.appt.time.CalendarTimeSlotEvent import com.vitorpamplona.quartz.nip52Calendar.calendar.CalendarCollectionEvent diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/RsvpDTagTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/RsvpDTagTest.kt index 878356910e..0275d41d48 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/RsvpDTagTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/RsvpDTagTest.kt @@ -20,8 +20,8 @@ */ package com.vitorpamplona.amethyst.calendar -import com.vitorpamplona.amethyst.ui.note.types.rsvpAddressFor -import com.vitorpamplona.amethyst.ui.note.types.rsvpDTagFor +import com.vitorpamplona.amethyst.commons.ui.note.types.rsvpAddressFor +import com.vitorpamplona.amethyst.commons.ui.note.types.rsvpDTagFor import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip52Calendar.rsvp.CalendarRSVPEvent import org.junit.Assert.assertEquals diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/RsvpTagAssemblyTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/RsvpTagAssemblyTest.kt index 5045edf354..6c17a54f33 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/RsvpTagAssemblyTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/calendar/RsvpTagAssemblyTest.kt @@ -31,7 +31,7 @@ import org.junit.Assert.assertEquals import org.junit.Test /** - * Locks in the tag shape [com.vitorpamplona.amethyst.ui.note.types.CalendarRsvpRow] assembles. + * Locks in the tag shape [com.vitorpamplona.amethyst.commons.ui.note.types.CalendarRsvpRow] assembles. * * The `p` count is the load-bearing assertion. Kind 31925 is in `NOTIFICATION_KINDS`, and * `NotificationFeedFilter.tagsAnEventByUser` returns true for it (a `BaseAddressableEvent` falls diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/nip46Signer/Nip46ConsentInfoBuilderTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/connectedApps/consent/Nip46ConsentInfoBuilderTest.kt similarity index 98% rename from amethyst/src/test/java/com/vitorpamplona/amethyst/model/nip46Signer/Nip46ConsentInfoBuilderTest.kt rename to amethyst/src/test/java/com/vitorpamplona/amethyst/connectedApps/consent/Nip46ConsentInfoBuilderTest.kt index bb5344e8c6..59cc601902 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/nip46Signer/Nip46ConsentInfoBuilderTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/connectedApps/consent/Nip46ConsentInfoBuilderTest.kt @@ -18,10 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip46Signer +package com.vitorpamplona.amethyst.connectedApps.consent import com.vitorpamplona.amethyst.commons.connectedApps.signers.NostrSignerOp -import com.vitorpamplona.amethyst.connectedApps.consent.SignerConsentInfo import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequest diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/cordn/CordnRuntimeTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/cordn/CordnRuntimeTest.kt index 8adf6ce8db..7a370320b6 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/cordn/CordnRuntimeTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/cordn/CordnRuntimeTest.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.amethyst.commons.cordn.CordnCoordinatorLink import com.vitorpamplona.amethyst.commons.cordn.CordnCoordinatorLinkFactory import com.vitorpamplona.amethyst.commons.cordn.CordnHandedOffException import com.vitorpamplona.amethyst.commons.cordn.CordnStorageLayout -import com.vitorpamplona.amethyst.model.cordn.CordnRuntime +import com.vitorpamplona.amethyst.commons.model.cordn.CordnRuntime import com.vitorpamplona.quartz.contextvm.core.CvmKinds import com.vitorpamplona.quartz.cordn.spec00Coordinator.AvailableKeyPackage import com.vitorpamplona.quartz.cordn.spec00Coordinator.ConsumedJoinRequestRef @@ -59,6 +59,7 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withTimeoutOrNull +import okio.Path.Companion.toOkioPath import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse @@ -180,7 +181,7 @@ class CordnRuntimeTest { ) = CordnRuntime( accountSigner = signer, client = client, - filesDir = root, + filesDir = root.toOkioPath(), scope = scope, cipher = XorCipher(), links = links, @@ -443,8 +444,8 @@ class CordnRuntimeTest { // A gid is unique only within one coordinator, so both hold // "shared-gid" as unrelated groups. Deleting a level too high takes // both, and the only visible symptom is a room that vanished. - assertFalse(CordnStorageLayout.directoryFor(root, account, keyA).exists()) - assertTrue(CordnStorageLayout.directoryFor(root, account, keyB).exists()) + assertFalse(CordnStorageLayout.directoryFor(root.toOkioPath(), account, keyA).toFile().exists()) + assertTrue(CordnStorageLayout.directoryFor(root.toOkioPath(), account, keyB).toFile().exists()) assertEquals( listOf(keyB), runtime.groups.all.value @@ -466,7 +467,7 @@ class CordnRuntimeTest { CordnRuntime( accountSigner = NostrSignerInternal(KeyPair()), client = EmptyNostrClient(), - filesDir = root, + filesDir = root.toOkioPath(), scope = runtimeScope(), cipher = XorCipher(), links = links, diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/AddressedAuthorRoutingTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/AddressedAuthorRoutingTest.kt index 3033cec228..8c90baa29f 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/AddressedAuthorRoutingTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/AddressedAuthorRoutingTest.kt @@ -20,6 +20,8 @@ */ package com.vitorpamplona.amethyst.model +import com.vitorpamplona.amethyst.commons.model.EventBroadcaster +import com.vitorpamplona.amethyst.commons.model.addressedAuthors import com.vitorpamplona.quartz.nip52Calendar.calendar.CalendarCollectionEvent import com.vitorpamplona.quartz.nip52Calendar.rsvp.CalendarRSVPEvent import org.junit.Assert.assertEquals diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/BuzzDmNotificationResolutionTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/BuzzDmNotificationResolutionTest.kt index 1ede333c8f..2f5e9c8449 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/BuzzDmNotificationResolutionTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/BuzzDmNotificationResolutionTest.kt @@ -87,7 +87,7 @@ class BuzzDmNotificationResolutionTest { ) // Attach a 40002 by consuming it (which materializes the group channel) and then set its 39000 - // metadata directly — the real 39000 consume gates on Amethyst.instance.nip11Cache, which isn't + // metadata directly — the real 39000 consume gates on LocalCache.appHost.nip11Cache, which isn't // available in a plain JVM test (see BuzzWorkspaceChannelTest). We still drive the real resolver. private fun consumeMessageInto( channelId: String, diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/MutedPublicChatsSyncTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/MutedPublicChatsSyncTest.kt index 9954f481e6..a228d9fcfc 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/MutedPublicChatsSyncTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/MutedPublicChatsSyncTest.kt @@ -20,6 +20,7 @@ */ package com.vitorpamplona.amethyst.model +import com.vitorpamplona.amethyst.commons.model.AccountChatPreferencesInternal import com.vitorpamplona.amethyst.commons.model.mergeMutedPublicChats import com.vitorpamplona.quartz.nip01Core.core.JsonMapper import org.junit.Assert.assertEquals diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/PinnedChatroomsSyncTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/PinnedChatroomsSyncTest.kt index f03d3ec739..07ccb7390f 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/PinnedChatroomsSyncTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/PinnedChatroomsSyncTest.kt @@ -20,6 +20,8 @@ */ package com.vitorpamplona.amethyst.model +import com.vitorpamplona.amethyst.commons.model.AccountChatPreferencesInternal +import com.vitorpamplona.amethyst.commons.model.toChatroomKeys import com.vitorpamplona.quartz.nip01Core.core.JsonMapper import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey import org.junit.Assert.assertEquals diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/ZapAmountMergeTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/ZapAmountMergeTest.kt index 88128d7053..adbbe40256 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/ZapAmountMergeTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/ZapAmountMergeTest.kt @@ -20,6 +20,11 @@ */ package com.vitorpamplona.amethyst.model +import com.vitorpamplona.amethyst.commons.model.AccountZapPreferencesInternal +import com.vitorpamplona.amethyst.commons.model.DefaultOnchainZapAmounts +import com.vitorpamplona.amethyst.commons.model.DefaultZapAmounts +import com.vitorpamplona.amethyst.commons.model.MIN_ONCHAIN_ZAP_SATS +import com.vitorpamplona.amethyst.commons.model.mergeZapAmounts import org.junit.Assert.assertEquals import org.junit.Test diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/buzz/BuzzChannelTypesTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/buzz/BuzzChannelTypesTest.kt index 14ed2d4e7c..b14e6a29c6 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/buzz/BuzzChannelTypesTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/buzz/BuzzChannelTypesTest.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.model.buzz import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.buzz.ChannelClassification +import com.vitorpamplona.amethyst.commons.model.buzz.buzzChannelTypes import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip29RelayGroups.metadata.GroupMetadataEvent import org.junit.Assert.assertEquals diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/nip51Lists/BlockedRelayListAddRelayTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/nip51Lists/BlockedRelayListAddRelayTest.kt index a015169a59..ba878c694c 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/nip51Lists/BlockedRelayListAddRelayTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/nip51Lists/BlockedRelayListAddRelayTest.kt @@ -21,10 +21,10 @@ package com.vitorpamplona.amethyst.model.nip51Lists import android.os.Looper +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip51Lists.blockedRelays.BlockedRelayListDecryptionCache -import com.vitorpamplona.amethyst.model.AccountSettings -import com.vitorpamplona.amethyst.model.nip51Lists.blockedRelays.BlockedRelayListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.blockedRelays.BlockedRelayListState import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/nipB7Blossom/BlossomServerListResetTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/nipB7Blossom/BlossomServerListResetTest.kt index f8a584dda1..ee388a6c5f 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/nipB7Blossom/BlossomServerListResetTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/nipB7Blossom/BlossomServerListResetTest.kt @@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.model.nipB7Blossom import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType +import com.vitorpamplona.amethyst.commons.model.nipB7Blossom.resetTargetOrNull import org.junit.Assert.assertEquals import org.junit.Assert.assertNull import org.junit.Test diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/preferences/BottomBarPersistenceTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/preferences/BottomBarPersistenceTest.kt index 5a510edfd8..654afd7901 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/preferences/BottomBarPersistenceTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/preferences/BottomBarPersistenceTest.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.amethyst.model.preferences +import com.vitorpamplona.amethyst.commons.model.AccountNavigationPreferencesInternal import com.vitorpamplona.amethyst.commons.model.navigation.BottomBarEntry +import com.vitorpamplona.amethyst.commons.model.navigation.DefaultBottomBarEntries import com.vitorpamplona.amethyst.commons.model.navigation.NavBarItem -import com.vitorpamplona.amethyst.model.AccountNavigationPreferencesInternal -import com.vitorpamplona.amethyst.ui.navigation.bottombars.DefaultBottomBarEntries import com.vitorpamplona.quartz.nip01Core.core.JsonMapper import org.junit.Assert.assertEquals import org.junit.Test @@ -31,7 +31,7 @@ import org.junit.Test /** * Locks the per-account bottom-bar persistence: the pinned list now lives inside the NIP-78 * app-specific data blob ([AccountNavigationPreferencesInternal], one field of - * [com.vitorpamplona.amethyst.model.AccountSyncedSettingsInternal]) rather than the app-global + * [com.vitorpamplona.amethyst.commons.model.AccountSyncedSettingsInternal]) rather than the app-global * DataStore, so every account keeps its own bar and it syncs across the user's devices. */ class BottomBarPersistenceTest { diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/preferences/DrawerPersistenceTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/preferences/DrawerPersistenceTest.kt index 00bf72e09e..e9135212b4 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/preferences/DrawerPersistenceTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/preferences/DrawerPersistenceTest.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.amethyst.model.preferences +import com.vitorpamplona.amethyst.commons.model.AccountNavigationPreferencesInternal import com.vitorpamplona.amethyst.commons.model.navigation.NavBarItem import com.vitorpamplona.amethyst.commons.model.navigation.navBarItemsFromNames import com.vitorpamplona.amethyst.commons.model.navigation.toNames -import com.vitorpamplona.amethyst.model.AccountNavigationPreferencesInternal import com.vitorpamplona.quartz.nip01Core.core.JsonMapper import org.junit.Assert.assertEquals import org.junit.Test diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/zap/RailCapabilityOnchainGateTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/zap/RailCapabilityOnchainGateTest.kt index 3625643392..43c3193a9b 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/model/zap/RailCapabilityOnchainGateTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/model/zap/RailCapabilityOnchainGateTest.kt @@ -20,7 +20,7 @@ */ package com.vitorpamplona.amethyst.model.zap -import com.vitorpamplona.amethyst.model.MIN_ONCHAIN_ZAP_SATS +import com.vitorpamplona.amethyst.commons.model.MIN_ONCHAIN_ZAP_SATS import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/navigation/BottomBarSettingsStateTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/navigation/BottomBarSettingsStateTest.kt index 634f92765d..9d8beb9dd6 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/navigation/BottomBarSettingsStateTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/navigation/BottomBarSettingsStateTest.kt @@ -21,9 +21,9 @@ package com.vitorpamplona.amethyst.navigation import com.vitorpamplona.amethyst.commons.model.navigation.BottomBarEntry +import com.vitorpamplona.amethyst.commons.model.navigation.DefaultBottomBarEntries import com.vitorpamplona.amethyst.commons.model.navigation.NavBarItem import com.vitorpamplona.amethyst.commons.model.navigation.stableKey -import com.vitorpamplona.amethyst.ui.navigation.bottombars.DefaultBottomBarEntries import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.BottomBarEditing import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.BottomBarSettingsState import org.junit.Assert.assertEquals diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/Bolt12LightningFallbackTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/Bolt12LightningFallbackTest.kt index 98fe9c90fc..1140a2021f 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/Bolt12LightningFallbackTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/Bolt12LightningFallbackTest.kt @@ -20,6 +20,7 @@ */ package com.vitorpamplona.amethyst.service +import com.vitorpamplona.amethyst.commons.service.Bolt12LightningFallback import com.vitorpamplona.quartz.nip47WalletConnect.rpc.NwcErrorCode import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/location/LocationStateTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/location/LocationStateTest.kt index 7c9e471bce..f8dfd2ae0a 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/location/LocationStateTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/location/LocationStateTest.kt @@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.service.location import android.content.Context import android.location.Location +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.CoroutineScope @@ -164,7 +165,7 @@ class LocationStateTest { advanceUntilIdle() val fixWhileForeground = state.geohashStateFlow.value - assertTrue("expected a Success, got $fixWhileForeground", fixWhileForeground is LocationState.LocationResult.Success) + assertTrue("expected a Success, got $fixWhileForeground", fixWhileForeground is LocationResult.Success) foreground.value = false // Real grace-period wait, not a test artefact: `settledForeground` @@ -210,7 +211,7 @@ class LocationStateTest { val state = stateWith(backgroundScope, foreground, probe) state.setLocationPermission(true) - val seen = mutableListOf() + val seen = mutableListOf() backgroundScope.launch { state.geohashStateFlow.collect { seen.add(it) } } advanceUntilIdle() @@ -227,7 +228,7 @@ class LocationStateTest { assertTrue( "returning to foreground must not flash Loading — AroundMeFeedFlow renders an empty feed for it. Saw: ${seen.drop(afterBackground)}", - seen.drop(afterBackground).none { it is LocationState.LocationResult.Loading }, + seen.drop(afterBackground).none { it is LocationResult.Loading }, ) } @@ -253,11 +254,11 @@ class LocationStateTest { val state = stateWith(backgroundScope, foreground, probe) state.setLocationPermission(true) - val seen = mutableListOf() + val seen = mutableListOf() backgroundScope.launch { state.geohashStateFlow.collect { seen.add(it) } } advanceUntilIdle() - assertTrue("expected Loading, saw $seen", seen.any { it is LocationState.LocationResult.Loading }) + assertTrue("expected Loading, saw $seen", seen.any { it is LocationResult.Loading }) } @Test @@ -271,7 +272,7 @@ class LocationStateTest { backgroundScope.launch { state.geohashStateFlow.collect { } } advanceUntilIdle() - assertEquals(LocationState.LocationResult.LackPermission, state.geohashStateFlow.value) + assertEquals(LocationResult.LackPermission, state.geohashStateFlow.value) assertEquals(0, probe.subscriptions) } diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/notifications/NotificationDeepLinkTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/notifications/NotificationDeepLinkTest.kt index 60739b6680..7c7a87114e 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/notifications/NotificationDeepLinkTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/notifications/NotificationDeepLinkTest.kt @@ -20,16 +20,16 @@ */ package com.vitorpamplona.amethyst.service.notifications +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.ui.chatroomRoute import com.vitorpamplona.amethyst.ui.isChatroomRoute import com.vitorpamplona.amethyst.ui.isPrivateNoteRoute import com.vitorpamplona.amethyst.ui.navigation.findParameterValue import com.vitorpamplona.amethyst.ui.navigation.findQueryParameterValue -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.ui.privateNoteRoute import com.vitorpamplona.amethyst.ui.uriToRoute import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/RelayAuthPolicyEverywhereTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/RelayAuthPolicyEverywhereTest.kt index a8e74c6479..01cb095e42 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/RelayAuthPolicyEverywhereTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/RelayAuthPolicyEverywhereTest.kt @@ -149,7 +149,7 @@ class RelayAuthPolicyEverywhereTest { } /** - * Why the coordinator routes this through [com.vitorpamplona.amethyst.model.Account], which drops + * Why the coordinator routes this through [com.vitorpamplona.amethyst.commons.model.Account], which drops * the session grants with the flip: a grant left behind outranks the policy, so "never log in" * would keep authenticating exactly the relays the user had just answered "log in" for. */ diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/buzz/FilterWorkspaceInboxToPubkeyTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/buzz/FilterWorkspaceInboxToPubkeyTest.kt index 1349e0ca9a..4200ecd662 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/buzz/FilterWorkspaceInboxToPubkeyTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/buzz/FilterWorkspaceInboxToPubkeyTest.kt @@ -20,6 +20,8 @@ */ package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.buzz +import com.vitorpamplona.amethyst.commons.model.buzz.MembershipNotificationKinds +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.buzz.filterWorkspaceInboxToPubkey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import org.junit.Assert.assertEquals import org.junit.Assert.assertNull diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/PickAccountDataRelaysTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/PickAccountDataRelaysTest.kt index 052d4266b1..51d100705d 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/PickAccountDataRelaysTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/PickAccountDataRelaysTest.kt @@ -20,6 +20,7 @@ */ package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.metadata +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.metadata.pickAccountDataRelays import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import org.junit.Assert.assertEquals import org.junit.Test diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/loaders/AddressableAuthorRelayLoaderSubAssemblerTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/loaders/AddressableAuthorRelayLoaderSubAssemblerTest.kt index 1e30d86b88..927aa17ea2 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/loaders/AddressableAuthorRelayLoaderSubAssemblerTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/loaders/AddressableAuthorRelayLoaderSubAssemblerTest.kt @@ -20,12 +20,12 @@ */ package com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.loaders +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relayClient.event.EventFinderQueryState import com.vitorpamplona.amethyst.commons.relayClient.event.loaders.AddressableAuthorRelayLoaderSubAssembler import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderQueryState -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.Address import io.mockk.every import io.mockk.mockk diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/GiftWrapRedirectRouteTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/GiftWrapRedirectRouteTest.kt index af223a9489..b19891c408 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/GiftWrapRedirectRouteTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/GiftWrapRedirectRouteTest.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.amethyst.ui +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/UriToRouteTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/UriToRouteTest.kt index f1d599464d..8ba0523bc1 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/UriToRouteTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/UriToRouteTest.kt @@ -20,8 +20,8 @@ */ package com.vitorpamplona.amethyst.ui +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.navigation.Route -import com.vitorpamplona.amethyst.model.Account import io.mockk.every import io.mockk.mockk import org.junit.Assert.assertEquals diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedOrderCardTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedOrderCardTest.kt index b34b57ba14..6a61990f50 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedOrderCardTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/dal/NotificationFeedOrderCardTest.kt @@ -20,10 +20,12 @@ */ package com.vitorpamplona.amethyst.ui.dal +import com.vitorpamplona.amethyst.commons.feeds.Card +import com.vitorpamplona.amethyst.commons.feeds.DefaultFeedOrderCard +import com.vitorpamplona.amethyst.commons.feeds.NotificationFeedOrderCard import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.buzz.BuzzChannelInvite -import com.vitorpamplona.amethyst.commons.ui.notifications.Card -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.ChannelInviteCard +import com.vitorpamplona.amethyst.commons.notifications.ChannelInviteCard import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import org.junit.Assert.assertEquals import org.junit.Test diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/CanStartThreadHereTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/CanStartThreadHereTest.kt index 624d5bdf15..3ddc68980c 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/CanStartThreadHereTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/CanStartThreadHereTest.kt @@ -20,6 +20,7 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.canStartThreadHere import com.vitorpamplona.quartz.buzz.workspace.BUZZ_CHANNEL_TYPE_DM import com.vitorpamplona.quartz.buzz.workspace.BUZZ_CHANNEL_TYPE_FORUM import com.vitorpamplona.quartz.buzz.workspace.BUZZ_CHANNEL_TYPE_STREAM diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityModelRulesTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityModelRulesTest.kt index 28871225f3..5183ecd75c 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityModelRulesTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/newCommunity/NewCommunityModelRulesTest.kt @@ -30,7 +30,7 @@ import org.junit.Test /** * Unit tests for the pure-helper portion of [NewCommunityModel] that wires the * structured-rules editor state into a NIP-9B `kind:34551` payload. The full - * `publish()` path needs a live [com.vitorpamplona.amethyst.model.Account] (and + * `publish()` path needs a live [com.vitorpamplona.amethyst.commons.model.Account] (and * thus relays + a signer), so here we exercise the deterministic mapping that * sits between the editor's drafts and the Quartz tag types. */ diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/Nip34NotificationCoverageTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/Nip34NotificationCoverageTest.kt index 11481575d7..0aec3f4deb 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/Nip34NotificationCoverageTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/Nip34NotificationCoverageTest.kt @@ -20,6 +20,7 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.dal +import com.vitorpamplona.amethyst.commons.notifications.dal.NotificationFeedFilter import com.vitorpamplona.amethyst.commons.relayClient.account.nip01Notifications.NotificationsPerKeyKinds2 import com.vitorpamplona.amethyst.commons.relayClient.event.watchers.RepliesAndReactionsKinds2 import com.vitorpamplona.amethyst.commons.relayClient.event.watchers.RootScopedRepliesKinds diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationKindsContractTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationKindsContractTest.kt index 886bf711b9..ddaf1eb3a8 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationKindsContractTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationKindsContractTest.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.dal import com.vitorpamplona.amethyst.commons.moderation.notifications.NotificationKinds +import com.vitorpamplona.amethyst.commons.notifications.dal.NotificationFeedFilter import com.vitorpamplona.quartz.nip59Giftwrap.wraps.EphemeralGiftWrapEvent import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent import com.vitorpamplona.quartz.nipC7Chats.ChatEvent diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationPublicChatReplyTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationPublicChatReplyTest.kt index 92022ae414..ae2aecf636 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationPublicChatReplyTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationPublicChatReplyTest.kt @@ -24,6 +24,7 @@ import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.UserContext +import com.vitorpamplona.amethyst.commons.notifications.dal.NotificationFeedFilter import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent import org.junit.Assert.assertFalse diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationTagsAnEventByUserTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationTagsAnEventByUserTest.kt index f57bf851e3..712d3d3ada 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationTagsAnEventByUserTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationTagsAnEventByUserTest.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.dal import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.notifications.dal.NotificationFeedFilter import com.vitorpamplona.quartz.nip22Comments.CommentEvent import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent import org.junit.Assert.assertFalse diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/eventsync/EventSyncTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/eventsync/EventSyncTest.kt index f729de7e9e..d0f4efe464 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/eventsync/EventSyncTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/eventsync/EventSyncTest.kt @@ -20,6 +20,7 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.eventsync +import com.vitorpamplona.amethyst.commons.relays.eventsync.EventSync import com.vitorpamplona.geode.InProcessRelays import com.vitorpamplona.geode.RelayEngine import com.vitorpamplona.geode.testing.RelayClientTest diff --git a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/CashuContext.kt b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/CashuContext.kt index 0ac9e65b23..fad27a6af2 100644 --- a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/CashuContext.kt +++ b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/CashuContext.kt @@ -31,6 +31,7 @@ import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip60Cashu.history.CashuSpendingHistoryEvent import com.vitorpamplona.quartz.nip60Cashu.mintApi.DeterministicSecretFactory +import com.vitorpamplona.quartz.nip60Cashu.mintApi.OkHttpMintTransport import com.vitorpamplona.quartz.nip60Cashu.quote.CashuMintQuoteEvent import com.vitorpamplona.quartz.nip60Cashu.seed.CashuDeterministic import com.vitorpamplona.quartz.nip60Cashu.token.CashuTokenEvent @@ -79,7 +80,7 @@ class CashuContext( // keypackage — is the CLI's closest analog, so the wallet lands // on the same broad relay set the app would use, not just outbox. publish = { event -> ctx.publish(event, ctx.anyRelays()) }, - okHttpClient = { ctx.okhttp }, + mintTransport = OkHttpMintTransport { ctx.okhttp }, secretFactory = DeterministicSecretFactory( seedProvider = { cachedSeed }, diff --git a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/CordnContext.kt b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/CordnContext.kt index 5e299d73ad..c62f7fe03c 100644 --- a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/CordnContext.kt +++ b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/CordnContext.kt @@ -32,7 +32,8 @@ import com.vitorpamplona.amethyst.commons.cordn.KeyedCordnBlobCipher import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import java.io.File +import okio.Path +import okio.Path.Companion.toOkioPath /** * cordn wiring for the CLI, split out of [Context] the way [CashuContext] is @@ -72,7 +73,7 @@ class CordnContext( accountPubKey = accountPubKey, scopes = FileBackedCordnScopeFactory( - root = ctx.dataDir.root, + root = migrationRoot, cipher = cipher, links = CordnLinks.over(ctx.signer, ctx.client), ), @@ -81,7 +82,7 @@ class CordnContext( private val coordinatorStore by lazy { FileCordnCoordinatorStore( - CordnStorageLayout.accountDirectoryFor(ctx.dataDir.root, accountPubKey), + CordnStorageLayout.accountDirectoryFor(migrationRoot, accountPubKey), cipher, ) } @@ -117,8 +118,8 @@ class CordnContext( it.keyPackages.restore() } - /** Where the cordn tree lives, for the migration verbs. */ - val migrationRoot: File get() = ctx.dataDir.root + /** The root the cordn tree is laid out under, for the stores and the migration verbs. */ + val migrationRoot: Path get() = ctx.dataDir.root.toOkioPath() /** The at-rest cipher, so a migration can read and write the same blobs. */ val blobCipher: CordnBlobCipher get() = cipher diff --git a/commons/ARCHITECTURE.md b/commons/ARCHITECTURE.md index 7fd1105b31..1606e47300 100644 --- a/commons/ARCHITECTURE.md +++ b/commons/ARCHITECTURE.md @@ -4,8 +4,8 @@ | Consumer | Kind | Uses from `commons` | |----------------|------------------------------|----------------------------------------------| -| `amethyst` | Android app (touch-first) | everything (models, state, ViewModels) + `commonsUI` | -| `desktopApp` | Desktop JVM app (mouse-first)| everything (models, state, ViewModels) + `commonsUI` | +| `amethyst` | Android app (phones, tablets, laptops) | everything (models, state, ViewModels) + `commonsUI` | +| `desktopApp` | Desktop JVM app | everything (models, state, ViewModels) + `commonsUI`; today's mouse-first screens are to be replaced by the shared UI | | `cli` (`amy`) | Headless JVM CLI (no UI) | everything — `commons` is headless by construction; it never sees `commonsUI` | | `nappletHost` | Android WebView sandbox | napplet contract + `commonsUI` (for the shell/shim Compose resources) | | iOS (future) | iOS app | everything + `commonsUI`; expected to share most UI with Android | @@ -15,17 +15,21 @@ - **`quartz/`** — Nostr protocol: events, NIPs, crypto, relay framing. No app state, no UI, no caches of "what this user follows." -- **`commons/`** — everything an Amethyst *client* needs that isn't a - platform-native screen, navigation shell, **or Compose UI**: domain models +- **`commons/`** — everything an Amethyst *client* needs that isn't + platform-specific **or Compose UI**: domain models (`Note`, `User`), in-memory state holders, ViewModels, the relay-subscription client, shared business services. - **`commonsUI/`** — the Compose UI components that more than one front end renders, plus everything only they need (icons, theme, Coil fetchers, markdown, the `composeResources` strings/fonts and the generated `Res`). Depends on `commons` as `api`. See `commonsUI/ARCHITECTURE.md`. -- **`amethyst/` & `desktopApp/`** — platform-native screens, navigation - (bottom-nav vs sidebar), gestures, system integration. They assemble - `commons` pieces; they should not re-implement them. +- **`amethyst/` & `desktopApp/`** — platform shims: the Activity / Window + entry points, services, system integration, and the platform implementations + of shared ports. They assemble `commons` pieces; they should not + re-implement them. **Screens and navigation are being moved into + `commonsUI`** so Android (which now also runs on laptops) and a new JVM + Desktop app render one UI; see + [`plans/2026-09-27-one-ui-android-desktop.md`](plans/2026-09-27-one-ui-android-desktop.md). > The goal is **"write it once in `commons`"**. Before adding a manager, cache, > filter, ViewModel, or composable to an app module, check whether it already @@ -223,9 +227,10 @@ compiles: `commonMain` → `jvmAndroid` → platform-specific. See ### Where does my code go? (quick guide) 1. **Pure Nostr protocol** (events/NIPs/crypto)? → not here, it's `quartz`. -2. **A composable** rendered by ≥2 front ends, or that you want iOS to share? → - `commonsUI`, in `ui/` or `/ui` (same package tree as here). - Also anything that imports Coil, `Res`, or a `foundation`/`ui` state type. +2. **A composable** (screens and navigation chrome included)? → `commonsUI`, in + `ui/` or `/ui` (same package tree as here). Also anything that + imports Coil, `Res`, or a `foundation`/`ui` state type. Only the platform + entry points and system integrations stay in `amethyst/`/`desktopApp/`. 3. **A ViewModel / `StateFlow` state holder**? → `viewmodels` or `state` (or `` if feature-scoped). Keep it CLI-safe where practical. 4. **Relay subscription / filter assembly**? → `relayClient`. diff --git a/commons/plans/2026-08-30-commons-migration-sweep.md b/commons/plans/2026-08-30-commons-migration-sweep.md index e5ee522cd6..685daf0746 100644 --- a/commons/plans/2026-08-30-commons-migration-sweep.md +++ b/commons/plans/2026-08-30-commons-migration-sweep.md @@ -1,5 +1,14 @@ # Full sweep: `amethyst/` → `:commons` migration candidates +> **Direction change (2026-09-27): one UI.** Android now ships on laptops, so every +> screen and the navigation shell move to `commonsUI`, `amethyst` becomes an Android +> shim, and a new JVM `desktopApp` replaces the current one with the same UI. See +> [2026-09-27-one-ui-android-desktop.md](2026-09-27-one-ui-android-desktop.md). That +> supersedes, below: the STAY list's screens/navigation entries, "decompose `Account`, +> shrink `AccountViewModel`" (both now **move**), Wave 2 part B (dropped), and the +> "Desktop phase" merges of Desktop's own forks (dropped). This file stays the log of +> what moved; Wave 4 is planned and measured in the new plan. + > **Execution status (updated 2026-08-30, same branch):** Waves 0-1 are DONE > on this branch — the 12 shim deletions, the 38-file relayClient batch > (with `AccountScopedQuery` generalized to `IAccount`), the okhttp stack → @@ -297,10 +306,15 @@ formatters). ## STAY (correctly platform-native) -- **Navigation shell & screens**: `*Screen.kt`, `*TopBar.kt`, `New*Button.kt`, +> **Revised 2026-09-27.** The navigation shell and the screens no longer stay: they move +> to `commonsUI` (see the one-UI plan). What is listed below is what remains +> platform-native. The media, capture and service entries stay as *implementations*; +> the screens that render them reach them through ports or slots. + +- ~~**Navigation shell & screens**: `*Screen.kt`, `*TopBar.kt`, `New*Button.kt`, `INav`/`Route`/`RouteMaker`/`AppNavigation`, drawer/bottom-bar, `AccountScreen`/`AccountSessionManager`/`LoggedInPage`, `loggedOff/`, - `settings/` screens (~480 files import INav/Route — by design). + `settings/` screens.~~ Moving to `commonsUI` (`RouteMaker` to `commons`). - **Process/DI roots**: `Amethyst.kt`, `AppModules.kt`, `EncryptedStorage`, `LocalPreferences`, `DebugUtils`, `model/accountsCache`, `model/preferences/` (the one genuinely-Android model package: DataStore/ @@ -807,7 +821,11 @@ Options, for the maintainer to pick: `ui/theme/Shape.kt` into `commons/ui/theme/Sizes.kt`, plus `painterRes`/`TimeAgo`/`NewItemsBubble` decisions — the audit's "strings-only" tally under-counted transitive deps. -- **Wave 4: Account/AccountViewModel decomposition** — long-tail. +- **Wave 4: Account/AccountViewModel** — **re-scoped 2026-09-27** from + "decomposition" to **moving both to `commons`**. Measured and sequenced in + [2026-09-27-one-ui-android-desktop.md](2026-09-27-one-ui-android-desktop.md): the + `Account` group is 77 files / ~23.9k lines inside `model/`, with 5 hard-blocked files + and 14 exit edges to cut. ### Environment notes for the next session (hard-won) @@ -924,6 +942,10 @@ and `RailCapability` use it, `OnchainZapResolver` does not. ### Wave 2 part B — compatibility analysis and the road to deleting `DesktopLocalCache` (2026-09-19) +> **Dropped 2026-09-27.** The new desktop app uses `LocalCache` and `Account` directly; +> the current `desktopApp` keeps its fork until it is retired. The analysis below is +> kept for the record. + Part A moved the cache. Part B is retiring the Desktop fork. The naive framing ("repoint ~70 consumers and delete 1,177 lines") is wrong; what follows is the measured picture. @@ -1751,3 +1773,29 @@ first. None of the findings below came from the move; all are on `main`. drops it, so a refresh only spins for a second. - `ScheduledFlag` still reads `TimeUtils.now()` once, so a card composed before the start time keeps the date after it passes. + +## 2026-09-28 — cordn file stores and `EncryptedAppendLog` to `commonMain` + +`cordn/FileCordnStores.kt` (`CordnStorageLayout` and the group, key-package, +coordinator and handoff stores), `cordn/FileBackedCordnScopeFactory.kt`, +`cordn/CordnMigrationStores.kt` and `storage/EncryptedAppendLog.kt` moved from +jvmAndroid to commonMain. They take an okio `Path` plus a `FileSystem` +(default `platformFileSystem`), the `ScheduledPostStore` shape. + +These files hold encrypted MLS group state that cannot be re-derived, so the +format is pinned first: `CordnStorageFormatGoldenTest` was committed against the +`java.io` implementation, asserting the exact tree of paths and the exact bytes +of every file, and passes unchanged on the okio one. Notes on the port: + +- `ByteBuffer` framing (the cursor file) is okio `Buffer.writeLong`/`readLong`; + both are big-endian. +- `java.util.Base64` in the migration snapshot is `kotlin.io.encoding.Base64.Default` + with `PaddingOption.PRESENT_OPTIONAL`, the same shape as the napplet move. +- `File.delete()`/`deleteRecursively()` returned false instead of throwing, and + `renameTo` fell back to copy-and-delete. okio throws; the File behaviour is kept + by `deleteQuietly`, `deleteRecursivelyQuietly` and `moveOrCopy` in + `commons/util/FileSystemExt.kt`. One deliberate difference: the recursive delete + removes symlinks instead of following them. +- The log's `fsync`s are `FileHandle.flush()`, which is `FileDescriptor.sync()` + on the JVM and Android. +- `EncryptedMarmotMessageStore` stays in jvmAndroid and passes `toOkioPath()` to the log. diff --git a/commons/plans/2026-09-27-one-ui-android-desktop.md b/commons/plans/2026-09-27-one-ui-android-desktop.md new file mode 100644 index 0000000000..2ee47b6ae1 --- /dev/null +++ b/commons/plans/2026-09-27-one-ui-android-desktop.md @@ -0,0 +1,391 @@ +--- +title: "One UI: the whole app moves to commonsUI, Android and Desktop become shims" +type: refactor +status: in-progress +date: 2026-09-27 +owner: commons +consumers: amethyst, desktopApp, commonsUI +--- + +# One UI for Android and Desktop + +## The decision (maintainer, 2026-09-27) + +Android now ships on laptops, so Amethyst Android needs a desktop-class UI. Rather than +maintain two desktop UIs, there will be one: + +- **`commonsUI` holds the whole app UI.** Every screen, the navigation host, and the + navigation chrome at every size (bottom bar, rail, permanent drawer, docked panels). +- **`amethyst/` becomes an Android shim**: Activities, services, notifications, media3, + camera, WebView, Health Connect, Keystore/DataStore actuals, flavours. Nothing that is not + Android itself. +- **A new `desktopApp` becomes a JVM shim** that runs the same `commonsUI` app, so Desktop + looks exactly like Android on a laptop: Window, tray, menu bar, keyring, file pickers. + It **replaces** the current `desktopApp`, which keeps shipping until the new one reaches + parity, then goes. + +This supersedes the "screens and navigation stay platform-native" rule that +`.claude/CLAUDE.md`, `commons/ARCHITECTURE.md`, the `kotlin-multiplatform` / +`compose-expert` / `desktop-expert` skills and the sweep tracker's STAY list used to state. +Those were updated alongside this plan. + +## What this changes in the running migration + +The tracker ([2026-08-30-commons-migration-sweep.md](2026-08-30-commons-migration-sweep.md)) +stays the log of what moved. These of its conclusions no longer hold: + +| Old conclusion | Now | +|---|---| +| `Account` is a god object: "decompose, don't move". `AccountViewModel`: "shrink, don't move". | **Move both** to `commons`. They were only to be decomposed because Desktop was going to keep its own; the shared screens now need the same `Account` on both platforms. Narrow interfaces can still be carved out later, for tests and the CLI, but they are not a prerequisite. | +| STAY: `*Screen.kt`, `*TopBar.kt`, `AppNavigation`, `INav`/`Route`/`RouteMaker`, drawer/bottom bar, `LoggedInPage`, `loggedOff/`, `settings/` screens | **All move** to `commonsUI` (`RouteMaker` to `commons`, it has no Compose). | +| Wave 2 part B: turn `DesktopLocalCache` into a facade over `EventCache` | **Dropped.** The new desktop app uses `LocalCache` and `Account` directly. The old `desktopApp` keeps its fork until it is retired. | +| "Desktop phase": merge Desktop's `ToggleableTimeAgoText`, `TimeAgoFormatter`, `ChatBubbleLayout` forks onto the shared ones | **Dropped** for the same reason. | +| `jdk.localedata` in Desktop's packaged runtime (+~28 MB) is "a packaging call" | **Required** by the new desktop app: the shared date formatters need the CLDR data. | + +## Where we start from + +The Android app already contains the laptop UI. `ScreenLayoutSpec` (now in +`commonsUI/…/ui/layouts/ScreenLayout.kt`) picks one of three navigation tiers from the window +size alone (bottom bar below 600dp, rail, permanent drawer when wide, landscape and at least +600dp tall), docks the notification panel from 1200dp, and caps every destination to a 600dp +reading column (`CappedScreenContent`). A JVM window can feed it `widthDp`/`heightDp` and +get the same answer. Still app-side and part of the move: `AppNavigation.kt` (1,370 lines), +`AppNavigationRail.kt`, the permanent drawer in `AccountSwitcherAndLeftDrawerLayout.kt`, +`MessagesTwoPane.kt`, and `MainActivity.kt` (493 lines, the part that is not Activity +plumbing). + +## Prerequisites the move surfaced + +- **Navigation library.** The app uses `androidx.navigation:navigation-compose` 2.10.1. Its + Gradle module metadata publishes an `androidJvm` variant and only **`jvmStubs`** for `jvm` + (checked 2026-09-27), so it cannot run the nav host on Desktop. The multiplatform path is + JetBrains' `org.jetbrains.androidx.navigation:navigation-compose`, which resolves to the + androidx artifact on Android. That swap (and its licence check, per CLAUDE.md) comes before + `AppNavigation` can move. +- **The app root.** `Amethyst.instance` (the `AppModules` graph) is read by 178 files, 115 of + them under `ui/`. Shared screens cannot reach an Android `Application`. The root needs a + commons-side interface for what screens read from it, provided once at the composition root + (as `LocalUserFinderAccount` / `LocalEventFinder` already are), with an Android and a JVM + implementation. +- **Android-only libraries rendered inside screens.** Each needs an expect/actual or a slot the + shim fills: media3 (46 files), Vico charts (8), WebView (5), CameraX (4), Health Connect (4), + ML Kit (3, `play` flavour only). +- **Current-Desktop-only features.** The current `desktopApp` (260 files, ~70k lines) has + features Android lacks: deck columns, the article editor, highlights, scheduled-post + screens, keyboard shortcuts, menu bar, tray. Each needs a call before the old app is + retired: bring it into `commonsUI` for both platforms, or keep it in the new JVM shim. That + inventory is not done yet. + +## Wave 4, measured: what moves with `Account` + +Measured 2026-09-27 on `main` @ `c13e496c` with a closure script (not committed; the method +is below) over `amethyst/src/{main,play,fdroid}`. + +**An unconstrained closure is useless.** Following every edge from `Account.kt` reaches +1,724 of the app's 1,762 files, because a few edges leave `model/` for the app root +(`Amethyst.kt`), `ui/navigation` and `ui/screen`, and those reach everything. The useful +measure is the group reachable **inside `model/`**, plus the list of edges that leave it. +Each leaving edge is a seam to cut before the group can move. + +### The group + +- **75 files, 22,753 lines**: `Account.kt`, `AccountSettings.kt`, the `Account*Actions` files, + `EventBroadcaster`, and 60-odd per-feature state holders (`nip51Lists/*`, `nip65RelayList`, + `serverList/*`, `topNavFeeds/*`, `nip46Signer/*`, `cordn/*`, …). That is 75 of the 89 files + in `model/`. +- **Adding `EventProcessor`** (`ui/screen/loggedIn/DecryptAndIndexProcessor.kt`, which + `Account` constructs) brings it to 77 files, 23,850 lines, and adds no new exit edge except + two `Amethyst.instance.notificationDispatcher` calls. +- **11 files use `java.*`** (`BigDecimal`, `ConcurrentHashMap`, `UUID`, `Base64`, `File`, + `Locale`, and `OkHttpClient` in `CashuWalletState`). So the group lands in + **`commons/jvmAndroid`** first and promotes to `commonMain` later, the same route + `LocalCache` took. +- **No Compose UI** in any of them. + +### Hard blockers inside the group (5 files) + +| File | Blocker | Proposed cut | +|---|---|---| +| `Account.kt` | `BuildConfig.VERSION_NAME` (donation prompt, 3 sites) | constructor parameter `appVersion: String`. **Done 2026-09-27**: `AccountCacheState` takes it too and `AppModules` passes `BuildConfig.VERSION_NAME`. | +| `AccountSyncedSettingsInternal.kt` | `Resources.getSystem()` + `ConfigurationCompat` for the system language list; `DefaultBottomBarEntries` from `ui/navigation/bottombars/NavBarItem.kt` | languages: an injected `() -> List` or a small expect/actual; defaults: move the default entry list to `commons/model/navigation`, beside `BottomBarEntry`. **Defaults done 2026-09-28**: `DefaultBottomBarItems` + `DefaultBottomBarEntries` are in `commons/…/model/navigation/DefaultBottomBar.kt`. **Languages done 2026-09-28**: an `expect fun getLanguagesSpokenByUser()` in `commons/util/SpokenLanguages.kt` (it is a `@Serializable` default, so it could not be injected). | +| `GeohashChatIdentityState.kt` | `androidx.core.content.edit`, `LegacySharedPreferences`, `LocalPreferences.LEGACY_WRITES_RETIRED`, `Amethyst.instance.encryptedStorage` | the legacy-prefs read/write is a migration path; put it behind a `GeohashIdentityLegacyStore` port, implemented in the app. **Done 2026-09-28** as `GeohashIdentityStore` (model/), implemented by `AndroidGeohashIdentityStore` (app root). | +| `AccountZapActions.kt` | `onError: (StringResource, String?)` with `Res.string.bolt12_*` (compose resources, which `commons` cannot see) | a typed error (sealed class) that the UI maps to a string. **Done 2026-09-28**: `Bolt12ZapFailure` (commons/model); `ZapPaymentHandler` maps it to the same strings. | +| `nip46Signer/Nip46ConsentBridge.kt` | `Res` + `loadStringRes`; `Amethyst.instance.appContext`; the app's `SignerConnectCoordinator` / `SignerConsentCoordinator` / napplet op labels | it is the Android consent-dialog bridge: leave it in the app and inject it into `Account` through an interface. **Done 2026-09-28**: `Nip46ConsentPrompter` (model/nip46Signer); the bridge and `Nip46ConsentInfoBuilder` moved to `connectedApps/consent`. | + +### Edges that leave the group (14 targets) + +| Target | Used for | Proposed cut | +|---|---|---| +| `Amethyst.kt` | `keyCache` (Account), `encryptedStorage` (Geohash), `appContext` (Nip46 bridge), `notificationDispatcher` (EventProcessor) | constructor parameters / ports; the notification dispatcher gets an interface. **Done 2026-09-28**: `keyCache` → `Account.encryptionKeyCache`; the notifications → `MarmotGroupNotifier`, which `NotificationDispatcher` implements; `encryptedStorage` and `appContext` left with the Geohash and Nip46 cuts. | +| `LocalPreferences.kt` | `saveToEncryptedStorage(accountSettings)` on settings change | **Done 2026-09-28** as a constructor lambda, `Account.saveSettings: suspend (AccountSettings) -> Unit`, rather than a named port. | +| `DebugUtils.kt` | `logTime` (2 sites) | **Done 2026-09-28.** `commons/util` already had an identical `logTime`; its Android `isDebug` was hard-coded `false`, so it now reads `AndroidDebugFlag.enabled`, which `Amethyst.onCreate` sets. The app copy is gone. | +| `service/MainThreadChecker.kt` | `checkNotInMainThread` (HiddenUsersState) | **Done 2026-09-28**: `LocalCache.appHost.assertNotMainThread()`, which the app host delegates to the same check. | +| `service/location/LocationState.kt` | the `LocationResult` type in `geolocationFlow` and the around-me feed | **Done 2026-09-28**: `commons/model/location/LocationResult.kt`; 25 files repointed. | +| `service/uploads/FileHeader.kt` | the `FileHeader` data type in three send methods | **Done 2026-09-28**: `commons/service/upload/FileHeader.kt` (with `BlurhashWrapper`/`ThumbhashWrapper` moved from commonsUI, same package); `prepare` stays in the app as `FileHeader.Companion` extensions. | +| `service/relayClient/…/BuzzMembershipEoseManager.kt` | the `MembershipNotificationKinds` constant | **Done 2026-09-28**: `commons/model/buzz/BuzzMembershipKinds.kt`. | +| `ui/navigation/bottombars/NavBarItem.kt` | `DefaultBottomBarEntries` | moved to `commons` (done 2026-09-28) | +| `ui/screen/loggedIn/DecryptAndIndexProcessor.kt` | `EventProcessor`, built by `Account` | moves with the group (see above) | +| `AccountSecretsStore.kt`, `LegacySharedPreferences.kt` | Geohash identity storage | behind the Geohash port above | +| `connectedApps/consent/*Coordinator.kt`, `napplet/NostrSignerOpLabels.kt` | Nip46 consent bridge | stay in the app with the bridge | + +About twenty small cuts, most of them "pass it in" or "move one declaration". None is a +redesign. + +## Wave 4, measured: `AccountViewModel` + +`AccountViewModel.kt` is 3,303 lines. + +- **Android imports.** Its Android imports are `Context` (3 methods take one), `Toast`, + `Uri`, `Handler`/`Looper`, `android.util.LruCache` (5 sites), `NotificationManager` and + `ContextCompat`. It has no `R` references left. +- **`Amethyst.instance`.** It reads the app root in six places: `websocketBuilder`, + `relayStats`, `powPublishQueue`, `localBlossomCacheProbe`, `blossomResolver` and + `appContext`. +- **Other app files.** Outside the `Account` group it depends on 29 app files. They fall into + three kinds: + - **Headless, should move with it:** `RelaySubscriptionsCoordinator`, `ClinkDebitPayer`, + `CallSessionBridge`, `NestBridge`, `MarkChatRoomsAsRead`, `RowUnread`, + `ReloadMintViewModel`, `EventSync`, `CardFeedContentState`, `RoleBasedHttpClientBuilder`. + - **Payment and intent handlers:** `ZapPaymentHandler`, `V4VPaymentHandler`, + `LightningAddressResolver`, `MeltProcessor`, `ZapCustomDialog.payViaIntent`. They take an + Android `Context` to fire payment intents; that needs a `PaymentLauncher` port. + - **Composable files it borrows a type or constant from:** `ZapAmountCommentNotification` + (`MultiSetCompose`), `ZapraiserStatus` (`ReactionsRow`), `NOTIFICATION_LAST_READ_KEY` + (`NotificationScreen`). The declarations move to `commons`; the composables don't have to. + - **Genuinely Android:** `MediaSaverToDisk`, `MarmotGroupIconUploader`, + `dismissNotificationForEvent` (`NotificationUtils`). These go behind ports. + +`AccountViewModel` moves after the `Account` group, into `commons/viewmodels` (jvmAndroid +first). + +### Re-measured 2026-09-28, after `Account` moved + +With `Account` in commons, `AccountViewModel` (3,334 lines) sits on a headless group of **64 +app files, 11,322 lines** (the relay-subscription coordinator and its assemblers, the chat-room +read markers, the Clink/call/nest bridges, `ReloadMintViewModel`, …). Leaving that group are +**25 edges**, in four kinds: + +| Kind | Edges | Cut | +|---|---|---| +| A type or constant borrowed from a composable or Android file | `NOTIFICATION_LAST_READ_KEY` (NotificationScreen), `ZapAmountCommentNotification` (MultiSetCompose), `ZapraiserStatus` (ReactionsRow), `CombinedZap` (CardFeedContentState), `sats` (ReloadMintScreen) | move the declaration to commons | +| A JVM-only file that is otherwise headless | `NwcNotificationsEoseManager`, `FollowingGeohashChatSubAssembler`, `CardFeedContentState`, `EventSync`, `AccountFeedContentStates` (a `ComponentCallbacks2` level constant) | KMP swaps, then it joins the group | +| An Android service it calls | `ZapPaymentHandler`, `V4VPaymentHandler`, `MeltProcessor`, `LightningAddressResolver`, `payViaIntent`, `dismissNotificationForEvent`, `MediaSaverToDisk`, `MarmotGroupIconUploader`, `UrlCachedPreviewer`, `powKindLabelRes`, `LocalPreferences`/`AccountInfo`, `Amethyst.instance` (6 reads in the VM, 1 in `ClinkDebitPayer`), `isDebug`, `checkNotInMainThread` | ports / constructor parameters, as for `Account` | +| Its own Android calls | `Context` parameters (payments, media save, NWC setup), `Toast` + `Handler(Looper)`, `Uri`, `android.util.LruCache` (5), `NotificationManager` via `ContextCompat` | `androidx.collection.LruCache`; the rest behind the same ports | + +The preview helpers at the bottom of the file (`mockAccountViewModel`, `mockVitorAccountViewModel`) +wire app classes and stay in the app, in their own file. + +### What that measurement missed, and where the VM lands + +The survey above counted any `com.vitorpamplona.amethyst.commons.*` import as shared. Two kinds +of shared symbol are not usable from `commons/commonMain`, and it missed both: + +- **`commonsUI`-only symbols.** The VM toasts through compose-resources strings (`Res`, 33 + imports), `ToastManager` and `loadStringRes`; the payment stack's error messages are `Res` + strings too; `NotificationSummaryState` builds a Vico chart model. By the rule in CLAUDE.md + ("anything that imports … `Res` belongs in `commonsUI`"), **`AccountViewModel` lands in + `commonsUI/commonMain`**, not `commons`. That changes nothing for its callers (all + composables, all moving to `commonsUI`) and only rules out the CLI, which has `Account`. +- **`jvmAndroid`-only symbols** in commons and quartz: the relay pagers and window trackers, + `showAmount`, the calendar sort keys, `LnurlEndpointCache`, `OnlineChecker`, + `GeoRelayCsvLoader`, `IRoleBasedHttpClientBuilder`. + +The cuts, 2026-09-28 (each its own commit on this branch): + +| Cut | How | +|---|---| +| Android services the VM read | `AccountViewModelHost` (commons): memory pressure, Blossom-cache probe, PoW failures, relay stats, crawl socket builder, saved accounts, tray-notification dismissal, the wallet-app hand-off, the LNURL transport and money-op relay routing. `AndroidAccountViewModelHost` implements it over `AppModules`; previews pass a no-op. | +| Android-only actions | `saveMediaToGallery`, `uploadMarmotGroupIcon`, `urlPreview`, `checkVideoIsOnline` became app-side extensions with the same call shape. | +| `Context` threaded through payments | Never read; removed from the VM, the zap/V4V/melt handlers and the resolver. | +| OkHttp in the zap stack | `LnurlHttpTransport` port; the resolver on kotlinx JSON with Jackson-lenient readers; a scripted-transport test. | +| JVM collections, locks, dates, BigDecimal | commons `ConcurrentSet` (+`contains`/`isEmpty`/`snapshot`), `KmpLock`, quartz `ConcurrentMap`/`PlatformLock`, `LocalClock.epochDayCounter()`, `SearchDate`, quartz `BigDecimal.toDoubleValue()`, `expect fun showAmount` (DecimalFormat stays the JVM actual; a test pins the common port to it). | +| App singletons | `ClinkDebitPayer` takes `MoneyOpRelayRouting`; NIP-11 reads go through `LocalCacheHost.relayInfo`; `GeohashRelays` gets its loader installed at startup; `OnlineStatusCache` split from `OnlineChecker`. | +| `IRoleBasedHttpClientBuilder` | An `expect interface` in commonMain; the JVM actual is a typealias to the OkHttp interface, so every caller is unchanged. | + +**Re-measured after the cuts:** the group reachable from `AccountViewModel` is **127 files, +22.4k lines, with no edges leaving it**. By what they import, **33 files (10.2k lines) go to +`commonsUI`** (the VM, `AccountFeedContentStates`, the payment stack, `TopNavFilterState`, +`NotificationSummaryState`, the account filter assemblers that hold the feed states, the nest +assemblers) and **94 (12.2k lines) to `commons`** (feed filters, the chat/relay-group/hashtag +assemblers, `EventSync`, …). Packages are renamed on the way: +`ui.screen.loggedIn` → `commons.viewmodels`, `ui.screen.loggedIn.X` → `commons.X`, +`ui.screen`/`ui.dal` → `commons.feeds`, `service.relayClient.X` → `commons.relayClient.X`, +`service.X` → `commons.service.X`. + +## Sequence + +1. **Docs** (this plan, and the rule changes in CLAUDE.md, both ARCHITECTURE files, three + skills and the tracker). Done 2026-09-27. +2. **Cut the `Account` group's seams**, one small PR each, in the app, with no move yet. Every + cut is a behaviour-preserving refactor that compiles and tests on its own: + - the `BuildConfig` parameter (done); + - `DefaultBottomBarEntries` (done); + - `MembershipNotificationKinds` (done); + - `logTime` (done); + - `checkNotInMainThread` (done); + - the `LocationResult` and `FileHeader` types (done); + - the settings saver and the media key cache (done, as constructor parameters); + - the typed zap error (done); + - the language list (done); + - the Geohash identity store, the Nip46 consent prompter and the Marmot notifier (done). + + **Result, re-measured 2026-09-28:** the group reachable from `Account.kt` inside `model/` + (plus `EventProcessor`) is 77 files, 23,474 lines, with **no hard blockers, no edges leaving + it and no `commonsUI`-only symbols**. It is ready for step 3. +3. **Move the group** (77 files) to `commons/jvmAndroid` in one PR. Desktop keeps its + `DesktopIAccount` until the old app is retired; `IAccount` stays as the port it already is. + + **Done 2026-09-28, to `commonMain` rather than `jvmAndroid`** (maintainer's call), and with the + packages renamed to `com.vitorpamplona.amethyst.commons.model.*`. Getting there took more than + the seam cuts: + - JVM-only APIs in the group swapped for KMP ones: `BigDecimal` (quartz), `UUID` + (`kotlin.uuid`), `Base64` (`kotlin.io.encoding`), concurrent maps and sets (quartz + `ConcurrentMap`, commons `ConcurrentSet` + new `snapshot()`), `Locale` (an expect). + - Cashu rewritten as KMP: quartz `MintHttpTransport` under `MintHttpClient` and + `CashuMintOperations` (OkHttp is the jvmAndroid implementation, wired in `AccountCacheState` + and the CLI); `CashuWalletOps`, `CashuWalletReader`, `CashuMintDirectoryState` to commonMain. + - cordn's file stores and `EncryptedAppendLog` rewritten on okio, with a golden test pinning + the on-disk bytes from the old `java.io` code. + - Desktop's own `Nip65RelayListState`, `BlossomServerListState` and + `Nip65RelayListRepository` moved into `desktopApp`, freeing those names for the app's. + - Two blockers that arrived from `main` meanwhile were injected: the Android Keystore cordn + cipher, and the `marmotQuic` stream transport. + - `NestsServerListState` moved too (a line-split fully-qualified name hid it from the survey). + + The app's `model/` keeps 13 Android-bound files (`AccountCacheState`, preferences, Tor, …). + `IAccount` and `DesktopIAccount` are unchanged. +4. **`AccountViewModel`**: the same recipe, using the dependency list above. + + **Done 2026-09-28**, after the cuts listed under "What that measurement missed": the VM + and 32 files that need compose resources, Vico or commonsUI symbols went to + `commonsUI/commonMain`, the other 94 to `commons/commonMain`, with the package renames + given there. The app keeps `AndroidAccountViewModelHost`, the Android-only extensions in + `AccountViewModelAndroidActions.kt`, and the previews. iOS compiles are unverified in this + container (unrelated pre-existing failures); CI checks them. +5. **The shared composables and their helpers** (sized in the tracker's 2026-09-27 section): + - `RouteMaker`; + - drop the `accountViewModel` overloads of the `observe*` helpers; + - `DisappearingScaffold`'s immersive-scrolling read goes onto `DisplaySettings`; + - then `UserProfilePicture`, `UsernameDisplay`, `Loaders`, `RichTextViewer`, + `NoteCompose`. + + Once `AccountViewModel` is in `commons`, these move without retyping. + + **Progress 2026-09-28.** With the VM shared, re-measured closures were far smaller than the + tracker's counts: + - **Moved to `commonsUI`:** `RouteMaker`; `UserProfilePicture`, `UsernameDisplay` and + `Loaders` (`commons.ui.note`, with `LoadUser`); `RobohashAsyncImage` (jvmAndroid → + commonMain). + - **The `accountViewModel` overloads were moved, not dropped.** That covers + `DisappearingScaffold` and the per-note, per-user and user-finder `observe*` helpers, + which now sit in `commonsUI` beside the shared versions they delegate to + (`Account*.kt` files). They read the account and data sources off the VM, so they work + under Activity roots that provide no composition locals. Dropping them would rewrite + ~176 call sites, and stays a later cleanup. + - **Promoted to commonMain:** `CachedRichTextParser` and `CachedAsciiDocToMarkdown`. + Their only JVM tie was `ConcurrentLruCache`, which moved in step 4. + - **Left: `RichTextViewer` and `NoteCompose`.** They depend on each other (embedded notes + ↔ rich text) and reach the Android media stack, so they need a design, not a move: + - **Media:** media3 video, the zoomable image viewer, GIF video, LaTeX (JLatexMath), + the OSM map. + - **Intents and share sheets:** Blossom URIs, torrents, chat links, napplets. + - **Old JVM formatting:** `SimpleDateFormat`/`NumberFormat` in a dozen note types. + - **Translations:** the flavour-only `TranslatableRichTextViewer`. + + The likely shape is renderer slots provided through a CompositionLocal at the Android + root (and later the Desktop one) for the media and intents, plus KMP swaps for the + formatting. RichTextViewer's own closure is 32 files with 41 exits; NoteCompose's is + 144 files with 81. + + **Progress 2026-09-28, later.** The shape held: slots at the root, KMP swaps below them. + - **`RichTextViewer` moved** over `RichTextPlatform` (`LocalRichTextPlatform`): the + platform's segment renderer, its markdown renderer, and the secret-message body. The + quoted-note card is `LocalInlineQuoteRenderer`. + - **Translation** is `TranslationPlatform` (`LocalTranslationPlatform`, commonsUI). The + shared `TranslatableRichTextViewer` asks it; Play installs ML Kit and F-Droid the no-op. + - **Platform verbs** became small commonsUI expect/actuals instead of Android calls in + note code: `rememberTextSharer()` (the `ACTION_SEND` chooser), `rememberShortNotice()` + (a toast), `rememberBlossomUriOpener()` (on `LocalUriHandler`), + `argbPixelsToImageBitmap`. Plain `VIEW` intents became `LocalUriHandler.openUri`. + - **Formatting:** `formatDateTime(epochMillis, DateTimeStyle, DateTimeStyle)`, + `DecimalPatternFormatter`, `PlatformNumberFormatter`, `phonePrefersMiles()` and the + quartz `BigDecimal` (+ `parseBigDecimalOrNull`) replace `java.text` / `java.math` in + the note types. `UrlInfoItem` resolves OpenGraph URLs through `resolveHttpUrl`, and + NIP-95 local media is an okio `Path` served by `Nip95BlobStore.path(id)`. + - **The rest of the note card** goes through `NotePlatform` (`LocalNotePlatform`): the + zoomable viewer and video/GIF players, link previews, the map and reverse geocoding, + the note types built on a platform engine (audio players, chess, the git browser, + meeting rooms, napplets/nsites), the reactions/zap row and the post editor. Shared + code calls same-named shims in `commons.ui.note.platform`, so call sites only changed + imports. Each of those pieces can later get a shared implementation and leave the slot. + - **`NoteCompose` moved.** Its whole closure, 176 files (the card, `ui/note/types`, + `elements`, `nip22Comments`, the channel/DM headers it embeds, and the slot itself), + is now `commonsUI/commonMain` under `commons.ui.*` / `commons.relayClient.*`, and + compiles for Android, Desktop and iOS. `AndroidNotePlatform` stays in the app and is + installed in `AmethystTheme`. What remains app-side is what the slots name: the media + players, the map, the platform-engine note types, the reactions/zap row and the editor. +6. **Screens**, feature by feature, into `commonsUI`. + + **Measured 2026-09-28** (after NoteCompose moved), with the same closure method: of 252 + `*Screen.kt` files, 23 had no Android-only exit, 45 had one. The exits most screens share: + `Amethyst.instance` (109 screens), `LoadRelayInfo`/`Nip11CachedRetriever` (73), + `NappletFavoriteIcon` (65), `ConcordCommunityImage` (64), `PrefetchFeedMedia` (48), the + gallery picker (38), the app's `StringResourceCache` (35), `FeedFilterSpinner` (32) and + direct `ReactionsRow` imports (30). Most `Amethyst.instance` reads already have an + `AccountViewModel` equivalent (`httpClientBuilder`, `account.encryptionKeyCache`, + `host.relayStats`, `account.client`, `LocalCache`); the rest need an app-services port. + - **Wave 1 moved:** the 23 zero-exit screens with their closures, 43 files: buzz forum/ + persona/new-DM, contact lists, emoji-pack selection, interest sets, geocache hunts, + Concord invite/members, relay-group threads, the import-follow-list flow, poll results, + badges, podcast authoring and four settings screens. `viewModel()` became the shared + `rememberViewModel` (with a factory overload). + - **Wave 2 cuts:** + - The NIP-11 cache is now commonMain behind a `Nip11Fetcher`, served by + `LocalCacheHost.nip11Cache`. + - `Amethyst.instance` reads that have an `AccountViewModel` equivalent now use it. + - More files use the shared `stringRes`/`painterRes`, and six drawables are Compose + resources. + - `PrefetchFeedMedia` is common: Coil's `SingletonImageLoader`, `ConcurrentSet`, and + link previews warmed through `NotePlatform.warmUrlPreview`. + - The shared date formatter replaced `LocalizedDateTimeFormat` in four screens. + - An `AppPlatform` slot (`LocalAppPlatform`) holds the bottom bar, the "around me" + location label and the geohash location picker. `AndroidAppPlatform` is installed in + the theme. + - **Wave 2 moved:** 37 more screens with their closures, 105 files. That covers the + bookmark, pinned-note, draft, people-list, emoji-pack and interest-set lists; the Cashu + mint screens; relay and relay-group members; communities; Event Sync; the vanish + screens; and the feed filter spinner with the feed views they share. `ViewModelProvider.Factory` + implementations now override the multiplatform `create(KClass, CreationExtras)`. + - **Next:** re-measure; the exits now in front are the upload/gallery stack, the + Android-only `AccountViewModel` actions (`urlPreview`, media saving), `LoadCityName`, + `ReactionsRow` imports, the remaining `Amethyst.instance` reads (location, favorites, + Tor, browser icons, scheduled posts) and `AppSettingsScreen`. +7. **Navigation**: the library swap, then `AppNavigation` + rail + drawer + bottom bar. +8. **The app root port** and the new JVM shim. Then the Desktop feature inventory, and + retiring the old `desktopApp`. + +Steps 2–5 can interleave. Step 5's helpers can start before 3–4 if they take `Account` / +`AccountViewModel` unchanged and only move later. + +## Method (so the numbers can be re-run) + +The closure script indexes every public top-level declaration in +`amethyst/src/{main,play,fdroid}`. For each file it follows edges of four kinds: + +- explicit imports; +- wildcard imports; +- inline fully-qualified names; +- **same-package references**, which need no import. This is the undercount the tracker's + header warns about. + +A same-package lowercase name reached through a `.` counts only when it is an extension. The +lexer blanks strings but keeps `${…}` templates. A file is marked blocked by any of: + +- `android.*`, `com.google.*`, or a non-KMP `androidx.*`; +- `R`/`BuildConfig`; +- a library `commons` lacks. + +Symbols from `commons.*` that actually live in `commonsUI` (`Res`, `loadStringRes`) are +checked separately. The first pass missed them. Known over-count: same-package token matching +can link a file to a same-named declaration it does not use; the edges above were checked by +hand. diff --git a/commons/plans/README.md b/commons/plans/README.md index faf2fdd620..46009a7720 100644 --- a/commons/plans/README.md +++ b/commons/plans/README.md @@ -1,13 +1,14 @@ # commons plans -_Audited 2026-06-30 (+ 2026-09-12 split entry, 2026-09-27 migration entries)._ +_Audited 2026-06-30 (+ 2026-09-12 split entry, 2026-09-27 migration and one-UI entries)._ ## In progress | Plan | Summary | | ---- | ------- | | [2026-05-04-custom-feeds-plan.md](2026-05-04-custom-feeds-plan.md) | Custom feed creation/discovery/management for Desktop; core model + builder + kind 31890 + desktop UI shipped, but relay-filter layer, DVM marketplace, kind 10090 sync, and list resolution still pending. | | [2026-05-06-nest-subscription-manager-extraction.md](2026-05-06-nest-subscription-manager-extraction.md) | Split the per-speaker subscription state machine out of `NestViewModel`; only the `ActiveSubscription` stepping-stone is extracted so far. | -| [2026-08-30-commons-migration-sweep.md](2026-08-30-commons-migration-sweep.md) | The running tracker for moving `amethyst/` code into `commons`/`commonsUI`: waves, what moved each round, what stays and why. `LocalCache` has moved; retiring `DesktopLocalCache` (Wave 2 part B) and the `AccountViewModel` hub composables are next. | +| [2026-09-27-one-ui-android-desktop.md](2026-09-27-one-ui-android-desktop.md) | **The target.** Android ships on laptops, so the whole UI (screens + navigation shell) moves to `commonsUI`, `amethyst` becomes an Android shim, and a new JVM `desktopApp` renders the same UI. Measures Wave 4: `Account`'s 77-file move-group, its 5 blocked files and 14 seams, and `AccountViewModel`'s dependencies; sequences the rest. | +| [2026-08-30-commons-migration-sweep.md](2026-08-30-commons-migration-sweep.md) | The running log of moving `amethyst/` code into `commons`/`commonsUI`: waves, what moved each round. `LocalCache` has moved. Its STAY list and Wave 2 part B are superseded by the one-UI plan above. | | [2026-05-30-amethyst-to-commons-migration.md](2026-05-30-amethyst-to-commons-migration.md) | The original roadmap for the same move; superseded in practice by the sweep tracker above. | ## Queued diff --git a/commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/util/DebugUtils.android.kt b/commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/util/DebugUtils.android.kt index a7f8e4597d..b7f4e55b8f 100644 --- a/commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/util/DebugUtils.android.kt +++ b/commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/util/DebugUtils.android.kt @@ -20,6 +20,14 @@ */ package com.vitorpamplona.amethyst.commons.util -// Debug flag for commons module - kept false to avoid application dependencies -// Application-level modules (amethyst, desktopApp) can implement their own debug timing -actual val isDebug: Boolean = false +/** + * The Android side of [isDebug]. `commons` can't see the app's `BuildConfig`, so the app sets this + * once at startup (`Amethyst.onCreate`) from its own debug flag. Until then, and in any process that + * never sets it, debug-only logging stays off. + */ +object AndroidDebugFlag { + @Volatile + var enabled: Boolean = false +} + +actual val isDebug: Boolean get() = AndroidDebugFlag.enabled diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/MeasurementSystem.kt b/commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/util/MeasurementSystem.android.kt similarity index 87% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/MeasurementSystem.kt rename to commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/util/MeasurementSystem.android.kt index 24ff98836e..983f6be6b1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/MeasurementSystem.kt +++ b/commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/util/MeasurementSystem.android.kt @@ -18,19 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts +package com.vitorpamplona.amethyst.commons.util import android.icu.util.LocaleData import android.icu.util.ULocale import android.os.Build import java.util.Locale -/** Countries that use miles for road distance (imperial / US customary). */ -private val MILES_COUNTRIES = setOf("US", "GB", "LR", "MM") - /** - * Whether the phone's measurement preference favours miles for distance. - * * Honours the Android 14+ "Regional preferences → Measurement system" override, * which the platform surfaces through the default locale's Unicode `-u-ms-` * extension (`metric` / `ussystem` / `uksystem`). When no explicit override is @@ -38,7 +33,7 @@ private val MILES_COUNTRIES = setOf("US", "GB", "LR", "MM") * use miles for distance), available since API 28; on older releases it falls * back to a country-code check. */ -fun phonePrefersMiles(): Boolean { +actual fun phonePrefersMiles(): Boolean { val locale = Locale.getDefault(Locale.Category.FORMAT) locale.getUnicodeLocaleType("ms")?.let { ms -> diff --git a/commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/util/SpokenLanguages.android.kt b/commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/util/SpokenLanguages.android.kt new file mode 100644 index 0000000000..418dabd421 --- /dev/null +++ b/commons/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/util/SpokenLanguages.android.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import android.content.res.Resources +import androidx.core.os.ConfigurationCompat +import java.util.Locale + +actual fun getLanguagesSpokenByUser(): Set { + val languageList = ConfigurationCompat.getLocales(Resources.getSystem().configuration) + val codedList = mutableSetOf() + for (i in 0 until languageList.size()) { + languageList.get(i)?.let { codedList.add(it.language) } + } + return codedList +} + +actual fun getDefaultLanguageCode(): String = Locale.getDefault().language diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/dal/ArticlesFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/articles/dal/ArticlesFeedFilter.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/dal/ArticlesFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/articles/dal/ArticlesFeedFilter.kt index 56bdbdcce6..e9022b00a3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/articles/dal/ArticlesFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/articles/dal/ArticlesFeedFilter.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.articles.dal +package com.vitorpamplona.amethyst.commons.articles.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip23LongContent.LongFormContentEvent class ArticlesFeedFilter( diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/audio/WaveformData.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/audio/WaveformData.kt new file mode 100644 index 0000000000..28dbb7dbc7 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/audio/WaveformData.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.audio + +import androidx.compose.runtime.Immutable + +/** An audio clip's amplitude envelope, one value per bar, as the voice-message players draw it. */ +@Immutable +class WaveformData( + val wave: List, +) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/dal/BadgesFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/badges/dal/BadgesFeedFilter.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/dal/BadgesFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/badges/dal/BadgesFeedFilter.kt index 3425254468..71cd872f09 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/dal/BadgesFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/badges/dal/BadgesFeedFilter.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.dal +package com.vitorpamplona.amethyst.commons.badges.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip58Badges.definition.BadgeDefinitionEvent class BadgesFeedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/dal/CalendarAppointmentsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/calendars/dal/CalendarAppointmentsFeedFilter.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/dal/CalendarAppointmentsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/calendars/dal/CalendarAppointmentsFeedFilter.kt index 50b42f8a00..70ef56cba9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/dal/CalendarAppointmentsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/calendars/dal/CalendarAppointmentsFeedFilter.kt @@ -18,17 +18,17 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.dal +package com.vitorpamplona.amethyst.commons.calendars.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.nip52Calendar.upcomingFirstCalendarOrder import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip52Calendar.appt.day.CalendarDateSlotEvent import com.vitorpamplona.quartz.nip52Calendar.appt.time.CalendarTimeSlotEvent import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/dal/CalendarCollectionsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/calendars/dal/CalendarCollectionsFeedFilter.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/dal/CalendarCollectionsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/calendars/dal/CalendarCollectionsFeedFilter.kt index ef43b1e29b..a3acae56c5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/dal/CalendarCollectionsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/calendars/dal/CalendarCollectionsFeedFilter.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.dal +package com.vitorpamplona.amethyst.commons.calendars.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip52Calendar.calendar.CalendarCollectionEvent class CalendarCollectionsFeedFilter( diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cashu/CashuWalletReader.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/cashu/CashuWalletReader.kt similarity index 96% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cashu/CashuWalletReader.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/cashu/CashuWalletReader.kt index 1ea5966ad5..9499bbfdd3 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cashu/CashuWalletReader.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/cashu/CashuWalletReader.kt @@ -89,10 +89,10 @@ class CashuWalletReader( if (walletEvent == null || event.createdAt > walletEvent.createdAt) walletEvent = event is NutzapInfoEvent -> if (nutzapInfoEvent == null || event.createdAt > nutzapInfoEvent.createdAt) nutzapInfoEvent = event - is CashuTokenEvent -> tokenEvents.putIfAbsent(event.id, event) - is CashuSpendingHistoryEvent -> historyEvents.putIfAbsent(event.id, event) - is CashuMintQuoteEvent -> quoteEvents.putIfAbsent(event.id, event) - is NutzapEvent -> nutzapEvents.putIfAbsent(event.id, event) + is CashuTokenEvent -> tokenEvents.getOrPut(event.id) { event } + is CashuSpendingHistoryEvent -> historyEvents.getOrPut(event.id) { event } + is CashuMintQuoteEvent -> quoteEvents.getOrPut(event.id) { event } + is NutzapEvent -> nutzapEvents.getOrPut(event.id) { event } is MintRecommendationEvent -> { val key = event.dTag() ?: event.id val current = recommendationEvents[key] diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cashu/ops/CashuWalletOps.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/cashu/ops/CashuWalletOps.kt similarity index 99% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cashu/ops/CashuWalletOps.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/cashu/ops/CashuWalletOps.kt index f40c21c608..3bfa9f2b5a 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cashu/ops/CashuWalletOps.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/cashu/ops/CashuWalletOps.kt @@ -39,6 +39,7 @@ import com.vitorpamplona.quartz.nip60Cashu.mintApi.DleqProofDto import com.vitorpamplona.quartz.nip60Cashu.mintApi.MeltQuoteBolt11ResponseDto import com.vitorpamplona.quartz.nip60Cashu.mintApi.MintHttpClient import com.vitorpamplona.quartz.nip60Cashu.mintApi.MintHttpException +import com.vitorpamplona.quartz.nip60Cashu.mintApi.MintHttpTransport import com.vitorpamplona.quartz.nip60Cashu.mintApi.MintProtocolException import com.vitorpamplona.quartz.nip60Cashu.mintApi.MintQuoteBolt11ResponseDto import com.vitorpamplona.quartz.nip60Cashu.mintApi.ProofState @@ -61,6 +62,7 @@ import com.vitorpamplona.quartz.nip61Nutzaps.redemption.notifySender import com.vitorpamplona.quartz.nip87Ecash.cashu.CashuMintEvent import com.vitorpamplona.quartz.nip87Ecash.recommendation.MintRecommendationEvent import com.vitorpamplona.quartz.utils.Log +import com.vitorpamplona.quartz.utils.concurrent.ConcurrentMap import com.vitorpamplona.quartz.utils.secp256k1.Secp256k1 import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll @@ -70,8 +72,6 @@ import kotlinx.coroutines.sync.withPermit import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json -import okhttp3.OkHttpClient -import java.util.concurrent.ConcurrentHashMap /** * Wallet-level operations that combine the [CashuMintOperations] HTTP layer @@ -81,7 +81,7 @@ import java.util.concurrent.ConcurrentHashMap * Stateless w.r.t. wallet contents — each call receives the current state * from `CashuWalletState`. Signing and broadcast are abstracted behind the * [signer] + [publish] callbacks so the ops layer can be unit-tested without - * a full [com.vitorpamplona.amethyst.model.Account] graph. + * a full [com.vitorpamplona.amethyst.commons.model.Account] graph. * * Per-mint [CashuMintOperations] instances are cached so repeated calls * against the same mint reuse the same `MintHttpClient` and avoid re- @@ -90,7 +90,8 @@ import java.util.concurrent.ConcurrentHashMap class CashuWalletOps( private val signer: NostrSigner, private val publish: suspend (Event) -> Unit, - private val okHttpClient: (String) -> OkHttpClient, + /** How mint requests go out (OkHttp on Android and the JVM, picking Tor or a proxy per URL). */ + private val mintTransport: MintHttpTransport, /** * NUT-13 secret strategy. Defaults to random for backwards * compatibility with tests that don't carry a seed. The wallet state @@ -129,13 +130,13 @@ class CashuWalletOps( */ private val reserveCashuCounters: suspend (keysetId: String, count: Int) -> Long = { _, _ -> 0L }, ) { - private val opsCache = ConcurrentHashMap() + private val opsCache = ConcurrentMap() private fun ops(mintUrl: String): CashuMintOperations = opsCache.getOrPut(mintUrl.trimEnd('/')) { // userConfigured: these are the mints of the user's own NIP-60 wallet, // added deliberately, so a self-hosted mint on the LAN stays usable. - CashuMintOperations(MintHttpClient(mintUrl, userConfigured = true, okHttpClient = okHttpClient), secretFactory) + CashuMintOperations(MintHttpClient(mintUrl, userConfigured = true, transport = mintTransport), secretFactory) } /** @@ -960,7 +961,7 @@ class CashuWalletOps( * `userConfigured = true`: the URL was typed by the user into the Add-Mint UI, * so a self-hosted mint on the LAN is a legitimate target here. */ - suspend fun pingMint(mintUrl: String): String? = MintHttpClient(mintUrl, userConfigured = true, okHttpClient = okHttpClient).info().name + suspend fun pingMint(mintUrl: String): String? = MintHttpClient(mintUrl, userConfigured = true, transport = mintTransport).info().name /** * Fetch the currently-active keyset id for [mintUrl]. Cheap wrapper diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/privateDM/datasource/ChatroomFilterAssembler.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/privateDM/datasource/ChatroomFilterAssembler.kt index ff00e2fcc7..d33a866769 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/privateDM/datasource/ChatroomFilterAssembler.kt @@ -18,11 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.datasource +package com.vitorpamplona.amethyst.commons.chats.privateDM.datasource +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomNip04HistorySubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/privateDM/datasource/ChatroomNip04HistorySubAssembler.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomNip04HistorySubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/privateDM/datasource/ChatroomNip04HistorySubAssembler.kt index 58c84ef479..129bd9ddf8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomNip04HistorySubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/privateDM/datasource/ChatroomNip04HistorySubAssembler.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.datasource +package com.vitorpamplona.amethyst.commons.chats.privateDM.datasource +import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.DmRelayLog import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserAndFollowListEoseManager import com.vitorpamplona.amethyst.commons.relayClient.paging.BackwardRelayPager import com.vitorpamplona.amethyst.commons.relayClient.paging.PagingStatus import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.DmRelayLog import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomNip04SubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/privateDM/datasource/ChatroomNip04SubAssembler.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomNip04SubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/privateDM/datasource/ChatroomNip04SubAssembler.kt index bac11ccaf0..995523408e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/ChatroomNip04SubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/privateDM/datasource/ChatroomNip04SubAssembler.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.datasource +package com.vitorpamplona.amethyst.commons.chats.privateDM.datasource import com.vitorpamplona.amethyst.commons.model.privateChats.DmHistoryTuning +import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.DmRelayLog import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserAndFollowListEoseManager import com.vitorpamplona.amethyst.commons.relayClient.paging.WindowLoadTracker import com.vitorpamplona.amethyst.commons.relayClient.paging.trackingListener import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.DmRelayLog import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/FilterNip04DMs.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/privateDM/datasource/FilterNip04DMs.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/FilterNip04DMs.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/privateDM/datasource/FilterNip04DMs.kt index 2254624aee..e36ede08c2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/FilterNip04DMs.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/privateDM/datasource/FilterNip04DMs.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.datasource +package com.vitorpamplona.amethyst.commons.chats.privateDM.datasource +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordUnread.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/concord/ConcordUnread.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordUnread.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/concord/ConcordUnread.kt index 82b63aa77e..e1b694ccf7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordUnread.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/concord/ConcordUnread.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord +package com.vitorpamplona.amethyst.commons.chats.publicChannels.concord +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Channel import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.concord.ConcordChannel import com.vitorpamplona.amethyst.commons.model.concordChannelLastReadRoute -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.concord.cord03Channels.ConcordChannelId import com.vitorpamplona.quartz.nip22Comments.CommentEvent import kotlinx.coroutines.ExperimentalCoroutinesApi diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/concord/datasource/ConcordChannelFilterAssembler.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/concord/datasource/ConcordChannelFilterAssembler.kt index b3855591cd..4dbc823a2f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/concord/datasource/ConcordChannelFilterAssembler.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource +package com.vitorpamplona.amethyst.commons.chats.publicChannels.concord.datasource import com.vitorpamplona.amethyst.commons.actions.ConcordSubscriptionPlanner +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUniqueIdEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.launchChatFeedToggleObserver import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.launchChatFeedToggleObserver import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelHistoryFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/concord/datasource/ConcordChannelHistoryFilterAssembler.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelHistoryFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/concord/datasource/ConcordChannelHistoryFilterAssembler.kt index b8a7c920f9..c5f7f5cdf9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelHistoryFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/concord/datasource/ConcordChannelHistoryFilterAssembler.kt @@ -18,8 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource +package com.vitorpamplona.amethyst.commons.chats.publicChannels.concord.datasource +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager @@ -29,7 +30,6 @@ import com.vitorpamplona.amethyst.commons.relayClient.paging.PagingStatus import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.concord.cord03Channels.ConcordChannelId import com.vitorpamplona.quartz.concord.envelope.ConcordStreamEnvelope import com.vitorpamplona.quartz.nip01Core.core.Event @@ -54,7 +54,7 @@ class ConcordChannelHistoryQueryState( * Mounts the on-demand **history** pager for whichever Concord Channel screen is open. The live * [ConcordChannelFilterAssembler] only holds the recent tail the relay serves for each channel plane; * this pages older messages backward by `until`+`limit` per relay, exactly like the NIP-04 per- - * conversation history ([com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.datasource.ChatroomNip04HistorySubAssembler]). + * conversation history ([com.vitorpamplona.amethyst.commons.chats.privateDM.datasource.ChatroomNip04HistorySubAssembler]). */ class ConcordChannelHistoryFilterAssembler( client: INostrClient, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupUnread.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/RelayGroupUnread.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupUnread.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/RelayGroupUnread.kt index 1a8ef9e314..56a7901513 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupUnread.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/RelayGroupUnread.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup +package com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.chats.isMinichatReply import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.model.relayGroupChannelLastReadRoute -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip29RelayGroups.GroupId diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/dal/RelayGroupDiscoveryFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/dal/RelayGroupDiscoveryFeedFilter.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/dal/RelayGroupDiscoveryFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/dal/RelayGroupDiscoveryFeedFilter.kt index 7aec5941ff..55683755e1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/dal/RelayGroupDiscoveryFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/dal/RelayGroupDiscoveryFeedFilter.kt @@ -18,9 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.dal +package com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet @@ -28,9 +30,7 @@ import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.GroupDiscoveryC import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.toGroupConstraints import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.nip11RelayInfo.isRelaySignedRelayGroup -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.isRelaySignedRelayGroup import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip29RelayGroups.GroupId @@ -55,7 +55,7 @@ fun relayGroupDiscoveryChannelFor(note: Note): RelayGroupChannel? { * that decides which groups qualify: every group for Global, relay-key / admin / member for the * people filters (rosters read from the group's [RelayGroupChannel]), or a `#t`/`#g` tag match * for topic/geo filters. Structurally identical to - * [com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepositories.dal.GitRepositoriesFeedFilter]; + * [com.vitorpamplona.amethyst.commons.gitRepositories.dal.GitRepositoriesFeedFilter]; * the only difference is that a group's author is its relay, so the match runs through the * roster-aware constraint rather than the author-based [com.vitorpamplona.amethyst.ui.dal.FilterByListParams]. */ diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/BuzzDmJoinedChatTailFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/BuzzDmJoinedChatTailFilterAssembler.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/BuzzDmJoinedChatTailFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/BuzzDmJoinedChatTailFilterAssembler.kt index a91cf06711..a87a196619 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/BuzzDmJoinedChatTailFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/BuzzDmJoinedChatTailFilterAssembler.kt @@ -18,8 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource +package com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.buzz.BuzzDmChannels import com.vitorpamplona.amethyst.commons.model.buzz.BuzzDmRegistry import com.vitorpamplona.amethyst.commons.model.privateChats.DmHistoryTuning @@ -33,7 +34,6 @@ import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUniqueIdEo import com.vitorpamplona.amethyst.commons.relayClient.paging.WindowLoadTracker import com.vitorpamplona.amethyst.commons.relayClient.paging.trackingListener import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupCardWarmupFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupCardWarmupFilterAssembler.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupCardWarmupFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupCardWarmupFilterAssembler.kt index 7f6fc59e17..a9dbee971b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupCardWarmupFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupCardWarmupFilterAssembler.kt @@ -18,8 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource +package com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.channel.filterRelayGroupState @@ -30,7 +31,6 @@ import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUniqueIdEo import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip29RelayGroups.GroupId diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupJoinedChatTailFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupJoinedChatTailFilterAssembler.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupJoinedChatTailFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupJoinedChatTailFilterAssembler.kt index 45720e264c..96cc774394 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupJoinedChatTailFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupJoinedChatTailFilterAssembler.kt @@ -18,8 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource +package com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.buzz.BuzzRelayDialect import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType import com.vitorpamplona.amethyst.commons.model.privateChats.DmHistoryTuning @@ -34,7 +35,6 @@ import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUniqueIdEo import com.vitorpamplona.amethyst.commons.relayClient.paging.WindowLoadTracker import com.vitorpamplona.amethyst.commons.relayClient.paging.trackingListener import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription @@ -53,7 +53,7 @@ class RelayGroupJoinedChatTailQueryState( /** * Always-on **live tail** for the recent chat of every NIP-29 group the user has joined — the group * analog of the NIP-04 rooms-list live tail - * ([com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource.ChatroomListNip04SubAssembler]). + * ([com.vitorpamplona.amethyst.commons.chats.rooms.datasource.ChatroomListNip04SubAssembler]). * * **One subscription per joined group**, each a single-valued `#h` filter with `since = recentBoundary()` * and no `limit` — a time floor bounds it, so it stays reconnect-safe. This keeps the Messages-list diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupJoinedStateFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupJoinedStateFilterAssembler.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupJoinedStateFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupJoinedStateFilterAssembler.kt index 3d4d4f2960..74e13c073a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupJoinedStateFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupJoinedStateFilterAssembler.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource +package com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.channel.relayGroup.buildRelayGroupStateFilters import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUniqueIdEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.launchChatFeedToggleObserver import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.launchChatFeedToggleObserver import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupOpenChatHistoryFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupOpenChatHistoryFilterAssembler.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupOpenChatHistoryFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupOpenChatHistoryFilterAssembler.kt index 0ba237caf7..1863991cc4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupOpenChatHistoryFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupOpenChatHistoryFilterAssembler.kt @@ -18,8 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource +package com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.channel.relayGroup.buildRelayGroupHistoryFilters @@ -28,7 +29,6 @@ import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUniqueIdEo import com.vitorpamplona.amethyst.commons.relayClient.paging.BackwardRelayPager import com.vitorpamplona.amethyst.commons.relayClient.paging.PagingStatus import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter @@ -51,7 +51,7 @@ class RelayGroupOpenChatHistoryQueryState( * tail ([RelayGroupOpenChatTailFilterAssembler]) holds the recent window each host relay serves; this * pages older kind-9/poll messages backward by `until`+`limit` on the group's host relay, exactly * like the per-conversation NIP-04 history and the Concord channel history - * ([com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelHistoryFilterAssembler]). + * ([com.vitorpamplona.amethyst.commons.chats.publicChannels.concord.datasource.ConcordChannelHistoryFilterAssembler]). */ class RelayGroupOpenChatHistoryFilterAssembler( client: INostrClient, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupOpenChatTailFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupOpenChatTailFilterAssembler.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupOpenChatTailFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupOpenChatTailFilterAssembler.kt index e1b3fb92d9..b6c04a72c2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupOpenChatTailFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupOpenChatTailFilterAssembler.kt @@ -18,8 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource +package com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.privateChats.DmHistoryTuning import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.channel.relayGroup.buildRelayGroupAuxFilter @@ -29,7 +30,6 @@ import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUniqueIdEo import com.vitorpamplona.amethyst.commons.relayClient.paging.WindowLoadTracker import com.vitorpamplona.amethyst.commons.relayClient.paging.trackingListener import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupOpenThreadsHistoryFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupOpenThreadsHistoryFilterAssembler.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupOpenThreadsHistoryFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupOpenThreadsHistoryFilterAssembler.kt index 738a50c699..5eecee556e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupOpenThreadsHistoryFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupOpenThreadsHistoryFilterAssembler.kt @@ -18,8 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource +package com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.channel.relayGroup.buildRelayGroupThreadsHistoryFilters @@ -28,7 +29,6 @@ import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUniqueIdEo import com.vitorpamplona.amethyst.commons.relayClient.paging.BackwardRelayPager import com.vitorpamplona.amethyst.commons.relayClient.paging.PagingStatus import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsOnRelayFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupsOnRelayFilterAssembler.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsOnRelayFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupsOnRelayFilterAssembler.kt index 0059a589b8..b7a35d07ab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsOnRelayFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupsOnRelayFilterAssembler.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource +package com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.channel.relayGroup.buildRelayGroupDirectoryFilter import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUniqueIdEoseManager import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/MarkChatRoomsAsRead.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/MarkChatRoomsAsRead.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/MarkChatRoomsAsRead.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/MarkChatRoomsAsRead.kt index 48914bf464..0902b25af5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/MarkChatRoomsAsRead.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/MarkChatRoomsAsRead.kt @@ -18,8 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms +package com.vitorpamplona.amethyst.commons.chats.rooms +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.chats.ConcordServerRoomNote import com.vitorpamplona.amethyst.commons.model.chats.RelayGroupServerRoomNote @@ -31,7 +32,6 @@ import com.vitorpamplona.amethyst.commons.model.marmotGroups.MarmotGroupChatroom import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.model.privateChatLastReadRoute import com.vitorpamplona.amethyst.commons.model.relayGroupChannelLastReadRoute -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/RowUnread.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/RowUnread.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/RowUnread.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/RowUnread.kt index 7b2a052e2e..9d82babd6a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/RowUnread.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/RowUnread.kt @@ -18,8 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms +package com.vitorpamplona.amethyst.commons.chats.rooms +import com.vitorpamplona.amethyst.commons.chats.publicChannels.concord.concordCommunityHasUnreadFlow +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.relayGroupServerHasUnreadFlow +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.chats.ConcordServerRoomNote import com.vitorpamplona.amethyst.commons.model.chats.RelayGroupServerRoomNote @@ -32,9 +35,6 @@ import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChann import com.vitorpamplona.amethyst.commons.model.publicChatChannelIdOf import com.vitorpamplona.amethyst.commons.model.relayGroupChannelLastReadRoute import com.vitorpamplona.amethyst.commons.model.unreadPrivateChatRoute -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.concordCommunityHasUnreadFlow -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.relayGroupServerHasUnreadFlow import com.vitorpamplona.quartz.experimental.bitchat.geohash.GeohashChatEvent import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/dal/ChatroomListKnownFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/dal/ChatroomListKnownFeedFilter.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/dal/ChatroomListKnownFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/dal/ChatroomListKnownFeedFilter.kt index f3e9c55adf..b0ddbebba3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/dal/ChatroomListKnownFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/dal/ChatroomListKnownFeedFilter.kt @@ -18,9 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.dal +package com.vitorpamplona.amethyst.commons.chats.rooms.dal +import com.vitorpamplona.amethyst.commons.chats.publicChannels.concord.isConcordTimelineMessage +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.isRelayGroupTimelineMessage +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.newestTimelineNote import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType @@ -33,11 +38,6 @@ import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChann import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupViewMode import com.vitorpamplona.amethyst.commons.model.publicChatChannelIdOf import com.vitorpamplona.amethyst.commons.util.replace -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.isConcordTimelineMessage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.isRelayGroupTimelineMessage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.newestTimelineNote import com.vitorpamplona.quartz.concord.cord03Channels.ConcordChannelId import com.vitorpamplona.quartz.experimental.bitchat.geohash.GeohashChatEvent import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/dal/ChatroomListNewFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/dal/ChatroomListNewFeedFilter.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/dal/ChatroomListNewFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/dal/ChatroomListNewFeedFilter.kt index 14ef60fd83..68a11e6b21 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/dal/ChatroomListNewFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/dal/ChatroomListNewFeedFilter.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.dal +package com.vitorpamplona.amethyst.commons.chats.rooms.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType import com.vitorpamplona.amethyst.commons.util.replace -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip04Dm.messages.EncryptedDmEvent import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/ChatroomListFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/ChatroomListFilterAssembler.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/ChatroomListFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/ChatroomListFilterAssembler.kt index ce9a7b9ccc..87c8cb9762 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/ChatroomListFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/ChatroomListFilterAssembler.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource +package com.vitorpamplona.amethyst.commons.chats.rooms.datasource import androidx.compose.runtime.Stable +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient // This allows multiple screen to be listening to tags, even the same tag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/ChatroomListNip04HistorySubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/ChatroomListNip04HistorySubAssembler.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/ChatroomListNip04HistorySubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/ChatroomListNip04HistorySubAssembler.kt index 976c38b64f..8f58e7ebc5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/ChatroomListNip04HistorySubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/ChatroomListNip04HistorySubAssembler.kt @@ -18,17 +18,17 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource +package com.vitorpamplona.amethyst.commons.chats.rooms.datasource +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType import com.vitorpamplona.amethyst.commons.relayClient.chatrooms.filterNip04DMsFromMe import com.vitorpamplona.amethyst.commons.relayClient.chatrooms.filterNip04DMsToMe +import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.DmRelayLog import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager import com.vitorpamplona.amethyst.commons.relayClient.paging.BackwardRelayPager import com.vitorpamplona.amethyst.commons.relayClient.paging.PagingStatus import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.DmRelayLog import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter @@ -43,7 +43,7 @@ import kotlinx.coroutines.flow.StateFlow /** * Loads older NIP-04 DMs (kind 4) for the rooms list by **`until`+`limit` paging, per relay, on * demand** — the same model as the gift-wrap history loader - * ([com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip59GiftWraps.AccountGiftWrapsHistoryEoseManager]), + * ([com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip59GiftWraps.AccountGiftWrapsHistoryEoseManager]), * across the account's home (outbox, *from me*) + DM (inbox, *to me*) relays. Each relay advances one * page when its on-screen window-limit marker asks ([advance]); otherwise it parks. Nothing is walked * proactively. The per-relay cursors live on the account's diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/ChatroomListNip04SubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/ChatroomListNip04SubAssembler.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/ChatroomListNip04SubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/ChatroomListNip04SubAssembler.kt index 6eb9f65478..eb2a88afec 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/ChatroomListNip04SubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/ChatroomListNip04SubAssembler.kt @@ -18,19 +18,19 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource +package com.vitorpamplona.amethyst.commons.chats.rooms.datasource import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType import com.vitorpamplona.amethyst.commons.model.privateChats.DmHistoryTuning import com.vitorpamplona.amethyst.commons.relayClient.chatrooms.filterNip04DMsFromMe import com.vitorpamplona.amethyst.commons.relayClient.chatrooms.filterNip04DMsToMe +import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.DmRelayLog import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.launchChatFeedToggleObserver import com.vitorpamplona.amethyst.commons.relayClient.paging.WindowLoadTracker import com.vitorpamplona.amethyst.commons.relayClient.paging.trackingListener import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.DmRelayLog -import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.launchChatFeedToggleObserver import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription @@ -38,6 +38,7 @@ import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collectLatest diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FilterFollowingGeohashChats.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/FilterFollowingGeohashChats.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FilterFollowingGeohashChats.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/FilterFollowingGeohashChats.kt index 17769e3157..1922a06c1a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FilterFollowingGeohashChats.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/FilterFollowingGeohashChats.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource +package com.vitorpamplona.amethyst.commons.chats.rooms.datasource import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.geohash.GeohashRelays +import com.vitorpamplona.amethyst.commons.service.georelay.GeohashRelays import com.vitorpamplona.quartz.experimental.bitchat.geohash.GeohashChatEvent import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingEphemeralChatSubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/FollowingEphemeralChatSubAssembler.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingEphemeralChatSubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/FollowingEphemeralChatSubAssembler.kt index c13664a974..d99a11e29d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingEphemeralChatSubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/FollowingEphemeralChatSubAssembler.kt @@ -18,19 +18,20 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource +package com.vitorpamplona.amethyst.commons.chats.rooms.datasource import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType import com.vitorpamplona.amethyst.commons.relayClient.chatrooms.filterFollowingEphemeralChats import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.launchChatFeedToggleObserver import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.launchChatFeedToggleObserver import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.sample diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingGeohashChatSubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/FollowingGeohashChatSubAssembler.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingGeohashChatSubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/FollowingGeohashChatSubAssembler.kt index 48ef715cb4..5199e1a9fc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingGeohashChatSubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/FollowingGeohashChatSubAssembler.kt @@ -18,24 +18,25 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource +package com.vitorpamplona.amethyst.commons.chats.rooms.datasource import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.launchChatFeedToggleObserver import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.geohash.GeohashRelays -import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.launchChatFeedToggleObserver +import com.vitorpamplona.amethyst.commons.service.georelay.GeohashRelays import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription +import com.vitorpamplona.quartz.utils.concurrent.ConcurrentMap import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.sample import kotlinx.coroutines.launch -import java.util.concurrent.ConcurrentHashMap /** * Keeps the user's joined geohash location channels ([account.geohashList]) live @@ -62,7 +63,7 @@ class FollowingGeohashChatSubAssembler( override fun user(key: ChatroomListState) = key.account.userProfile() - private val userJobMap = ConcurrentHashMap>() + private val userJobMap = ConcurrentMap>() @OptIn(FlowPreview::class) override fun newSub(key: ChatroomListState): Subscription { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingPublicChatSubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/FollowingPublicChatSubAssembler.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingPublicChatSubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/FollowingPublicChatSubAssembler.kt index d4ad165145..417b66b09a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingPublicChatSubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/rooms/datasource/FollowingPublicChatSubAssembler.kt @@ -18,20 +18,21 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource +package com.vitorpamplona.amethyst.commons.chats.rooms.datasource import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType import com.vitorpamplona.amethyst.commons.relayClient.chatrooms.filterFollowingPublicChatsCreationEvent import com.vitorpamplona.amethyst.commons.relayClient.chatrooms.filterLastMessageFollowingPublicChats import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.launchChatFeedToggleObserver import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.launchChatFeedToggleObserver import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.sample diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/dal/CommunitiesFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/communities/list/dal/CommunitiesFeedFilter.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/dal/CommunitiesFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/communities/list/dal/CommunitiesFeedFilter.kt index d60215b38a..65bb0662e5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/list/dal/CommunitiesFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/communities/list/dal/CommunitiesFeedFilter.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.list.dal +package com.vitorpamplona.amethyst.commons.communities.list.dal +import com.vitorpamplona.amethyst.commons.discover.nip72Communities.DiscoverCommunityFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.mapNotNullIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip72Communities.DiscoverCommunityFeedFilter import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip72ModCommunities.approval.CommunityPostApprovalEvent diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cordn/CordnMigrationStores.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/cordn/CordnMigrationStores.kt similarity index 87% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cordn/CordnMigrationStores.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/cordn/CordnMigrationStores.kt index d48d7eebbc..5ec3a51bf1 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cordn/CordnMigrationStores.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/cordn/CordnMigrationStores.kt @@ -20,13 +20,16 @@ */ package com.vitorpamplona.amethyst.commons.cordn +import com.vitorpamplona.amethyst.commons.util.deleteRecursivelyQuietly +import com.vitorpamplona.amethyst.commons.util.platformFileSystem import com.vitorpamplona.quartz.cordn.appMultiDevice.CordnCarriedKeyPackage import com.vitorpamplona.quartz.cordn.spec02Envelopes.CordnDeliveredMessageCodec import com.vitorpamplona.quartz.cordn.sync.GroupCursor import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import java.io.File -import java.util.Base64 +import okio.FileSystem +import okio.Path +import kotlin.io.encoding.Base64 /** * Reading a handoff snapshot off the cordn stores, and writing one back. @@ -46,18 +49,19 @@ object CordnMigrationStores { * precisely when it matters. */ suspend fun read( - root: File, + root: Path, accountPubKey: HexKey, cipher: CordnBlobCipher, configs: List, + fileSystem: FileSystem = platformFileSystem, ): CordnMigrationSnapshot { val groups = mutableListOf() val keyPackages = mutableListOf() configs.forEach { config -> val dir = CordnStorageLayout.directoryFor(root, accountPubKey, config.pubKey) - val groupStore = FileCordnGroupStore(dir, cipher) - val keyPackageStore = FileCordnKeyPackageStore(dir, cipher) + val groupStore = FileCordnGroupStore(dir, cipher, fileSystem) + val keyPackageStore = FileCordnKeyPackageStore(dir, cipher, fileSystem) groupStore.listGroups().forEach { gid -> val state = groupStore.loadGroup(gid) ?: return@forEach @@ -127,19 +131,20 @@ object CordnMigrationStores { * `gid` present in both cannot end up half from each. */ suspend fun write( - root: File, + root: Path, accountPubKey: HexKey, cipher: CordnBlobCipher, snapshot: CordnMigrationSnapshot, + fileSystem: FileSystem = platformFileSystem, ): List { require(snapshot.accountPubKey == accountPubKey) { "this migration belongs to a different account" } - File(root, "cordn/$accountPubKey").deleteRecursively() + fileSystem.deleteRecursivelyQuietly(root / "cordn" / accountPubKey) snapshot.groups.forEach { group -> - val store = FileCordnGroupStore(CordnStorageLayout.directoryFor(root, accountPubKey, group.coordinatorPubKey), cipher) + val store = FileCordnGroupStore(CordnStorageLayout.directoryFor(root, accountPubKey, group.coordinatorPubKey), cipher, fileSystem) store.saveGroup(group.gid, group.clientStateBase64.fromBase64()) // Before the cursor, for the same reason the live path writes them in // that order: a seeding that wrote the cursor and then failed would @@ -158,7 +163,7 @@ object CordnMigrationStores { } snapshot.keyPackages.forEach { keyPackage -> - FileCordnKeyPackageStore(CordnStorageLayout.directoryFor(root, accountPubKey, keyPackage.coordinatorPubKey), cipher) + FileCordnKeyPackageStore(CordnStorageLayout.directoryFor(root, accountPubKey, keyPackage.coordinatorPubKey), cipher, fileSystem) .save(keyPackage.keyPackageRef, keyPackage.bundle.fromBase64()) } @@ -176,7 +181,15 @@ object CordnMigrationStores { } } - private fun ByteArray.toBase64() = Base64.getEncoder().encodeToString(this) + /** + * Standard alphabet, padded on the way out and optional on the way in, + * which is what `java.util.Base64`'s basic encoder and decoder did — so a + * snapshot written by an older build still reads, and one written here + * reads on an older build. + */ + private val base64 = Base64.Default.withPadding(Base64.PaddingOption.PRESENT_OPTIONAL) - private fun String.fromBase64(): ByteArray = Base64.getDecoder().decode(this) + private fun ByteArray.toBase64() = base64.encode(this) + + private fun String.fromBase64(): ByteArray = base64.decode(this) } diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cordn/FileBackedCordnScopeFactory.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/cordn/FileBackedCordnScopeFactory.kt similarity index 92% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cordn/FileBackedCordnScopeFactory.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/cordn/FileBackedCordnScopeFactory.kt index 6a4dec3613..35f48ec0d5 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cordn/FileBackedCordnScopeFactory.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/cordn/FileBackedCordnScopeFactory.kt @@ -20,8 +20,10 @@ */ package com.vitorpamplona.amethyst.commons.cordn +import com.vitorpamplona.amethyst.commons.util.platformFileSystem import com.vitorpamplona.quartz.nip01Core.core.HexKey -import java.io.File +import okio.FileSystem +import okio.Path /** * The production [CordnCoordinatorScopeFactory]: encrypted files on disk, plus @@ -38,9 +40,10 @@ import java.io.File * `/cordn//`; see [CordnStorageLayout]. */ class FileBackedCordnScopeFactory( - private val root: File, + private val root: Path, private val cipher: CordnBlobCipher, private val links: CordnCoordinatorLinkFactory, + private val fileSystem: FileSystem = platformFileSystem, ) : CordnCoordinatorScopeFactory { override suspend fun open( accountPubKey: HexKey, @@ -54,8 +57,8 @@ class FileBackedCordnScopeFactory( override suspend fun serverInfo() = link.serverInfo() - override val groupStore = FileCordnGroupStore(dir, cipher) - override val keyPackageStore = FileCordnKeyPackageStore(dir, cipher) + override val groupStore = FileCordnGroupStore(dir, cipher, fileSystem) + override val keyPackageStore = FileCordnKeyPackageStore(dir, cipher, fileSystem) // Only the transport closes. The files outlive the session by // design — closing a coordinator is not leaving its groups, and diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cordn/FileCordnStores.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/cordn/FileCordnStores.kt similarity index 75% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cordn/FileCordnStores.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/cordn/FileCordnStores.kt index 914fb8c555..15484ae4c1 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cordn/FileCordnStores.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/cordn/FileCordnStores.kt @@ -21,6 +21,11 @@ package com.vitorpamplona.amethyst.commons.cordn import com.vitorpamplona.amethyst.commons.storage.EncryptedAppendLog +import com.vitorpamplona.amethyst.commons.util.deleteQuietly +import com.vitorpamplona.amethyst.commons.util.deleteRecursivelyQuietly +import com.vitorpamplona.amethyst.commons.util.moveOrCopy +import com.vitorpamplona.amethyst.commons.util.platformFileSystem +import com.vitorpamplona.amethyst.commons.util.sibling import com.vitorpamplona.quartz.cordn.spec02Envelopes.CordnDeliveredMessage import com.vitorpamplona.quartz.cordn.spec02Envelopes.CordnDeliveredMessageCodec import com.vitorpamplona.quartz.cordn.sync.EchoState @@ -28,11 +33,13 @@ import com.vitorpamplona.quartz.cordn.sync.GroupCursor import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext -import java.io.File -import java.nio.ByteBuffer +import okio.Buffer +import okio.FileSystem +import okio.Path import kotlin.io.encoding.Base64 import kotlin.io.encoding.ExperimentalEncodingApi @@ -56,13 +63,13 @@ object CordnStorageLayout { * a caller could smuggle `..` into a directory name. */ fun directoryFor( - root: File, + root: Path, accountPubKey: HexKey, coordinatorPubKey: HexKey, - ): File { + ): Path { require(accountPubKey.matches(HEX)) { "account pubkey must be hex" } require(coordinatorPubKey.matches(HEX)) { "coordinator pubkey must be hex" } - return File(root, "cordn/$accountPubKey/$coordinatorPubKey") + return root / "cordn" / accountPubKey / coordinatorPubKey } /** @@ -74,11 +81,11 @@ object CordnStorageLayout { * make that coordinator's removal delete the record of the others. */ fun accountDirectoryFor( - root: File, + root: Path, accountPubKey: HexKey, - ): File { + ): Path { require(accountPubKey.matches(HEX)) { "account pubkey must be hex" } - return File(root, "cordn/$accountPubKey") + return root / "cordn" / accountPubKey } /** @@ -126,19 +133,22 @@ private const val TAG = "CordnStores" * is not a stale group, it is an unreadable one, and the group cannot be * re-derived from anywhere else on this device. */ -private fun atomicWrite( - file: File, +private fun FileSystem.atomicWrite( + file: Path, data: ByteArray, ) { - file.parentFile?.mkdirs() - val temp = File(file.parentFile, "${file.name}.tmp") - temp.writeBytes(data) - if (!temp.renameTo(file)) { - temp.copyTo(file, overwrite = true) - temp.delete() - } + file.parent?.let { createDirectories(it) } + val temp = file.sibling("${file.name}.tmp") + write(temp) { write(data) } + moveOrCopy(temp, file) } +private fun FileSystem.readBytes(file: Path): ByteArray = read(file) { readByteArray() } + +private fun FileSystem.isDirectory(path: Path): Boolean = metadataOrNull(path)?.isDirectory == true + +private fun FileSystem.isRegularFile(path: Path): Boolean = metadataOrNull(path)?.isRegularFile == true + /** * A [CordnGroupStore] on the filesystem, encrypted through [cipher]. * @@ -158,29 +168,30 @@ private fun atomicWrite( * that both encrypt blobs, which is not an abstraction worth having. */ class FileCordnGroupStore( - private val dir: File, + private val dir: Path, private val cipher: CordnBlobCipher, + private val fileSystem: FileSystem = platformFileSystem, ) : CordnGroupStore { - private fun groupDir(gid: String) = File(dir, "groups/${CordnStorageLayout.encodeKey(gid)}") + private fun groupDir(gid: String) = dir / "groups" / CordnStorageLayout.encodeKey(gid) - private fun stateFile(gid: String) = File(groupDir(gid), "state") + private fun stateFile(gid: String) = groupDir(gid) / "state" - private fun cursorFile(gid: String) = File(groupDir(gid), "cursor") + private fun cursorFile(gid: String) = groupDir(gid) / "cursor" - private fun joinOriginFile(gid: String) = File(groupDir(gid), "via-request") + private fun joinOriginFile(gid: String) = groupDir(gid) / "via-request" - private fun roomStateFile(gid: String) = File(groupDir(gid), "room") + private fun roomStateFile(gid: String) = groupDir(gid) / "room" - private fun echoStateFile(gid: String) = File(groupDir(gid), "echoes") + private fun echoStateFile(gid: String) = groupDir(gid) / "echoes" /** * Inside [groupDir] so [deleteGroup]'s recursive delete already covers it: * a group that left its history behind would keep the plaintext of an * end-to-end encrypted conversation after the key that read it was gone. */ - private fun messagesFile(gid: String) = File(groupDir(gid), "messages") + private fun messagesFile(gid: String) = groupDir(gid) / "messages" - private fun summaryFile(gid: String) = File(groupDir(gid), "newest") + private fun summaryFile(gid: String) = groupDir(gid) / "newest" /** * Appending a segment rather than rewriting the conversation, so the cost @@ -192,6 +203,7 @@ class FileCordnGroupStore( // The log treats null as "this segment is unreadable" and carries on // with the rest, which is what one corrupt segment should cost. decrypt = { runCatching { cipher.decrypt(it) }.getOrNull() }, + fileSystem = fileSystem, ) private val messageLock = Mutex() @@ -217,13 +229,13 @@ class FileCordnGroupStore( gid: String, state: ByteArray, ) = withContext(Dispatchers.IO) { - atomicWrite(stateFile(gid), cipher.encrypt(state)) + fileSystem.atomicWrite(stateFile(gid), cipher.encrypt(state)) } override suspend fun loadGroup(gid: String): ByteArray? = withContext(Dispatchers.IO) { val file = stateFile(gid) - if (!file.exists()) null else cipher.decrypt(file.readBytes()) + if (!fileSystem.exists(file)) null else cipher.decrypt(fileSystem.readBytes(file)) } override suspend fun deleteGroup(gid: String) { @@ -238,35 +250,39 @@ class FileCordnGroupStore( // The cursor goes with it. Leaving one behind would mean a later // re-join of the same gid resumes from a cursor belonging to a // group it is no longer in, skipping everything before it. - groupDir(gid).deleteRecursively() + fileSystem.deleteRecursivelyQuietly(groupDir(gid)) } } override suspend fun listGroups(): List = withContext(Dispatchers.IO) { - File(dir, "groups") - .listFiles() + fileSystem + .listOrNull(dir / "groups") .orEmpty() - .filter { it.isDirectory && File(it, "state").exists() } + .filter { fileSystem.isDirectory(it) && fileSystem.exists(it / "state") } .mapNotNull { CordnStorageLayout.decodeKey(it.name) } } + // Two big-endian int64s, which is what ByteBuffer wrote: its default order + // is BIG_ENDIAN, and so is okio's Buffer. override suspend fun saveCursor( gid: String, cursor: GroupCursor, ) = withContext(Dispatchers.IO) { - val buffer = ByteBuffer.allocate(16).putLong(cursor.fetchCursor).putLong(cursor.lastCursor) - atomicWrite(cursorFile(gid), cipher.encrypt(buffer.array())) + val bytes = Buffer().writeLong(cursor.fetchCursor).writeLong(cursor.lastCursor).readByteArray() + fileSystem.atomicWrite(cursorFile(gid), cipher.encrypt(bytes)) } override suspend fun loadCursor(gid: String): GroupCursor? = withContext(Dispatchers.IO) { val file = cursorFile(gid) - if (!file.exists()) return@withContext null - val bytes = cipher.decrypt(file.readBytes()) + if (!fileSystem.exists(file)) return@withContext null + val bytes = cipher.decrypt(fileSystem.readBytes(file)) if (bytes.size < 16) return@withContext null - val buffer = ByteBuffer.wrap(bytes) - GroupCursor(fetchCursor = buffer.long, lastCursor = buffer.long) + // Only the first 16 bytes are read, as ByteBuffer.wrap did; a longer + // blob's tail is ignored rather than refused. + val buffer = Buffer().write(bytes, 0, 16) + GroupCursor(fetchCursor = buffer.readLong(), lastCursor = buffer.readLong()) } // Existence IS the flag, so there is nothing to encrypt and nothing to @@ -275,11 +291,11 @@ class FileCordnGroupStore( // later re-join of the same gid is a different admission. override suspend fun saveJoinedViaRequest(gid: String) { withContext(Dispatchers.IO) { - atomicWrite(joinOriginFile(gid), ByteArray(0)) + fileSystem.atomicWrite(joinOriginFile(gid), ByteArray(0)) } } - override suspend fun loadJoinedViaRequest(gid: String): Boolean = withContext(Dispatchers.IO) { joinOriginFile(gid).exists() } + override suspend fun loadJoinedViaRequest(gid: String): Boolean = withContext(Dispatchers.IO) { fileSystem.exists(joinOriginFile(gid)) } override suspend fun saveRoomState( gid: String, @@ -288,18 +304,18 @@ class FileCordnGroupStore( // Deleted rather than blanked when there is nothing to remember, so an // emptied draft leaves no plaintext behind in an old file. if (state.isBlank) { - roomStateFile(gid).delete() + fileSystem.deleteQuietly(roomStateFile(gid)) return@withContext } - atomicWrite(roomStateFile(gid), cipher.encrypt(CordnRoomStateCodec.encode(state))) + fileSystem.atomicWrite(roomStateFile(gid), cipher.encrypt(CordnRoomStateCodec.encode(state))) } override suspend fun loadRoomState(gid: String): CordnRoomState = withContext(Dispatchers.IO) { val file = roomStateFile(gid) - if (!file.exists()) return@withContext CordnRoomState() + if (!fileSystem.exists(file)) return@withContext CordnRoomState() try { - CordnRoomStateCodec.decode(cipher.decrypt(file.readBytes())) + CordnRoomStateCodec.decode(cipher.decrypt(fileSystem.readBytes(file))) } catch (e: Exception) { CordnRoomState() } @@ -316,12 +332,12 @@ class FileCordnGroupStore( // this check that makes re-delivery free rather than duplicating. if (!ids.add(message.envelope.id)) return@withContext - groupDir(gid).mkdirs() + fileSystem.createDirectories(groupDir(gid)) messageLog.append(messagesFile(gid), CordnDeliveredMessageCodec.encode(message)) // Written on the same beat, so the inbox preview cannot disagree // with the room. Whole-blob rather than appended: it is one entry // that is always overwritten. - atomicWrite(summaryFile(gid), cipher.encrypt(CordnMessageSummaryCodec.encode(message, ids.size))) + fileSystem.atomicWrite(summaryFile(gid), cipher.encrypt(CordnMessageSummaryCodec.encode(message, ids.size))) } } @@ -337,9 +353,9 @@ class FileCordnGroupStore( override suspend fun loadMessageSummary(gid: String): CordnMessageSummary? = withContext(Dispatchers.IO) { val file = summaryFile(gid) - if (!file.exists()) return@withContext null + if (!fileSystem.exists(file)) return@withContext null try { - CordnMessageSummaryCodec.decode(cipher.decrypt(file.readBytes())) + CordnMessageSummaryCodec.decode(cipher.decrypt(fileSystem.readBytes(file))) } catch (e: Exception) { // A summary is a derived convenience; losing one costs a preview // line until the next message, not the history it summarises. @@ -355,18 +371,18 @@ class FileCordnGroupStore( // Deleted when there is nothing pending, so the common steady state is // no file rather than an empty one. if (state.isEmpty) { - echoStateFile(gid).delete() + fileSystem.deleteQuietly(echoStateFile(gid)) return@withContext } - atomicWrite(echoStateFile(gid), cipher.encrypt(EchoStateCodec.encode(state))) + fileSystem.atomicWrite(echoStateFile(gid), cipher.encrypt(EchoStateCodec.encode(state))) } override suspend fun loadEchoState(gid: String): EchoState = withContext(Dispatchers.IO) { val file = echoStateFile(gid) - if (!file.exists()) return@withContext EchoState() + if (!fileSystem.exists(file)) return@withContext EchoState() try { - EchoStateCodec.decode(cipher.decrypt(file.readBytes())) + EchoStateCodec.decode(cipher.decrypt(fileSystem.readBytes(file))) } catch (e: Exception) { EchoState() } @@ -385,36 +401,37 @@ class FileCordnGroupStore( * publishes different ones to different coordinators. */ class FileCordnKeyPackageStore( - private val dir: File, + private val dir: Path, private val cipher: CordnBlobCipher, + private val fileSystem: FileSystem = platformFileSystem, ) : CordnKeyPackageStore { - private fun bundleFile(keyPackageRef: String) = File(dir, "keypackages/${CordnStorageLayout.encodeKey(keyPackageRef)}") + private fun bundleFile(keyPackageRef: String) = dir / "keypackages" / CordnStorageLayout.encodeKey(keyPackageRef) override suspend fun save( keyPackageRef: String, bundle: ByteArray, ) = withContext(Dispatchers.IO) { - atomicWrite(bundleFile(keyPackageRef), cipher.encrypt(bundle)) + fileSystem.atomicWrite(bundleFile(keyPackageRef), cipher.encrypt(bundle)) } override suspend fun load(keyPackageRef: String): ByteArray? = withContext(Dispatchers.IO) { val file = bundleFile(keyPackageRef) - if (!file.exists()) null else cipher.decrypt(file.readBytes()) + if (!fileSystem.exists(file)) null else cipher.decrypt(fileSystem.readBytes(file)) } override suspend fun delete(keyPackageRef: String) { withContext(Dispatchers.IO) { - bundleFile(keyPackageRef).delete() + fileSystem.deleteQuietly(bundleFile(keyPackageRef)) } } override suspend fun list(): List = withContext(Dispatchers.IO) { - File(dir, "keypackages") - .listFiles() + fileSystem + .listOrNull(dir / "keypackages") .orEmpty() - .filter { it.isFile } + .filter { fileSystem.isRegularFile(it) } // No explicit ".tmp" exclusion, because the encoding already // is one: '.' is not in the base64url alphabet, so a temp file // left behind by a crashed write cannot decode to a ref and @@ -435,22 +452,23 @@ class FileCordnKeyPackageStore( * account, sitting above the per-coordinator directories it names. */ class FileCordnCoordinatorStore( - private val dir: File, + private val dir: Path, private val cipher: CordnBlobCipher, + private val fileSystem: FileSystem = platformFileSystem, ) : CordnCoordinatorStore { - private val file get() = File(dir, "coordinators") + private val file get() = dir / "coordinators" override suspend fun save(configs: List) = withContext(Dispatchers.IO) { - atomicWrite(file, cipher.encrypt(CoordinatorListCodec.encode(configs))) + fileSystem.atomicWrite(file, cipher.encrypt(CoordinatorListCodec.encode(configs))) } override suspend fun load(): List = withContext(Dispatchers.IO) { val stored = file - if (!stored.exists()) return@withContext emptyList() + if (!fileSystem.exists(stored)) return@withContext emptyList() try { - CoordinatorListCodec.decode(cipher.decrypt(stored.readBytes())) + CoordinatorListCodec.decode(cipher.decrypt(fileSystem.readBytes(stored))) } catch (e: Exception) { // A list written by a future build, or one the keystore can no // longer decrypt. Returning nothing loses the coordinators but @@ -463,7 +481,8 @@ class FileCordnCoordinatorStore( // the rooms are gone from the inbox and the invitations screen // says there is nowhere to look. One line is the difference // between a diagnosable fault and a mystery. - Log.w(TAG, "could not read ${stored.length()} bytes of coordinators, losing them: ${e.message}", e) + val size = fileSystem.metadataOrNull(stored)?.size ?: 0L + Log.w(TAG, "could not read $size bytes of coordinators, losing them: ${e.message}", e) emptyList() } } @@ -478,19 +497,20 @@ class FileCordnCoordinatorStore( * groups to another one, the exact fork the flag exists to prevent. */ class FileCordnHandoffStore( - private val accountDir: File, + private val accountDir: Path, + private val fileSystem: FileSystem = platformFileSystem, ) : CordnHandoffStore { - override suspend fun load(): Boolean = marker().exists() + override suspend fun load(): Boolean = fileSystem.exists(marker()) override suspend fun save(handedOff: Boolean) { val file = marker() if (handedOff) { - file.parentFile?.mkdirs() - file.writeBytes(ByteArray(0)) + file.parent?.let { fileSystem.createDirectories(it) } + fileSystem.write(file) { } } else { - file.delete() + fileSystem.deleteQuietly(file) } } - private fun marker() = File(accountDir, "handed-off") + private fun marker() = accountDir / "handed-off" } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/DiscoverLongFormFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip23LongForm/DiscoverLongFormFeedFilter.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/DiscoverLongFormFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip23LongForm/DiscoverLongFormFeedFilter.kt index 49df00f59d..f34723263c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/DiscoverLongFormFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip23LongForm/DiscoverLongFormFeedFilter.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip23LongForm +package com.vitorpamplona.amethyst.commons.discover.nip23LongForm import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip23LongContent.LongFormContentEvent open class DiscoverLongFormFeedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip28Chats/DiscoverChatFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip28Chats/DiscoverChatFeedFilter.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip28Chats/DiscoverChatFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip28Chats/DiscoverChatFeedFilter.kt index 3c2f9df44d..1aa6a9a329 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip28Chats/DiscoverChatFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip28Chats/DiscoverChatFeedFilter.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip28Chats +package com.vitorpamplona.amethyst.commons.discover.nip28Chats import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent import com.vitorpamplona.quartz.nip28PublicChat.base.IsInPublicChatChannel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip51FollowSets/DiscoverFollowSetsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip51FollowSets/DiscoverFollowSetsFeedFilter.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip51FollowSets/DiscoverFollowSetsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip51FollowSets/DiscoverFollowSetsFeedFilter.kt index a1a3eb2311..e27df8ccdd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip51FollowSets/DiscoverFollowSetsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip51FollowSets/DiscoverFollowSetsFeedFilter.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip51FollowSets +package com.vitorpamplona.amethyst.commons.discover.nip51FollowSets import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip51Lists.starterPack.StarterPackEvent open class DiscoverFollowSetsFeedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/DiscoverLiveFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip53LiveActivities/DiscoverLiveFeedFilter.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/DiscoverLiveFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip53LiveActivities/DiscoverLiveFeedFilter.kt index 6189aa50e5..7ed0ab797e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/DiscoverLiveFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip53LiveActivities/DiscoverLiveFeedFilter.kt @@ -18,10 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip53LiveActivities +package com.vitorpamplona.amethyst.commons.discover.nip53LiveActivities import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.ParticipantListBuilder import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -33,8 +34,7 @@ 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.service.OnlineChecker -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.service.OnlineStatusCache import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingRoomEvent import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent @@ -107,7 +107,7 @@ open class DiscoverLiveFeedFilter( items.associate { it to counter.countFollowsThatParticipateOn(it, null) } // Snapshots the status order once per item. convertStatusToOrder reads the - // OnlineChecker cache and the moving five-minute window, both of which can change + // OnlineStatusCache and the moving five-minute window, both of which can change // mid-sort (a background online check can update the cache). Reading it lazily inside // the comparator makes the ordering unstable and TimSort throws // "Comparison method violates its general contract!". @@ -138,7 +138,7 @@ open class DiscoverLiveFeedFilter( val url = event.streaming() ?: return 0 when (event.status()) { StatusTag.STATUS.LIVE -> { - if (OnlineChecker.isCachedAndOffline(url)) 0 else 2 + if (OnlineStatusCache.isCachedAndOffline(url)) 0 else 2 } StatusTag.STATUS.PLANNED -> { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/DiscoverCommunityFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip72Communities/DiscoverCommunityFeedFilter.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/DiscoverCommunityFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip72Communities/DiscoverCommunityFeedFilter.kt index baa0d09d50..6caf390e57 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/DiscoverCommunityFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip72Communities/DiscoverCommunityFeedFilter.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip72Communities +package com.vitorpamplona.amethyst.commons.discover.nip72Communities import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.mapNotNullIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip72ModCommunities.approval.CommunityPostApprovalEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DiscoverNIP89FeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip90DVMs/DiscoverNIP89FeedFilter.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DiscoverNIP89FeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip90DVMs/DiscoverNIP89FeedFilter.kt index e337baf17c..0e961d9f8b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DiscoverNIP89FeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip90DVMs/DiscoverNIP89FeedFilter.kt @@ -18,10 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip90DVMs +package com.vitorpamplona.amethyst.commons.discover.nip90DVMs import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.ParticipantListBuilder import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -35,7 +36,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.model.Account import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/DiscoverMarketplaceFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip99Classifieds/DiscoverMarketplaceFeedFilter.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/DiscoverMarketplaceFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip99Classifieds/DiscoverMarketplaceFeedFilter.kt index c84934f8c4..0339c43341 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/DiscoverMarketplaceFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/discover/nip99Classifieds/DiscoverMarketplaceFeedFilter.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip99Classifieds +package com.vitorpamplona.amethyst.commons.discover.nip99Classifieds import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent open class DiscoverMarketplaceFeedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/drafts/dal/DraftEventsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/drafts/dal/DraftEventsFeedFilter.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/drafts/dal/DraftEventsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/drafts/dal/DraftEventsFeedFilter.kt index 77f7e82ea3..90ecf05ecd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/drafts/dal/DraftEventsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/drafts/dal/DraftEventsFeedFilter.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.drafts.dal +package com.vitorpamplona.amethyst.commons.drafts.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip37Drafts.DraftWrapEvent class DraftEventsFeedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/browse/dal/BrowseEmojiSetsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/emojipacks/browse/dal/BrowseEmojiSetsFeedFilter.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/browse/dal/BrowseEmojiSetsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/emojipacks/browse/dal/BrowseEmojiSetsFeedFilter.kt index ded1c94b30..2c47132483 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/browse/dal/BrowseEmojiSetsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/emojipacks/browse/dal/BrowseEmojiSetsFeedFilter.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.browse.dal +package com.vitorpamplona.amethyst.commons.emojipacks.browse.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent class BrowseEmojiSetsFeedFilter( diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/notifications/CardFeedState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/feeds/CardFeedState.kt similarity index 95% rename from commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/notifications/CardFeedState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/feeds/CardFeedState.kt index 88bdf56eb7..db788aa093 100644 --- a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/notifications/CardFeedState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/feeds/CardFeedState.kt @@ -18,11 +18,10 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.commons.ui.notifications +package com.vitorpamplona.amethyst.commons.feeds import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable -import com.vitorpamplona.amethyst.commons.feeds.LoadedFeedState import kotlinx.coroutines.flow.MutableStateFlow /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DefaultFeedOrder.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/feeds/FeedOrders.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DefaultFeedOrder.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/feeds/FeedOrders.kt index 7e4ef554d9..2a65e34e86 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/DefaultFeedOrder.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/feeds/FeedOrders.kt @@ -18,16 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.dal +package com.vitorpamplona.amethyst.commons.feeds +import com.vitorpamplona.amethyst.commons.feeds.Card import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.commons.ui.notifications.Card -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.ChannelInviteCard +import com.vitorpamplona.amethyst.commons.notifications.ChannelInviteCard import com.vitorpamplona.quartz.nip01Core.core.Event -val DefaultFeedOrder: Comparator = - compareByDescending { it.createdAt() }.thenBy { it.idHex } - val DefaultFeedOrderEvent: Comparator = compareByDescending { it.createdAt }.thenBy { it.id } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/datasource/FollowPackFeedFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/followPacks/feed/datasource/FollowPackFeedFilterAssembler.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/datasource/FollowPackFeedFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/followPacks/feed/datasource/FollowPackFeedFilterAssembler.kt index 72b1d00801..f58a865b27 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/datasource/FollowPackFeedFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/followPacks/feed/datasource/FollowPackFeedFilterAssembler.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.datasource +package com.vitorpamplona.amethyst.commons.followPacks.feed.datasource import androidx.compose.runtime.Stable +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient // This allows multiple screen to be listening to tags, even the same tag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/datasource/FollowPackFeedFilterSubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/followPacks/feed/datasource/FollowPackFeedFilterSubAssembler.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/datasource/FollowPackFeedFilterSubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/followPacks/feed/datasource/FollowPackFeedFilterSubAssembler.kt index 13c6fe051f..affa839047 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/feed/datasource/FollowPackFeedFilterSubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/followPacks/feed/datasource/FollowPackFeedFilterSubAssembler.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.datasource +package com.vitorpamplona.amethyst.commons.followPacks.feed.datasource import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows.AllUserFollowsByOutboxTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows.AllUserFollowsByProxyTopNavFilter diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/dal/FollowPacksFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/followPacks/list/dal/FollowPacksFeedFilter.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/dal/FollowPacksFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/followPacks/list/dal/FollowPacksFeedFilter.kt index d42d44d8ac..d7d9cfecf5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/followPacks/list/dal/FollowPacksFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/followPacks/list/dal/FollowPacksFeedFilter.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.list.dal +package com.vitorpamplona.amethyst.commons.followPacks.list.dal +import com.vitorpamplona.amethyst.commons.discover.nip51FollowSets.DiscoverFollowSetsFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip51FollowSets.DiscoverFollowSetsFeedFilter class FollowPacksFeedFilter( account: Account, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocacheFindsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/geocaches/dal/GeocacheFindsFeedFilter.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocacheFindsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/geocaches/dal/GeocacheFindsFeedFilter.kt index aead50a2c6..d80b5b5e23 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocacheFindsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/geocaches/dal/GeocacheFindsFeedFilter.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.dal +package com.vitorpamplona.amethyst.commons.geocaches.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nipCCGeocaching.foundLog.GeocacheFoundLogEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocacheHuntsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/geocaches/dal/GeocacheHuntsFeedFilter.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocacheHuntsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/geocaches/dal/GeocacheHuntsFeedFilter.kt index c052a0fa78..0c41e94bf2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocacheHuntsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/geocaches/dal/GeocacheHuntsFeedFilter.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.dal +package com.vitorpamplona.amethyst.commons.geocaches.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nipCCGeocaching.curation.GeocacheCurationListEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocacheMineFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/geocaches/dal/GeocacheMineFeedFilter.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocacheMineFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/geocaches/dal/GeocacheMineFeedFilter.kt index 6bb4e8a551..51e9db4407 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocacheMineFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/geocaches/dal/GeocacheMineFeedFilter.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.dal +package com.vitorpamplona.amethyst.commons.geocaches.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.relayClient.geocaches.GeocacheListingKinds -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nipCCGeocaching.listing.GeocacheListingEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocachesFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/geocaches/dal/GeocachesFeedFilter.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocachesFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/geocaches/dal/GeocachesFeedFilter.kt index b1e60aaaad..e448ef0260 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/dal/GeocachesFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/geocaches/dal/GeocachesFeedFilter.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.dal +package com.vitorpamplona.amethyst.commons.geocaches.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.relayClient.geocaches.GeocacheListingKinds -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nipCCGeocaching.listing.GeocacheListingEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepositories/dal/GitRepositoriesFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/gitRepositories/dal/GitRepositoriesFeedFilter.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepositories/dal/GitRepositoriesFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/gitRepositories/dal/GitRepositoriesFeedFilter.kt index 298bea2bfb..b989bc228a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepositories/dal/GitRepositoriesFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/gitRepositories/dal/GitRepositoriesFeedFilter.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepositories.dal +package com.vitorpamplona.amethyst.commons.gitRepositories.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent class GitRepositoriesFeedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/datasource/FilterHashtagLabels.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/hashtag/datasource/FilterHashtagLabels.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/datasource/FilterHashtagLabels.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/hashtag/datasource/FilterHashtagLabels.kt index 4d69d08c88..292842be39 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/datasource/FilterHashtagLabels.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/hashtag/datasource/FilterHashtagLabels.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.datasource +package com.vitorpamplona.amethyst.commons.hashtag.datasource +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relayClient.event.loaders.filterMissingEvents import com.vitorpamplona.amethyst.commons.relayClient.event.loaders.potentialRelaysToFindEvent import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtagAlts diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/datasource/HashtagFeedFilterSubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/hashtag/datasource/HashtagFeedFilterSubAssembler.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/datasource/HashtagFeedFilterSubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/hashtag/datasource/HashtagFeedFilterSubAssembler.kt index 9a7425b921..1b65efc252 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/datasource/HashtagFeedFilterSubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/hashtag/datasource/HashtagFeedFilterSubAssembler.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.datasource +package com.vitorpamplona.amethyst.commons.hashtag.datasource import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUniqueIdEoseManager import com.vitorpamplona.amethyst.commons.relayClient.hashtag.filterPostsByHashtags diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/datasource/HashtagFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/hashtag/datasource/HashtagFilterAssembler.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/datasource/HashtagFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/hashtag/datasource/HashtagFilterAssembler.kt index d00ccb0eb3..180f822749 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/datasource/HashtagFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/hashtag/datasource/HashtagFilterAssembler.kt @@ -18,11 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.datasource +package com.vitorpamplona.amethyst.commons.hashtag.datasource +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/datasource/HashtagLabelSubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/hashtag/datasource/HashtagLabelSubAssembler.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/datasource/HashtagLabelSubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/hashtag/datasource/HashtagLabelSubAssembler.kt index 4dab878792..10a85bcf3c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/datasource/HashtagLabelSubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/hashtag/datasource/HashtagLabelSubAssembler.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.datasource +package com.vitorpamplona.amethyst.commons.hashtag.datasource import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUniqueIdEoseManager import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/dal/HighlightsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/highlights/dal/HighlightsFeedFilter.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/dal/HighlightsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/highlights/dal/HighlightsFeedFilter.kt index d0eeb79514..f114331090 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/dal/HighlightsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/highlights/dal/HighlightsFeedFilter.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.highlights.dal +package com.vitorpamplona.amethyst.commons.highlights.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip84Highlights.HighlightEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeConversationsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/home/dal/HomeConversationsFeedFilter.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeConversationsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/home/dal/HomeConversationsFeedFilter.kt index 3479a85771..5fb4ff6059 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeConversationsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/home/dal/HomeConversationsFeedFilter.kt @@ -18,17 +18,17 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.home.dal +package com.vitorpamplona.amethyst.commons.home.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.HomeFeedType import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.MutedAuthorsByOutboxTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.MutedAuthorsByProxyTopNavFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeEverythingFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/home/dal/HomeEverythingFeedFilter.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeEverythingFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/home/dal/HomeEverythingFeedFilter.kt index 9f0d69fce1..53410aa865 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeEverythingFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/home/dal/HomeEverythingFeedFilter.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.home.dal +package com.vitorpamplona.amethyst.commons.home.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.MutedAuthorsByOutboxTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.MutedAuthorsByProxyTopNavFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent import com.vitorpamplona.quartz.nip18Reposts.RepostEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeLiveFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/home/dal/HomeLiveFilter.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeLiveFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/home/dal/HomeLiveFilter.kt index 2448f89a4e..cda5010da3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeLiveFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/home/dal/HomeLiveFilter.kt @@ -18,10 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.home.dal +package com.vitorpamplona.amethyst.commons.home.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveComplexFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Channel import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -34,7 +35,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.model.Account import com.vitorpamplona.quartz.experimental.bitchat.geohash.GeohashChatEvent import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeNewThreadFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/home/dal/HomeNewThreadFeedFilter.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeNewThreadFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/home/dal/HomeNewThreadFeedFilter.kt index d0c9e9c634..98515b40aa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeNewThreadFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/home/dal/HomeNewThreadFeedFilter.kt @@ -18,11 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.home.dal +package com.vitorpamplona.amethyst.commons.home.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams import com.vitorpamplona.amethyst.commons.feeds.isRenderableRepost +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.HomeFeedType import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -31,8 +33,6 @@ import com.vitorpamplona.amethyst.commons.model.nip52Calendar.isLatestAnswerIn import com.vitorpamplona.amethyst.commons.model.nip52Calendar.latestRsvpAnswers import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.MutedAuthorsByOutboxTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.MutedAuthorsByProxyTopNavFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.agora.FundraiserEvent import com.vitorpamplona.quartz.experimental.attestations.attestation.AttestationEvent import com.vitorpamplona.quartz.experimental.attestations.proficiency.AttestorProficiencyEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/dal/LiveStreamsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/livestreams/dal/LiveStreamsFeedFilter.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/dal/LiveStreamsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/livestreams/dal/LiveStreamsFeedFilter.kt index 4c70fbfb1a..78688fcef4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/livestreams/dal/LiveStreamsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/livestreams/dal/LiveStreamsFeedFilter.kt @@ -18,10 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.livestreams.dal +package com.vitorpamplona.amethyst.commons.livestreams.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.ParticipantListBuilder import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -33,8 +34,7 @@ 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.service.OnlineChecker -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.service.OnlineStatusCache import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingRoomEvent import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent @@ -107,7 +107,7 @@ class LiveStreamsFeedFilter( items.associate { it to counter.countFollowsThatParticipateOn(it, null) } // Snapshots the status order once per item. convertStatusToOrder reads the - // OnlineChecker cache and the moving five-minute window, both of which can change + // OnlineStatusCache and the moving five-minute window, both of which can change // mid-sort (a background online check can update the cache). Reading it lazily inside // the comparator makes the ordering unstable and TimSort throws // "Comparison method violates its general contract!". @@ -138,7 +138,7 @@ class LiveStreamsFeedFilter( val url = event.streaming() ?: return 0 when (event.status()) { StatusTag.STATUS.LIVE -> { - if (OnlineChecker.isCachedAndOffline(url)) 0 else 2 + if (OnlineStatusCache.isCachedAndOffline(url)) 0 else 2 } StatusTag.STATUS.PLANNED -> { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/dal/LongsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/longs/dal/LongsFeedFilter.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/dal/LongsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/longs/dal/LongsFeedFilter.kt index a8b24ae923..859061a9bd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/longs/dal/LongsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/longs/dal/LongsFeedFilter.kt @@ -18,11 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.longs.dal +package com.vitorpamplona.amethyst.commons.longs.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams import com.vitorpamplona.amethyst.commons.feeds.SupportedContent +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -30,8 +32,6 @@ import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.relayClient.video.SUPPORTED_VIDEO_FEED_MIME_TYPES_SET import com.vitorpamplona.amethyst.commons.richtext.RichTextParser -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip71Video.AddressableNormalVideoEvent import com.vitorpamplona.quartz.nip71Video.VideoMeta diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/marmot/MarmotGroupIcon.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/marmot/MarmotGroupIcon.kt new file mode 100644 index 0000000000..df9d17d538 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/marmot/MarmotGroupIcon.kt @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.marmot + +import com.vitorpamplona.quartz.nip01Core.core.HexKey + +/** + * The parameters produced by encrypting + uploading a new Marmot group avatar, + * ready to be folded into a [com.vitorpamplona.quartz.marmot.mip01Groups.MarmotGroupData] + * via [com.vitorpamplona.quartz.marmot.mip01Groups.MarmotGroupData.withImage]. + */ +class MarmotGroupIconUpload( + /** SHA-256 (hex) of the encrypted blob = its Blossom content hash. */ + val imageHash: HexKey, + /** 32-byte HKDF seed for the image AEAD key (MIP-01 v2). */ + val imageKey: ByteArray, + /** 12-byte nonce. */ + val imageNonce: ByteArray, + /** 32-byte HKDF seed for the Blossom-auth keypair (MIP-01 v2). */ + val imageUploadKey: ByteArray, + /** + * Media type of the DECRYPTED image. + * + * MIP-01's blob never carried one, but the current profile's `0x8002` + * component requires it on a present image — and it is bound into the + * AEAD's AAD there, so a receiver cannot be steered into decoding the + * plaintext as a different type than the uploader meant. + */ + val mediaType: String, +) + +/** + * How a metadata update should treat the group icon. + */ +sealed class MarmotGroupIconChange { + /** Leave the existing icon (if any) untouched. */ + data object Keep : MarmotGroupIconChange() + + /** Remove the current icon. */ + data object Clear : MarmotGroupIconChange() + + /** Replace the icon with a freshly-uploaded one. */ + class Set( + val upload: MarmotGroupIconUpload, + ) : MarmotGroupIconChange() +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/Account.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/Account.kt index b77738a2d9..0a511017c8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/Account.kt @@ -18,45 +18,69 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model +package com.vitorpamplona.amethyst.commons.model import androidx.compose.runtime.Stable -import com.vitorpamplona.amethyst.Amethyst -import com.vitorpamplona.amethyst.BuildConfig -import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.commons.audio.VisualizerStyle import com.vitorpamplona.amethyst.commons.connectedApps.nip46.InMemoryNip46ClientStore import com.vitorpamplona.amethyst.commons.connectedApps.nip46.Nip46ClientStore import com.vitorpamplona.amethyst.commons.connectedApps.signers.InMemoryNostrSignerPermissionStore import com.vitorpamplona.amethyst.commons.connectedApps.signers.NostrSignerPermissionLedger import com.vitorpamplona.amethyst.commons.connectedApps.signers.NostrSignerPermissionStore +import com.vitorpamplona.amethyst.commons.cordn.CordnBlobCipher import com.vitorpamplona.amethyst.commons.defaults.Constants import com.vitorpamplona.amethyst.commons.marmot.MarmotManager import com.vitorpamplona.amethyst.commons.marmot.MarmotPublisher import com.vitorpamplona.amethyst.commons.marmot.MarmotPushCoordinator import com.vitorpamplona.amethyst.commons.model.AddressableNote +import com.vitorpamplona.amethyst.commons.model.EventProcessor import com.vitorpamplona.amethyst.commons.model.IAccount import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.VideoPostKind +import com.vitorpamplona.amethyst.commons.model.algoFeeds.FavoriteAlgoFeedsOrchestrator import com.vitorpamplona.amethyst.commons.model.backups.BackupRestore import com.vitorpamplona.amethyst.commons.model.backups.ReplaceableBackupConflict +import com.vitorpamplona.amethyst.commons.model.bolt12Offers.Bolt12OfferListState import com.vitorpamplona.amethyst.commons.model.buzz.BuzzChannelStars import com.vitorpamplona.amethyst.commons.model.buzz.BuzzHeldAttestations import com.vitorpamplona.amethyst.commons.model.buzz.BuzzRelayDialect import com.vitorpamplona.amethyst.commons.model.buzz.BuzzWorkspaces +import com.vitorpamplona.amethyst.commons.model.buzz.ChannelInvitesState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filter import com.vitorpamplona.amethyst.commons.model.composer.NewMessageTagger import com.vitorpamplona.amethyst.commons.model.concord.ConcordChannel import com.vitorpamplona.amethyst.commons.model.concord.ConcordChannelListState import com.vitorpamplona.amethyst.commons.model.concord.ConcordSessionManager +import com.vitorpamplona.amethyst.commons.model.cordn.CordnRuntime import com.vitorpamplona.amethyst.commons.model.edits.PrivateStorageRelayListDecryptionCache +import com.vitorpamplona.amethyst.commons.model.edits.PrivateStorageRelayListState import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatListDecryptionCache import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatListState +import com.vitorpamplona.amethyst.commons.model.localRelays.ForwardKind0ToLocalRelayState +import com.vitorpamplona.amethyst.commons.model.localRelays.LocalRelayListState +import com.vitorpamplona.amethyst.commons.model.location.LocationResult +import com.vitorpamplona.amethyst.commons.model.marmot.KeyPackageRelayListState +import com.vitorpamplona.amethyst.commons.model.marmot.MarmotGroupNotifier +import com.vitorpamplona.amethyst.commons.model.marmotGroups.MarmotGroupList import com.vitorpamplona.amethyst.commons.model.navigation.BottomBarEntry import com.vitorpamplona.amethyst.commons.model.navigation.NavBarItem +import com.vitorpamplona.amethyst.commons.model.nip01UserMetadata.AccountHomeRelayState +import com.vitorpamplona.amethyst.commons.model.nip01UserMetadata.AccountMineRelayState +import com.vitorpamplona.amethyst.commons.model.nip01UserMetadata.AccountOutboxRelayState +import com.vitorpamplona.amethyst.commons.model.nip01UserMetadata.NotificationInboxRelayState +import com.vitorpamplona.amethyst.commons.model.nip01UserMetadata.UserMetadataState +import com.vitorpamplona.amethyst.commons.model.nip02FollowLists.DeclaredFollowsPerOutboxRelay +import com.vitorpamplona.amethyst.commons.model.nip02FollowLists.DeclaredFollowsPerUsingRelay +import com.vitorpamplona.amethyst.commons.model.nip02FollowLists.FollowListOutboxOrProxyRelays +import com.vitorpamplona.amethyst.commons.model.nip02FollowLists.FollowListReusedOutboxOrProxyRelays +import com.vitorpamplona.amethyst.commons.model.nip02FollowLists.FollowsPerOutboxRelay +import com.vitorpamplona.amethyst.commons.model.nip02FollowLists.Kind3FollowListState +import com.vitorpamplona.amethyst.commons.model.nip03Timestamp.OtsState +import com.vitorpamplona.amethyst.commons.model.nip17Dms.DmInboxRelayState +import com.vitorpamplona.amethyst.commons.model.nip17Dms.DmRelayListState import com.vitorpamplona.amethyst.commons.model.nip18Reposts.RepostAction import com.vitorpamplona.amethyst.commons.model.nip25Reactions.ReactionAction import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel @@ -66,39 +90,77 @@ import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChann import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupListDecryptionCache import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupListState import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiPackState +import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.OwnedEmojiPacksState import com.vitorpamplona.amethyst.commons.model.nip38UserStatuses.UserStatusAction +import com.vitorpamplona.amethyst.commons.model.nip46Signer.Nip46ConsentPrompter +import com.vitorpamplona.amethyst.commons.model.nip46Signer.Nip46SignerState import com.vitorpamplona.amethyst.commons.model.nip47WalletConnect.NwcInfoCache +import com.vitorpamplona.amethyst.commons.model.nip47WalletConnect.NwcSignerState import com.vitorpamplona.amethyst.commons.model.nip51Lists.BookmarkListState import com.vitorpamplona.amethyst.commons.model.nip51Lists.GitRepositoryListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.HiddenUsersState import com.vitorpamplona.amethyst.commons.model.nip51Lists.OldBookmarkListState import com.vitorpamplona.amethyst.commons.model.nip51Lists.PinListState import com.vitorpamplona.amethyst.commons.model.nip51Lists.blockPeopleList.BlockPeopleListState import com.vitorpamplona.amethyst.commons.model.nip51Lists.blockedRelays.BlockedRelayListDecryptionCache +import com.vitorpamplona.amethyst.commons.model.nip51Lists.blockedRelays.BlockedRelayListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.bookmarkSets.BookmarkSetsState import com.vitorpamplona.amethyst.commons.model.nip51Lists.broadcastRelays.BroadcastRelayListDecryptionCache +import com.vitorpamplona.amethyst.commons.model.nip51Lists.broadcastRelays.BroadcastRelayListState import com.vitorpamplona.amethyst.commons.model.nip51Lists.favoriteAlgoFeedsLists.FavoriteAlgoFeedsListDecryptionCache +import com.vitorpamplona.amethyst.commons.model.nip51Lists.favoriteAlgoFeedsLists.FavoriteAlgoFeedsListState import com.vitorpamplona.amethyst.commons.model.nip51Lists.favoriteFollowSetsLists.FavoriteFollowSetsListDecryptionCache +import com.vitorpamplona.amethyst.commons.model.nip51Lists.favoriteFollowSetsLists.FavoriteFollowSetsListState import com.vitorpamplona.amethyst.commons.model.nip51Lists.favoriteRelays.FavoriteRelayListDecryptionCache +import com.vitorpamplona.amethyst.commons.model.nip51Lists.favoriteRelays.FavoriteRelayListState import com.vitorpamplona.amethyst.commons.model.nip51Lists.followSets.FollowSetDecryptionCache +import com.vitorpamplona.amethyst.commons.model.nip51Lists.followSets.FollowSetsState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.followSets.StarterPacksState import com.vitorpamplona.amethyst.commons.model.nip51Lists.geohashLists.GeohashListDecryptionCache +import com.vitorpamplona.amethyst.commons.model.nip51Lists.geohashLists.GeohashListState import com.vitorpamplona.amethyst.commons.model.nip51Lists.indexerRelays.IndexerRelayListDecryptionCache +import com.vitorpamplona.amethyst.commons.model.nip51Lists.indexerRelays.IndexerRelayListState import com.vitorpamplona.amethyst.commons.model.nip51Lists.interestLists.InterestListDecryptionCache +import com.vitorpamplona.amethyst.commons.model.nip51Lists.interestLists.InterestListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.interestSets.InterestSetsState import com.vitorpamplona.amethyst.commons.model.nip51Lists.muteList.MuteListDecryptionCache +import com.vitorpamplona.amethyst.commons.model.nip51Lists.muteList.MuteListState import com.vitorpamplona.amethyst.commons.model.nip51Lists.proxyRelays.ProxyRelayListDecryptionCache +import com.vitorpamplona.amethyst.commons.model.nip51Lists.proxyRelays.ProxyRelayListState import com.vitorpamplona.amethyst.commons.model.nip51Lists.searchRelays.SearchRelayListDecryptionCache +import com.vitorpamplona.amethyst.commons.model.nip51Lists.searchRelays.SearchRelayListState import com.vitorpamplona.amethyst.commons.model.nip51Lists.trustedRelays.TrustedRelayListDecryptionCache +import com.vitorpamplona.amethyst.commons.model.nip51Lists.trustedRelays.TrustedRelayListState +import com.vitorpamplona.amethyst.commons.model.nip53NestsServers.NestsServerListState import com.vitorpamplona.amethyst.commons.model.nip56Reports.ReportAction +import com.vitorpamplona.amethyst.commons.model.nip60Cashu.CashuMintDirectoryState +import com.vitorpamplona.amethyst.commons.model.nip60Cashu.CashuWalletState import com.vitorpamplona.amethyst.commons.model.nip62Vanish.VanishRequestsState +import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState import com.vitorpamplona.amethyst.commons.model.nip72Communities.CommunityListDecryptionCache +import com.vitorpamplona.amethyst.commons.model.nip72Communities.CommunityListState +import com.vitorpamplona.amethyst.commons.model.nip78AppSpecific.AppSpecificState import com.vitorpamplona.amethyst.commons.model.nip85TrustedAssertions.TrustProviderListDecryptionCache import com.vitorpamplona.amethyst.commons.model.nip85TrustedAssertions.UserAssertionDecryptionCache import com.vitorpamplona.amethyst.commons.model.nip85TrustedAssertions.UserAssertionsState +import com.vitorpamplona.amethyst.commons.model.nip89AppHandlers.AppRecommendationsState +import com.vitorpamplona.amethyst.commons.model.nipA3PaymentTargets.NipA3PaymentTargetsState +import com.vitorpamplona.amethyst.commons.model.nipB7Blossom.BlossomServerListState import com.vitorpamplona.amethyst.commons.model.nipBCOnchainZaps.OnchainWalletState import com.vitorpamplona.amethyst.commons.model.privateChatLastReadRoute import com.vitorpamplona.amethyst.commons.model.privateChats.hasEncryptedContent +import com.vitorpamplona.amethyst.commons.model.serverList.AssumedRelayListsState +import com.vitorpamplona.amethyst.commons.model.serverList.MergedFollowListsState +import com.vitorpamplona.amethyst.commons.model.serverList.MergedFollowPlusMineRelayListsState +import com.vitorpamplona.amethyst.commons.model.serverList.MergedFollowPlusMineWithIndexRelayListsState +import com.vitorpamplona.amethyst.commons.model.serverList.MergedFollowPlusMineWithSearchRelayListsState +import com.vitorpamplona.amethyst.commons.model.serverList.TrustedRelayListsState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.FeedDecryptionCaches +import com.vitorpamplona.amethyst.commons.model.topNavFeeds.FeedTopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.OutboxLoaderState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter +import com.vitorpamplona.amethyst.commons.model.trustedAssertions.TrustProviderListState import com.vitorpamplona.amethyst.commons.nipACWebRtcCalls.CallManager import com.vitorpamplona.amethyst.commons.relayClient.auth.InMemoryRelayAuthPermissionStore import com.vitorpamplona.amethyst.commons.relayClient.auth.RelayAuthPermissionCache @@ -113,73 +175,15 @@ import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthCustomToggles import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthPermissionStore import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthPolicy import com.vitorpamplona.amethyst.commons.richtext.RichTextParser +import com.vitorpamplona.amethyst.commons.service.http.EncryptionKeyCache import com.vitorpamplona.amethyst.commons.service.pow.PersistedPoWJob import com.vitorpamplona.amethyst.commons.service.pow.PoWCategory import com.vitorpamplona.amethyst.commons.service.pow.PoWPolicy import com.vitorpamplona.amethyst.commons.service.pow.PoWPublishQueue import com.vitorpamplona.amethyst.commons.service.pow.PoWReplay +import com.vitorpamplona.amethyst.commons.service.upload.FileHeader +import com.vitorpamplona.amethyst.commons.util.logTime import com.vitorpamplona.amethyst.commons.viewmodels.ReplyMode -import com.vitorpamplona.amethyst.logTime -import com.vitorpamplona.amethyst.model.algoFeeds.FavoriteAlgoFeedsOrchestrator -import com.vitorpamplona.amethyst.model.bolt12Offers.Bolt12OfferListState -import com.vitorpamplona.amethyst.model.buzz.ChannelInvitesState -import com.vitorpamplona.amethyst.model.cordn.CordnRuntime -import com.vitorpamplona.amethyst.model.edits.PrivateStorageRelayListState -import com.vitorpamplona.amethyst.model.localRelays.ForwardKind0ToLocalRelayState -import com.vitorpamplona.amethyst.model.localRelays.LocalRelayListState -import com.vitorpamplona.amethyst.model.marmot.KeyPackageRelayListState -import com.vitorpamplona.amethyst.model.nip01UserMetadata.AccountHomeRelayState -import com.vitorpamplona.amethyst.model.nip01UserMetadata.AccountMineRelayState -import com.vitorpamplona.amethyst.model.nip01UserMetadata.AccountOutboxRelayState -import com.vitorpamplona.amethyst.model.nip01UserMetadata.NotificationInboxRelayState -import com.vitorpamplona.amethyst.model.nip01UserMetadata.UserMetadataState -import com.vitorpamplona.amethyst.model.nip02FollowLists.DeclaredFollowsPerOutboxRelay -import com.vitorpamplona.amethyst.model.nip02FollowLists.DeclaredFollowsPerUsingRelay -import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowListOutboxOrProxyRelays -import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowListReusedOutboxOrProxyRelays -import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowsPerOutboxRelay -import com.vitorpamplona.amethyst.model.nip02FollowLists.Kind3FollowListState -import com.vitorpamplona.amethyst.model.nip03Timestamp.OtsState -import com.vitorpamplona.amethyst.model.nip17Dms.DmInboxRelayState -import com.vitorpamplona.amethyst.model.nip17Dms.DmRelayListState -import com.vitorpamplona.amethyst.model.nip30CustomEmojis.OwnedEmojiPacksState -import com.vitorpamplona.amethyst.model.nip46Signer.Nip46SignerState -import com.vitorpamplona.amethyst.model.nip47WalletConnect.NwcSignerState -import com.vitorpamplona.amethyst.model.nip51Lists.HiddenUsersState -import com.vitorpamplona.amethyst.model.nip51Lists.blockedRelays.BlockedRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.bookmarkSets.BookmarkSetsState -import com.vitorpamplona.amethyst.model.nip51Lists.broadcastRelays.BroadcastRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.favoriteAlgoFeedsLists.FavoriteAlgoFeedsListState -import com.vitorpamplona.amethyst.model.nip51Lists.favoriteFollowSetsLists.FavoriteFollowSetsListState -import com.vitorpamplona.amethyst.model.nip51Lists.favoriteRelays.FavoriteRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.followSets.FollowSetsState -import com.vitorpamplona.amethyst.model.nip51Lists.followSets.StarterPacksState -import com.vitorpamplona.amethyst.model.nip51Lists.geohashLists.GeohashListState -import com.vitorpamplona.amethyst.model.nip51Lists.indexerRelays.IndexerRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.interestLists.InterestListState -import com.vitorpamplona.amethyst.model.nip51Lists.interestSets.InterestSetsState -import com.vitorpamplona.amethyst.model.nip51Lists.muteList.MuteListState -import com.vitorpamplona.amethyst.model.nip51Lists.proxyRelays.ProxyRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.searchRelays.SearchRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.trustedRelays.TrustedRelayListState -import com.vitorpamplona.amethyst.model.nip65RelayList.Nip65RelayListState -import com.vitorpamplona.amethyst.model.nip72Communities.CommunityListState -import com.vitorpamplona.amethyst.model.nip78AppSpecific.AppSpecificState -import com.vitorpamplona.amethyst.model.nip89AppHandlers.AppRecommendationsState -import com.vitorpamplona.amethyst.model.nipA3PaymentTargets.NipA3PaymentTargetsState -import com.vitorpamplona.amethyst.model.nipB7Blossom.BlossomServerListState -import com.vitorpamplona.amethyst.model.serverList.AssumedRelayListsState -import com.vitorpamplona.amethyst.model.serverList.MergedFollowListsState -import com.vitorpamplona.amethyst.model.serverList.MergedFollowPlusMineRelayListsState -import com.vitorpamplona.amethyst.model.serverList.MergedFollowPlusMineWithIndexRelayListsState -import com.vitorpamplona.amethyst.model.serverList.MergedFollowPlusMineWithSearchRelayListsState -import com.vitorpamplona.amethyst.model.serverList.TrustedRelayListsState -import com.vitorpamplona.amethyst.model.topNavFeeds.FeedTopNavFilterState -import com.vitorpamplona.amethyst.model.trustedAssertions.TrustProviderListState -import com.vitorpamplona.amethyst.service.location.LocationState -import com.vitorpamplona.amethyst.service.uploads.FileHeader -import com.vitorpamplona.amethyst.ui.screen.loggedIn.EventProcessor -import com.vitorpamplona.marmotquic.QuicAgentTextStreamTransport import com.vitorpamplona.quartz.buzz.threading.buzzThread import com.vitorpamplona.quartz.buzz.threading.buzzThreadReply import com.vitorpamplona.quartz.buzz.threading.buzzThreadRoot @@ -299,6 +303,7 @@ import com.vitorpamplona.quartz.nip59Giftwrap.rumors.RumorAssembler import com.vitorpamplona.quartz.nip59Giftwrap.wraps.EphemeralGiftWrapEvent import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapTemplateConversion +import com.vitorpamplona.quartz.nip60Cashu.mintApi.MintHttpTransport import com.vitorpamplona.quartz.nip62RequestToVanish.RequestToVanishEvent import com.vitorpamplona.quartz.nip65RelayList.tags.AdvertisedRelayInfo import com.vitorpamplona.quartz.nip68Picture.PictureEvent @@ -341,16 +346,18 @@ import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceReplyEvent import com.vitorpamplona.quartz.nipA3PaymentTargets.PaymentTarget import com.vitorpamplona.quartz.nipB0WebBookmarks.WebBookmarkEvent import com.vitorpamplona.quartz.nipC7Chats.ChatEvent +import com.vitorpamplona.quartz.utils.BigDecimal import com.vitorpamplona.quartz.utils.DualCase import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.RandomInstance import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.ciphers.AESGCM +import com.vitorpamplona.quartz.utils.ciphers.AES_GCM_NAME import com.vitorpamplona.quartz.utils.containsAny -import com.vitorpamplona.quic.tls.JdkCertificateValidator import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -362,7 +369,7 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock -import java.math.BigDecimal +import okio.Path import kotlin.coroutines.cancellation.CancellationException import com.vitorpamplona.quartz.experimental.nip95.header.thumbhash as nip95thumbhash import com.vitorpamplona.quartz.experimental.profileGallery.thumbhash as galleryThumbhash @@ -372,14 +379,39 @@ import com.vitorpamplona.quartz.experimental.profileGallery.thumbhash as gallery class Account( val settings: AccountSettings = AccountSettings(KeyPair()), override val signer: NostrSigner, - val geolocationFlow: () -> StateFlow, + val geolocationFlow: () -> StateFlow, val nwcFilterAssembler: () -> NWCPaymentFilterAssembler, val cashuMintDirectoryFilterAssembler: () -> com.vitorpamplona.amethyst.commons.relayClient.assemblers.CashuMintDirectoryFilterAssembler, - val okHttpClientForMoney: (String) -> okhttp3.OkHttpClient, + /** How Cashu mint requests go out (the app's money-role HTTP: Tor or proxy per URL). */ + val cashuMintTransport: MintHttpTransport, val otsResolverBuilder: () -> OtsResolver, val cache: LocalCache, val client: INostrClient, val scope: CoroutineScope, + /** + * The running app's version name. The zap-the-devs prompt is dismissed per version, so a + * donation in one release doesn't hide it in the next. Passed in rather than read from the + * app's `BuildConfig`, which a shared module can't see. + */ + val appVersion: String, + /** + * The app-wide store of media decryption keys. Encrypted attachments (Concord images, NIP-17 + * files) register their key here by URL, and the HTTP layer decrypts the blob on fetch. + */ + val encryptionKeyCache: EncryptionKeyCache, + /** Persists this account's settings. Called on the IO dispatcher, debounced, after changes. */ + val saveSettings: suspend (AccountSettings) -> Unit, + /** + * Where Marmot Welcomes and group messages are announced to the user (system notifications). + * A provider, read when a message arrives, because the app builds its notifier after its accounts. + */ + val marmotNotifier: () -> MarmotGroupNotifier, + /** Asks the user to approve NIP-46 client connections and operations (the app's signer dialogs). */ + val nip46Consent: Nip46ConsentPrompter, + /** Where this account's geohash-chat seed and nickname are kept (the app's encrypted storage). */ + val geohashIdentityStore: GeohashIdentityStore, + /** Builds the raw-QUIC transport for agent text stream previews, on the account's scope. */ + val marmotStreamTransportFactory: (CoroutineScope) -> MarmotQuicTransport, /** * Where cordn keeps its encrypted group state, or null to run without it. * @@ -388,7 +420,12 @@ class Account( * Nothing about it is shared with Marmot's stores above — cordn has its * own, by the §3.1 rule in `amethyst/plans/2026-09-19-cordn-ui.md`. */ - val cordnFilesDir: java.io.File? = null, + val cordnFilesDir: Path? = null, + /** + * Encrypts cordn's state at rest (the Android Keystore in the app). Called once, when + * [cordnFilesDir] is set; without both, the account runs without cordn. + */ + val cordnBlobCipher: (() -> CordnBlobCipher)? = null, val mlsGroupStateStore: MlsGroupStateStore? = null, val marmotMessageStore: com.vitorpamplona.quartz.marmot.groups.MarmotMessageStore? = null, val marmotKeyPackageStore: com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageBundleStore? = null, @@ -615,6 +652,7 @@ class Account( inboxRelays = nip65RelayList.inboxFlow, scope = scope, settings = settings, + consent = nip46Consent, ) val forwardKind0ToLocalRelay = ForwardKind0ToLocalRelayState(client, localRelayList, settings) @@ -707,17 +745,16 @@ class Account( /** * Register any encrypted image attachments on a Concord message ([ChannelChat.encryptedImagesOf]) * so the shared media pipeline can display them: the ciphertext blob's AES-256-GCM key/nonce go - * into [com.vitorpamplona.amethyst.AppModules.keyCache], and the OkHttp EncryptedBlobInterceptor + * into [encryptionKeyCache], and the OkHttp EncryptedBlobInterceptor * decrypts the blob transparently on fetch (keyed by URL) — the same path NIP-17 encrypted media * uses. Runs for both inbound wraps and our own local echo, so a sent image renders immediately. */ private fun registerConcordEncryptedImages(rumor: Event) { val images = ChannelChat.encryptedImagesOf(rumor) if (images.isEmpty()) return - val keyCache = Amethyst.instance.keyCache images.forEach { img -> - if (img.algo == AESGCM.NAME) { - keyCache.add(img.url, AESGCM(img.key, img.nonce), img.mimeType) + if (img.algo == AES_GCM_NAME) { + encryptionKeyCache.add(img.url, AESGCM(img.key, img.nonce), img.mimeType) } } } @@ -774,7 +811,7 @@ class Account( val geohashList = GeohashListState(signer, cache, geohashListDecryptionCache, scope, settings) // Anonymous, per-geohash throwaway identities for Bitchat-interoperable location chats. - val geohashIdentity = GeohashChatIdentityState(signer, scope) + val geohashIdentity = GeohashChatIdentityState(signer, scope, geohashIdentityStore) val muteListDecryptionCache = MuteListDecryptionCache(signer) val muteList = MuteListState(signer, cache, muteListDecryptionCache, scope, settings) @@ -810,8 +847,7 @@ class Account( val blossomServers = BlossomServerListState(signer, cache, scope, settings) val nestsServers = - com.vitorpamplona.amethyst.model.nip53NestsServers - .NestsServerListState(signer, cache, scope) + NestsServerListState(signer, cache, scope) // Relay settings val homeRelays = AccountHomeRelayState(nip65RelayList, privateStorageRelayList, localRelayList, scope) @@ -844,7 +880,7 @@ class Account( ) val cashuWalletState = - com.vitorpamplona.amethyst.model.nip60Cashu.CashuWalletState( + CashuWalletState( pubKey = signer.pubKey, signer = signer, cache = cache, @@ -854,7 +890,7 @@ class Account( inboxRelaysFlow = notificationRelays.flow, dmRelaysFlow = dmRelays.flow, settings = settings, - okHttpClient = okHttpClientForMoney, + mintTransport = cashuMintTransport, ) /** @@ -863,7 +899,7 @@ class Account( * relay subscription only runs while at least one opener is active. */ val cashuMintDirectoryState = - com.vitorpamplona.amethyst.commons.model.nip60Cashu.CashuMintDirectoryState( + CashuMintDirectoryState( cache = cache, scope = scope, assembler = cashuMintDirectoryFilterAssembler(), @@ -906,8 +942,7 @@ class Account( override val chatroomList = cache.getOrCreateChatroomList(signer.pubKey) override val marmotGroupList = - com.vitorpamplona.amethyst.commons.model.marmotGroups - .MarmotGroupList(signer.pubKey) + MarmotGroupList(signer.pubKey) val newNotesPreProcessor = EventProcessor(this, cache) @@ -969,12 +1004,16 @@ class Account( * network and no coordinator learns anything from it. */ val cordnRuntime: CordnRuntime? = - cordnFilesDir?.let { + cordnFilesDir?.let { dir -> + // Loud rather than silently cordn-less: a caller that sets the directory and forgets + // the cipher would otherwise just lose the user's cordn groups with no error. + val cipher = requireNotNull(cordnBlobCipher) { "cordnFilesDir is set but cordnBlobCipher is not" } CordnRuntime( accountSigner = signer, client = client, - filesDir = it, + filesDir = dir, scope = scope, + cipher = cipher(), ) } @@ -1019,15 +1058,7 @@ class Account( * authoritative kind:9 like ordinary chat — which is why this is a * separate optional piece rather than part of [marmotManager]. */ - val marmotStreamTransport: MarmotQuicTransport by lazy { - QuicAgentTextStreamTransport( - parentScope = scope, - // Preview brokers are commonly self-signed and the binding expects - // that; the platform trust store is still the default answer, and - // a deployment that pins does it here. - certificateValidator = JdkCertificateValidator(), - ) - } + val marmotStreamTransport: MarmotQuicTransport by lazy { marmotStreamTransportFactory(scope) } val paymentTargetsState = NipA3PaymentTargetsState(signer, cache, scope, settings) @@ -1332,7 +1363,7 @@ class Account( sendNewAppSpecificData() } - internal suspend fun sendNewAppSpecificData() = sendMyPublicAndPrivateOutbox(appSpecific.saveNewAppSpecificData()) + suspend fun sendNewAppSpecificData() = sendMyPublicAndPrivateOutbox(appSpecific.saveNewAppSpecificData()) // --- // NIP-13 proof-of-work publishing @@ -2600,6 +2631,8 @@ class Account( val isImage = headerInfo.mimeType?.startsWith("image/") == true || RichTextParser.isImageUrl(url) val isVideo = headerInfo.mimeType?.startsWith("video/") == true || RichTextParser.isVideoUrl(url) + // A local, so the null check below smart-casts: FileHeader lives in another module. + val dim = headerInfo.dim val template = if (isImage) { @@ -2625,7 +2658,7 @@ class Account( // add title contentWarningReason?.let { contentWarning(contentWarningReason) } } - } else if (isVideo && headerInfo.dim != null) { + } else if (isVideo && dim != null) { val videoMeta = VideoMeta( url = url, @@ -2641,7 +2674,7 @@ class Account( // The composer forces the kind when it was opened from a feed that only reads one of // them (Shorts, Longs) or from that feed's share target, so the post lands where the // user asked for it. Everywhere else the orientation decides. - if (videoKind.isShort(headerInfo.dim)) { + if (videoKind.isShort(dim)) { VideoShortEvent.build(videoMeta, alt ?: "") { contentWarningReason?.let { contentWarning(contentWarningReason) } } @@ -3919,15 +3952,15 @@ class Account( fun loadLastReadFlow(route: String) = settings.getLastReadFlow(route) - fun hasDonatedInThisVersion() = settings.hasDonatedInVersion(BuildConfig.VERSION_NAME) + fun hasDonatedInThisVersion() = settings.hasDonatedInVersion(appVersion) fun observeDonatedInThisVersion() = settings - .observeDonatedInVersion(BuildConfig.VERSION_NAME) + .observeDonatedInVersion(appVersion) .flowOn(Dispatchers.IO) .stateIn(scope, SharingStarted.Eagerly, hasDonatedInThisVersion()) - fun markDonatedInThisVersion() = settings.markDonatedInThisVersion(BuildConfig.VERSION_NAME) + fun markDonatedInThisVersion() = settings.markDonatedInThisVersion(appVersion) fun dismissPollNotification(noteId: String) = settings.dismissPollNotification(noteId) @@ -4135,7 +4168,7 @@ class Account( @OptIn(kotlinx.coroutines.FlowPreview::class) settings.saveable.debounce(1000).collect { if (it.accountSettings != null) { - LocalPreferences.saveToEncryptedStorage(it.accountSettings) + saveSettings(it.accountSettings) } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountConcordActions.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountConcordActions.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountConcordActions.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountConcordActions.kt index 198509f959..7f82a96786 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountConcordActions.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountConcordActions.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model +package com.vitorpamplona.amethyst.commons.model import com.vitorpamplona.amethyst.commons.actions.ConcordActions import com.vitorpamplona.amethyst.commons.actions.ConcordModeration @@ -70,10 +70,11 @@ import com.vitorpamplona.quartz.nipC7Chats.ChatEvent import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.RandomInstance import com.vitorpamplona.quartz.utils.TimeUtils +import com.vitorpamplona.quartz.utils.concurrent.ConcurrentMap +import com.vitorpamplona.quartz.utils.concurrent.ConcurrentSet import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope -import java.util.concurrent.ConcurrentHashMap /** Name of the default Concord community Admin role minted by "Make admin". */ private const val CONCORD_ADMIN_ROLE = "Admin" @@ -1222,7 +1223,7 @@ class AccountConcordActions( // Rotations we've already adopted ("communityId:epoch"), so a base-rekey wrap still buffered // in the pre-rebuild window (the session rebuild off `liveCommunities` is async) is not // adopted — and re-published — twice on successive revision ticks. - private val adoptedConcordRotations = java.util.Collections.synchronizedSet(HashSet()) + private val adoptedConcordRotations = ConcurrentSet() /** * Persist a rotated access root/epoch for [entry], keeping the prior root as a @@ -1341,7 +1342,7 @@ class AccountConcordActions( // Last time we re-resolved each community's invite_ref, so the recovery sweep rides the // Concord revision tick (which fires on every structural change) without turning it into a // relay-fetch loop. - private val lastConcordRecoveryCheck = ConcurrentHashMap() + private val lastConcordRecoveryCheck = ConcurrentMap() /** * Stranded recovery (CORD-05/06 receive path). A Refounding carries only diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountMarmotActions.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountMarmotActions.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountMarmotActions.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountMarmotActions.kt index 4e2d9a7f8d..7c90b37298 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountMarmotActions.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountMarmotActions.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model +package com.vitorpamplona.amethyst.commons.model import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType @@ -667,7 +667,7 @@ class AccountMarmotActions( * a flaky relay or missing outbox config at startup to crash account * initialization. */ - internal suspend fun ensureMarmotKeyPackagePublished() { + suspend fun ensureMarmotKeyPackagePublished() { val manager = account.marmotManager ?: return if (!account.isWriteable()) return try { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountRelayGroupActions.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountRelayGroupActions.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountRelayGroupActions.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountRelayGroupActions.kt index 3d900e1f80..120dc22ff8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountRelayGroupActions.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountRelayGroupActions.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model +package com.vitorpamplona.amethyst.commons.model import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.buzz.BuzzRelayDialect diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSettings.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountSettings.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSettings.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountSettings.kt index fbf80b4a67..475f4c3d17 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSettings.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountSettings.kt @@ -18,7 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model +@file:OptIn(ExperimentalUuidApi::class) + +package com.vitorpamplona.amethyst.commons.model import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.commons.audio.VisualizerStyle @@ -60,9 +62,7 @@ import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey import com.vitorpamplona.quartz.nip17Dm.settings.DmRelayListEvent import com.vitorpamplona.quartz.nip28PublicChat.list.PublicChatListEvent -import com.vitorpamplona.quartz.nip37Drafts.DraftWrapEvent import com.vitorpamplona.quartz.nip37Drafts.privateOutbox.PrivateOutboxRelayListEvent -import com.vitorpamplona.quartz.nip42RelayAuth.RelayAuthEvent import com.vitorpamplona.quartz.nip47WalletConnect.Nip47WalletConnect import com.vitorpamplona.quartz.nip50Search.SearchRelayListEvent import com.vitorpamplona.quartz.nip51Lists.favoriteAlgoFeedsList.FavoriteAlgoFeedsListEvent @@ -74,8 +74,6 @@ import com.vitorpamplona.quartz.nip51Lists.relayLists.FavoriteRelayListEvent import com.vitorpamplona.quartz.nip51Lists.relayLists.IndexerRelayListEvent import com.vitorpamplona.quartz.nip51Lists.relayLists.TrustedRelayListEvent import com.vitorpamplona.quartz.nip51Lists.simpleGroupList.SimpleGroupListEvent -import com.vitorpamplona.quartz.nip55AndroidSigner.api.CommandType -import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.Permission import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent import com.vitorpamplona.quartz.nip60Cashu.wallet.CashuWalletEvent import com.vitorpamplona.quartz.nip61Nutzaps.info.NutzapInfoEvent @@ -92,17 +90,8 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update import kotlinx.serialization.Serializable - -val DefaultSignerPermissions = - listOf( - Permission(CommandType.SIGN_EVENT, RelayAuthEvent.KIND), - Permission(CommandType.SIGN_EVENT, DraftWrapEvent.KIND), - Permission(CommandType.NIP04_ENCRYPT), - Permission(CommandType.NIP04_DECRYPT), - Permission(CommandType.NIP44_DECRYPT), - Permission(CommandType.NIP44_DECRYPT), - Permission(CommandType.DECRYPT_ZAP_EVENT), - ) +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Stable class AccountSettings( @@ -127,7 +116,7 @@ class AccountSettings( /** * NIP-46: when true, this account acts as a remote signer (a "bunker") for * other apps, listening on the user's inbox relays for kind:24133 requests. - * See [com.vitorpamplona.amethyst.model.nip46Signer.Nip46SignerState]. + * See [com.vitorpamplona.amethyst.commons.model.nip46Signer.Nip46SignerState]. */ val nip46SignerEnabled: MutableStateFlow = MutableStateFlow(false), /** @@ -596,9 +585,7 @@ class AccountSettings( val entry = NwcWalletEntryNorm( id = - java.util.UUID - .randomUUID() - .toString(), + Uuid.random().toString(), name = "Wallet", uri = newServer, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSyncedSettings.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountSyncedSettings.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSyncedSettings.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountSyncedSettings.kt index 3e6978ed94..46cf021685 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSyncedSettings.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountSyncedSettings.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model +package com.vitorpamplona.amethyst.commons.model import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.commons.audio.VisualizerStyle @@ -30,6 +30,7 @@ import com.vitorpamplona.amethyst.commons.model.navigation.toNames import com.vitorpamplona.amethyst.commons.service.pow.PoWCategory import com.vitorpamplona.amethyst.commons.service.pow.PoWPolicy import com.vitorpamplona.amethyst.commons.util.equalImmutableLists +import com.vitorpamplona.amethyst.commons.util.getLanguagesSpokenByUser import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent import kotlinx.collections.immutable.ImmutableList @@ -275,7 +276,7 @@ class AccountZapPreferences( * legacy `onchainZapAmountChoices`. Idempotent: [AccountSyncedSettings.toInternal] * re-derives the on-chain field as a subset of this list. */ -internal fun mergeZapAmounts(zaps: AccountZapPreferencesInternal): List = (zaps.zapAmountChoices + zaps.onchainZapAmountChoices).distinct() +fun mergeZapAmounts(zaps: AccountZapPreferencesInternal): List = (zaps.zapAmountChoices + zaps.onchainZapAmountChoices).distinct() @Stable class AccountLanguagePreferences( @@ -393,7 +394,7 @@ class AccountPoWPreferences( } } -internal fun AccountChatPreferencesInternal.toChatroomKeys(): Set = pinnedRooms.mapTo(mutableSetOf()) { ChatroomKey(it.toSet()) } +fun AccountChatPreferencesInternal.toChatroomKeys(): Set = pinnedRooms.mapTo(mutableSetOf()) { ChatroomKey(it.toSet()) } @Stable class AccountSecurityPreferences( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSyncedSettingsInternal.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountSyncedSettingsInternal.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSyncedSettingsInternal.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountSyncedSettingsInternal.kt index de721aefbe..64f3fc6624 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSyncedSettingsInternal.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountSyncedSettingsInternal.kt @@ -18,16 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model +package com.vitorpamplona.amethyst.commons.model -import android.content.res.Resources -import androidx.core.os.ConfigurationCompat import com.vitorpamplona.amethyst.commons.model.navigation.BottomBarEntry +import com.vitorpamplona.amethyst.commons.model.navigation.DefaultBottomBarEntries import com.vitorpamplona.amethyst.commons.service.pow.PoWCategory -import com.vitorpamplona.amethyst.ui.navigation.bottombars.DefaultBottomBarEntries +import com.vitorpamplona.amethyst.commons.util.getDefaultLanguageCode +import com.vitorpamplona.amethyst.commons.util.getLanguagesSpokenByUser import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent import kotlinx.serialization.Serializable -import java.util.Locale val DefaultReactions = listOf( @@ -144,15 +143,6 @@ fun mergeWithDefaultVideoPlayerButtons(saved: List): List return if (missing.isEmpty()) saved else saved + missing } -fun getLanguagesSpokenByUser(): Set { - val languageList = ConfigurationCompat.getLocales(Resources.getSystem().getConfiguration()) - val codedList = mutableSetOf() - for (i in 0 until languageList.size()) { - languageList.get(i)?.let { codedList.add(it.language) } - } - return codedList -} - @Serializable class AccountSyncedSettingsInternal( val reactions: AccountReactionPreferencesInternal = AccountReactionPreferencesInternal(), @@ -214,7 +204,7 @@ class AccountZapPreferencesInternal( class AccountLanguagePreferencesInternal( var dontTranslateFrom: Set = getLanguagesSpokenByUser(), var languagePreferences: Map = mapOf(), - var translateTo: String = Locale.getDefault().language, + var translateTo: String = getDefaultLanguageCode(), ) @Serializable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountZapActions.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountZapActions.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountZapActions.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountZapActions.kt index cf994956f6..4a3adcd8eb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountZapActions.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountZapActions.kt @@ -18,20 +18,18 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model +package com.vitorpamplona.amethyst.commons.model +import com.vitorpamplona.amethyst.commons.model.Bolt12ZapFailure import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.nip47WalletConnect.NwcSignerState import com.vitorpamplona.amethyst.commons.onchain.OnchainZapSendError import com.vitorpamplona.amethyst.commons.onchain.OnchainZapSendResult import com.vitorpamplona.amethyst.commons.onchain.OnchainZapSendStage import com.vitorpamplona.amethyst.commons.onchain.OnchainZapSender import com.vitorpamplona.amethyst.commons.onchain.OnchainZapShare -import com.vitorpamplona.amethyst.commons.resources.Res -import com.vitorpamplona.amethyst.commons.resources.bolt12_zap_invalid_receipt -import com.vitorpamplona.amethyst.commons.resources.bolt12_zap_paid_no_receipt -import com.vitorpamplona.amethyst.model.nip47WalletConnect.NwcSignerState import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair @@ -52,10 +50,9 @@ import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent import com.vitorpamplona.quartz.nip57Zaps.ZapRequestEvent import com.vitorpamplona.quartz.nipB1Bolt12Zaps.builder.Bolt12ZapBuilder import com.vitorpamplona.quartz.nipB1Bolt12Zaps.verify.Bolt12ZapValidation +import com.vitorpamplona.quartz.utils.BigDecimal import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.launch -import org.jetbrains.compose.resources.StringResource -import java.math.BigDecimal import kotlin.coroutines.cancellation.CancellationException private const val ONCHAIN_BACKEND_NOT_CONFIGURED = "Bitcoin chain backend is not configured" @@ -187,7 +184,7 @@ class AccountZapActions( * validates — builds, self-consumes, and publishes the kind 9736 zap. Validation * is the fail-safe: a wallet that drops or misroutes the note yields a proof that * fails the binding check, so no invalid receipt is ever published (the payment - * still happened; [onError] reports "paid, no receipt"). [zappedEvent] is null for + * still happened; [onError] reports [Bolt12ZapFailure.InvalidReceipt]). [zappedEvent] is null for * a profile zap. Requires an NWC wallet (see [hasNwcWallet]); BOLT12 zaps have no * external-wallet or LNURL fallback because only NWC returns the proof. * @@ -206,8 +203,8 @@ class AccountZapActions( amountMillisats: Long, message: String, zapType: ZapReceiptEvent.ZapType, - // (messageResId, detail) — the caller localizes; detail carries a wallet error, if any. - onError: (StringResource, String?) -> Unit, + // Paid, but no receipt came of it; the caller words it. + onError: (Bolt12ZapFailure) -> Unit, // (code, detail) — the wallet refused or failed the payment; no funds moved. onNotPaid: suspend (NwcErrorCode?, String?) -> Unit, onTimeout: () -> Unit, @@ -253,27 +250,27 @@ class AccountZapActions( is PaySuccessResponse -> { val proof = response.result?.payer_proof if (proof.isNullOrBlank()) { - onError(Res.string.bolt12_zap_paid_no_receipt, null) + onError(Bolt12ZapFailure.PaidNoReceipt) } else { val zap = Bolt12ZapBuilder.buildZap(zapSigner, intent, proof, anonymous) if (account.cache.bolt12ZapValidator.validate(zap, verifyEventSignature = false) is Bolt12ZapValidation.Valid) { account.cache.justConsumeMyOwnEvent(zap) account.client.publish(zap, account.broadcaster.computeRelayListToBroadcast(zap)) } else { - onError(Res.string.bolt12_zap_invalid_receipt, null) + onError(Bolt12ZapFailure.InvalidReceipt) } } } is IErrorResponseLike -> onNotPaid(response.nwcErrorCode(), response.errorMessage()) - else -> onError(Res.string.bolt12_zap_paid_no_receipt, null) + else -> onError(Bolt12ZapFailure.PaidNoReceipt) } } catch (e: CancellationException) { throw e } catch (e: Exception) { Log.w("Account", "BOLT12 zap receipt assembly failed after payment", e) - onError(Res.string.bolt12_zap_paid_no_receipt, null) + onError(Bolt12ZapFailure.PaidNoReceipt) } finally { onProcessed() } diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/Bolt12ZapFailure.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/Bolt12ZapFailure.kt new file mode 100644 index 0000000000..cfd8a6f78d --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/Bolt12ZapFailure.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.model + +/** + * Why a BOLT12 zap that the wallet reports as paid produced no zap receipt. Either way the money + * moved, so neither case may be retried; the UI only words them differently. + */ +enum class Bolt12ZapFailure { + /** Paid, but the wallet returned no payer proof, or building/publishing the receipt failed. */ + PaidNoReceipt, + + /** Paid, but the receipt built from the wallet's payer proof did not validate. */ + InvalidReceipt, +} diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/ConcordLastRead.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/ConcordLastRead.kt index 3fffed0ce4..7794cd4029 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/ConcordLastRead.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/ConcordLastRead.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.commons.model /** * The per-account last-read route key for one Concord channel — the string - * [com.vitorpamplona.amethyst.model.Account.markAsRead]/`loadLastReadFlow` are keyed by. + * [com.vitorpamplona.amethyst.commons.model.Account.markAsRead]/`loadLastReadFlow` are keyed by. * Shared by the write side (the open channel marks messages read as they show) and the * read side (the hub's unread indicators) so the two can never drift apart. */ diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DecryptAndIndexProcessor.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/DecryptAndIndexProcessor.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DecryptAndIndexProcessor.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/DecryptAndIndexProcessor.kt index b9924db662..ccea35dc44 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DecryptAndIndexProcessor.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/DecryptAndIndexProcessor.kt @@ -18,16 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn +package com.vitorpamplona.amethyst.commons.model -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.chatMessageMarksRoomAsRead import com.vitorpamplona.amethyst.commons.model.privateChatLastReadRoute import com.vitorpamplona.amethyst.commons.model.privateChats.ChatroomList import com.vitorpamplona.amethyst.commons.nipACWebRtcCalls.CallManager -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent import com.vitorpamplona.quartz.marmot.GroupEventResult import com.vitorpamplona.quartz.marmot.MarmotInboundProcessor @@ -56,6 +55,7 @@ import com.vitorpamplona.quartz.nipC7Chats.ChatEvent import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex @@ -444,7 +444,7 @@ private suspend fun processMarmotWelcomeFlow( // Fire the "You've been added to " notification. Welcomes // have no `p` tag, so the cache-observer path can't route them; // this is the single point where we know the recipient account. - Amethyst.instance.notificationDispatcher.notifyWelcome(innerEvent, account) + account.marmotNotifier().notifyWelcome(innerEvent, account) } is WelcomeResult.AlreadyJoined -> { @@ -809,7 +809,7 @@ class GroupEventHandler( // reactions, deletions, and control messages stay // silent. if (innerEvent is ChatEvent) { - Amethyst.instance.notificationDispatcher.notifyGroupMessage( + account.marmotNotifier().notifyGroupMessage( innerEvent, result.groupId, account, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/EventBroadcaster.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/EventBroadcaster.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/EventBroadcaster.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/EventBroadcaster.kt index c5a8d6737c..571665cebb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/EventBroadcaster.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/EventBroadcaster.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model +package com.vitorpamplona.amethyst.commons.model import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/GeohashChatIdentityState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/GeohashChatIdentityState.kt similarity index 71% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/GeohashChatIdentityState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/GeohashChatIdentityState.kt index e45bc638b7..31b77ddc93 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/GeohashChatIdentityState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/GeohashChatIdentityState.kt @@ -18,28 +18,22 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model +package com.vitorpamplona.amethyst.commons.model -import androidx.core.content.edit -import com.vitorpamplona.amethyst.Amethyst -import com.vitorpamplona.amethyst.LegacySharedPreferences -import com.vitorpamplona.amethyst.LocalPreferences -import com.vitorpamplona.amethyst.accountSecretsStore import com.vitorpamplona.amethyst.commons.model.preferences.GeohashIdentitySecrets -import com.vitorpamplona.amethyst.commons.model.preferences.readLegacyGeohashIdentity import com.vitorpamplona.quartz.experimental.bitchat.identity.GeohashKeyDerivation import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal -import com.vitorpamplona.quartz.nip19Bech32.toNpub import com.vitorpamplona.quartz.utils.RandomInstance +import com.vitorpamplona.quartz.utils.concurrent.ConcurrentMap import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock -import java.util.concurrent.ConcurrentHashMap +import kotlin.concurrent.Volatile /** * The account's anonymous, per-geohash chat identities. @@ -64,6 +58,7 @@ import java.util.concurrent.ConcurrentHashMap class GeohashChatIdentityState( private val signer: NostrSigner, private val scope: CoroutineScope, + private val store: GeohashIdentityStore, ) { /** * Guards seed creation as well as the key cache: two callers racing into @@ -72,45 +67,25 @@ class GeohashChatIdentityState( * `synchronized`, because the store reads it protects are suspending. */ private val mutex = Mutex() - private val cache = ConcurrentHashMap() - - /** - * The npub the current store is keyed by. - * - * The legacy file is keyed by the pubkey *hex* — the old code passed - * `signer.pubKey` where every other caller passes an npub, so the identity - * lived in `secret_keeper_`, a different file from the account's own - * `secret_keeper_`. The copy below reads that file and writes the - * npub-keyed store, which is what folds this orphan back in with the rest. - */ - private val npub by lazy { signer.pubKey.hexToByteArray().toNpub() } + private val cache = ConcurrentMap() @Volatile private var loaded: GeohashIdentitySecrets? = null /** - * What `secret_keeper_` holds. - * - * Only called when the store has nothing yet: opening this file creates it, - * so reading it unconditionally would resurrect it after the cleanup has - * deleted it. Touches disk; callers are off the main thread. - */ - private fun legacy(): GeohashIdentitySecrets = readLegacyGeohashIdentity(LegacySharedPreferences(Amethyst.instance.encryptedStorage(signer.pubKey))) - - /** - * The stored identity, copying it out of the legacy file the first time. + * The stored identity, read once from [store]. * * **Call under [mutex].** Not self-locking, because [keyPair] already holds * the lock when it reaches here and [Mutex] is not reentrant. */ private suspend fun current(): GeohashIdentitySecrets { loaded?.let { return it } - return accountSecretsStore.readGeohashIdentity(npub) { legacy() }.also { loaded = it } + return store.read().also { loaded = it } } /** Call under [mutex], for the reason [current] gives. */ private suspend fun persist(value: GeohashIdentitySecrets) { loaded = value - accountSecretsStore.mirrorGeohashIdentity(npub, value) + store.write(value) } /** @@ -138,13 +113,7 @@ class GeohashChatIdentityState( // session would be unreproducible on the next launch. mutex.withLock { persist(current().copy(nickname = trimmed)) - // Mirrored, not moved: the legacy file stays readable until the - // legacy writes are retired app-wide, so a rollback keeps the handle. - // Gated on the same switch as every other mirror — otherwise flipping - // it would retire the documented four and leave this one writing. - if (!LocalPreferences.LEGACY_WRITES_RETIRED) { - Amethyst.instance.encryptedStorage(signer.pubKey).edit { putString(PREF_NICKNAME, trimmed) } - } + store.mirrorLegacyNickname(trimmed) } } } @@ -175,14 +144,7 @@ class GeohashChatIdentityState( val fresh = RandomInstance.bytes(GeohashKeyDerivation.SEED_SIZE) persist(current().copy(deviceSeed = fresh.toHexKey())) - if (!LocalPreferences.LEGACY_WRITES_RETIRED) { - Amethyst.instance.encryptedStorage(signer.pubKey).edit { putString(PREF_KEY, fresh.toHexKey()) } - } + store.mirrorLegacyDeviceSeed(fresh.toHexKey()) return fresh } - - companion object { - private const val PREF_KEY = "geohash_chat_device_seed" - private const val PREF_NICKNAME = "geohash_chat_nickname" - } } diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/GeohashIdentityStore.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/GeohashIdentityStore.kt new file mode 100644 index 0000000000..42b1ffc359 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/GeohashIdentityStore.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.model + +import com.vitorpamplona.amethyst.commons.model.preferences.GeohashIdentitySecrets +import kotlin.concurrent.Volatile + +/** + * Where one account's geohash-chat identity secrets (the device seed and the location-chat + * nickname) are kept. [GeohashChatIdentityState] does the locking and derivation; this only moves + * bytes. Reads and writes touch disk, so callers are off the main thread. + */ +interface GeohashIdentityStore { + /** The stored secrets. The first read may copy them in from an older location. */ + suspend fun read(): GeohashIdentitySecrets + + /** Replaces the stored secrets with [value]. */ + suspend fun write(value: GeohashIdentitySecrets) + + /** Also records a new nickname wherever older app versions look for it, if the platform still does. */ + fun mirrorLegacyNickname(nickname: String) = Unit + + /** Also records a new device seed wherever older app versions look for it, if the platform still does. */ + fun mirrorLegacyDeviceSeed(seedHex: String) = Unit +} + +/** Keeps the secrets in memory only (previews, tests). */ +class InMemoryGeohashIdentityStore : GeohashIdentityStore { + @Volatile private var value = GeohashIdentitySecrets() + + override suspend fun read() = value + + override suspend fun write(value: GeohashIdentitySecrets) { + this.value = value + } +} diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/NotificationLastRead.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/NotificationLastRead.kt new file mode 100644 index 0000000000..137fa298bc --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/NotificationLastRead.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.model + +const val NOTIFICATION_LAST_READ_KEY = "Notification" diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/ZapNotifications.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/ZapNotifications.kt new file mode 100644 index 0000000000..8e3d52d356 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/ZapNotifications.kt @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.model + +import androidx.compose.runtime.Immutable +import com.vitorpamplona.amethyst.commons.util.showAmount +import com.vitorpamplona.quartz.utils.BigDecimal +import com.vitorpamplona.quartz.utils.toDoubleValue + +@Immutable +data class ZapAmountCommentNotification( + val user: User?, + val comment: String?, + val amount: String?, + // The zap receipt (kind 9735) note, when available, so the chip can offer + // actions that target the zap itself (e.g. replying to it). + val zapNote: Note? = null, +) + +@Immutable +data class CombinedZap( + val request: Note, + val response: Note, +) { + fun createdAt() = response.createdAt() + + fun idHex() = response.idHex +} + +@Immutable data class ZapraiserStatus( + val progress: Float, + val left: String, +) + +/** + * How far [zapped] sats have come toward a [goal] of sats: the progress (capped at 1) and the + * amount left, formatted. A goal of zero is met by definition. + */ +fun zapraiserStatus( + zapped: BigDecimal, + goal: Long, +): ZapraiserStatus { + val percentage = if (goal > 0) (zapped.toDoubleValue() / goal).toFloat().coerceAtMost(1f) else 1f + val left = if (percentage > 0.99) "0" else showAmount(BigDecimal((goal * (1 - percentage)).toString())) + return ZapraiserStatus(percentage, left) +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/algoFeeds/FavoriteAlgoFeedsOrchestrator.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/algoFeeds/FavoriteAlgoFeedsOrchestrator.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/algoFeeds/FavoriteAlgoFeedsOrchestrator.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/algoFeeds/FavoriteAlgoFeedsOrchestrator.kt index e8aa1a078b..3201f15412 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/algoFeeds/FavoriteAlgoFeedsOrchestrator.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/algoFeeds/FavoriteAlgoFeedsOrchestrator.kt @@ -18,9 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.algoFeeds +package com.vitorpamplona.amethyst.commons.model.algoFeeds -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter @@ -31,6 +31,7 @@ import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/bolt12Offers/Bolt12OfferListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/bolt12Offers/Bolt12OfferListState.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/bolt12Offers/Bolt12OfferListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/bolt12Offers/Bolt12OfferListState.kt index 3cff972cc8..00b72132b3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/bolt12Offers/Bolt12OfferListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/bolt12Offers/Bolt12OfferListState.kt @@ -18,17 +18,18 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.bolt12Offers +package com.vitorpamplona.amethyst.commons.model.bolt12Offers +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nipB1Bolt12Zaps.offer.Bolt12OfferListEvent import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn @@ -38,7 +39,7 @@ import kotlinx.coroutines.launch /** * The logged-in user's NIP-B1 BOLT12 offer list (kind 10058) as live account state, - * mirroring [com.vitorpamplona.amethyst.model.nipA3PaymentTargets.NipA3PaymentTargetsState]. + * mirroring [com.vitorpamplona.amethyst.commons.model.nipA3PaymentTargets.NipA3PaymentTargetsState]. * Exposes the current offers as a [flow], persists them across restarts (via * [AccountSettings]), and publishes updates with [saveOffers]. */ diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/buzz/BuzzMembershipKinds.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/buzz/BuzzMembershipKinds.kt new file mode 100644 index 0000000000..c0e62223da --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/buzz/BuzzMembershipKinds.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.model.buzz + +import com.vitorpamplona.quartz.buzz.notifications.MemberAddedNotificationEvent +import com.vitorpamplona.quartz.buzz.notifications.MemberRemovedNotificationEvent + +/** The relay's membership verdicts addressed to me: 44100 "you were added", 44101 "you were removed". */ +val MembershipNotificationKinds = + listOf( + MemberAddedNotificationEvent.KIND, + MemberRemovedNotificationEvent.KIND, + ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/buzz/BuzzMembershipNotices.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/buzz/BuzzMembershipNotices.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/buzz/BuzzMembershipNotices.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/buzz/BuzzMembershipNotices.kt index 6665b1de53..25824a7b2a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/buzz/BuzzMembershipNotices.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/buzz/BuzzMembershipNotices.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.buzz +package com.vitorpamplona.amethyst.commons.model.buzz import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.buzz.ChannelClassification import com.vitorpamplona.amethyst.commons.model.buzz.MembershipNotice +import com.vitorpamplona.amethyst.commons.model.buzz.MembershipNotificationKinds import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.buzz.MembershipNotificationKinds import com.vitorpamplona.quartz.buzz.notifications.MemberAddedNotificationEvent import com.vitorpamplona.quartz.buzz.notifications.MemberRemovedNotificationEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/buzz/ChannelInvitesState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/buzz/ChannelInvitesState.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/buzz/ChannelInvitesState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/buzz/ChannelInvitesState.kt index c3ef6ae3dc..6aeca87879 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/buzz/ChannelInvitesState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/buzz/ChannelInvitesState.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.buzz +package com.vitorpamplona.amethyst.commons.model.buzz import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.commons.model.buzz.BuzzChannelInvite @@ -31,6 +31,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip29RelayGroups.metadata.GroupMetadataEvent import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine @@ -49,7 +50,7 @@ import kotlinx.coroutines.flow.stateIn * * ### Account state, not screen state * - * This hangs off [com.vitorpamplona.amethyst.model.Account] rather than a feed holder because the + * This hangs off [com.vitorpamplona.amethyst.commons.model.Account] rather than a feed holder because the * notifications DAL reads it: `NotificationFeedFilter.acceptableEvent` consults [pendingByEventId] to * decide whether a cached kind-44100 is still a live question, and `convertToCard` uses the same map to * build the row. A projection only the UI could reach would have forced the DAL to re-derive it. diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/cache/LocalCacheHost.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/cache/LocalCacheHost.kt index 12d33d9fe5..e004e23b69 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/cache/LocalCacheHost.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/cache/LocalCacheHost.kt @@ -20,9 +20,12 @@ */ package com.vitorpamplona.amethyst.commons.model.cache +import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.Nip11CachedRetriever +import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.Nip11Fetcher import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStats import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl +import com.vitorpamplona.quartz.nip11RelayInfo.Nip11RelayInformation import com.vitorpamplona.quartz.nip57Zaps.validate.LnurlEndpointInfo import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -63,6 +66,12 @@ interface LocalCacheHost { */ val nip95Blobs: Nip95BlobStore? + /** + * Relays' NIP-11 documents, shared by the cache (relay `self` keys) and the screens that show + * relay details. The default fetches nothing. + */ + val nip11Cache: Nip11CachedRetriever get() = OfflineNip11Cache + /** Per-relay counters the anti-spam filter reports duplicate events to. */ val relayStats: RelayStats? @@ -72,6 +81,13 @@ interface LocalCacheHost { */ fun relaySelfPubKey(relay: NormalizedRelayUrl): HexKey? = null + /** + * The relay's NIP-11 document as far as the shell has it in memory. Never fetches: `null` + * (or a document with nothing in it) means "not loaded yet", which callers must treat as + * unknown rather than as "unsupported". + */ + fun relayInfo(relay: NormalizedRelayUrl): Nip11RelayInformation? = null + /** * LNURL-pay endpoint metadata the shell has already resolved for [lnurlpUrl], used to * validate a zap receipt's signer against the provider's `nostrPubkey` (NIP-57 Appendix F). @@ -96,3 +112,5 @@ interface LocalCacheHost { override val relayStats: RelayStats? = null } } + +private val OfflineNip11Cache = Nip11CachedRetriever(Nip11Fetcher.Offline) diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/cache/Nip95BlobStore.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/cache/Nip95BlobStore.kt index e35c28513f..5fdad26f7a 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/cache/Nip95BlobStore.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/cache/Nip95BlobStore.kt @@ -38,6 +38,9 @@ interface Nip95BlobStore { /** Whether a blob is already stored under [id]. */ fun exists(id: String): Boolean + /** Where the blob for [id] lives (or would), for a media player or image loader to read. */ + fun path(id: String): Path + /** Stores [bytes] under [id]. Returns false when the write failed. */ fun store( id: String, @@ -60,6 +63,8 @@ class FileSystemNip95BlobStore( override fun exists(id: String): Boolean = fileSystem.exists(directory / id) + override fun path(id: String): Path = directory / id + override fun store( id: String, bytes: ByteArray, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/cordn/CordnRuntime.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/cordn/CordnRuntime.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/cordn/CordnRuntime.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/cordn/CordnRuntime.kt index 934a3f383a..e8fce64797 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/cordn/CordnRuntime.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/cordn/CordnRuntime.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.cordn +package com.vitorpamplona.amethyst.commons.model.cordn import com.vitorpamplona.amethyst.commons.cordn.CoordinatorConfig import com.vitorpamplona.amethyst.commons.cordn.CoordinatorHealth @@ -43,9 +43,10 @@ import com.vitorpamplona.amethyst.commons.cordn.FileCordnCoordinatorStore import com.vitorpamplona.amethyst.commons.cordn.FileCordnGroupStore import com.vitorpamplona.amethyst.commons.cordn.FileCordnHandoffStore import com.vitorpamplona.amethyst.commons.cordn.FileCordnKeyPackageStore -import com.vitorpamplona.amethyst.commons.cordn.KeyStoreCordnBlobCipher import com.vitorpamplona.amethyst.commons.cordn.OpenedWelcome import com.vitorpamplona.amethyst.commons.model.cordnGroups.CordnGroupList +import com.vitorpamplona.amethyst.commons.util.deleteRecursivelyQuietly +import com.vitorpamplona.amethyst.commons.util.platformFileSystem import com.vitorpamplona.quartz.contextvm.core.CvmKinds import com.vitorpamplona.quartz.cordn.appMultiDevice.CordnHandoffCode import com.vitorpamplona.quartz.cordn.spec00Coordinator.CoordinatorServerInfo @@ -63,6 +64,7 @@ import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.distinctUntilChanged @@ -71,7 +73,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext -import java.io.File +import okio.Path import kotlin.coroutines.cancellation.CancellationException import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid @@ -98,9 +100,9 @@ import kotlin.uuid.Uuid class CordnRuntime( private val accountSigner: NostrSigner, private val client: INostrClient, - private val filesDir: File, + private val filesDir: Path, private val scope: CoroutineScope, - private val cipher: CordnBlobCipher = KeyStoreCordnBlobCipher(), + private val cipher: CordnBlobCipher, /** * How a coordinator connection is opened. The default is the real one. * @@ -696,7 +698,7 @@ class CordnRuntime( forget(coordinatorPubKey) groups.forgetCoordinator(coordinatorPubKey) withContext(Dispatchers.IO) { - CordnStorageLayout.directoryFor(filesDir, accountSigner.pubKey, coordinatorPubKey).deleteRecursively() + platformFileSystem.deleteRecursivelyQuietly(CordnStorageLayout.directoryFor(filesDir, accountSigner.pubKey, coordinatorPubKey)) } } @@ -841,7 +843,7 @@ class CordnRuntime( // The old state goes first. Leaving it would merge two devices' // histories for any gid present in both, which is the one outcome // this must never produce. - File(filesDir, "cordn/${accountSigner.pubKey}").deleteRecursively() + platformFileSystem.deleteRecursivelyQuietly(filesDir / "cordn" / accountSigner.pubKey) archive.groups.forEach { group -> val store = FileCordnGroupStore(CordnStorageLayout.directoryFor(filesDir, accountSigner.pubKey, group.coordinatorPubKey), cipher) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/edits/PrivateStorageRelayListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/edits/PrivateStorageRelayListState.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/edits/PrivateStorageRelayListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/edits/PrivateStorageRelayListState.kt index 531afe8cef..85af03ccb6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/edits/PrivateStorageRelayListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/edits/PrivateStorageRelayListState.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.edits +package com.vitorpamplona.amethyst.commons.model.edits +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.edits.PrivateStorageRelayListDecryptionCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip37Drafts.privateOutbox.PrivateOutboxRelayListEvent @@ -32,6 +32,7 @@ import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/localRelays/ForwardKind0ToLocalRelayState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/localRelays/ForwardKind0ToLocalRelayState.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/localRelays/ForwardKind0ToLocalRelayState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/localRelays/ForwardKind0ToLocalRelayState.kt index 3fc1e0bdf6..84895c30f1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/localRelays/ForwardKind0ToLocalRelayState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/localRelays/ForwardKind0ToLocalRelayState.kt @@ -18,9 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.localRelays +package com.vitorpamplona.amethyst.commons.model.localRelays -import com.vitorpamplona.amethyst.model.AccountSettings +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.EventCollector diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/localRelays/LocalRelayListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/localRelays/LocalRelayListState.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/localRelays/LocalRelayListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/localRelays/LocalRelayListState.kt index 920e15ae5f..25f4b609e8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/localRelays/LocalRelayListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/localRelays/LocalRelayListState.kt @@ -18,15 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.localRelays +package com.vitorpamplona.amethyst.commons.model.localRelays +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/location/LocationResult.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/location/LocationResult.kt new file mode 100644 index 0000000000..d6332c86c3 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/location/LocationResult.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.model.location + +import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeoHash + +/** + * Where the device is, as far as location-scoped feeds (Around Me, geohash chats) need to know: a + * geohash once a fix arrives, a missing permission, or still waiting. Each platform's location + * service produces these; the account and its feeds only read them. + */ +sealed class LocationResult { + data class Success( + val geoHash: GeoHash, + ) : LocationResult() + + object LackPermission : LocationResult() + + object Loading : LocationResult() +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/marmot/KeyPackageRelayListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/marmot/KeyPackageRelayListState.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/marmot/KeyPackageRelayListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/marmot/KeyPackageRelayListState.kt index d472599499..64535e286c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/marmot/KeyPackageRelayListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/marmot/KeyPackageRelayListState.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.marmot +package com.vitorpamplona.amethyst.commons.model.marmot +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageRelayListEvent import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner @@ -31,6 +31,7 @@ import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/marmot/MarmotGroupNotifier.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/marmot/MarmotGroupNotifier.kt new file mode 100644 index 0000000000..d6fd91b773 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/marmot/MarmotGroupNotifier.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.model.marmot + +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.quartz.marmot.mip02Welcome.WelcomeEvent +import com.vitorpamplona.quartz.nipC7Chats.ChatEvent + +/** + * Where the account's Marmot processing reports what the user should hear about. A Welcome has no + * `p` tag and a group message arrives inside a gift wrap, so the cache-observer notification path + * never sees either; the decrypting side calls this instead. The app shows system notifications; a + * host without them passes [None]. + */ +interface MarmotGroupNotifier { + /** "You've been added to ": [event] was just accepted for [account]. */ + suspend fun notifyWelcome( + event: WelcomeEvent, + account: Account, + ) + + /** A new chat message, [innerEvent], arrived in the Marmot group [nostrGroupId] for [account]. */ + suspend fun notifyGroupMessage( + innerEvent: ChatEvent, + nostrGroupId: String, + account: Account, + ) + + /** Notifies nothing (previews, tests). */ + object None : MarmotGroupNotifier { + override suspend fun notifyWelcome( + event: WelcomeEvent, + account: Account, + ) = Unit + + override suspend fun notifyGroupMessage( + innerEvent: ChatEvent, + nostrGroupId: String, + account: Account, + ) = Unit + } +} diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/navigation/BottomBarEntry.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/navigation/BottomBarEntry.kt index d5ae335101..e3533ba2ae 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/navigation/BottomBarEntry.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/navigation/BottomBarEntry.kt @@ -26,7 +26,7 @@ import kotlinx.serialization.Serializable /** * One slot in the bottom navigation bar. A single ordered list of these (persisted per-account in * the NIP-78 app-specific data event via - * [com.vitorpamplona.amethyst.model.AccountNavigationPreferencesInternal.bottomBarItems]) holds + * [com.vitorpamplona.amethyst.commons.model.AccountNavigationPreferencesInternal.bottomBarItems]) holds * built-in destinations, favorite apps, and individual joined chats/groups, so the user can pin and * drag-reorder them together in one list. * diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/navigation/DefaultBottomBar.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/navigation/DefaultBottomBar.kt new file mode 100644 index 0000000000..8d610cc5b7 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/navigation/DefaultBottomBar.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.model.navigation + +/** The destinations a fresh account's bottom bar shows, in order. */ +val DefaultBottomBarItems: List = + listOf( + NavBarItem.HOME, + NavBarItem.MESSAGES, + NavBarItem.WALLET, + NavBarItem.BROWSER, + NavBarItem.NOTIFICATIONS, + ) + +/** The default bottom bar as unified entries (all built-in; favorites are added by the user). */ +val DefaultBottomBarEntries: List = DefaultBottomBarItems.map { BottomBarEntry.BuiltIn(it) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/AccountHomeRelayState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip01UserMetadata/AccountHomeRelayState.kt similarity index 85% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/AccountHomeRelayState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip01UserMetadata/AccountHomeRelayState.kt index 47d1c0c33a..c5c25252a9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/AccountHomeRelayState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip01UserMetadata/AccountHomeRelayState.kt @@ -18,13 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip01UserMetadata +package com.vitorpamplona.amethyst.commons.model.nip01UserMetadata -import com.vitorpamplona.amethyst.model.edits.PrivateStorageRelayListState -import com.vitorpamplona.amethyst.model.localRelays.LocalRelayListState -import com.vitorpamplona.amethyst.model.nip65RelayList.Nip65RelayListState +import com.vitorpamplona.amethyst.commons.model.edits.PrivateStorageRelayListState +import com.vitorpamplona.amethyst.commons.model.localRelays.LocalRelayListState +import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/AccountMineRelayState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip01UserMetadata/AccountMineRelayState.kt similarity index 85% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/AccountMineRelayState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip01UserMetadata/AccountMineRelayState.kt index 7205249d3b..1d48ee513c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/AccountMineRelayState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip01UserMetadata/AccountMineRelayState.kt @@ -18,14 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip01UserMetadata +package com.vitorpamplona.amethyst.commons.model.nip01UserMetadata -import com.vitorpamplona.amethyst.model.edits.PrivateStorageRelayListState -import com.vitorpamplona.amethyst.model.localRelays.LocalRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.proxyRelays.ProxyRelayListState -import com.vitorpamplona.amethyst.model.nip65RelayList.Nip65RelayListState +import com.vitorpamplona.amethyst.commons.model.edits.PrivateStorageRelayListState +import com.vitorpamplona.amethyst.commons.model.localRelays.LocalRelayListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.proxyRelays.ProxyRelayListState +import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/AccountOutboxRelayState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip01UserMetadata/AccountOutboxRelayState.kt similarity index 83% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/AccountOutboxRelayState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip01UserMetadata/AccountOutboxRelayState.kt index d0f30f87c9..e564e69580 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/AccountOutboxRelayState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip01UserMetadata/AccountOutboxRelayState.kt @@ -18,14 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip01UserMetadata +package com.vitorpamplona.amethyst.commons.model.nip01UserMetadata -import com.vitorpamplona.amethyst.model.edits.PrivateStorageRelayListState -import com.vitorpamplona.amethyst.model.localRelays.LocalRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.broadcastRelays.BroadcastRelayListState -import com.vitorpamplona.amethyst.model.nip65RelayList.Nip65RelayListState +import com.vitorpamplona.amethyst.commons.model.edits.PrivateStorageRelayListState +import com.vitorpamplona.amethyst.commons.model.localRelays.LocalRelayListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.broadcastRelays.BroadcastRelayListState +import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/NotificationInboxRelayState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip01UserMetadata/NotificationInboxRelayState.kt similarity index 87% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/NotificationInboxRelayState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip01UserMetadata/NotificationInboxRelayState.kt index 1878e54fe5..9c228a663a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/NotificationInboxRelayState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip01UserMetadata/NotificationInboxRelayState.kt @@ -18,12 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip01UserMetadata +package com.vitorpamplona.amethyst.commons.model.nip01UserMetadata -import com.vitorpamplona.amethyst.model.localRelays.LocalRelayListState -import com.vitorpamplona.amethyst.model.nip65RelayList.Nip65RelayListState +import com.vitorpamplona.amethyst.commons.model.localRelays.LocalRelayListState +import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/UserMetadataState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip01UserMetadata/UserMetadataState.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/UserMetadataState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip01UserMetadata/UserMetadataState.kt index 4c4d211e5b..696055bf81 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/UserMetadataState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip01UserMetadata/UserMetadataState.kt @@ -18,10 +18,10 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip01UserMetadata +package com.vitorpamplona.amethyst.commons.model.nip01UserMetadata +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip39ExtIdentities.ExternalIdentitiesEvent @@ -29,6 +29,7 @@ import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.launch class UserMetadataState( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/DeclaredFollowsPerOutboxRelay.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/DeclaredFollowsPerOutboxRelay.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/DeclaredFollowsPerOutboxRelay.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/DeclaredFollowsPerOutboxRelay.kt index 14b9e9385b..accdd28de9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/DeclaredFollowsPerOutboxRelay.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/DeclaredFollowsPerOutboxRelay.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip02FollowLists +package com.vitorpamplona.amethyst.commons.model.nip02FollowLists import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.topNavFeeds.OutboxRelayLoader @@ -27,6 +27,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.distinctUntilChanged diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/DeclaredFollowsPerUsingRelay.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/DeclaredFollowsPerUsingRelay.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/DeclaredFollowsPerUsingRelay.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/DeclaredFollowsPerUsingRelay.kt index a13d61a8ba..e489f3484c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/DeclaredFollowsPerUsingRelay.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/DeclaredFollowsPerUsingRelay.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip02FollowLists +package com.vitorpamplona.amethyst.commons.model.nip02FollowLists import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.topNavFeeds.UsingRelayUnwrapper @@ -27,6 +27,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.distinctUntilChanged diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/FollowListOutboxOrProxyRelays.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/FollowListOutboxOrProxyRelays.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/FollowListOutboxOrProxyRelays.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/FollowListOutboxOrProxyRelays.kt index 4ee9ddb634..591162afee 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/FollowListOutboxOrProxyRelays.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/FollowListOutboxOrProxyRelays.kt @@ -18,16 +18,17 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip02FollowLists +package com.vitorpamplona.amethyst.commons.model.nip02FollowLists import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.nip51Lists.blockedRelays.BlockedRelayListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.proxyRelays.ProxyRelayListState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.OutboxRelayLoader -import com.vitorpamplona.amethyst.model.nip51Lists.blockedRelays.BlockedRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.proxyRelays.ProxyRelayListState import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/FollowListReusedOutboxOrProxyRelays.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/FollowListReusedOutboxOrProxyRelays.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/FollowListReusedOutboxOrProxyRelays.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/FollowListReusedOutboxOrProxyRelays.kt index da14281d14..914873689e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/FollowListReusedOutboxOrProxyRelays.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/FollowListReusedOutboxOrProxyRelays.kt @@ -18,16 +18,17 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip02FollowLists +package com.vitorpamplona.amethyst.commons.model.nip02FollowLists import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.nip51Lists.blockedRelays.BlockedRelayListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.proxyRelays.ProxyRelayListState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.OutboxRelayLoader -import com.vitorpamplona.amethyst.model.nip51Lists.blockedRelays.BlockedRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.proxyRelays.ProxyRelayListState import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/FollowsPerOutboxRelay.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/FollowsPerOutboxRelay.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/FollowsPerOutboxRelay.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/FollowsPerOutboxRelay.kt index 056d0c63ae..18ccec2d31 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/FollowsPerOutboxRelay.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/FollowsPerOutboxRelay.kt @@ -18,17 +18,18 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip02FollowLists +package com.vitorpamplona.amethyst.commons.model.nip02FollowLists import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.nip51Lists.blockedRelays.BlockedRelayListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.proxyRelays.ProxyRelayListState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.OutboxRelayLoader -import com.vitorpamplona.amethyst.model.nip51Lists.blockedRelays.BlockedRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.proxyRelays.ProxyRelayListState import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/Kind3FollowListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/Kind3FollowListState.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/Kind3FollowListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/Kind3FollowListState.kt index b3dc8afdc3..f89106b32a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/Kind3FollowListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip02FollowLists/Kind3FollowListState.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip02FollowLists +package com.vitorpamplona.amethyst.commons.model.nip02FollowLists import androidx.compose.runtime.Immutable +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent @@ -34,6 +34,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/OtsState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip03Timestamp/OtsState.kt similarity index 86% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/OtsState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip03Timestamp/OtsState.kt index d606671d44..0cde2dcd15 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/OtsState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip03Timestamp/OtsState.kt @@ -18,11 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip03Timestamp +package com.vitorpamplona.amethyst.commons.model.nip03Timestamp +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip03Timestamp.OtsEvent @@ -32,7 +32,7 @@ import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import java.util.Base64 +import kotlin.io.encoding.Base64 class OtsState( val signer: NostrSigner, @@ -58,7 +58,7 @@ class OtsState( Log.d("Pending Attestations") { "Updating ${settings.pendingAttestations.value.size} pending attestations" } return settings.pendingAttestations.value.toList().mapNotNull { (key, value) -> - val otsState = OtsEvent.upgrade(Base64.getDecoder().decode(value), key, otsResolver()) + val otsState = OtsEvent.upgrade(lenientBase64.decode(value), key, otsResolver()) if (otsState != null) { val hint = cache.getNoteIfExists(key)?.toEventHint() @@ -93,7 +93,7 @@ class OtsState( settings.addPendingAttestation( id = id, stamp = - Base64.getEncoder().encodeToString( + Base64.encode( OtsEvent.stamp( id, otsResolver(), @@ -102,3 +102,9 @@ class OtsState( ) } } + +/** + * Decodes with or without padding, as `java.util.Base64.getDecoder()` did before this moved to + * commonMain; kotlin's `Base64.Default` requires it. Encoding still pads. + */ +private val lenientBase64 = Base64.Default.withPadding(Base64.PaddingOption.PRESENT_OPTIONAL) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip17Dms/DmInboxRelayState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip17Dms/DmInboxRelayState.kt similarity index 87% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip17Dms/DmInboxRelayState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip17Dms/DmInboxRelayState.kt index 9478c71b78..450b947aa2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip17Dms/DmInboxRelayState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip17Dms/DmInboxRelayState.kt @@ -18,13 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip17Dms +package com.vitorpamplona.amethyst.commons.model.nip17Dms -import com.vitorpamplona.amethyst.model.edits.PrivateStorageRelayListState -import com.vitorpamplona.amethyst.model.localRelays.LocalRelayListState -import com.vitorpamplona.amethyst.model.nip65RelayList.Nip65RelayListState +import com.vitorpamplona.amethyst.commons.model.edits.PrivateStorageRelayListState +import com.vitorpamplona.amethyst.commons.model.localRelays.LocalRelayListState +import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip17Dms/DmRelayListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip17Dms/DmRelayListState.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip17Dms/DmRelayListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip17Dms/DmRelayListState.kt index 1f97c26b2f..6bbcb0ab90 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip17Dms/DmRelayListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip17Dms/DmRelayListState.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip17Dms +package com.vitorpamplona.amethyst.commons.model.nip17Dms +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip17Dm.settings.DmRelayListEvent @@ -31,6 +31,7 @@ import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip30CustomEmojis/OwnedEmojiPacksState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip30CustomEmojis/OwnedEmojiPacksState.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip30CustomEmojis/OwnedEmojiPacksState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip30CustomEmojis/OwnedEmojiPacksState.kt index b9af0de585..79f8d3ea2b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip30CustomEmojis/OwnedEmojiPacksState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip30CustomEmojis/OwnedEmojiPacksState.kt @@ -18,8 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip30CustomEmojis +package com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.anyNotNullEvent @@ -29,7 +30,6 @@ import com.vitorpamplona.amethyst.commons.model.eventIdSet import com.vitorpamplona.amethyst.commons.model.events import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.OwnedEmojiPack import com.vitorpamplona.amethyst.commons.model.updateFlow -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.update @@ -49,6 +49,7 @@ import com.vitorpamplona.quartz.nip51Lists.tags.TitleTag import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip46Signer/Nip46ConsentPrompter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip46Signer/Nip46ConsentPrompter.kt new file mode 100644 index 0000000000..3c4567ee15 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip46Signer/Nip46ConsentPrompter.kt @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.model.nip46Signer + +import com.vitorpamplona.amethyst.commons.connectedApps.signers.AppConnectResult +import com.vitorpamplona.amethyst.commons.connectedApps.signers.NostrSignerOp +import com.vitorpamplona.amethyst.commons.connectedApps.signers.SignerOpGrant +import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequest +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestConnect + +/** + * Asks the user whether a NIP-46 client may connect or perform an operation. [Nip46SignerState] + * calls it whenever the permission ledger says ASK; each platform shows its own dialog. Every + * method suspends until the user answers, and must fail closed ([AppConnectResult.Cancelled], + * [SignerOpGrant.DenyOnce]) if they never do. + */ +interface Nip46ConsentPrompter { + /** First connect over `bunker://`: the client's self-declared identity, and a trust level to pick. */ + suspend fun requestConnect( + coordinate: String, + clientPubKey: HexKey, + request: BunkerRequestConnect, + ): AppConnectResult + + /** First connect over `nostrconnect://`: like [requestConnect], showing the [requestedOps] it pre-grants. */ + suspend fun requestNostrConnectConsent( + coordinate: String, + name: String?, + url: String?, + image: String?, + requestedOps: List, + ): AppConnectResult + + /** One operation. [signer] is the account's own, so a decrypt can be previewed locally before the user decides. */ + suspend fun requestOp( + coordinate: String, + clientPubKey: HexKey, + op: NostrSignerOp, + request: BunkerRequest, + signer: NostrSigner, + ): SignerOpGrant + + /** Declines everything, as an unanswered prompt does (previews, tests). */ + object Unanswered : Nip46ConsentPrompter { + override suspend fun requestConnect( + coordinate: String, + clientPubKey: HexKey, + request: BunkerRequestConnect, + ): AppConnectResult = AppConnectResult.Cancelled + + override suspend fun requestNostrConnectConsent( + coordinate: String, + name: String?, + url: String?, + image: String?, + requestedOps: List, + ): AppConnectResult = AppConnectResult.Cancelled + + override suspend fun requestOp( + coordinate: String, + clientPubKey: HexKey, + op: NostrSignerOp, + request: BunkerRequest, + signer: NostrSigner, + ): SignerOpGrant = SignerOpGrant.DenyOnce + } +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip46Signer/Nip46SignerState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip46Signer/Nip46SignerState.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip46Signer/Nip46SignerState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip46Signer/Nip46SignerState.kt index c59faae4f6..a7b2f91915 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip46Signer/Nip46SignerState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip46Signer/Nip46SignerState.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip46Signer +package com.vitorpamplona.amethyst.commons.model.nip46Signer import com.vitorpamplona.amethyst.commons.connectedApps.nip46.Nip46ClientInfo import com.vitorpamplona.amethyst.commons.connectedApps.nip46.Nip46ClientStore @@ -27,9 +27,9 @@ import com.vitorpamplona.amethyst.commons.connectedApps.signers.AppConnectResult import com.vitorpamplona.amethyst.commons.connectedApps.signers.AppSignerPolicy import com.vitorpamplona.amethyst.commons.connectedApps.signers.NostrOpDecision import com.vitorpamplona.amethyst.commons.connectedApps.signers.NostrSignerPermissionLedger +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.nip46Signer.Nip46ActivityEntry import com.vitorpamplona.amethyst.commons.model.nip46Signer.Nip46ActivityLog -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.core.toHexKey @@ -52,6 +52,7 @@ import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -100,6 +101,8 @@ class Nip46SignerState( val inboxRelays: StateFlow>, val scope: CoroutineScope, val settings: AccountSettings, + /** Asks the user when the ledger says ASK (the app's signer dialogs). */ + val consent: Nip46ConsentPrompter, ) { /** Relays contributed by pasted `nostrconnect://` offers this session, unioned with the inbox set. */ private val extraRelays = MutableStateFlow>(emptySet()) @@ -171,12 +174,12 @@ class Nip46SignerState( // Interactive consent through the shared signer dialogs: a trust-level picker on first // connect, and an allow/deny prompt whenever the ledger says ASK (dangerous kinds, // decryption, DMs, or a PARANOID app). Same surface + ledger as napplet/browser signing. - connectConsent = Nip46ConsentBridge::requestConnect, + connectConsent = consent::requestConnect, // The account's own signer goes to the bridge so a decrypt request can be decrypted // BEFORE the prompt — the dialog shows the actual plaintext instead of an opaque // "wants to read your private messages". Local only; nothing is disclosed until approval. opConsent = { coordinate, clientPubKey, op, request -> - Nip46ConsentBridge.requestOp(coordinate, clientPubKey, op, request, signer) + consent.requestOp(coordinate, clientPubKey, op, request, signer) }, ) @@ -340,7 +343,7 @@ class Nip46SignerState( // per-op decisions the user may have since changed (e.g. an op set to DENY), so it skips the prompt. val grantedPolicy: AppSignerPolicy? = if (firstContact) { - when (val result = Nip46ConsentBridge.requestNostrConnectConsent(coordinate, offer.name, offer.url, offer.image, requestedOps)) { + when (val result = consent.requestNostrConnectConsent(coordinate, offer.name, offer.url, offer.image, requestedOps)) { is AppConnectResult.Connected -> result.policy AppConnectResult.Blocked, AppConnectResult.Cancelled -> return ConnectResult.Declined } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip47WalletConnect/NwcSignerState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip47WalletConnect/NwcSignerState.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip47WalletConnect/NwcSignerState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip47WalletConnect/NwcSignerState.kt index 1c576e1a4f..5e6b49d842 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip47WalletConnect/NwcSignerState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip47WalletConnect/NwcSignerState.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip47WalletConnect +package com.vitorpamplona.amethyst.commons.model.nip47WalletConnect +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.INwcSignerState import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip47WalletConnect.NwcInfoCache import com.vitorpamplona.amethyst.commons.relayClient.nip47WalletConnect.NWCPaymentFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.nip47WalletConnect.NWCPaymentQueryState -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair @@ -50,6 +50,7 @@ import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow @@ -79,7 +80,7 @@ class NwcSignerState( val settings: AccountSettings, /** * Shared cache of wallets' kind 13194 info events, used here to negotiate - * encryption. Injected by [com.vitorpamplona.amethyst.model.Account] (which + * encryption. Injected by [com.vitorpamplona.amethyst.commons.model.Account] (which * owns the relay client). Null in tests / when unavailable — requests then * fall back to NIP-04. */ diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/HiddenUsersState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/HiddenUsersState.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/HiddenUsersState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/HiddenUsersState.kt index a2946aec11..7f50f68545 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/HiddenUsersState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/HiddenUsersState.kt @@ -18,11 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists +package com.vitorpamplona.amethyst.commons.model.nip51Lists +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.LiveHiddenUsers -import com.vitorpamplona.amethyst.model.AccountSettings -import com.vitorpamplona.amethyst.service.checkNotInMainThread +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip51Lists.muteList.tags.EventTag import com.vitorpamplona.quartz.nip51Lists.muteList.tags.HashtagTag @@ -32,6 +32,7 @@ import com.vitorpamplona.quartz.nip51Lists.muteList.tags.WordTag import com.vitorpamplona.quartz.utils.DualCase import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -83,7 +84,7 @@ class HiddenUsersState( settings.syncedSettings.security.showSensitiveContent, settings.syncedSettings.security.maxHashtagLimit, ) { blockList, muteList, transientHiddenUsers, showSensitiveContent, maxHashtagLimit -> - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() emit(assembleLiveHiddenUsers(blockList, muteList, transientHiddenUsers, showSensitiveContent, maxHashtagLimit)) }.onStart { emit( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/blockedRelays/BlockedRelayListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/blockedRelays/BlockedRelayListState.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/blockedRelays/BlockedRelayListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/blockedRelays/BlockedRelayListState.kt index 544f7131e6..1d4b80e3f1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/blockedRelays/BlockedRelayListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/blockedRelays/BlockedRelayListState.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists.blockedRelays +package com.vitorpamplona.amethyst.commons.model.nip51Lists.blockedRelays +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip51Lists.blockedRelays.BlockedRelayListDecryptionCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions @@ -33,6 +33,7 @@ import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/bookmarkSets/BookmarkSetsState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/bookmarkSets/BookmarkSetsState.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/bookmarkSets/BookmarkSetsState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/bookmarkSets/BookmarkSetsState.kt index 305f9c26e0..b5f44e3765 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/bookmarkSets/BookmarkSetsState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/bookmarkSets/BookmarkSetsState.kt @@ -18,8 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists.bookmarkSets +package com.vitorpamplona.amethyst.commons.model.nip51Lists.bookmarkSets +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.anyNotNullEvent @@ -29,7 +30,6 @@ import com.vitorpamplona.amethyst.commons.model.eventIdSet import com.vitorpamplona.amethyst.commons.model.events import com.vitorpamplona.amethyst.commons.model.nip51Lists.bookmarkSets.BookmarkSet import com.vitorpamplona.amethyst.commons.model.updateFlow -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.update @@ -44,6 +44,7 @@ import com.vitorpamplona.quartz.nip51Lists.bookmarkSet.title import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/broadcastRelays/BroadcastRelayListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/broadcastRelays/BroadcastRelayListState.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/broadcastRelays/BroadcastRelayListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/broadcastRelays/BroadcastRelayListState.kt index 96d71f0c30..2346b4c4bb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/broadcastRelays/BroadcastRelayListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/broadcastRelays/BroadcastRelayListState.kt @@ -18,18 +18,19 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists.broadcastRelays +package com.vitorpamplona.amethyst.commons.model.nip51Lists.broadcastRelays +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip51Lists.broadcastRelays.BroadcastRelayListDecryptionCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip51Lists.relayLists.BroadcastRelayListEvent import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/favoriteAlgoFeedsLists/FavoriteAlgoFeedsListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/favoriteAlgoFeedsLists/FavoriteAlgoFeedsListState.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/favoriteAlgoFeedsLists/FavoriteAlgoFeedsListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/favoriteAlgoFeedsLists/FavoriteAlgoFeedsListState.kt index fa635297bc..6aca746ec2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/favoriteAlgoFeedsLists/FavoriteAlgoFeedsListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/favoriteAlgoFeedsLists/FavoriteAlgoFeedsListState.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists.favoriteAlgoFeedsLists +package com.vitorpamplona.amethyst.commons.model.nip51Lists.favoriteAlgoFeedsLists +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip51Lists.favoriteAlgoFeedsLists.FavoriteAlgoFeedsListDecryptionCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.AddressBookmark @@ -35,6 +35,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/favoriteFollowSetsLists/FavoriteFollowSetsListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/favoriteFollowSetsLists/FavoriteFollowSetsListState.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/favoriteFollowSetsLists/FavoriteFollowSetsListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/favoriteFollowSetsLists/FavoriteFollowSetsListState.kt index e7b8309762..5df3da2b51 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/favoriteFollowSetsLists/FavoriteFollowSetsListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/favoriteFollowSetsLists/FavoriteFollowSetsListState.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists.favoriteFollowSetsLists +package com.vitorpamplona.amethyst.commons.model.nip51Lists.favoriteFollowSetsLists import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note @@ -32,6 +32,7 @@ import com.vitorpamplona.quartz.nip51Lists.favoriteFollowSetsList.FavoriteFollow import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/favoriteRelays/FavoriteRelayListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/favoriteRelays/FavoriteRelayListState.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/favoriteRelays/FavoriteRelayListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/favoriteRelays/FavoriteRelayListState.kt index 2f0fa88e44..325dab92e5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/favoriteRelays/FavoriteRelayListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/favoriteRelays/FavoriteRelayListState.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists.favoriteRelays +package com.vitorpamplona.amethyst.commons.model.nip51Lists.favoriteRelays +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip51Lists.favoriteRelays.FavoriteRelayListDecryptionCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip51Lists.relayLists.FavoriteRelayListEvent @@ -32,6 +32,7 @@ import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/followSets/FollowSetsState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/followSets/FollowSetsState.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/followSets/FollowSetsState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/followSets/FollowSetsState.kt index 4b002aec38..5e857b9282 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/followSets/FollowSetsState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/followSets/FollowSetsState.kt @@ -18,8 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists.followSets +@file:OptIn(ExperimentalUuidApi::class) +package com.vitorpamplona.amethyst.commons.model.nip51Lists.followSets + +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User @@ -31,7 +34,6 @@ import com.vitorpamplona.amethyst.commons.model.events import com.vitorpamplona.amethyst.commons.model.nip51Lists.followSets.FollowSetDecryptionCache import com.vitorpamplona.amethyst.commons.model.nip51Lists.followSets.PeopleList import com.vitorpamplona.amethyst.commons.model.updateFlow -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.update @@ -45,6 +47,7 @@ import com.vitorpamplona.quartz.utils.flattenToSet import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -55,7 +58,8 @@ import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.flow.update -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid /** * Maintains several stateflows for each step in processing PeopleLists @@ -205,7 +209,7 @@ class FollowSetsState( isPrivate: Boolean = false, account: Account, ): String { - val dTag = UUID.randomUUID().toString() + val dTag = Uuid.random().toString() val newListTemplate = FollowSetEvent.build( dTag = dTag, @@ -253,7 +257,7 @@ class FollowSetsState( ) { val newList = FollowSetEvent.createListWithDescription( - dTag = UUID.randomUUID().toString(), + dTag = Uuid.random().toString(), title = customCloneName ?: currentPeopleList.title, description = customCloneDescription ?: currentPeopleList.description, publicMembers = currentPeopleList.publicMembers.toUserTags(), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/followSets/StarterPacksState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/followSets/StarterPacksState.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/followSets/StarterPacksState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/followSets/StarterPacksState.kt index 881b97a43d..14f064f0c8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/followSets/StarterPacksState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/followSets/StarterPacksState.kt @@ -18,8 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists.followSets +@file:OptIn(ExperimentalUuidApi::class) +package com.vitorpamplona.amethyst.commons.model.nip51Lists.followSets + +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User @@ -30,7 +33,6 @@ import com.vitorpamplona.amethyst.commons.model.eventIdSet import com.vitorpamplona.amethyst.commons.model.events import com.vitorpamplona.amethyst.commons.model.nip51Lists.followSets.PeopleList import com.vitorpamplona.amethyst.commons.model.updateFlow -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.update @@ -48,6 +50,7 @@ import com.vitorpamplona.quartz.utils.flattenToSet import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -58,7 +61,8 @@ import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.flow.update -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid /** * Maintains several stateflows for each step in processing PeopleLists @@ -195,7 +199,7 @@ class StarterPacksState( isPrivate: Boolean = false, account: Account, ): String { - val dTag = UUID.randomUUID().toString() + val dTag = Uuid.random().toString() val newListTemplate = StarterPackEvent.build( @@ -245,7 +249,7 @@ class StarterPacksState( val template = listEvent.update { // new list - dTag(UUID.randomUUID().toString()) + dTag(Uuid.random().toString()) // updates names if (customCloneName != null) title(customCloneName) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/geohashLists/GeohashListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/geohashLists/GeohashListState.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/geohashLists/GeohashListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/geohashLists/GeohashListState.kt index 6f8538e3d2..679af857c2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/geohashLists/GeohashListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/geohashLists/GeohashListState.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists.geohashLists +package com.vitorpamplona.amethyst.commons.model.nip51Lists.geohashLists +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip51Lists.geohashLists.GeohashListDecryptionCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip51Lists.geohashList.GeohashListEvent import com.vitorpamplona.quartz.utils.Log @@ -32,6 +32,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/indexerRelays/IndexerRelayListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/indexerRelays/IndexerRelayListState.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/indexerRelays/IndexerRelayListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/indexerRelays/IndexerRelayListState.kt index 495e5b147f..89a14049d9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/indexerRelays/IndexerRelayListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/indexerRelays/IndexerRelayListState.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists.indexerRelays +package com.vitorpamplona.amethyst.commons.model.nip51Lists.indexerRelays import com.vitorpamplona.amethyst.commons.defaults.DefaultIndexerRelayList +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip51Lists.indexerRelays.IndexerRelayListDecryptionCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip51Lists.relayLists.IndexerRelayListEvent @@ -33,6 +33,7 @@ import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/interestLists/InterestListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/interestLists/InterestListState.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/interestLists/InterestListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/interestLists/InterestListState.kt index 25dcf8712b..906323b360 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/interestLists/InterestListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/interestLists/InterestListState.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists.interestLists +package com.vitorpamplona.amethyst.commons.model.nip51Lists.interestLists +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip51Lists.interestLists.InterestListDecryptionCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip51Lists.interestList.InterestListEvent import com.vitorpamplona.quartz.utils.Log @@ -32,6 +32,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/interestSets/InterestSetsState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/interestSets/InterestSetsState.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/interestSets/InterestSetsState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/interestSets/InterestSetsState.kt index f70f9a13cb..cb5b45bd1d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/interestSets/InterestSetsState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/interestSets/InterestSetsState.kt @@ -18,8 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists.interestSets +package com.vitorpamplona.amethyst.commons.model.nip51Lists.interestSets +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.anyNotNullEvent @@ -29,7 +30,6 @@ import com.vitorpamplona.amethyst.commons.model.eventIdSet import com.vitorpamplona.amethyst.commons.model.events import com.vitorpamplona.amethyst.commons.model.nip51Lists.interestSets.InterestSet import com.vitorpamplona.amethyst.commons.model.updateFlow -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip09Deletions.DeletionRequestEvent import com.vitorpamplona.quartz.nip51Lists.interestSet.InterestSetEvent @@ -37,6 +37,7 @@ import com.vitorpamplona.quartz.nip51Lists.tags.TitleTag import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/muteList/MuteListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/muteList/MuteListState.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/muteList/MuteListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/muteList/MuteListState.kt index 2badb31fd1..3c428663cb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/muteList/MuteListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/muteList/MuteListState.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists.muteList +package com.vitorpamplona.amethyst.commons.model.nip51Lists.muteList +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip51Lists.muteList.MuteListDecryptionCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip51Lists.muteList.MuteListEvent @@ -37,6 +37,7 @@ import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/proxyRelays/ProxyRelayListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/proxyRelays/ProxyRelayListState.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/proxyRelays/ProxyRelayListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/proxyRelays/ProxyRelayListState.kt index cbabc48672..7f00fc35e4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/proxyRelays/ProxyRelayListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/proxyRelays/ProxyRelayListState.kt @@ -18,18 +18,19 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists.proxyRelays +package com.vitorpamplona.amethyst.commons.model.nip51Lists.proxyRelays +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip51Lists.proxyRelays.ProxyRelayListDecryptionCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip51Lists.relayLists.ProxyRelayListEvent import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/searchRelays/SearchRelayListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/searchRelays/SearchRelayListState.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/searchRelays/SearchRelayListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/searchRelays/SearchRelayListState.kt index c41ec49513..90ce1f524b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/searchRelays/SearchRelayListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/searchRelays/SearchRelayListState.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists.searchRelays +package com.vitorpamplona.amethyst.commons.model.nip51Lists.searchRelays import com.vitorpamplona.amethyst.commons.defaults.DefaultSearchRelayList +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip51Lists.searchRelays.SearchRelayListDecryptionCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip50Search.SearchRelayListEvent @@ -33,6 +33,7 @@ import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/trustedRelays/TrustedRelayListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/trustedRelays/TrustedRelayListState.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/trustedRelays/TrustedRelayListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/trustedRelays/TrustedRelayListState.kt index 32b043cc47..d5f6f44e4d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/trustedRelays/TrustedRelayListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip51Lists/trustedRelays/TrustedRelayListState.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip51Lists.trustedRelays +package com.vitorpamplona.amethyst.commons.model.nip51Lists.trustedRelays +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip51Lists.trustedRelays.TrustedRelayListDecryptionCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip51Lists.relayLists.TrustedRelayListEvent @@ -32,6 +32,7 @@ import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/nip52Calendar/CalendarAppointmentView.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip52Calendar/CalendarAppointmentView.kt similarity index 100% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/nip52Calendar/CalendarAppointmentView.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip52Calendar/CalendarAppointmentView.kt diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/nip52Calendar/CalendarSortKeys.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip52Calendar/CalendarSortKeys.kt similarity index 80% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/nip52Calendar/CalendarSortKeys.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip52Calendar/CalendarSortKeys.kt index a09f17880c..dfba93c744 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/nip52Calendar/CalendarSortKeys.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip52Calendar/CalendarSortKeys.kt @@ -21,33 +21,23 @@ package com.vitorpamplona.amethyst.commons.model.nip52Calendar import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.search.calendar.LocalClock +import com.vitorpamplona.amethyst.commons.search.calendar.SearchDate import com.vitorpamplona.quartz.nip52Calendar.appt.day.CalendarDateSlotEvent import com.vitorpamplona.quartz.nip52Calendar.appt.time.CalendarTimeSlotEvent import com.vitorpamplona.quartz.utils.TimeUtils -import java.time.Instant -import java.time.LocalDate -import java.time.ZoneId -import java.time.format.DateTimeFormatter -// java.time formatters are thread-safe; the SimpleDateFormat predecessor was shared by sort -// (background) and grouping (UI) paths and could throw under concurrent use. -private val IsoDateParser: DateTimeFormatter = DateTimeFormatter.ISO_LOCAL_DATE +// A strict YYYY-MM-DD read (an impossible day such as 02-31 is refused, not rolled over). +private fun parseIsoDate(date: String?): SearchDate? = if (date.isNullOrBlank()) null else SearchDate.parse(date) -private fun parseIsoDate(date: String?): LocalDate? { - if (date.isNullOrBlank()) return null - return try { - LocalDate.parse(date, IsoDateParser) - } catch (_: Throwable) { - null - } -} +private fun localEpochDay(unixSeconds: Long): Long = LocalClock.epochDayCounter().epochDay(unixSeconds) /** * Calendar 31922 carries a calendar date (no instant). Anchor it at local midnight so that * "Jan 15" lands on Jan 15 in the user's grid and ordering reflects their local zone — UTC * anchoring made date-only events appear a day early west of UTC. */ -fun parseIsoDateToUnixSeconds(date: String?): Long? = parseIsoDate(date)?.atStartOfDay(ZoneId.systemDefault())?.toEpochSecond() +fun parseIsoDateToUnixSeconds(date: String?): Long? = parseIsoDate(date)?.let { LocalClock.startOfDay(it) } /** * Unified start time as unix-seconds. For 31923 (time-slot) this is the event's instant; for @@ -77,20 +67,13 @@ fun Note.calendarEndSeconds(): Long? = */ fun Note.calendarLocalDayKey(): Long? = when (val e = event) { - is CalendarTimeSlotEvent -> - e.start()?.let { - Instant - .ofEpochSecond(it) - .atZone(ZoneId.systemDefault()) - .toLocalDate() - .toEpochDay() - } - is CalendarDateSlotEvent -> parseIsoDate(e.start())?.toEpochDay() + is CalendarTimeSlotEvent -> e.start()?.let(::localEpochDay) + is CalendarDateSlotEvent -> parseIsoDate(e.start())?.daysFromEpoch() else -> null } /** - * Buckets appointments by local calendar day (returned as `LocalDate.toEpochDay`). Notes that + * Buckets appointments by local calendar day (days since 1970-01-01). Notes that * are not calendar appointments or whose start can't be parsed are dropped. */ fun groupByDayKey(notes: List): Map> { @@ -113,15 +96,8 @@ fun Note.calendarLocalDayKeyRange(): LongRange? { val startKey = calendarLocalDayKey() ?: return null val endKey = when (val e = event) { - is CalendarTimeSlotEvent -> - e.end()?.let { - Instant - .ofEpochSecond(it) - .atZone(ZoneId.systemDefault()) - .toLocalDate() - .toEpochDay() - } ?: startKey - is CalendarDateSlotEvent -> parseIsoDate(e.end())?.toEpochDay() ?: startKey + is CalendarTimeSlotEvent -> e.end()?.let(::localEpochDay) ?: startKey + is CalendarDateSlotEvent -> parseIsoDate(e.end())?.daysFromEpoch() ?: startKey else -> startKey } val safeEnd = endKey.coerceAtLeast(startKey).coerceAtMost(startKey + 366) diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/nip52Calendar/FollowsGoing.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip52Calendar/FollowsGoing.kt similarity index 100% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/nip52Calendar/FollowsGoing.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip52Calendar/FollowsGoing.kt diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip53LiveActivities/LiveActivitiesChannel.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip53LiveActivities/LiveActivitiesChannel.kt index 1638b54d6a..50a294b0c1 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip53LiveActivities/LiveActivitiesChannel.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip53LiveActivities/LiveActivitiesChannel.kt @@ -54,8 +54,8 @@ class LiveActivitiesChannel( * iterating it just to find presence is wasteful. Feeds that need * "is anyone live on stage in this room?" iterate this index * directly. See - * [com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.dal.NestsFeedFilter] - * and [com.vitorpamplona.amethyst.ui.screen.loggedIn.home.dal.HomeLiveFilter]. + * [com.vitorpamplona.amethyst.commons.nests.dal.NestsFeedFilter] + * and [com.vitorpamplona.amethyst.commons.home.dal.HomeLiveFilter]. */ val presenceNotes = LargeCache() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip53NestsServers/NestsServerListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip53NestsServers/NestsServerListState.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip53NestsServers/NestsServerListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip53NestsServers/NestsServerListState.kt index 98a8f87737..403f6a6745 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip53NestsServers/NestsServerListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip53NestsServers/NestsServerListState.kt @@ -18,17 +18,18 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip53NestsServers +package com.vitorpamplona.amethyst.commons.model.nip53NestsServers import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.ICacheProvider -import com.vitorpamplona.amethyst.model.nipB7Blossom.BlossomServerListState +import com.vitorpamplona.amethyst.commons.model.nipB7Blossom.BlossomServerListState import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip53LiveActivities.nestsServers.NestsServer import com.vitorpamplona.quartz.nip53LiveActivities.nestsServers.NestsServersEvent import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/nip60Cashu/CashuMintDirectoryState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip60Cashu/CashuMintDirectoryState.kt similarity index 91% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/nip60Cashu/CashuMintDirectoryState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip60Cashu/CashuMintDirectoryState.kt index b93f9348cd..9ca368adad 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/nip60Cashu/CashuMintDirectoryState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip60Cashu/CashuMintDirectoryState.kt @@ -24,10 +24,14 @@ import androidx.compose.runtime.Immutable import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relayClient.assemblers.CashuMintDirectoryFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.assemblers.CashuMintDirectoryQueryState +import com.vitorpamplona.amethyst.commons.util.ConcurrentSet +import com.vitorpamplona.amethyst.commons.util.KmpLock +import com.vitorpamplona.amethyst.commons.util.withLock import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip87Ecash.cashu.CashuMintEvent import com.vitorpamplona.quartz.nip87Ecash.recommendation.MintRecommendationEvent +import com.vitorpamplona.quartz.utils.concurrent.ConcurrentMap import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -39,7 +43,6 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import java.util.concurrent.ConcurrentHashMap /** * One mint as it appears in the NIP-87 directory. @@ -91,10 +94,10 @@ class CashuMintDirectoryState( private val followsFlow: StateFlow>, ) { /** Mint announcements keyed by the announcement event id. */ - private val announcements = ConcurrentHashMap() + private val announcements = ConcurrentMap() /** Recommendations keyed by event id — value is the parsed event. */ - private val recommendations = ConcurrentHashMap() + private val recommendations = ConcurrentMap() private val _entries = MutableStateFlow>(emptyList()) @@ -116,8 +119,8 @@ class CashuMintDirectoryState( // Subscription lifecycle (open while a picker is on screen) // ============================================================ private var currentSubscription: CashuMintDirectoryQueryState? = null - private val openers = ConcurrentHashMap.newKeySet() - private val liveJobLock = Any() + private val openers = ConcurrentSet() + private val liveJobLock = KmpLock() private var liveJob: Job? = null /** @@ -130,7 +133,7 @@ class CashuMintDirectoryState( opener: Any, relays: Set, ) { - if (openers.isEmpty()) { + if (openers.size == 0) { // First opener — start the live indexer + relay subscription. startLiveIndex() backfillFromCacheAsync() @@ -141,10 +144,10 @@ class CashuMintDirectoryState( fun close(opener: Any) { openers.remove(opener) - if (openers.isEmpty()) { + if (openers.size == 0) { currentSubscription?.let { runCatching { assembler.unsubscribe(it) } } currentSubscription = null - synchronized(liveJobLock) { + liveJobLock.withLock { liveJob?.cancel() liveJob = null } @@ -167,7 +170,7 @@ class CashuMintDirectoryState( } private fun startLiveIndex() { - synchronized(liveJobLock) { + liveJobLock.withLock { if (liveJob != null) return liveJob = scope.launch(Dispatchers.Default) { @@ -175,10 +178,14 @@ class CashuMintDirectoryState( val touched = notes.mapNotNull { note -> when (val e = note.event) { - is CashuMintEvent -> announcements.put(e.id, e).let { true } + is CashuMintEvent -> { + announcements[e.id] = e + true + } is MintRecommendationEvent -> { if (e.isCashuRecommendation()) { - recommendations.put(e.id, e).let { true } + recommendations[e.id] = e + true } else { false } @@ -210,8 +217,10 @@ class CashuMintDirectoryState( // ============================================================ private fun rebuildEntries() { // 1. Group announcements by mint URL — most recent wins for display. + // One copy for both passes, so byUrl and urlByDTag describe the same set of announcements. + val announced = announcements.snapshot().values val byUrl: MutableMap = HashMap() - announcements.values.forEach { e -> + announced.forEach { e -> val url = e.mintUrl() ?: return@forEach val existing = byUrl[url] if (existing == null || e.createdAt > existing.createdAt) byUrl[url] = e @@ -223,7 +232,7 @@ class CashuMintDirectoryState( // clients also store the mint URL in the `u` tag of the // recommendation, so we accept both. val urlByDTag: MutableMap = HashMap() - announcements.values.forEach { e -> + announced.forEach { e -> val d = e.dTag() val url = e.mintUrl() if (d != null && url != null) urlByDTag[d] = url @@ -234,7 +243,7 @@ class CashuMintDirectoryState( val perUrlFollows: MutableMap> = HashMap() val followSet = currentFollowSnapshot() - recommendations.values.forEach { rec -> + recommendations.asMap().values.forEach { rec -> // Mints recommended via `u` tag(s) — directly carry the URL. val urlsFromU = rec.mintUrls() // Mints recommended via `a` tag(s) — look up the URL by mint d-tag. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip60Cashu/CashuWalletState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip60Cashu/CashuWalletState.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip60Cashu/CashuWalletState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip60Cashu/CashuWalletState.kt index 1a97ee66c1..8726daaecd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip60Cashu/CashuWalletState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip60Cashu/CashuWalletState.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip60Cashu +package com.vitorpamplona.amethyst.commons.model.nip60Cashu import com.vitorpamplona.amethyst.commons.cashu.CashuWalletReader import com.vitorpamplona.amethyst.commons.cashu.ops.CashuWalletOps @@ -28,9 +28,9 @@ import com.vitorpamplona.amethyst.commons.cashu.ops.RestoreOutcome import com.vitorpamplona.amethyst.commons.cashu.ops.SendTokenCompleted import com.vitorpamplona.amethyst.commons.cashu.ops.TokenEntry import com.vitorpamplona.amethyst.commons.cashu.ops.describeMintError +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relayClient.assemblers.cashuProofBackfillFilters -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray @@ -45,6 +45,7 @@ import com.vitorpamplona.quartz.nip09Deletions.DeletionRequestEvent import com.vitorpamplona.quartz.nip60Cashu.history.CashuSpendingHistoryEvent import com.vitorpamplona.quartz.nip60Cashu.mintApi.DeterministicSecretFactory import com.vitorpamplona.quartz.nip60Cashu.mintApi.MeltQuoteBolt11ResponseDto +import com.vitorpamplona.quartz.nip60Cashu.mintApi.MintHttpTransport import com.vitorpamplona.quartz.nip60Cashu.quote.CashuMintQuoteEvent import com.vitorpamplona.quartz.nip60Cashu.seed.CashuDeterministic import com.vitorpamplona.quartz.nip60Cashu.token.CashuTokenEvent @@ -54,9 +55,12 @@ import com.vitorpamplona.quartz.nip61Nutzaps.info.NutzapInfoEvent import com.vitorpamplona.quartz.nip61Nutzaps.nutzap.NutzapEvent import com.vitorpamplona.quartz.nip87Ecash.recommendation.MintRecommendationEvent import com.vitorpamplona.quartz.utils.Log +import com.vitorpamplona.quartz.utils.concurrent.ConcurrentMap +import com.vitorpamplona.quartz.utils.concurrent.ConcurrentSet import com.vitorpamplona.quartz.utils.secp256k1.Secp256k1 import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow @@ -72,13 +76,12 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withTimeoutOrNull -import okhttp3.OkHttpClient -import java.util.concurrent.ConcurrentHashMap +import kotlin.concurrent.Volatile /** * Account-scoped state holder for the NIP-60 Cashu wallet + NIP-61 nutzaps. * - * Lives on [com.vitorpamplona.amethyst.model.Account], so it stays alive for + * Lives on [com.vitorpamplona.amethyst.commons.model.Account], so it stays alive for * the lifetime of the login session — not just while the wallet screen is * visible. This matters because: * @@ -88,7 +91,7 @@ import java.util.concurrent.ConcurrentHashMap * launch (or on fresh device sign-in) without requiring the user to open * the wallet screen first. * - * Mirrors the shape of [com.vitorpamplona.amethyst.model.nip47WalletConnect.NwcSignerState] + * Mirrors the shape of [com.vitorpamplona.amethyst.commons.model.nip47WalletConnect.NwcSignerState] * — a single state object on Account, ViewModels are thin presenters. * * Reactivity: subscribes to [LocalCache.live.newEventBundles] (and the @@ -110,13 +113,13 @@ class CashuWalletState( private val inboxRelaysFlow: StateFlow>, private val dmRelaysFlow: StateFlow>, private val settings: AccountSettings, - okHttpClient: (String) -> OkHttpClient, + mintTransport: MintHttpTransport, ) { val ops: CashuWalletOps = CashuWalletOps( signer = signer, publish = ::publishEvent, - okHttpClient = okHttpClient, + mintTransport = mintTransport, // NUT-13 wiring: the factory closure reads the cached seed at // mint-op time. cachedSeed is populated by ensureSeed() — // CashuWalletOps' seedWarmer below calls it before any blind @@ -152,10 +155,10 @@ class CashuWalletState( // ============================================================ private var walletEventInternal: CashuWalletEvent? = null private var nutzapInfoEventInternal: NutzapInfoEvent? = null - private val tokenEvents = ConcurrentHashMap() - private val historyEvents = ConcurrentHashMap() - private val quoteEvents = ConcurrentHashMap() - private val nutzapEvents = ConcurrentHashMap() + private val tokenEvents = ConcurrentMap() + private val historyEvents = ConcurrentMap() + private val quoteEvents = ConcurrentMap() + private val nutzapEvents = ConcurrentMap() /** * NIP-87 cashu mint recommendations published by this account. Keyed by @@ -164,10 +167,10 @@ class CashuWalletState( * mint replaces the older one and we don't show duplicates in the * Settings screen list. */ - private val recommendationEvents = ConcurrentHashMap() + private val recommendationEvents = ConcurrentMap() /** NIP-44 decryption cache for token contents, keyed by event id. */ - private val tokenContents = ConcurrentHashMap() + private val tokenContents = ConcurrentMap() private val redeemMutex = Mutex() /** @@ -180,7 +183,7 @@ class CashuWalletState( * double-redeem race. The set is process-local; on next launch the * persisted kind:7376 events rebuild equivalent state. */ - private val sessionRedeemedNutzaps = ConcurrentHashMap.newKeySet() + private val sessionRedeemedNutzaps = ConcurrentSet() /** * Nutzap event ids that failed redemption with a deterministic @@ -193,7 +196,7 @@ class CashuWalletState( * process-local — if the user rotates their P2PK key, restarting * gives the redeem another shot. */ - private val sessionUnredeemableNutzaps = ConcurrentHashMap.newKeySet() + private val sessionUnredeemableNutzaps = ConcurrentSet() // ============================================================ // Public flows @@ -624,7 +627,7 @@ class CashuWalletState( val filters = cashuProofBackfillFilters(pubKey) // The callback runs on the relay reader thread and must not suspend, // so collect first and index after the walk. - val collected = ConcurrentHashMap() + val collected = ConcurrentMap() runCatching { client.fetchAllPagesFromPool( filters = relays.associateWith { filters }, @@ -645,9 +648,9 @@ class CashuWalletState( proofBackfillDone = true } - val fresh = collected.values.filter { !tokenEvents.containsKey(it.id) } + val fresh = collected.asMap().values.filter { tokenEvents[it.id] == null } Log.i("CashuWallet") { - "Proof backfill over ${relays.size} relay(s): ${collected.size} kind:7375 seen, ${fresh.size} new" + "Proof backfill over ${relays.size} relay(s): ${collected.size()} kind:7375 seen, ${fresh.size} new" } if (fresh.isNotEmpty()) { @@ -720,16 +723,16 @@ class CashuWalletState( } } is CashuTokenEvent -> { - if (tokenEvents.put(event.id, event) == null) dirtyTokens = true + if (tokenEvents.putIfAbsent(event.id, event) == null) dirtyTokens = true } is CashuSpendingHistoryEvent -> { - if (historyEvents.put(event.id, event) == null) dirtyHistory = true + if (historyEvents.putIfAbsent(event.id, event) == null) dirtyHistory = true } is CashuMintQuoteEvent -> { - if (quoteEvents.put(event.id, event) == null) dirtyQuotes = true + if (quoteEvents.putIfAbsent(event.id, event) == null) dirtyQuotes = true } is NutzapEvent -> { - if (nutzapEvents.put(event.id, event) == null) dirtyNutzaps = true + if (nutzapEvents.putIfAbsent(event.id, event) == null) dirtyNutzaps = true } is MintRecommendationEvent -> { // kind:38000 is parameterized-replaceable — keep only the @@ -776,7 +779,7 @@ class CashuWalletState( } if (dirtyTokens) recomputeUnspent() if (dirtyHistory) { - _history.value = historyEvents.values.sortedByDescending { it.createdAt } + _history.value = historyEvents.asMap().values.sortedByDescending { it.createdAt } } if (dirtyQuotes || dirtyHistory) { // History gains might mark quotes as fulfilled (via the "destroyed" @@ -787,7 +790,7 @@ class CashuWalletState( triggerAutoRedeem() } if (dirtyRecommendations) { - _ownRecommendations.value = recommendationEvents.values.sortedByDescending { it.createdAt } + _ownRecommendations.value = recommendationEvents.asMap().values.sortedByDescending { it.createdAt } } } @@ -819,7 +822,11 @@ class CashuWalletState( // Recommendations are indexed by dTag, not event id — find by // matching event.id and drop the entry. val recoKey = - recommendationEvents.entries.firstOrNull { it.value.id == id }?.key + recommendationEvents + .asMap() + .entries + .firstOrNull { it.value.id == id } + ?.key if (recoKey != null) { recommendationEvents.remove(recoKey) dirtyRecommendations = true @@ -840,26 +847,26 @@ class CashuWalletState( settings.clearNutzapInfo() } if (dirtyTokens) recomputeUnspent() - if (dirtyHistory) _history.value = historyEvents.values.sortedByDescending { it.createdAt } + if (dirtyHistory) _history.value = historyEvents.asMap().values.sortedByDescending { it.createdAt } if (dirtyQuotes || dirtyHistory) recomputePending() // dirtyNutzaps would trigger UI surfacing for inbound nutzaps; auto- // redeem already fires from the live-event observer, so no extra // signal is needed here. if (dirtyNutzaps) Unit if (dirtyRecommendations) { - _ownRecommendations.value = recommendationEvents.values.sortedByDescending { it.createdAt } + _ownRecommendations.value = recommendationEvents.asMap().values.sortedByDescending { it.createdAt } } } private suspend fun recomputeUnspent() { - val all = tokenEvents.values.toList() + val all = tokenEvents.asMap().values.toList() // Decrypt anything we haven't seen before; reuse cached TokenContent // for events we've already decrypted. Only successes are cached, so a // failure is retried on the next recompute rather than being pinned as // "empty" for the session. var undecryptable = 0 all.forEach { evt -> - if (!tokenContents.containsKey(evt.id)) { + if (tokenContents[evt.id] == null) { val content = runCatching { evt.tokenContent(signer) } .onFailure { @@ -884,15 +891,18 @@ class CashuWalletState( } // Shared del-rollover + sort with the headless reader. - _tokenEntries.value = CashuWalletReader.computeUnspent(all, tokenContents) + _tokenEntries.value = CashuWalletReader.computeUnspent(all, tokenContents.asMap()) } /** Token events we hold but have never managed to decrypt. See [recomputeUnspent]. */ - private fun undecryptedTokenCount(): Int = tokenEvents.keys.count { it !in tokenContents.keys } + private fun undecryptedTokenCount(): Int { + val decrypted = tokenContents.asMap() + return tokenEvents.asMap().keys.count { it !in decrypted } + } private fun recomputePending() { // Shared destroyed/expired filter with the headless reader. - _pendingQuotes.value = CashuWalletReader.computePending(quoteEvents.values, historyEvents.values) + _pendingQuotes.value = CashuWalletReader.computePending(quoteEvents.asMap().values, historyEvents.asMap().values) } private fun scanCacheForOwnEvents(): List { @@ -921,15 +931,15 @@ class CashuWalletState( // (Amber even prompts on some configurations), paid on every bundle // by a wallet whose nutzaps were all redeemed months ago. Nothing // above the candidate filter needs a key, so hoist the filter. - if (nutzapEvents.isEmpty()) return + if (nutzapEvents.size() == 0) return val skipIds = HashSet() - historyEvents.values.forEach { h -> + historyEvents.asMap().values.forEach { h -> h.redeemedReferences().forEach { skipIds.add(it.eventId) } } - skipIds.addAll(sessionRedeemedNutzaps) - skipIds.addAll(sessionUnredeemableNutzaps) + skipIds.addAll(sessionRedeemedNutzaps.snapshot()) + skipIds.addAll(sessionUnredeemableNutzaps.snapshot()) - val candidates = nutzapEvents.values.filter { it.id !in skipIds } + val candidates = nutzapEvents.asMap().values.filter { it.id !in skipIds } if (candidates.isEmpty()) return val privkey = walletPrivkeyHex() ?: return diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip65RelayList/Nip65RelayListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip65RelayList/Nip65RelayListState.kt index 557e3fd0f2..fc8ea5a67a 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip65RelayList/Nip65RelayListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip65RelayList/Nip65RelayListState.kt @@ -20,9 +20,12 @@ */ package com.vitorpamplona.amethyst.commons.model.nip65RelayList +import com.vitorpamplona.amethyst.commons.defaults.Constants +import com.vitorpamplona.amethyst.commons.defaults.relayListOrDefaultsWhenUnknown +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState -import com.vitorpamplona.amethyst.commons.model.cache.ICacheProvider +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent @@ -42,11 +45,11 @@ import kotlinx.coroutines.launch class Nip65RelayListState( val signer: NostrSigner, - val cache: ICacheProvider, + val cache: LocalCache, val scope: CoroutineScope, - val settings: Nip65RelayListRepository, + val settings: AccountSettings, ) { - // Creates a long-term reference for this note so that the GC doesn't collect the note itself + // Creates a long-term reference for this note so that the GC doesn't collect the note it self val nip65ListNote = cache.getOrCreateAddressableNote(getNIP65RelayListAddress()) fun getNIP65RelayListAddress() = AdvertisedRelayListEvent.createAddress(signer.pubKey) @@ -57,18 +60,39 @@ class Nip65RelayListState( fun nip65Event(note: Note) = note.event as? AdvertisedRelayListEvent ?: settings.backupNIP65RelayList - fun normalizeNIP65WriteRelayListWithBackup(note: Note): Set = nip65Event(note)?.writeRelaysNorm()?.toSet() ?: settings.defaultOutboxRelays + fun normalizeNIP65WriteRelayListWithBackup(note: Note): Set = relayListOrDefaultsWhenUnknown(nip65Event(note), Constants.eventFinderRelays) { it.writeRelaysNorm()?.toSet() } - fun normalizeNIP65ReadRelayListWithBackup(note: Note): Set = nip65Event(note)?.readRelaysNorm()?.toSet() ?: settings.defaultInboxRelays + fun normalizeNIP65ReadRelayListWithBackup(note: Note): Set = relayListOrDefaultsWhenUnknown(nip65Event(note), Constants.bootstrapInbox) { it.readRelaysNorm()?.toSet() } fun normalizeNIP65WriteRelayListNoDefaults(note: Note): Set = nip65Event(note)?.writeRelaysNorm()?.toSet() ?: emptySet() fun normalizeNIP65ReadRelayListNoDefaults(note: Note): Set = nip65Event(note)?.readRelaysNorm()?.toSet() ?: emptySet() - fun normalizeNIP65AllRelayListWithBackup(note: Note): Set = nip65Event(note)?.relays()?.map { it.relayUrl }?.toSet() ?: settings.defaultOutboxRelays + fun normalizeNIP65AllRelayListWithBackup(note: Note): Set = nip65Event(note)?.relays()?.map { it.relayUrl }?.toSet() ?: Constants.eventFinderRelays fun normalizeNIP65AllRelayListWithBackupNoDefaults(note: Note): Set = nip65Event(note)?.relays()?.map { it.relayUrl }?.toSet() ?: emptySet() + /** + * The app defaults currently standing in for a user we have no kind:10002 for — empty as soon + * as one exists, including an empty one. + * + * Uses the same `nip65Event(note) == null` predicate the substitution itself uses, so the two + * cannot drift: whatever is listed here is exactly what the app is guessing on the user's + * behalf. See [relayListOrDefaultsWhenUnknown]. + */ + fun assumedDefaults(note: Note): Set = if (nip65Event(note) == null) Constants.bootstrapInbox + Constants.eventFinderRelays else emptySet() + + val assumedDefaultsFlow = + getNIP65RelayListFlow() + .map { assumedDefaults(it.note) } + .onStart { emit(assumedDefaults(nip65ListNote)) } + .flowOn(Dispatchers.IO) + .stateIn( + scope, + SharingStarted.Eagerly, + assumedDefaults(nip65ListNote), + ) + val outboxFlow = getNIP65RelayListFlow() .map { normalizeNIP65WriteRelayListWithBackup(it.note) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip72Communities/CommunityListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip72Communities/CommunityListState.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip72Communities/CommunityListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip72Communities/CommunityListState.kt index e1ae825bc2..0d623856e0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip72Communities/CommunityListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip72Communities/CommunityListState.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip72Communities +package com.vitorpamplona.amethyst.commons.model.nip72Communities +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip72Communities.CommunityListDecryptionCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent import com.vitorpamplona.quartz.nip72ModCommunities.follow.CommunityListEvent @@ -35,6 +35,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip78AppSpecific/AppSpecificState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip78AppSpecific/AppSpecificState.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip78AppSpecific/AppSpecificState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip78AppSpecific/AppSpecificState.kt index b402ab56bd..7875c521ce 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip78AppSpecific/AppSpecificState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip78AppSpecific/AppSpecificState.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip78AppSpecific +package com.vitorpamplona.amethyst.commons.model.nip78AppSpecific +import com.vitorpamplona.amethyst.commons.model.AccountSettings +import com.vitorpamplona.amethyst.commons.model.AccountSyncedSettingsInternal import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.AccountSettings -import com.vitorpamplona.amethyst.model.AccountSyncedSettingsInternal import com.vitorpamplona.quartz.nip01Core.core.JsonMapper import com.vitorpamplona.quartz.nip01Core.core.awaitCreatedAtToSupersede import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner @@ -32,6 +32,7 @@ import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip89AppHandlers/AppRecommendationsState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip89AppHandlers/AppRecommendationsState.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip89AppHandlers/AppRecommendationsState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip89AppHandlers/AppRecommendationsState.kt index 40ff855b42..999bc03915 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip89AppHandlers/AppRecommendationsState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip89AppHandlers/AppRecommendationsState.kt @@ -18,11 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip89AppHandlers +package com.vitorpamplona.amethyst.commons.model.nip89AppHandlers +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.awaitCreatedAtToSupersede import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter @@ -34,6 +34,7 @@ import com.vitorpamplona.quartz.nip89AppHandlers.recommendation.AppRecommendatio import com.vitorpamplona.quartz.nip89AppHandlers.recommendation.tags.RecommendationTag import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nipA3PaymentTargets/NipA3PaymentTargetsState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nipA3PaymentTargets/NipA3PaymentTargetsState.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nipA3PaymentTargets/NipA3PaymentTargetsState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nipA3PaymentTargets/NipA3PaymentTargetsState.kt index fc58597571..63353f1a5e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nipA3PaymentTargets/NipA3PaymentTargetsState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nipA3PaymentTargets/NipA3PaymentTargetsState.kt @@ -18,11 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nipA3PaymentTargets +package com.vitorpamplona.amethyst.commons.model.nipA3PaymentTargets +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nipA3PaymentTargets.PaymentTarget import com.vitorpamplona.quartz.nipA3PaymentTargets.PaymentTargetsEvent @@ -30,6 +30,7 @@ import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nipB7Blossom/BlossomServerListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nipB7Blossom/BlossomServerListState.kt index 4bec8035ec..52d5b60825 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nipB7Blossom/BlossomServerListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nipB7Blossom/BlossomServerListState.kt @@ -20,11 +20,18 @@ */ package com.vitorpamplona.amethyst.commons.model.nipB7Blossom +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.ICacheProvider +import com.vitorpamplona.amethyst.commons.model.mediaServers.DEFAULT_MEDIA_SERVERS +import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerName +import com.vitorpamplona.amethyst.commons.model.mediaServers.ServerType +import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner +import com.vitorpamplona.quartz.nipB7Blossom.BlossomAuthorizationEvent import com.vitorpamplona.quartz.nipB7Blossom.BlossomServersEvent +import com.vitorpamplona.quartz.utils.Rfc3986 import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.IO @@ -32,25 +39,17 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn -/** - * Shared, platform-agnostic state holder for the user's Blossom media server - * list (NIP-B7 / kind 10063 [BlossomServersEvent]). - * - * This is the same event kind the Amethyst mobile app reads through its own - * `BlossomServerListState`: it loads the addressable event from the injected - * [ICacheProvider] and exposes the declared server URLs as a [StateFlow]. Both - * the Android and Desktop front ends can consume this so a server list - * configured on one client shows up on the other. - */ class BlossomServerListState( val signer: NostrSigner, val cache: ICacheProvider, val scope: CoroutineScope, + val settings: AccountSettings, ) { - // Creates a long-term reference for this note so that the GC doesn't collect the note itself + // Creates a long-term reference for this note so that the GC doesn't collect the note it self val blossomListNote = cache.getOrCreateAddressableNote(getBlossomServersAddress()) fun getBlossomServersAddress() = BlossomServersEvent.createAddress(signer.pubKey) @@ -59,19 +58,48 @@ class BlossomServerListState( fun getBlossomServersList(): BlossomServersEvent? = blossomListNote.event as? BlossomServersEvent - fun normalizeServers(note: Note): List = (note.event as? BlossomServersEvent)?.servers() ?: emptyList() + fun normalizeServers(note: Note): List { + val event = note.event as? BlossomServersEvent + return event?.servers() ?: emptyList() + } - val flow: StateFlow> = + fun host(url: String): String = + try { + Rfc3986.host(url).removePrefix("cdn.").removePrefix("blossom.") + } catch (e: Exception) { + url.removePrefix("cdn.").removePrefix("blossom.") + } + + val flow = getBlossomServersListFlow() - .map { normalizeServers(it.note) } - .onStart { emit(normalizeServers(blossomListNote)) } - .flowOn(Dispatchers.IO) + .map { + normalizeServers(it.note) + }.flowOn(Dispatchers.IO) .stateIn( scope, SharingStarted.Eagerly, emptyList(), ) + fun mergeServerList(blossom: List?): List = blossom?.map { ServerName(host(it), it, ServerType.Blossom) }?.ifEmpty { DEFAULT_MEDIA_SERVERS } ?: DEFAULT_MEDIA_SERVERS + + val hostNameFlow: StateFlow> = + flow + .map { blossoms -> + mergeServerList(blossoms) + }.onStart { + emit(mergeServerList(flow.value)) + }.onEach { servers -> + resetTargetOrNull(flow.value, servers, settings.defaultFileServer)?.let { + settings.changeDefaultFileServer(it) + } + }.flowOn(Dispatchers.IO) + .stateIn( + scope, + SharingStarted.Eagerly, + DEFAULT_MEDIA_SERVERS, + ) + suspend fun saveBlossomServersList(servers: List): BlossomServersEvent { val serverList = getBlossomServersList() @@ -88,4 +116,51 @@ class BlossomServerListState( ) } } + + suspend fun createBlossomUploadAuth( + hash: HexKey, + size: Long, + alt: String, + servers: List = emptyList(), + ): BlossomAuthorizationEvent = BlossomAuthorizationEvent.createUploadAuth(hash, size, alt, signer, servers) + + suspend fun createBlossomMediaAuth( + hash: HexKey, + size: Long, + alt: String, + servers: List = emptyList(), + ): BlossomAuthorizationEvent = BlossomAuthorizationEvent.createMediaAuth(hash, size, alt, signer, servers) + + suspend fun createBlossomDeleteAuth( + hash: HexKey, + alt: String, + servers: List = emptyList(), + ): BlossomAuthorizationEvent = BlossomAuthorizationEvent.createDeleteAuth(hash, alt, signer, servers) + + suspend fun createBlossomListAuth( + alt: String, + servers: List = emptyList(), + ): BlossomAuthorizationEvent = BlossomAuthorizationEvent.createListAuth(signer, alt, servers) } + +/** + * Decides whether the persisted default file server must be reset, and to what. + * + * Returns the new default server, or `null` when no change should happen. + * + * The guard on [rawList] being non-empty is what prevents the startup race: before the user's + * [BlossomServersEvent] (kind 10063) loads from cache/relay, [rawList] is empty and [merged] is the + * transient [DEFAULT_MEDIA_SERVERS] fallback. Resetting against that fallback would clobber the + * locally-saved pick on every launch. Only reset once a real, loaded list is in hand and it no + * longer contains the current pick (e.g. the user removed it from their list). + */ +fun resetTargetOrNull( + rawList: List, + merged: List, + current: ServerName, +): ServerName? = + if (rawList.isNotEmpty() && merged.none { it == current }) { + merged.firstOrNull() ?: DEFAULT_MEDIA_SERVERS[0] + } else { + null + } diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/nipBCOnchainZaps/OnchainWalletState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nipBCOnchainZaps/OnchainWalletState.kt similarity index 99% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/nipBCOnchainZaps/OnchainWalletState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nipBCOnchainZaps/OnchainWalletState.kt index 279510fb2f..2bff0602ec 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/nipBCOnchainZaps/OnchainWalletState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nipBCOnchainZaps/OnchainWalletState.kt @@ -31,12 +31,14 @@ import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import kotlin.concurrent.Volatile /** * A snapshot of the account's NIP-BC on-chain wallet: what is sitting on the diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/preferences/GeohashIdentitySecrets.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/preferences/GeohashIdentitySecrets.kt new file mode 100644 index 0000000000..22ddda8087 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/preferences/GeohashIdentitySecrets.kt @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.model.preferences + +/** + * The account's location-chat identity: the seed its per-geohash throwaway keys + * come from, and the handle it posts under. + * + * # Why this is not two more fields on [AccountSecrets] + * + * Every account save mirrors a whole [AccountSecrets], built field by field from + * `AccountSettings` — which does not hold these, because they are owned by + * `GeohashChatIdentityState` rather than by the settings object. Folding them in + * would make each save write null over them, and the group save uses + * `putOrRemove`, so null *deletes*. The seed would vanish on the next unrelated + * save and every geohash identity the user has would silently change. A separate + * group with its own save path cannot be wiped by a save that does not know + * about it. + * + * # Why encrypted + * + * The whole point of the seed is that the identities derived from it are + * unlinkable to the npub. Anyone who can read it can link every cell the user + * has ever posted in, to each other and to the device, which is exactly what the + * feature exists to prevent. It was in an encrypted file before; it stays in one. + */ +data class GeohashIdentitySecrets( + val deviceSeed: String? = null, + val nickname: String? = null, +) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/AssumedRelayListsState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/AssumedRelayListsState.kt similarity index 89% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/AssumedRelayListsState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/AssumedRelayListsState.kt index f2e6f30141..ab3d10afd1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/AssumedRelayListsState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/AssumedRelayListsState.kt @@ -18,14 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.serverList +package com.vitorpamplona.amethyst.commons.model.serverList -import com.vitorpamplona.amethyst.model.nip51Lists.indexerRelays.IndexerRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.searchRelays.SearchRelayListState -import com.vitorpamplona.amethyst.model.nip65RelayList.Nip65RelayListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.indexerRelays.IndexerRelayListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.searchRelays.SearchRelayListState +import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowListsState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/MergedFollowListsState.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowListsState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/MergedFollowListsState.kt index 29ad3470c2..f9a8ec6955 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowListsState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/MergedFollowListsState.kt @@ -18,21 +18,22 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.serverList +package com.vitorpamplona.amethyst.commons.model.serverList import androidx.compose.runtime.Immutable -import com.vitorpamplona.amethyst.model.nip02FollowLists.Kind3FollowListState -import com.vitorpamplona.amethyst.model.nip51Lists.followSets.FollowSetsState -import com.vitorpamplona.amethyst.model.nip51Lists.followSets.StarterPacksState -import com.vitorpamplona.amethyst.model.nip51Lists.geohashLists.GeohashListState -import com.vitorpamplona.amethyst.model.nip51Lists.interestLists.InterestListState -import com.vitorpamplona.amethyst.model.nip72Communities.CommunityListState +import com.vitorpamplona.amethyst.commons.model.nip02FollowLists.Kind3FollowListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.followSets.FollowSetsState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.followSets.StarterPacksState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.geohashLists.GeohashListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.interestLists.InterestListState +import com.vitorpamplona.amethyst.commons.model.nip72Communities.CommunityListState import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip72ModCommunities.follow.tags.CommunityTag import com.vitorpamplona.quartz.nip73ExternalIds.location.GeohashId import com.vitorpamplona.quartz.nip73ExternalIds.topics.HashtagId import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowPlusMineRelayListsState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/MergedFollowPlusMineRelayListsState.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowPlusMineRelayListsState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/MergedFollowPlusMineRelayListsState.kt index 6fd9937b59..9b4815637c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowPlusMineRelayListsState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/MergedFollowPlusMineRelayListsState.kt @@ -18,15 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.serverList +package com.vitorpamplona.amethyst.commons.model.serverList -import com.vitorpamplona.amethyst.model.edits.PrivateStorageRelayListState -import com.vitorpamplona.amethyst.model.localRelays.LocalRelayListState -import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowListOutboxOrProxyRelays -import com.vitorpamplona.amethyst.model.nip65RelayList.Nip65RelayListState +import com.vitorpamplona.amethyst.commons.model.edits.PrivateStorageRelayListState +import com.vitorpamplona.amethyst.commons.model.localRelays.LocalRelayListState +import com.vitorpamplona.amethyst.commons.model.nip02FollowLists.FollowListOutboxOrProxyRelays +import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowPlusMineWithIndexRelayListsState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/MergedFollowPlusMineWithIndexRelayListsState.kt similarity index 86% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowPlusMineWithIndexRelayListsState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/MergedFollowPlusMineWithIndexRelayListsState.kt index fe77f41867..4d3a1569cd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowPlusMineWithIndexRelayListsState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/MergedFollowPlusMineWithIndexRelayListsState.kt @@ -18,16 +18,17 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.serverList +package com.vitorpamplona.amethyst.commons.model.serverList -import com.vitorpamplona.amethyst.model.edits.PrivateStorageRelayListState -import com.vitorpamplona.amethyst.model.localRelays.LocalRelayListState -import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowListOutboxOrProxyRelays -import com.vitorpamplona.amethyst.model.nip51Lists.indexerRelays.IndexerRelayListState -import com.vitorpamplona.amethyst.model.nip65RelayList.Nip65RelayListState +import com.vitorpamplona.amethyst.commons.model.edits.PrivateStorageRelayListState +import com.vitorpamplona.amethyst.commons.model.localRelays.LocalRelayListState +import com.vitorpamplona.amethyst.commons.model.nip02FollowLists.FollowListOutboxOrProxyRelays +import com.vitorpamplona.amethyst.commons.model.nip51Lists.indexerRelays.IndexerRelayListState +import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowPlusMineWithSearchRelayListsState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/MergedFollowPlusMineWithSearchRelayListsState.kt similarity index 86% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowPlusMineWithSearchRelayListsState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/MergedFollowPlusMineWithSearchRelayListsState.kt index 07e8bfdb9f..05e276e0f1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowPlusMineWithSearchRelayListsState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/MergedFollowPlusMineWithSearchRelayListsState.kt @@ -18,16 +18,17 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.serverList +package com.vitorpamplona.amethyst.commons.model.serverList -import com.vitorpamplona.amethyst.model.edits.PrivateStorageRelayListState -import com.vitorpamplona.amethyst.model.localRelays.LocalRelayListState -import com.vitorpamplona.amethyst.model.nip02FollowLists.FollowListOutboxOrProxyRelays -import com.vitorpamplona.amethyst.model.nip51Lists.searchRelays.SearchRelayListState -import com.vitorpamplona.amethyst.model.nip65RelayList.Nip65RelayListState +import com.vitorpamplona.amethyst.commons.model.edits.PrivateStorageRelayListState +import com.vitorpamplona.amethyst.commons.model.localRelays.LocalRelayListState +import com.vitorpamplona.amethyst.commons.model.nip02FollowLists.FollowListOutboxOrProxyRelays +import com.vitorpamplona.amethyst.commons.model.nip51Lists.searchRelays.SearchRelayListState +import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/TrustedRelayListsState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/TrustedRelayListsState.kt similarity index 82% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/TrustedRelayListsState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/TrustedRelayListsState.kt index 96ce11bdf5..37e94a7fc8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/TrustedRelayListsState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/serverList/TrustedRelayListsState.kt @@ -18,20 +18,21 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.serverList +package com.vitorpamplona.amethyst.commons.model.serverList -import com.vitorpamplona.amethyst.model.edits.PrivateStorageRelayListState -import com.vitorpamplona.amethyst.model.localRelays.LocalRelayListState -import com.vitorpamplona.amethyst.model.nip17Dms.DmRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.broadcastRelays.BroadcastRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.indexerRelays.IndexerRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.proxyRelays.ProxyRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.searchRelays.SearchRelayListState -import com.vitorpamplona.amethyst.model.nip51Lists.trustedRelays.TrustedRelayListState -import com.vitorpamplona.amethyst.model.nip65RelayList.Nip65RelayListState +import com.vitorpamplona.amethyst.commons.model.edits.PrivateStorageRelayListState +import com.vitorpamplona.amethyst.commons.model.localRelays.LocalRelayListState +import com.vitorpamplona.amethyst.commons.model.nip17Dms.DmRelayListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.broadcastRelays.BroadcastRelayListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.indexerRelays.IndexerRelayListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.proxyRelays.ProxyRelayListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.searchRelays.SearchRelayListState +import com.vitorpamplona.amethyst.commons.model.nip51Lists.trustedRelays.TrustedRelayListState +import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/FeedTopNavFilterState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/FeedTopNavFilterState.kt similarity index 87% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/FeedTopNavFilterState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/FeedTopNavFilterState.kt index fbe2d07a80..3a78634afc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/FeedTopNavFilterState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/FeedTopNavFilterState.kt @@ -18,30 +18,30 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.topNavFeeds +package com.vitorpamplona.amethyst.commons.model.topNavFeeds +import com.vitorpamplona.amethyst.commons.model.algoFeeds.FavoriteAlgoFeedsOrchestrator import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.location.LocationResult +import com.vitorpamplona.amethyst.commons.model.nip02FollowLists.Kind3FollowListState +import com.vitorpamplona.amethyst.commons.model.serverList.MergedFollowListsState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.FeedDecryptionCaches import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedFlowsType import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter +import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allFollows.AllFollowsFeedFlow +import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows.AllUserFollowsFeedFlow +import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows.Kind3UserFollowsFeedFlow +import com.vitorpamplona.amethyst.commons.model.topNavFeeds.aroundMe.AroundMeFeedFlow import com.vitorpamplona.amethyst.commons.model.topNavFeeds.aroundMe.GeohashFeedFlow +import com.vitorpamplona.amethyst.commons.model.topNavFeeds.favoriteAlgoFeeds.AllFavoriteAlgoFeedsFlow +import com.vitorpamplona.amethyst.commons.model.topNavFeeds.favoriteAlgoFeeds.FavoriteAlgoFeedFlow import com.vitorpamplona.amethyst.commons.model.topNavFeeds.global.GlobalFeedFlow import com.vitorpamplona.amethyst.commons.model.topNavFeeds.hashtag.HashtagFeedFlow import com.vitorpamplona.amethyst.commons.model.topNavFeeds.hashtag.MultiHashtagFeedFlow import com.vitorpamplona.amethyst.commons.model.topNavFeeds.mine.MineFeedFlow import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.NoteFeedFlow import com.vitorpamplona.amethyst.commons.model.topNavFeeds.relay.RelayFeedFlow -import com.vitorpamplona.amethyst.model.algoFeeds.FavoriteAlgoFeedsOrchestrator -import com.vitorpamplona.amethyst.model.nip02FollowLists.Kind3FollowListState -import com.vitorpamplona.amethyst.model.serverList.MergedFollowListsState -import com.vitorpamplona.amethyst.model.topNavFeeds.allFollows.AllFollowsFeedFlow -import com.vitorpamplona.amethyst.model.topNavFeeds.allUserFollows.AllUserFollowsFeedFlow -import com.vitorpamplona.amethyst.model.topNavFeeds.allUserFollows.Kind3UserFollowsFeedFlow -import com.vitorpamplona.amethyst.model.topNavFeeds.aroundMe.AroundMeFeedFlow -import com.vitorpamplona.amethyst.model.topNavFeeds.favoriteAlgoFeeds.AllFavoriteAlgoFeedsFlow -import com.vitorpamplona.amethyst.model.topNavFeeds.favoriteAlgoFeeds.FavoriteAlgoFeedFlow -import com.vitorpamplona.amethyst.service.location.LocationState import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.normalizeRelayUrl @@ -49,6 +49,7 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -62,7 +63,7 @@ class FeedTopNavFilterState( val feedFilterListName: MutableStateFlow, val kind3Follows: StateFlow, val allFollows: StateFlow, - val locationFlow: () -> StateFlow, + val locationFlow: () -> StateFlow, val followsRelays: StateFlow>, val blockedRelays: StateFlow>, val proxyRelays: StateFlow>, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsFeedFlow.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/allFollows/AllFollowsFeedFlow.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsFeedFlow.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/allFollows/AllFollowsFeedFlow.kt index ff6e40d15e..90d93bf41f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsFeedFlow.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/allFollows/AllFollowsFeedFlow.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.topNavFeeds.allFollows +package com.vitorpamplona.amethyst.commons.model.topNavFeeds.allFollows +import com.vitorpamplona.amethyst.commons.model.serverList.MergedFollowListsState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedFlowsType import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allFollows.AllFollowsByOutboxTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allFollows.AllFollowsByProxyTopNavFilter -import com.vitorpamplona.amethyst.model.serverList.MergedFollowListsState import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.StateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allUserFollows/AllUserFollowsFeedFlow.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/allUserFollows/AllUserFollowsFeedFlow.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allUserFollows/AllUserFollowsFeedFlow.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/allUserFollows/AllUserFollowsFeedFlow.kt index 63b2a8ee4d..8635189a1a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allUserFollows/AllUserFollowsFeedFlow.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/allUserFollows/AllUserFollowsFeedFlow.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.topNavFeeds.allUserFollows +package com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows +import com.vitorpamplona.amethyst.commons.model.serverList.MergedFollowListsState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedFlowsType import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows.AllUserFollowsByOutboxTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows.AllUserFollowsByProxyTopNavFilter -import com.vitorpamplona.amethyst.model.serverList.MergedFollowListsState import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.StateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allUserFollows/Kind3UserFollowsFeedFlow.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/allUserFollows/Kind3UserFollowsFeedFlow.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allUserFollows/Kind3UserFollowsFeedFlow.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/allUserFollows/Kind3UserFollowsFeedFlow.kt index e6dd1c5d8b..5b95f4d6a5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allUserFollows/Kind3UserFollowsFeedFlow.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/allUserFollows/Kind3UserFollowsFeedFlow.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.topNavFeeds.allUserFollows +package com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows +import com.vitorpamplona.amethyst.commons.model.nip02FollowLists.Kind3FollowListState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedFlowsType import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows.AllUserFollowsByOutboxTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.allUserFollows.AllUserFollowsByProxyTopNavFilter -import com.vitorpamplona.amethyst.model.nip02FollowLists.Kind3FollowListState import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.StateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/aroundMe/AroundMeFeedFlow.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/aroundMe/AroundMeFeedFlow.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/aroundMe/AroundMeFeedFlow.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/aroundMe/AroundMeFeedFlow.kt index a7a421eb48..bb3d6d035c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/aroundMe/AroundMeFeedFlow.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/aroundMe/AroundMeFeedFlow.kt @@ -18,29 +18,29 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.topNavFeeds.aroundMe +package com.vitorpamplona.amethyst.commons.model.topNavFeeds.aroundMe +import com.vitorpamplona.amethyst.commons.model.location.LocationResult import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedFlowsType import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.aroundMe.LocationTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.aroundMe.compute50kmRange -import com.vitorpamplona.amethyst.service.location.LocationState import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine class AroundMeFeedFlow( - val location: StateFlow, + val location: StateFlow, val outboxRelays: StateFlow>, val proxyRelays: StateFlow>, ) : IFeedFlowsType { fun convert( - result: LocationState.LocationResult, + result: LocationResult, outboxRelays: Set, proxyRelays: Set, ): LocationTopNavFilter = - if (result is LocationState.LocationResult.Success) { + if (result is LocationResult.Success) { // 2 neighbors deep = 25x25km LocationTopNavFilter( geotags = compute50kmRange(result.geoHash).toSet(), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteAlgoFeeds/AllFavoriteAlgoFeedsFlow.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/favoriteAlgoFeeds/AllFavoriteAlgoFeedsFlow.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteAlgoFeeds/AllFavoriteAlgoFeedsFlow.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/favoriteAlgoFeeds/AllFavoriteAlgoFeedsFlow.kt index 0745c7dde7..6dbda190bb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteAlgoFeeds/AllFavoriteAlgoFeedsFlow.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/favoriteAlgoFeeds/AllFavoriteAlgoFeedsFlow.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.topNavFeeds.favoriteAlgoFeeds +package com.vitorpamplona.amethyst.commons.model.topNavFeeds.favoriteAlgoFeeds +import com.vitorpamplona.amethyst.commons.model.algoFeeds.FavoriteAlgoFeedsOrchestrator +import com.vitorpamplona.amethyst.commons.model.algoFeeds.FavoriteAlgoFeedsSnapshot import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedFlowsType import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.favoriteAlgoFeeds.AllFavoriteAlgoFeedsTopNavFilter -import com.vitorpamplona.amethyst.model.algoFeeds.FavoriteAlgoFeedsOrchestrator -import com.vitorpamplona.amethyst.model.algoFeeds.FavoriteAlgoFeedsSnapshot import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.ExperimentalCoroutinesApi diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteAlgoFeeds/FavoriteAlgoFeedFlow.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/favoriteAlgoFeeds/FavoriteAlgoFeedFlow.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteAlgoFeeds/FavoriteAlgoFeedFlow.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/favoriteAlgoFeeds/FavoriteAlgoFeedFlow.kt index caf884be4f..cb36cf5992 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/favoriteAlgoFeeds/FavoriteAlgoFeedFlow.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/favoriteAlgoFeeds/FavoriteAlgoFeedFlow.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.topNavFeeds.favoriteAlgoFeeds +package com.vitorpamplona.amethyst.commons.model.topNavFeeds.favoriteAlgoFeeds +import com.vitorpamplona.amethyst.commons.model.algoFeeds.FavoriteAlgoFeedsOrchestrator import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedFlowsType import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.favoriteAlgoFeeds.FavoriteAlgoFeedTopNavFilter -import com.vitorpamplona.amethyst.model.algoFeeds.FavoriteAlgoFeedsOrchestrator import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.flow.Flow @@ -43,7 +43,7 @@ class FavoriteAlgoFeedFlow( ): Set = if (proxy.isNotEmpty()) proxy else outbox private fun buildFilter( - snapshot: com.vitorpamplona.amethyst.model.algoFeeds.FavoriteAlgoFeedsSnapshot, + snapshot: com.vitorpamplona.amethyst.commons.model.algoFeeds.FavoriteAlgoFeedsSnapshot, contentRelays: Set, ) = FavoriteAlgoFeedTopNavFilter( feedAddress = feedAddress, diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/mine/MineFeedFlow.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/mine/MineFeedFlow.kt index 1233fc4b49..ab9e76e994 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/mine/MineFeedFlow.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/topNavFeeds/mine/MineFeedFlow.kt @@ -33,7 +33,7 @@ import kotlinx.coroutines.flow.map /** * Resolves the "Mine" top-nav selection to an author filter scoped to the logged-in user's own * pubkey, pinned to the user's own relays — their outbox, private-storage, local and proxy relays - * (see [com.vitorpamplona.amethyst.model.nip01UserMetadata.AccountMineRelayState]). Unlike the + * (see [com.vitorpamplona.amethyst.commons.model.nip01UserMetadata.AccountMineRelayState]). Unlike the * follow filters, "Mine" doesn't need per-author outbox resolution from cache: the only author is * the user, and the user's relays are already known from their own account state — so we pin the * fixed set directly via [AuthorsByProxyTopNavFilter] (it associates each given relay with the diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/trustedAssertions/TrustProviderListState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/trustedAssertions/TrustProviderListState.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/trustedAssertions/TrustProviderListState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/trustedAssertions/TrustProviderListState.kt index 80f88da3cf..d7f1966968 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/trustedAssertions/TrustProviderListState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/trustedAssertions/TrustProviderListState.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.trustedAssertions +package com.vitorpamplona.amethyst.commons.model.trustedAssertions +import com.vitorpamplona.amethyst.commons.model.AccountSettings import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip85TrustedAssertions.TrustProviderListDecryptionCache -import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip85TrustedAssertions.list.TrustProviderListEvent import com.vitorpamplona.quartz.nip85TrustedAssertions.list.tags.ProviderTypes @@ -34,6 +34,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/dal/MusicPlaylistsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/music/dal/MusicPlaylistsFeedFilter.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/dal/MusicPlaylistsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/music/dal/MusicPlaylistsFeedFilter.kt index 818d11805d..7bb515d356 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/dal/MusicPlaylistsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/music/dal/MusicPlaylistsFeedFilter.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.music.dal +package com.vitorpamplona.amethyst.commons.music.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.music.playlist.MusicPlaylistEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/dal/MusicTracksFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/music/dal/MusicTracksFeedFilter.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/dal/MusicTracksFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/music/dal/MusicTracksFeedFilter.kt index f0de10a463..0d5383fa43 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/dal/MusicTracksFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/music/dal/MusicTracksFeedFilter.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.music.dal +package com.vitorpamplona.amethyst.commons.music.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.music.track.MusicTrackEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/dal/NestsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nests/dal/NestsFeedFilter.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/dal/NestsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nests/dal/NestsFeedFilter.kt index 85a35951f6..03e011f772 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/dal/NestsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nests/dal/NestsFeedFilter.kt @@ -18,10 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.dal +package com.vitorpamplona.amethyst.commons.nests.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.ParticipantListBuilder import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -34,7 +35,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.model.Account import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.tags.StatusTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedContentState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/notifications/CardFeedContentState.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedContentState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/notifications/CardFeedContentState.kt index 09e15458df..7fdd14bc57 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedContentState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/notifications/CardFeedContentState.kt @@ -18,32 +18,34 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications +package com.vitorpamplona.amethyst.commons.notifications -import androidx.compose.runtime.Immutable import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable import androidx.compose.runtime.mutableStateOf import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.Card +import com.vitorpamplona.amethyst.commons.feeds.CardFeedState import com.vitorpamplona.amethyst.commons.feeds.FeedFilter import com.vitorpamplona.amethyst.commons.feeds.InvalidatableContent import com.vitorpamplona.amethyst.commons.feeds.LoadedFeedState +import com.vitorpamplona.amethyst.commons.feeds.NotificationFeedOrderCard +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.model.CombinedZap import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.buzz.BuzzChannelInvite import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.LocalCache.getNoteIfExists import com.vitorpamplona.amethyst.commons.model.marmotGroups.MarmotGroupChatroom +import com.vitorpamplona.amethyst.commons.notifications.dal.NotificationFeedFilter +import com.vitorpamplona.amethyst.commons.search.calendar.LocalClock import com.vitorpamplona.amethyst.commons.service.BundledInsert import com.vitorpamplona.amethyst.commons.service.BundledUpdate -import com.vitorpamplona.amethyst.commons.ui.notifications.Card -import com.vitorpamplona.amethyst.commons.ui.notifications.CardFeedState +import com.vitorpamplona.amethyst.commons.util.KmpLock import com.vitorpamplona.amethyst.commons.util.equalImmutableLists -import com.vitorpamplona.amethyst.logTime -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.ui.dal.NotificationFeedOrderCard -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.dal.NotificationFeedFilter +import com.vitorpamplona.amethyst.commons.util.logTime +import com.vitorpamplona.amethyst.commons.util.withLock import com.vitorpamplona.quartz.buzz.notifications.MemberAddedNotificationEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip04Dm.messages.EncryptedDmEvent @@ -62,11 +64,10 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -import java.time.Instant -import java.time.ZoneId @Stable class CardFeedContentState( @@ -116,9 +117,13 @@ class CardFeedContentState( viewModelScope.launch(Dispatchers.IO) { refreshSuspended() } } - @Synchronized - private fun refreshSuspended() { - checkNotInMainThread() + // Refreshes can arrive from several IO coroutines at once; they must not interleave. + private val refreshLock = KmpLock() + + private fun refreshSuspended() = refreshLock.withLock { refreshLocked() } + + private fun refreshLocked() { + LocalCache.appHost.assertNotMainThread() try { isRefreshing.value = true @@ -165,7 +170,7 @@ class CardFeedContentState( } private fun convertToCard(notes: Collection): List { - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() val reactionsPerEvent = mutableMapOf>() notes @@ -274,14 +279,9 @@ class CardFeedContentState( // gives identical buckets and chronological ordering while avoiding a // DateTimeFormatter + ZonedDateTime + String allocation for every single // reaction/zap/repost — a meaningful GC saving on full feed conversions. - val zone = ZoneId.systemDefault() + val dayCounter = LocalClock.epochDayCounter() - fun epochDay(createdAt: Long?): Long = - Instant - .ofEpochSecond(createdAt ?: 0L) - .atZone(zone) - .toLocalDate() - .toEpochDay() + fun epochDay(createdAt: Long?): Long = dayCounter.epochDay(createdAt ?: 0L) val allBaseNotes = zapsPerEvent.keys + boostsPerEvent.keys + reactionsPerEvent.keys + nutzapsPerEvent.keys val multiCards = @@ -502,7 +502,7 @@ class CardFeedContentState( bundler.invalidate(ignoreIfDoing) { // adds the time to perform the refresh into this delay // holding off new updates in case of heavy refresh routines. - logTime("${this.javaClass.simpleName} Card update") { refreshSuspended() } + logTime("${this::class.simpleName} Card update") { refreshSuspended() } } } @@ -511,7 +511,7 @@ class CardFeedContentState( bundler.invalidate(ignoreIfDoing) { // adds the time to perform the refresh into this delay // holding off new updates in case of heavy refresh routines. - logTime("${this.javaClass.simpleName} Card update") { + logTime("${this::class.simpleName} Card update") { refreshSuspended() sendToTop() } @@ -524,7 +524,7 @@ class CardFeedContentState( bundler.invalidate(false) { // adds the time to perform the refresh into this delay // holding off new updates in case of heavy refresh routines. - logTime("${this.javaClass.simpleName} Card update: checkKeysInvalidateDataAndSendToTop") { + logTime("${this::class.simpleName} Card update: checkKeysInvalidateDataAndSendToTop") { refreshSuspended() sendToTop() } @@ -535,7 +535,7 @@ class CardFeedContentState( fun invalidateInsertData(newItems: Set) { bundlerInsert.invalidateList(newItems) { val newObjects = it.flattenToSet() - logTime("${this.javaClass.simpleName} Card additive receiving ${newObjects.size} items into ${it.size} items") { + logTime("${this::class.simpleName} Card additive receiving ${newObjects.size} items into ${it.size} items") { if (newObjects.isNotEmpty()) { refreshFromOldState(newObjects) } @@ -544,7 +544,7 @@ class CardFeedContentState( } fun updateFeedWith(newNotes: Set) { - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() if (localFilter is AdditiveFeedFilter && _feedContent.value is CardFeedState.Loaded) { invalidateInsertData(newNotes) @@ -560,21 +560,11 @@ class CardFeedContentState( } fun destroy() { - Log.d("Init") { "OnCleared: ${this.javaClass.simpleName}" } + Log.d("Init") { "OnCleared: ${this::class.simpleName}" } clear() bundlerInsert.cancel() bundler.cancel() } } -@Immutable -data class CombinedZap( - val request: Note, - val response: Note, -) { - fun createdAt() = response.createdAt() - - fun idHex() = response.idHex -} - private fun Note.isInMarmotGroup(): Boolean = inGatherers?.any { it is MarmotGroupChatroom } == true diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/notifications/CardFeedState.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/notifications/CardFeedState.kt index 130e84f7b1..97f9469312 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/notifications/CardFeedState.kt @@ -18,14 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications +package com.vitorpamplona.amethyst.commons.notifications import androidx.compose.runtime.Immutable +import com.vitorpamplona.amethyst.commons.feeds.Card +import com.vitorpamplona.amethyst.commons.model.CombinedZap import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.buzz.BuzzChannelInvite -import com.vitorpamplona.amethyst.commons.ui.notifications.Card import com.vitorpamplona.amethyst.commons.util.firstFullCharOrEmoji import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -134,7 +135,7 @@ class MessageSetCard( * "Somebody added you to a channel" — a relay-signed kind-44100 that is still unanswered, carrying the * [invite] the projection resolved it to (who did it, which channel, on which relay). * - * A question rather than a dated event, so [com.vitorpamplona.amethyst.ui.dal.NotificationFeedOrderCard] + * A question rather than a dated event, so [com.vitorpamplona.amethyst.commons.feeds.NotificationFeedOrderCard] * sorts these ahead of everything else instead of letting an old one sink into history. It still holds * its [note], so it dedups, scrolls-to and pages exactly like every other card. */ diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/OpenPollsState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/notifications/OpenPollsState.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/OpenPollsState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/notifications/OpenPollsState.kt index 7fd01ec4fe..5eb81aa5b6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/OpenPollsState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/notifications/OpenPollsState.kt @@ -18,17 +18,18 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications +package com.vitorpamplona.amethyst.commons.notifications import androidx.compose.runtime.Stable +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.delay import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/notifications/dal/NotificationFeedFilter.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/notifications/dal/NotificationFeedFilter.kt index 0a79bfd44a..bdb807d287 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/notifications/dal/NotificationFeedFilter.kt @@ -18,10 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.dal +package com.vitorpamplona.amethyst.commons.notifications.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -31,8 +33,6 @@ import com.vitorpamplona.amethyst.commons.model.isMutedPublicChatMessage import com.vitorpamplona.amethyst.commons.model.marmotGroups.MarmotGroupChatroom import com.vitorpamplona.amethyst.commons.model.topNavFeeds.IFeedTopNavFilter import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.buzz.jobs.JobErrorEvent import com.vitorpamplona.quartz.buzz.jobs.JobResultEvent import com.vitorpamplona.quartz.buzz.notifications.MemberAddedNotificationEvent @@ -479,7 +479,7 @@ class NotificationFeedFilter( * * Without it a reply to my message in a Buzz channel notifies nothing — and since a thread reply is * deliberately kept out of the channel timeline and its unread dot - * ([com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.isRelayGroupTimelineMessage]), + * ([com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.isRelayGroupTimelineMessage]), * it would be invisible on every surface. * * Only consulted when there is no `p` tag: a reply that does name me already passes the p-tag gate. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/dal/PictureFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/pictures/dal/PictureFeedFilter.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/dal/PictureFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/pictures/dal/PictureFeedFilter.kt index 39280f161a..6ec942a55d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/dal/PictureFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/pictures/dal/PictureFeedFilter.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.pictures.dal +package com.vitorpamplona.amethyst.commons.pictures.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip68Picture.PictureEvent class PictureFeedFilter( diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/podcasts/PreviewTextFetch.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/podcasts/PreviewTextFetch.kt new file mode 100644 index 0000000000..9dd9427f85 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/podcasts/PreviewTextFetch.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.podcasts + +import com.vitorpamplona.amethyst.commons.service.http.IRoleBasedHttpClientBuilder + +/** + * GETs a small text document (a Podcasting-2.0 chapters or transcript file) over the preview + * client for [url], or null on any failure or an oversized body. The iOS actual has no HTTP + * client yet and always returns null. + */ +expect suspend fun IRoleBasedHttpClientBuilder.fetchPreviewText(url: String): String? diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/dal/PodcastEpisodesFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/podcasts/dal/PodcastEpisodesFeedFilter.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/dal/PodcastEpisodesFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/podcasts/dal/PodcastEpisodesFeedFilter.kt index 4c816f5ece..1e317c6be4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/dal/PodcastEpisodesFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/podcasts/dal/PodcastEpisodesFeedFilter.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.dal +package com.vitorpamplona.amethyst.commons.podcasts.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nipXXPodcasting20.episode.Podcasting20EpisodeEvent import com.vitorpamplona.quartz.podcasts.PodcastEpisode diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/dal/PodcastsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/podcasts/dal/PodcastsFeedFilter.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/dal/PodcastsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/podcasts/dal/PodcastsFeedFilter.kt index 2092b73e6f..b4e972f5f4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/dal/PodcastsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/podcasts/dal/PodcastsFeedFilter.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.dal +package com.vitorpamplona.amethyst.commons.podcasts.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip78AppData.AppSpecificDataEvent import com.vitorpamplona.quartz.nipF4Podcasts.metadata.PodcastMetadataEvent import com.vitorpamplona.quartz.nipXXPodcasting20.metadata.isPodcastShowEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/dal/ClosedPollsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/polls/dal/ClosedPollsFeedFilter.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/dal/ClosedPollsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/polls/dal/ClosedPollsFeedFilter.kt index f1a3215b9f..4a05bf451b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/dal/ClosedPollsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/polls/dal/ClosedPollsFeedFilter.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.polls.dal +package com.vitorpamplona.amethyst.commons.polls.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/dal/OpenPollsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/polls/dal/OpenPollsFeedFilter.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/dal/OpenPollsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/polls/dal/OpenPollsFeedFilter.kt index c4ff649bfe..78cc711e04 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/dal/OpenPollsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/polls/dal/OpenPollsFeedFilter.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.polls.dal +package com.vitorpamplona.amethyst.commons.polls.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/dal/PollsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/polls/dal/PollsFeedFilter.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/dal/PollsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/polls/dal/PollsFeedFilter.kt index 97af35782c..1825e2521b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/dal/PollsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/polls/dal/PollsFeedFilter.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.polls.dal +package com.vitorpamplona.amethyst.commons.polls.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/preview/UrlInfoItem.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/preview/UrlInfoItem.kt similarity index 92% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/preview/UrlInfoItem.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/preview/UrlInfoItem.kt index 68c040e065..5cb955845d 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/preview/UrlInfoItem.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/preview/UrlInfoItem.kt @@ -23,7 +23,8 @@ package com.vitorpamplona.amethyst.commons.preview import androidx.compose.runtime.Immutable import com.vitorpamplona.amethyst.commons.richtext.MediaContentKind import com.vitorpamplona.amethyst.commons.richtext.RichTextParser -import java.net.URI +import com.vitorpamplona.amethyst.commons.util.absoluteUrlHost +import com.vitorpamplona.amethyst.commons.util.resolveHttpUrl @Immutable class UrlInfoItem( @@ -43,7 +44,8 @@ class UrlInfoItem( /** `og:type` — what the page says it is, e.g. `music.song`, `video.other`, `article`. */ val type: String = "", ) { - val verifiedUrl = runCatching { URI(url).toURL() }.getOrNull() + /** The page's host, or null when [url] is not an absolute URL. */ + val verifiedHost = absoluteUrlHost(url) /** * Resolves an OpenGraph URL against the page's own address, or null when it cannot be made @@ -57,17 +59,7 @@ class UrlInfoItem( */ private fun resolve(path: String): String? { if (path.isBlank()) return null - return runCatching { - val base = verifiedUrl?.toURI() - val resolved = if (base != null) base.resolve(path) else URI(path) - if (!resolved.scheme.equals("http", ignoreCase = true) && - !resolved.scheme.equals("https", ignoreCase = true) - ) { - null - } else { - resolved.toURL().toString() - } - }.getOrNull() + return resolveHttpUrl(url.takeIf { verifiedHost != null }, path) } // Falls back to the raw value so an unresolvable image degrades to "the loader shows nothing", diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/dal/ProductsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/products/dal/ProductsFeedFilter.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/dal/ProductsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/products/dal/ProductsFeedFilter.kt index 70c485d6c3..3628fbbb36 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/products/dal/ProductsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/products/dal/ProductsFeedFilter.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.products.dal +package com.vitorpamplona.amethyst.commons.products.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent class ProductsFeedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/dal/PublicChatsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/publicChats/dal/PublicChatsFeedFilter.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/dal/PublicChatsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/publicChats/dal/PublicChatsFeedFilter.kt index ac88e54778..77614ec4b5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/publicChats/dal/PublicChatsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/publicChats/dal/PublicChatsFeedFilter.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.publicChats.dal +package com.vitorpamplona.amethyst.commons.publicChats.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent import com.vitorpamplona.quartz.nip28PublicChat.base.IsInPublicChatChannel diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/InMemoryRelayAuthPermissionStore.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/InMemoryRelayAuthPermissionStore.kt index 18d29b2e39..dd36e952fc 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/InMemoryRelayAuthPermissionStore.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/InMemoryRelayAuthPermissionStore.kt @@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthDecision import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthPermissionStore /** - * Volatile, non-persistent [RelayAuthPermissionStore]. Used as the default for [com.vitorpamplona.amethyst.model.Account] + * Volatile, non-persistent [RelayAuthPermissionStore]. Used as the default for [com.vitorpamplona.amethyst.commons.model.Account] * instances built without a disk-backed store (Compose previews, unit tests, the mock account view * models) so nothing on the auth path has to null-check the store. */ diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthPermissionCache.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthPermissionCache.kt index efbae3a8b9..c795b1b574 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthPermissionCache.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthPermissionCache.kt @@ -34,7 +34,7 @@ import kotlinx.coroutines.launch /** * In-memory, warm-cached view over one account's [RelayAuthPermissionStore] (a per-account file — * see the Android `DataStoreRelayAuthPermissionStore` built from `accounts//`). Held on the - * [com.vitorpamplona.amethyst.model.Account] like the other state caches. + * [com.vitorpamplona.amethyst.commons.model.Account] like the other state caches. * * The ALLOW/DENY overrides are the only thing read on the hot NIP-42 decision path * ([RelayAuthPermissionLedger.decide]). They are snapshotted into memory once, right after the diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthPermissionLedger.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthPermissionLedger.kt index 20ab8d73b8..993d45a545 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthPermissionLedger.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthPermissionLedger.kt @@ -57,7 +57,7 @@ class RelayAuthPermissionLedger( * * Required, with no default, because it is shared state: one account's grants have to be the * same object on every AUTH path (the foreground screen and the background notification - * consumer both decide off this ledger — see [com.vitorpamplona.amethyst.model.Account]). A + * consumer both decide off this ledger — see [com.vitorpamplona.amethyst.commons.model.Account]). A * default would let a ledger built without one quietly get a private set instead, so answers * given on one path would not be seen on the other and the dialog would come back anyway. */ diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthPromptBus.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthPromptBus.kt index 32036f7945..03c24c9773 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthPromptBus.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthPromptBus.kt @@ -57,7 +57,7 @@ enum class UserAuthChoice { * Do not authenticate, and switch the asking account's top-level policy to * [RelayAuthPolicy.NEVER], so no relay is ever * answered again. The account-wide counterpart of [BLOCK], confirmed the same way — and, like - * every route through [com.vitorpamplona.amethyst.model.Account.changeDefaultRelayAuthPolicy], + * every route through [com.vitorpamplona.amethyst.commons.model.Account.changeDefaultRelayAuthPolicy], * it drops this run's session grants, which would otherwise outrank the policy it just set. */ NEVER_ALLOW_EVERYWHERE, diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthSessionGrants.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthSessionGrants.kt index 8b0381126a..809824009c 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthSessionGrants.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthSessionGrants.kt @@ -37,7 +37,7 @@ import kotlinx.coroutines.flow.update * as long as the user is plausibly still doing the thing they answered for. * * Deliberately **not** persisted: it is dropped when the process dies (this object lives on - * [com.vitorpamplona.amethyst.model.Account], which is built per process) and when the account is + * [com.vitorpamplona.amethyst.commons.model.Account], which is built per process) and when the account is * logged out, so the next cold start asks again. That is the whole difference from * [com.vitorpamplona.amethyst.commons.relayauth.RelayAuthDecision.ALLOW], which the "remember" * switch writes to disk. diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthVenues.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthVenues.kt index 5a0d3bdc06..970db9bd77 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthVenues.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/auth/RelayAuthVenues.kt @@ -33,7 +33,7 @@ import com.vitorpamplona.quartz.nip29RelayGroups.GroupId * other signal in the auth path — a NIP-29 group's content is `#h`-scoped and never names the user, * and a Concord plane is authored by and addressed to derived stream keys — so this is what feeds * them to [RelayAuthPermissionLedger] and [RelayAuthFirstParty]. Pure, so the id/url matching is - * testable without an [com.vitorpamplona.amethyst.model.Account]. + * testable without an [com.vitorpamplona.amethyst.commons.model.Account]. * * Everything here is per account, deliberately: these lists come off *this* account's own list events, * so one account's rooms can never grant another account's identity away. That rules out the diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/eoseManagers/ChatFeedToggle.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/eoseManagers/ChatFeedToggle.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/eoseManagers/ChatFeedToggle.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/eoseManagers/ChatFeedToggle.kt index 0e2b0e7b7e..7f0e72d6ff 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/eoseManagers/ChatFeedToggle.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/eoseManagers/ChatFeedToggle.kt @@ -18,12 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.eoseManagers +package com.vitorpamplona.amethyst.commons.relayClient.eoseManagers +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType -import com.vitorpamplona.amethyst.model.Account import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.drop diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/eoseManagers/DmRelayLog.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/eoseManagers/DmRelayLog.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/eoseManagers/DmRelayLog.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/eoseManagers/DmRelayLog.kt index 39d1370a16..3e88a482f6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/eoseManagers/DmRelayLog.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/eoseManagers/DmRelayLog.kt @@ -18,9 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.eoseManagers +package com.vitorpamplona.amethyst.commons.relayClient.eoseManagers -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.utils.Log diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/BackwardRelayPager.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/BackwardRelayPager.kt similarity index 98% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/BackwardRelayPager.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/BackwardRelayPager.kt index a38dc61050..4035d76f16 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/BackwardRelayPager.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/BackwardRelayPager.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.amethyst.commons.relayClient.paging import com.vitorpamplona.amethyst.commons.model.privateChats.DmHistoryTuning +import com.vitorpamplona.amethyst.commons.util.ConcurrentSet import com.vitorpamplona.quartz.nip01Core.relay.client.paging.RelayLoadingCursors import com.vitorpamplona.quartz.nip01Core.relay.client.paging.RelayPagingProgress import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @@ -30,7 +31,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow -import java.util.concurrent.ConcurrentHashMap +import kotlin.concurrent.Volatile /** * Atomic snapshot of a [BackwardRelayPager]'s display state. Every field is recomputed together in one @@ -110,7 +111,7 @@ class BackwardRelayPager( // Relays not advancing for the active scope (auth CLOSE / unreachable / silent). Transient: cleared // and recomputed on each [bind]; a stalled relay is kept (its sub stays open) and retried on advance. - private val stalledRelays = ConcurrentHashMap.newKeySet() + private val stalledRelays = ConcurrentSet() /** * True while any relay is mid-page. Starts false (an idle engine isn't "loading"). Kept apart from diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/PerRelayLoadTracker.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/PerRelayLoadTracker.kt similarity index 82% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/PerRelayLoadTracker.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/PerRelayLoadTracker.kt index 732b6d1917..3e1e2038fa 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/PerRelayLoadTracker.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/PerRelayLoadTracker.kt @@ -20,6 +20,9 @@ */ package com.vitorpamplona.amethyst.commons.relayClient.paging +import com.vitorpamplona.amethyst.commons.util.ConcurrentSet +import com.vitorpamplona.amethyst.commons.util.KmpLock +import com.vitorpamplona.amethyst.commons.util.withLock import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils @@ -31,7 +34,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.isActive import kotlinx.coroutines.launch -import java.util.concurrent.ConcurrentHashMap +import kotlin.concurrent.Volatile /** * Tracks which relays currently have a demand-driven history page **in flight**, so a caller can show a @@ -58,7 +61,10 @@ class PerRelayLoadTracker( private val _loading = MutableStateFlow(false) val loading: StateFlow = _loading.asStateFlow() - private val inFlight = ConcurrentHashMap.newKeySet() + // Guards the advance / settle / reset transitions, as the JVM monitor behind @Synchronized did. + private val lock = KmpLock() + + private val inFlight = ConcurrentSet() @Volatile private var lastActivityMs = 0L @@ -82,14 +88,15 @@ class PerRelayLoadTracker( fun count() = inFlight.size /** A relay's next page was just requested. Raises the spinner and (re)arms the silence watchdog. */ - @Synchronized fun onAdvance(relay: NormalizedRelayUrl) { - clearJob?.cancel() // a new page is starting — keep the spinner up, no flicker - clearJob = null - inFlight.add(relay) - lastActivityMs = TimeUtils.nowMillis() - _loading.value = true - ensureWatchdog() + lock.withLock { + clearJob?.cancel() // a new page is starting — keep the spinner up, no flicker + clearJob = null + inFlight.add(relay) + lastActivityMs = TimeUtils.nowMillis() + _loading.value = true + ensureWatchdog() + } } /** A sign of life from a relay (an event). Keeps the silence watchdog from firing. */ @@ -104,10 +111,11 @@ class PerRelayLoadTracker( * of flickering it off for the few ms between pages. The linger is cancelled the moment a new page * starts ([onAdvance]). */ - @Synchronized fun onSettled(relay: NormalizedRelayUrl) { - lastActivityMs = TimeUtils.nowMillis() - if (inFlight.remove(relay) && inFlight.isEmpty()) scheduleClear() + lock.withLock { + lastActivityMs = TimeUtils.nowMillis() + if (inFlight.remove(relay) && inFlight.isEmpty()) scheduleClear() + } } private fun scheduleClear() { @@ -120,21 +128,22 @@ class PerRelayLoadTracker( clearJob = s.launch { delay(LOADING_LINGER_MS) - synchronized(this@PerRelayLoadTracker) { + lock.withLock { if (inFlight.isEmpty()) _loading.value = false } } } /** Drops everything (e.g. the bound scope switched). */ - @Synchronized fun reset() { - inFlight.clear() - clearJob?.cancel() - clearJob = null - _loading.value = false - watchdog?.cancel() - watchdog = null + lock.withLock { + inFlight.clear() + clearJob?.cancel() + clearJob = null + _loading.value = false + watchdog?.cancel() + watchdog = null + } } private fun ensureWatchdog() { @@ -145,9 +154,9 @@ class PerRelayLoadTracker( while (isActive) { delay(WATCHDOG_TICK_MS) val silenced = - synchronized(this@PerRelayLoadTracker) { - if (inFlight.isNotEmpty() && TimeUtils.nowMillis() - lastActivityMs > silenceMs) { - val pending = inFlight.toSet() + lock.withLock { + if (!inFlight.isEmpty() && TimeUtils.nowMillis() - lastActivityMs > silenceMs) { + val pending = inFlight.snapshot() inFlight.clear() _loading.value = false pending diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/WindowLoadTracker.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/WindowLoadTracker.kt similarity index 74% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/WindowLoadTracker.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/WindowLoadTracker.kt index 80837de516..2ebd4c362d 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/WindowLoadTracker.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/paging/WindowLoadTracker.kt @@ -20,6 +20,9 @@ */ package com.vitorpamplona.amethyst.commons.relayClient.paging +import com.vitorpamplona.amethyst.commons.util.ConcurrentSet +import com.vitorpamplona.amethyst.commons.util.KmpLock +import com.vitorpamplona.amethyst.commons.util.withLock import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.SubscriptionListener import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter @@ -34,7 +37,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.isActive import kotlinx.coroutines.launch -import java.util.concurrent.ConcurrentHashMap +import kotlin.concurrent.Volatile import kotlin.time.Duration import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds @@ -81,11 +84,15 @@ class WindowLoadTracker( // Relays that have produced any signal at all (event / EOSE / CLOSED / cannot-connect). The idle // backstop only arms once this covers [expected], so a still-connecting relay can't be skipped. - private val heardFrom = ConcurrentHashMap.newKeySet() + private val heardFrom = ConcurrentSet() // Relays that reached a terminal signal (EOSE / CLOSED / cannot-connect). When this covers // [expected] the stored backfill is complete on every relay and the load is done. - private val settled = ConcurrentHashMap.newKeySet() + private val settled = ConcurrentSet() + + // Guards the window state below, as the JVM monitor behind @Synchronized did. Reentrant: tick() + // and setExpectedRelays() call finish() while holding it. + private val lock = KmpLock() private var watchdog: Job? = null @@ -99,66 +106,69 @@ class WindowLoadTracker( private var lastActivityMs = 0L /** Begins a fresh window load: clears the per-relay sets, raises [loading], and arms the watchdog. */ - @Synchronized fun startLoading(scope: CoroutineScope) { - val gen = ++generation - expected = emptySet() - heardFrom.clear() - settled.clear() - lastActivityMs = TimeUtils.nowMillis() - val wasLoading = _loading.value - _loading.value = true - Log.d(TAG) { "[$name] load start" + if (!wasLoading) "" else " (restart)" } - watchdog?.cancel() - watchdog = - scope.launch { - val deadline = TimeUtils.nowMillis() + absoluteCap.inWholeMilliseconds - while (isActive) { - delay(IDLE_CHECK_MS) - if (!tick(gen, TimeUtils.nowMillis(), deadline)) break + lock.withLock { + val gen = ++generation + expected = emptySet() + heardFrom.clear() + settled.clear() + lastActivityMs = TimeUtils.nowMillis() + val wasLoading = _loading.value + _loading.value = true + Log.d(TAG) { "[$name] load start" + if (!wasLoading) "" else " (restart)" } + watchdog?.cancel() + watchdog = + scope.launch { + val deadline = TimeUtils.nowMillis() + absoluteCap.inWholeMilliseconds + while (isActive) { + delay(IDLE_CHECK_MS) + if (!tick(gen, TimeUtils.nowMillis(), deadline)) break + } } - } + } } // One watchdog poll. Returns false (stop polling) when this watchdog has been superseded by a // newer load, the window already finished, or a completion deadline is reached. Synchronized so // the generation/loading checks and the completion are atomic against startLoading/finish. - @Synchronized private fun tick( gen: Int, now: Long, deadline: Long, ): Boolean { - if (gen != generation || !_loading.value) return false - if (expected.isNotEmpty()) { - // Once every relay has reached a terminal signal, nothing more is coming for this round. - if (settled.containsAll(expected)) { - finish("settled") - return false - } - // Idle backstop: every relay we're still waiting on has at least streamed something (so this - // isn't a connection gap) and the stream has gone quiet. Settled relays don't count. - val stillWaiting = expected.filterNot { settled.contains(it) } - if (stillWaiting.all { heardFrom.contains(it) } && now - lastActivityMs >= idleTimeout.inWholeMilliseconds) { - finish("idle") + lock.withLock { + if (gen != generation || !_loading.value) return false + if (expected.isNotEmpty()) { + // Once every relay has reached a terminal signal, nothing more is coming for this round. + if (expected.all { it in settled }) { + finish("settled") + return false + } + // Idle backstop: every relay we're still waiting on has at least streamed something (so this + // isn't a connection gap) and the stream has gone quiet. Settled relays don't count. + val stillWaiting = expected.filterNot { settled.contains(it) } + if (stillWaiting.all { heardFrom.contains(it) } && now - lastActivityMs >= idleTimeout.inWholeMilliseconds) { + finish("idle") + return false + } + } + if (now >= deadline) { + finish("cap") return false } + return true } - if (now >= deadline) { - finish("cap") - return false - } - return true } /** Records which relays the current REQ was sent to. Completes immediately if there are none. */ - @Synchronized fun setExpectedRelays(relays: Set) { - expected = relays - if (relays.isEmpty()) { - finish("no relays") - } else if (settled.containsAll(relays)) { - finish("all relays") + lock.withLock { + expected = relays + if (relays.isEmpty()) { + finish("no relays") + } else if (relays.all { it in settled }) { + finish("all relays") + } } } @@ -172,22 +182,24 @@ class WindowLoadTracker( * A terminal signal from [relay] — EOSE, CLOSED, or cannot-connect. Once every expected relay has * settled the stored backfill is complete and the load finishes. */ - @Synchronized fun onRelaySettled(relay: NormalizedRelayUrl) { - lastActivityMs = TimeUtils.nowMillis() - heardFrom.add(relay) - settled.add(relay) - if (expected.isNotEmpty() && settled.containsAll(expected)) finish("all relays") + lock.withLock { + lastActivityMs = TimeUtils.nowMillis() + heardFrom.add(relay) + settled.add(relay) + if (expected.isNotEmpty() && expected.all { it in settled }) finish("all relays") + } } // Idempotent: only the first call after a load actually completes (and logs); later calls no-op. - @Synchronized private fun finish(reason: String) { - if (!_loading.value) return - watchdog?.cancel() - watchdog = null - Log.d(TAG) { "[$name] load done: $reason" } - _loading.value = false + lock.withLock { + if (!_loading.value) return + watchdog?.cancel() + watchdog = null + Log.d(TAG) { "[$name] load done: $reason" } + _loading.value = false + } } companion object { diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/polls/results/FilterPollResponses.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/polls/results/FilterPollResponses.kt index 60343c0d38..55239aefe6 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/polls/results/FilterPollResponses.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/polls/results/FilterPollResponses.kt @@ -42,7 +42,7 @@ private const val VOTE_LIMIT = 1000 * Every vote cast on [poll], from the relays a vote could plausibly be on. * * NIP-88 tells respondents to publish to the relays the poll itself nominates, and - * [com.vitorpamplona.amethyst.model.EventBroadcaster] obeys that on the way out — those relays are + * [com.vitorpamplona.amethyst.commons.model.EventBroadcaster] obeys that on the way out — those relays are * usually neither the author's inbox nor where we happened to see the poll, so they have to be * asked explicitly or the tally silently under-counts. */ diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/polls/results/RelayPollResponseLoader.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/polls/results/RelayPollResponseLoader.kt index c3ebf26beb..ab5b95e779 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/polls/results/RelayPollResponseLoader.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/polls/results/RelayPollResponseLoader.kt @@ -76,7 +76,7 @@ class RelayPollResponseLoader( /** * Where a poll's votes live: the relays the poll itself nominates (NIP-88 tells respondents to - * publish there, and [com.vitorpamplona.amethyst.model.EventBroadcaster] obeys it), plus the + * publish there, and [com.vitorpamplona.amethyst.commons.model.EventBroadcaster] obeys it), plus the * relays we would look at for any other engagement. Same set the subscription asks. */ private fun responseRelays(poll: PollEvent): Set = (poll.relays() + pollNote.relayUrlsForReactions()).toSet() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/follows/FilterFindFollowMetadataForKey.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/follows/FilterFindFollowMetadataForKey.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/follows/FilterFindFollowMetadataForKey.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/follows/FilterFindFollowMetadataForKey.kt index b29560e16b..2b2f666e3f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/follows/FilterFindFollowMetadataForKey.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/follows/FilterFindFollowMetadataForKey.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.follows +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.follows import com.vitorpamplona.amethyst.commons.defaults.Constants import com.vitorpamplona.amethyst.commons.defaults.DefaultIndexerRelayList import com.vitorpamplona.amethyst.commons.defaults.DefaultSearchRelayList +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relayClient.user.pickRelaysToLoadUsers import com.vitorpamplona.amethyst.commons.relays.EOSEAccountFast -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/FilterAccountInfoAndListsFromKey.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/metadata/FilterAccountInfoAndListsFromKey.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/FilterAccountInfoAndListsFromKey.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/metadata/FilterAccountInfoAndListsFromKey.kt index 877aefd589..54af32e88e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/FilterAccountInfoAndListsFromKey.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/metadata/FilterAccountInfoAndListsFromKey.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.metadata +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.metadata +import com.vitorpamplona.amethyst.commons.model.nip78AppSpecific.AppSpecificState.Companion.APP_SPECIFIC_DATA_D_TAG import com.vitorpamplona.amethyst.commons.relayClient.assemblers.filterUserAssertionsByAuthorInTheRelay import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose -import com.vitorpamplona.amethyst.model.nip78AppSpecific.AppSpecificState.Companion.APP_SPECIFIC_DATA_D_TAG import com.vitorpamplona.quartz.concord.cord02Community.ConcordCommunityListEvent import com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageRelayListEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/ChannelFinderFilterAssemblyGroup.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/ChannelFinderFilterAssemblyGroup.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/ChannelFinderFilterAssemblyGroup.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/ChannelFinderFilterAssemblyGroup.kt index 2bbe2bcd61..452281910f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/ChannelFinderFilterAssemblyGroup.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/ChannelFinderFilterAssemblyGroup.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel import androidx.compose.runtime.Stable +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Channel import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.mixChatsLive.ChannelMetadataAndLiveActivityWatcherSubAssembler -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.nip28PublicChats.ChannelLoaderSubAssembler +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.mixChatsLive.ChannelMetadataAndLiveActivityWatcherSubAssembler +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.nip28PublicChats.ChannelLoaderSubAssembler import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient // This allows multiple screen to be listening to tags, even the same tag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/mixChatsLive/ChannelMetadataAndLiveActivityWatcherSubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/mixChatsLive/ChannelMetadataAndLiveActivityWatcherSubAssembler.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/mixChatsLive/ChannelMetadataAndLiveActivityWatcherSubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/mixChatsLive/ChannelMetadataAndLiveActivityWatcherSubAssembler.kt index e8e9660f7c..562e6005fb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/mixChatsLive/ChannelMetadataAndLiveActivityWatcherSubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/mixChatsLive/ChannelMetadataAndLiveActivityWatcherSubAssembler.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.mixChatsLive +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.mixChatsLive import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel import com.vitorpamplona.amethyst.commons.relayClient.channel.nip28PublicChats.filterChannelMetadataUpdatesById import com.vitorpamplona.amethyst.commons.relayClient.channel.nip53LiveActivities.filterLiveStreamUpdatesByAddress import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.SingleSubEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.ChannelFinderQueryState import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.ChannelFinderQueryState import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.utils.mapOfSet diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip28PublicChats/ChannelLoaderSubAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/nip28PublicChats/ChannelLoaderSubAssembler.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip28PublicChats/ChannelLoaderSubAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/nip28PublicChats/ChannelLoaderSubAssembler.kt index e688d004f1..0adc1520f0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip28PublicChats/ChannelLoaderSubAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/nip28PublicChats/ChannelLoaderSubAssembler.kt @@ -18,10 +18,10 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.nip28PublicChats +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.nip28PublicChats import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.AccountScopedSingleSubNoEoseCacheEoseManager -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.ChannelFinderQueryState +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.ChannelFinderQueryState import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip28PublicChats/FilterChannelMetadataCreationById.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/nip28PublicChats/FilterChannelMetadataCreationById.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip28PublicChats/FilterChannelMetadataCreationById.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/nip28PublicChats/FilterChannelMetadataCreationById.kt index ce2042c354..859c099b02 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip28PublicChats/FilterChannelMetadataCreationById.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/nip28PublicChats/FilterChannelMetadataCreationById.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.nip28PublicChats +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.nip28PublicChats import com.vitorpamplona.amethyst.commons.defaults.DefaultIndexerRelayList import com.vitorpamplona.amethyst.commons.defaults.DefaultSearchRelayList import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.ChannelFinderQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.ChannelFinderQueryState import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent import com.vitorpamplona.quartz.utils.mapOfSet diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/searchCommand/SearchFilterAssembler.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/searchCommand/SearchFilterAssembler.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/searchCommand/SearchFilterAssembler.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/searchCommand/SearchFilterAssembler.kt index 084706d591..bda0dbc5a2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/searchCommand/SearchFilterAssembler.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/searchCommand/SearchFilterAssembler.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.searchCommand +package com.vitorpamplona.amethyst.commons.relayClient.searchCommand import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.commons.model.cache.ICacheProvider diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/eventsync/EventSync.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relays/eventsync/EventSync.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/eventsync/EventSync.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relays/eventsync/EventSync.kt index 0a9066af70..1409885756 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/eventsync/EventSync.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relays/eventsync/EventSync.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.eventsync +package com.vitorpamplona.amethyst.commons.relays.eventsync import androidx.compose.runtime.Stable -import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.eventsync.EventSync.Companion.MAX_ACTIVITY_LOG -import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.eventsync.EventSync.Companion.MAX_CONCURRENT_RELAYS -import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.eventsync.EventSync.LiveSyncActivity.SourceRelayInfo +import com.vitorpamplona.amethyst.commons.relays.eventsync.EventSync.Companion.MAX_ACTIVITY_LOG +import com.vitorpamplona.amethyst.commons.relays.eventsync.EventSync.Companion.MAX_CONCURRENT_RELAYS +import com.vitorpamplona.amethyst.commons.relays.eventsync.EventSync.LiveSyncActivity.SourceRelayInfo import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient @@ -40,8 +40,12 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser import com.vitorpamplona.quartz.nip59Giftwrap.wraps.EphemeralGiftWrapEvent import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent +import com.vitorpamplona.quartz.utils.concurrent.ConcurrentMap +import com.vitorpamplona.quartz.utils.concurrent.ConcurrentSet +import com.vitorpamplona.quartz.utils.currentTimeMillis import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow @@ -49,7 +53,6 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.withTimeoutOrNull -import java.util.concurrent.ConcurrentHashMap import kotlin.coroutines.cancellation.CancellationException /** @@ -332,7 +335,7 @@ class EventSync( filterSince: Long? = null, filterUntil: Long? = null, ) { - val startTime = System.currentTimeMillis() + val startTime = currentTimeMillis() _liveActivity.value = LiveSyncActivity() @@ -391,18 +394,18 @@ class EventSync( // Thread-safe dedup sets — prevent the same event from being forwarded twice when // multiple source relays return the same event concurrently. - val outboxDedup = ConcurrentHashMap.newKeySet() - val inboxDedup = ConcurrentHashMap.newKeySet() - val dmDedup = ConcurrentHashMap.newKeySet() + val outboxDedup = ConcurrentSet() + val inboxDedup = ConcurrentSet() + val dmDedup = ConcurrentSet() - val sourceRelayOfEvent = ConcurrentHashMap() + val sourceRelayOfEvent = ConcurrentMap() // (event id, destination) pairs already counted as sent. The outbox is // at-least-once: it writes an event as soon as the socket is ready and // resends everything still unacknowledged when the connection finishes // syncing, so one event can hit the same relay twice before its OK lands. // The relay dedups the second copy; the counters must too. - val sentPairs = ConcurrentHashMap.newKeySet() + val sentPairs = ConcurrentSet() val runningState = SyncState.Running( @@ -608,14 +611,14 @@ class EventSync( // forwarded from the last page of the last relay are still waiting for a // socket or an OK when the outbox is destroyed — the sync reports Done and // silently never delivers them. Bounded by the same per-relay timeout. - awaitOutboxDrain(client, outboxDedup + inboxDedup + dmDedup) + awaitOutboxDrain(client, outboxDedup.snapshot() + inboxDedup.snapshot() + dmDedup.snapshot()) _syncState.value = SyncState.Done( totalEventsReceived = runningState.eventsReceived.value, totalEventsSent = runningState.eventsSent.value, totalEventsAccepted = runningState.eventsAccepted.value, - durationMs = System.currentTimeMillis() - startTime, + durationMs = currentTimeMillis() - startTime, sinceFilter = filterSince, untilFilter = filterUntil, ) @@ -625,7 +628,7 @@ class EventSync( totalEventsReceived = runningState.eventsReceived.value, totalEventsSent = runningState.eventsSent.value, totalEventsAccepted = runningState.eventsAccepted.value, - durationMs = System.currentTimeMillis() - startTime, + durationMs = currentTimeMillis() - startTime, sinceFilter = filterSince, untilFilter = filterUntil, ) diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11CachedRetriever.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11CachedRetriever.kt similarity index 95% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11CachedRetriever.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11CachedRetriever.kt index b6fc1b1e38..02aaea05b3 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11CachedRetriever.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11CachedRetriever.kt @@ -26,11 +26,11 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.toHttp import com.vitorpamplona.quartz.nip11RelayInfo.Nip11RelayInformation -import okhttp3.OkHttpClient +/** NIP-11 documents per relay, cached for an hour (errors too), with placeholders while loading. */ @Stable class Nip11CachedRetriever( - val okHttpClient: (NormalizedRelayUrl) -> OkHttpClient, + private val retriever: Nip11Fetcher, ) { private val relayInformationEmptyCache = LruCache(1000) @@ -39,7 +39,6 @@ class Nip11CachedRetriever( // the nullable argument compiled but never meant anything — get() returns null on a miss either // way, which is what the readers below already branch on. private val relayInformationDocumentCache = LruCache(1000) - private val retriever = Nip11Retriever(okHttpClient) /** * Drops any cached NIP-11 document (including a cached *error*) for [relay], so the next @@ -94,7 +93,7 @@ class Nip11CachedRetriever( suspend fun loadRelayInfo( relay: NormalizedRelayUrl, onInfo: (Nip11RelayInformation) -> Unit, - onError: (NormalizedRelayUrl, Nip11Retriever.ErrorCode, String?) -> Unit, + onError: (NormalizedRelayUrl, Nip11ErrorCode, String?) -> Unit, ) { val doc = relayInformationDocumentCache.get(relay) if (doc != null) { @@ -136,7 +135,7 @@ class Nip11CachedRetriever( private suspend fun retrieve( relay: NormalizedRelayUrl, onInfo: (Nip11RelayInformation) -> Unit, - onError: (NormalizedRelayUrl, Nip11Retriever.ErrorCode, String?) -> Unit, + onError: (NormalizedRelayUrl, Nip11ErrorCode, String?) -> Unit, ) { relayInformationDocumentCache.put(relay, RetrieveResult.Loading(getEmpty(relay))) retriever.loadRelayInfo( diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11Fetcher.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11Fetcher.kt new file mode 100644 index 0000000000..f1c12d0f6b --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11Fetcher.kt @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo + +import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl +import com.vitorpamplona.quartz.nip11RelayInfo.Nip11RelayInformation + +/** Why a NIP-11 document could not be had. */ +enum class Nip11ErrorCode { + FAIL_TO_ASSEMBLE_URL, + FAIL_TO_REACH_SERVER, + FAIL_TO_PARSE_RESULT, + FAIL_WITH_HTTP_STATUS, +} + +/** Fetches a relay's NIP-11 document over whatever HTTP stack the platform has. */ +interface Nip11Fetcher { + suspend fun loadRelayInfo( + relay: NormalizedRelayUrl, + onInfo: (Nip11RelayInformation) -> Unit, + onError: (NormalizedRelayUrl, Nip11ErrorCode, String?) -> Unit, + ) + + /** No network: every fetch fails as unreachable. For hosts that provide no fetcher. */ + object Offline : Nip11Fetcher { + override suspend fun loadRelayInfo( + relay: NormalizedRelayUrl, + onInfo: (Nip11RelayInformation) -> Unit, + onError: (NormalizedRelayUrl, Nip11ErrorCode, String?) -> Unit, + ) = onError(relay, Nip11ErrorCode.FAIL_TO_REACH_SERVER, null) + } +} diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/RelaySupportsNip.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/RelaySupportsNip.kt index d59f7bd6c1..38a7bf60c8 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/RelaySupportsNip.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/RelaySupportsNip.kt @@ -20,6 +20,7 @@ */ package com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.quartz.nip11RelayInfo.Nip11RelayInformation @@ -31,8 +32,7 @@ import com.vitorpamplona.quartz.nip11RelayInfo.Nip11RelayInformation * or the fetch failed), so it never triggers the warning. * * Takes the resolved document rather than a relay URL, which is what makes it shared: the cache - * lookup that produces one is the front end's business, the rule applied to it is not. The - * convenience forms that read Amethyst's in-memory cache stay in the app. + * lookup that produces one is the front end's business, the rule applied to it is not. */ fun looksLikeNonNip29Relay(relayInfo: Nip11RelayInformation): Boolean = relayInfo.supported_nips?.none { it == "29" } == true && relayInfo.self == null @@ -59,3 +59,6 @@ fun isRelaySignedRelayGroup( relayInfo.supported_nips?.any { it == "29" } == true } } + +/** [isRelaySignedRelayGroup] against whatever NIP-11 document the shell has cached for the host relay. */ +fun isRelaySignedRelayGroup(channel: RelayGroupChannel): Boolean = LocalCache.appHost.relayInfo(channel.groupId.relayUrl)?.let { isRelaySignedRelayGroup(channel, it) } == true diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/RetrieveResult.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/RetrieveResult.kt similarity index 97% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/RetrieveResult.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/RetrieveResult.kt index bb44f63cb7..59444f5764 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/RetrieveResult.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/RetrieveResult.kt @@ -29,7 +29,7 @@ sealed class RetrieveResult( ) { class Error( data: Nip11RelayInformation, - val error: Nip11Retriever.ErrorCode, + val error: Nip11ErrorCode, val msg: String? = null, ) : RetrieveResult(data, TimeUtils.now()) diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/richtext/CachedAsciiDocToMarkdown.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/richtext/CachedAsciiDocToMarkdown.kt similarity index 100% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/richtext/CachedAsciiDocToMarkdown.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/richtext/CachedAsciiDocToMarkdown.kt diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/richtext/CachedRichTextParser.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/richtext/CachedRichTextParser.kt similarity index 98% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/richtext/CachedRichTextParser.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/richtext/CachedRichTextParser.kt index 92a7bc5593..72c50178c0 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/richtext/CachedRichTextParser.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/richtext/CachedRichTextParser.kt @@ -27,10 +27,6 @@ import com.vitorpamplona.quartz.utils.cache.ConcurrentLruCache * The shared, cross-platform cache in front of [RichTextParser]. Both Amethyst * Android and Amethyst Desktop render the same parsed [RichTextViewerState] from * one place, so the same content quoted in multiple notes is only parsed once. - * - * Lives in `jvmAndroid` because it depends on [ConcurrentLruCache] (a JCA-free, - * lock-free-read LRU that is not in `commonMain`). iOS/`commonMain` callers use - * the uncached [RichTextParser] directly until a KMP cache is available. */ object CachedRichTextParser { // Global across every feed. Sized to hold the active feed's visible + prefetched diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/richtext/MediaContentModels.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/richtext/MediaContentModels.kt index c066025405..5f32aea49e 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/richtext/MediaContentModels.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/richtext/MediaContentModels.kt @@ -26,10 +26,8 @@ import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf -// URL-based media content models (KMP). The locally-cached variants -// (MediaPreloadedContent, MediaLocalImage, MediaLocalVideo) live in -// MediaLocalContent.kt under the jvmAndroid source set because they depend -// on java.io.File. +// URL-based media content models. The locally-cached variants +// (MediaPreloadedContent, MediaLocalImage, MediaLocalVideo) are in MediaLocalContent.kt. @Immutable abstract class BaseMediaContent( diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/richtext/MediaLocalContent.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/richtext/MediaLocalContent.kt similarity index 82% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/richtext/MediaLocalContent.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/richtext/MediaLocalContent.kt index 30c0de6441..9e56131aaa 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/richtext/MediaLocalContent.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/richtext/MediaLocalContent.kt @@ -21,18 +21,16 @@ package com.vitorpamplona.amethyst.commons.richtext import androidx.compose.runtime.Immutable +import com.vitorpamplona.amethyst.commons.util.platformFileSystem import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag -import java.io.File +import okio.Path -// Locally-cached media content. Lives in jvmAndroid because java.io.File is -// JVM-only; iOS support will arrive when we either swap to okio.Path or pull -// these classes back into commonMain behind an expect/actual File abstraction. -// URL-based media classes (MediaUrlImage, MediaUrlVideo, …) remain in -// commonMain in MediaContentModels.kt. +// Locally-cached media content: a file on this device (a NIP-95 blob) rather than a URL. +// URL-based media classes (MediaUrlImage, MediaUrlVideo, …) are in MediaContentModels.kt. @Immutable abstract class MediaPreloadedContent( - val localFile: File?, + val localFile: Path?, description: String? = null, val mimeType: String? = null, val isVerified: Boolean? = null, @@ -42,12 +40,12 @@ abstract class MediaPreloadedContent( val id: String? = null, thumbhash: String? = null, ) : BaseMediaContent(description, dim, blurhash, thumbhash) { - fun localFileExists() = localFile != null && localFile.exists() + fun localFileExists() = localFile != null && platformFileSystem.exists(localFile) } @Immutable class MediaLocalImage( - localFile: File?, + localFile: Path?, mimeType: String? = null, description: String? = null, dim: DimensionTag? = null, @@ -59,7 +57,7 @@ class MediaLocalImage( @Immutable class MediaLocalVideo( - localFile: File?, + localFile: Path?, mimeType: String? = null, description: String? = null, dim: DimensionTag? = null, diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/LocalClock.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/LocalClock.kt index 1b58d51d5b..c776a8d4d2 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/LocalClock.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/LocalClock.kt @@ -41,6 +41,12 @@ expect object LocalClock { /** Today, in the reader's timezone. */ fun today(): SearchDate + /** + * Which local day a unix second falls on, with the zone read once for the whole counter + * rather than per timestamp: for grouping a batch of events by day in one pass. + */ + fun epochDayCounter(): EpochDayCounter + /** Which weekday a week starts on here, 0 = Sunday. */ fun firstDayOfWeek(): Int @@ -53,3 +59,8 @@ expect object LocalClock { /** The seven column headings, narrow, indexed 0 = Sunday. The grid rotates them itself. */ fun narrowWeekdayNames(): List } + +/** Maps a unix second to the local day it falls on, counted in days since 1970-01-01. */ +fun interface EpochDayCounter { + fun epochDay(unixSeconds: Long): Long +} diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/SearchDate.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/SearchDate.kt index 764620313e..b185ec3973 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/SearchDate.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/SearchDate.kt @@ -97,6 +97,8 @@ data class SearchDate( fun parse(text: String?): SearchDate? { val s = text ?: return null if (s.length != 10 || s[4] != '-' || s[7] != '-') return null + // Digits only: toIntOrNull alone would let a sign through ("2026-+1-05"). + for (i in s.indices) if (i != 4 && i != 7 && s[i] !in '0'..'9') return null val year = s.substring(0, 4).toIntOrNull() ?: return null val month = s.substring(5, 7).toIntOrNull() ?: return null val day = s.substring(8, 10).toIntOrNull() ?: return null diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/ZoneMath.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/ZoneMath.kt index d9e39aa5a8..1098519ed1 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/ZoneMath.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/ZoneMath.kt @@ -85,5 +85,11 @@ internal object ZoneMath { fun dayAt( epochSeconds: Long, offsets: ZoneOffsets, - ): SearchDate = SearchDate.civilFromDays((epochSeconds + offsets.at(epochSeconds)).floorDiv(SECONDS_PER_DAY)) + ): SearchDate = SearchDate.civilFromDays(epochDayAt(epochSeconds, offsets)) + + /** The local day [epochSeconds] falls on, counted in days since 1970-01-01. */ + fun epochDayAt( + epochSeconds: Long, + offsets: ZoneOffsets, + ): Long = (epochSeconds + offsets.at(epochSeconds)).floorDiv(SECONDS_PER_DAY) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/Bolt12LightningFallback.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/Bolt12LightningFallback.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/Bolt12LightningFallback.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/Bolt12LightningFallback.kt index 4f73a3b2c2..8ea036665e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/Bolt12LightningFallback.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/Bolt12LightningFallback.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service +package com.vitorpamplona.amethyst.commons.service import com.vitorpamplona.quartz.nip47WalletConnect.rpc.NwcErrorCode diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/ClinkDebitPayer.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/ClinkDebitPayer.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/ClinkDebitPayer.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/ClinkDebitPayer.kt index 3ea9d1678d..3b8a37a99f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/ClinkDebitPayer.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/ClinkDebitPayer.kt @@ -18,10 +18,10 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service +package com.vitorpamplona.amethyst.commons.service -import com.vitorpamplona.amethyst.Amethyst -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.tor.MoneyOpRelayRouting import com.vitorpamplona.quartz.experimental.clink.client.DebitClient import com.vitorpamplona.quartz.experimental.clink.debits.DebitEvent import com.vitorpamplona.quartz.experimental.clink.debits.DebitFrequency @@ -35,6 +35,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeoutOrNull @@ -60,6 +61,7 @@ object ClinkDebitPayer { */ suspend fun payInvoice( account: Account, + moneyOpRelays: MoneyOpRelayRouting, pointer: NDebit, bolt11: String, amountSats: Long? = null, @@ -69,7 +71,7 @@ object ClinkDebitPayer { // this from Compose (Main) scopes (offer card, lightning-address row). See ClinkOfferPayer. withContext(Dispatchers.IO) { val client = clientFor(pointer, account) ?: return@withContext null - sendAndAwait(account, client, client.payInvoice(bolt11, amountSats), timeoutMs) + sendAndAwait(account, moneyOpRelays, client, client.payInvoice(bolt11, amountSats), timeoutMs) } /** @@ -78,6 +80,7 @@ object ClinkDebitPayer { */ suspend fun requestBudget( account: Account, + moneyOpRelays: MoneyOpRelayRouting, pointer: NDebit, amountSats: Long, frequency: DebitFrequency? = null, @@ -85,7 +88,7 @@ object ClinkDebitPayer { ): DebitResponse? = withContext(Dispatchers.IO) { val client = clientFor(pointer, account) ?: return@withContext null - sendAndAwait(account, client, client.requestBudget(amountSats, frequency), timeoutMs) + sendAndAwait(account, moneyOpRelays, client, client.requestBudget(amountSats, frequency), timeoutMs) } // Debits sign with the persistent account identity (unlike offer requests, which use a @@ -99,6 +102,7 @@ object ClinkDebitPayer { /** Publishes [request] to the pointer's relays and awaits the matching kind-21002 reply. */ private suspend fun sendAndAwait( account: Account, + moneyOpRelays: MoneyOpRelayRouting, client: DebitClient, request: DebitEvent, timeoutMs: Long, @@ -129,8 +133,7 @@ object ClinkDebitPayer { // but register here too so a freshly-added wallet paid before that flow propagates — and any // non-saved debit pointer — still routes under the money-operations Tor preference rather than // the generic `newRelaysViaTor` policy. - val torState = Amethyst.instance.torEvaluatorFlow - torState.registerMoneyOpRelays(relays) + moneyOpRelays.registerMoneyOpRelays(relays) account.client.subscribe(subId, filters, listener) return try { account.client.publish(request, relays) @@ -146,7 +149,7 @@ object ClinkDebitPayer { } } finally { account.client.unsubscribe(subId) - torState.unregisterMoneyOpRelays(relays) + moneyOpRelays.unregisterMoneyOpRelays(relays) } } } diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/OnlineStatusCache.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/OnlineStatusCache.kt new file mode 100644 index 0000000000..b0894155e7 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/OnlineStatusCache.kt @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.service + +import androidx.collection.LruCache +import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.utils.TimeUtils + +@Immutable data class OnlineCheckResult( + val timeInSecs: Long, + val online: Boolean, +) + +/** + * The last five minutes of stream-URL reachability checks. Reading it never touches the network, + * so feeds can rank by it; the checks that fill it are the platform's ([OnlineChecker] on the JVM). + */ +object OnlineStatusCache { + val cache = LruCache(100) + + /** A fresh answer for [url], or null when there is none within five minutes. */ + fun fresh(url: String): OnlineCheckResult? = cache.get(url)?.takeIf { it.timeInSecs > TimeUtils.fiveMinutesAgo() } + + fun record( + url: String, + online: Boolean, + ) { + cache.put(url, OnlineCheckResult(TimeUtils.now(), online)) + } + + fun isCachedAndOffline(url: String?): Boolean { + if (url.isNullOrBlank()) return false + return fresh(url)?.online == false + } + + fun isOnlineCached(url: String?): Boolean { + if (url.isNullOrBlank()) return false + return fresh(url)?.online == true + } + + fun resetIfOfflineToRetry(url: String) { + val cached = cache.get(url) + if (cached != null && !cached.online) { + cache.remove(url) + } + } +} diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/VideoOnlineProbe.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/VideoOnlineProbe.kt new file mode 100644 index 0000000000..b0ea59c23b --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/VideoOnlineProbe.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.service + +import com.vitorpamplona.amethyst.commons.service.http.IRoleBasedHttpClientBuilder + +/** + * Probes whether a live stream at [url] answers, over the video client, and records the answer + * in [OnlineStatusCache]. iOS has no HTTP client yet and reports every stream online, so it hides + * none of them. + */ +expect suspend fun IRoleBasedHttpClientBuilder.isVideoOnline(url: String): Boolean diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/geohash/GeohashRelays.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/georelay/GeohashRelays.kt similarity index 76% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/geohash/GeohashRelays.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/georelay/GeohashRelays.kt index 4c75d6813b..f1a1c57494 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/geohash/GeohashRelays.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/georelay/GeohashRelays.kt @@ -18,12 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.geohash +package com.vitorpamplona.amethyst.commons.service.georelay -import com.vitorpamplona.amethyst.Amethyst -import com.vitorpamplona.amethyst.commons.service.georelay.GeoRelayCsvLoader -import com.vitorpamplona.amethyst.commons.service.georelay.GeoRelayDirectory import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl +import kotlin.concurrent.Volatile +import kotlin.coroutines.cancellation.CancellationException /** * Process-wide geohash → relay directory, shared by everything that routes @@ -38,12 +37,24 @@ object GeohashRelays { @Volatile private var refreshed = false + /** + * Fetches the live directory. The app installs one at startup over its own HTTP clients, so + * the fetch honours the user's Tor settings; until then [ensureLoaded] keeps the fallback. + */ + @Volatile var liveRelayLoader: (suspend () -> List)? = null + /** Fetches the live directory once. Safe to call repeatedly; subsequent calls are no-ops. */ suspend fun ensureLoaded(): Boolean { if (refreshed) return false - runCatching { - GeoRelayCsvLoader { Amethyst.instance.okHttpClients.getHttpClient(false) }.refresh(directory) - } + val loader = liveRelayLoader ?: return false + val relays = + try { + loader() + } catch (e: Exception) { + if (e is CancellationException) throw e + emptyList() + } + directory.setRelays(relays) val loaded = directory.size > GeoRelayDirectory.FALLBACK.size refreshed = loaded return loaded diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/http/IRoleBasedHttpClientBuilder.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/http/IRoleBasedHttpClientBuilder.kt new file mode 100644 index 0000000000..0dbb52e2d5 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/http/IRoleBasedHttpClientBuilder.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.service.http + +/** + * The app's HTTP clients, one per role (images, video, money, uploads, …), each routed the way the + * user's Tor settings ask for that role and URL. Opaque to common code, which only carries it to the + * places that make requests; on the JVM it is [RoleBasedOkHttpClients] and hands out OkHttp clients. + */ +expect interface IRoleBasedHttpClientBuilder diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/http/LocalBlossomCacheHeaders.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/http/LocalBlossomCacheHeaders.kt new file mode 100644 index 0000000000..67a8c1d35a --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/http/LocalBlossomCacheHeaders.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.service.http + +/** + * The request marker the local Blossom cache bridge keys on. It lives apart from the OkHttp + * interceptor that strips it so image requests built in common code can set it. + */ +object LocalBlossomCacheHeaders { + /** Marks a request as a media download the local cache may serve. Stripped before sending. */ + const val MEDIA_HEADER = "X-Amethyst-Local-Blossom" + const val MEDIA = "media" + const val PROFILE_PICTURE = "profile-picture" +} diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/PreviewHashes.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/PreviewHashes.kt new file mode 100644 index 0000000000..13be2eaa80 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/PreviewHashes.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.service.image + +/** + * A BlurHash string, typed so an image loader can tell it apart from a URL (commonsUI's + * `BlurHashFetcher` decodes it into a placeholder bitmap). + */ +data class BlurhashWrapper( + val blurhash: String, +) + +/** A ThumbHash string, typed like [BlurhashWrapper] (decoded by commonsUI's `ThumbHashFetcher`). */ +data class ThumbhashWrapper( + val thumbhash: String, +) diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/LnurlHttpTransport.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/LnurlHttpTransport.kt new file mode 100644 index 0000000000..650f0d9289 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/LnurlHttpTransport.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.service.lnurl + +/** + * The HTTP an LNURL-pay flow needs: a GET that returns the status, the reason phrase and the body + * as text. Each platform supplies one (OkHttp on Android and the JVM). Implementations pick the + * per-URL client themselves (Tor, proxies), run off the main thread, and throw on a transport + * failure; an HTTP error status is an [LnurlHttpResponse], not an exception. + */ +fun interface LnurlHttpTransport { + suspend fun get(url: String): LnurlHttpResponse +} + +/** One LNURL server response. [reason] is the HTTP reason phrase, often empty over HTTP/2. */ +class LnurlHttpResponse( + val status: Int, + val reason: String, + val body: String, +) { + val isSuccessful: Boolean get() = status in 200..299 +} diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/upload/FileHeader.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/upload/FileHeader.kt new file mode 100644 index 0000000000..6bcb516fe5 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/upload/FileHeader.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.service.upload + +import com.vitorpamplona.amethyst.commons.service.image.BlurhashWrapper +import com.vitorpamplona.amethyst.commons.service.image.ThumbhashWrapper +import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag + +/** + * What an upload or a NIP-94/NIP-92 attachment needs to know about a file's bytes: its type, SHA-256, + * size, pixel dimensions and preview hashes. Computing it (download, hash, decode a frame) is + * platform work; each app provides a `FileHeader.prepare(...)` for that. + */ +class FileHeader( + val mimeType: String?, + val hash: String, + val size: Int, + val dim: DimensionTag?, + val blurHash: BlurhashWrapper?, + val thumbHash: ThumbhashWrapper? = null, +) { + class UnableToDownload( + val fileUrl: String, + ) : Exception() + + companion object +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/dal/ShortsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/shorts/dal/ShortsFeedFilter.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/dal/ShortsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/shorts/dal/ShortsFeedFilter.kt index 02aacf30d7..ca1bf1ca16 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/shorts/dal/ShortsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/shorts/dal/ShortsFeedFilter.kt @@ -18,11 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.shorts.dal +package com.vitorpamplona.amethyst.commons.shorts.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams import com.vitorpamplona.amethyst.commons.feeds.SupportedContent +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -30,8 +32,6 @@ import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.relayClient.video.SUPPORTED_VIDEO_FEED_MIME_TYPES_SET import com.vitorpamplona.amethyst.commons.richtext.RichTextParser -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip71Video.AddressableShortVideoEvent import com.vitorpamplona.quartz.nip71Video.VideoMeta diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/dal/SoftwareAppsFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/softwareapps/dal/SoftwareAppsFeedFilter.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/dal/SoftwareAppsFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/softwareapps/dal/SoftwareAppsFeedFilter.kt index a2cdbb0f7c..7279953f2b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/dal/SoftwareAppsFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/softwareapps/dal/SoftwareAppsFeedFilter.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.softwareapps.dal +package com.vitorpamplona.amethyst.commons.softwareapps.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.application.SoftwareApplicationEvent class SoftwareAppsFeedFilter( diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/storage/EncryptedAppendLog.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/storage/EncryptedAppendLog.kt similarity index 85% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/storage/EncryptedAppendLog.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/storage/EncryptedAppendLog.kt index 0573a8bc96..26b85d4b1d 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/storage/EncryptedAppendLog.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/storage/EncryptedAppendLog.kt @@ -20,9 +20,12 @@ */ package com.vitorpamplona.amethyst.commons.storage -import java.io.File -import java.io.FileOutputStream -import java.io.RandomAccessFile +import com.vitorpamplona.amethyst.commons.util.moveOrCopy +import com.vitorpamplona.amethyst.commons.util.platformFileSystem +import com.vitorpamplona.amethyst.commons.util.sibling +import okio.FileSystem +import okio.Path +import okio.use /** * An encrypted-at-rest log of UTF-8 entries that can be appended to in @@ -74,11 +77,14 @@ import java.io.RandomAccessFile * open. One unreadable segment then costs only its own entries; a throw would * abort the whole read, and a caller that reads an empty log can overwrite a * history that was merely unreadable. + * @param fileSystem where the logs live. Durability rests on + * [okio.FileHandle.flush], which on the JVM and Android is an `fsync`. */ class EncryptedAppendLog( private val encrypt: (ByteArray) -> ByteArray, private val decrypt: (ByteArray) -> ByteArray?, private val compactAfterSegments: Int = COMPACT_AFTER_SEGMENTS, + private val fileSystem: FileSystem = platformFileSystem, ) { /** Entries of one file, plus what it takes to append without re-reading it. */ private class LogState( @@ -94,10 +100,15 @@ class EncryptedAppendLog( var looseEntries: Int, ) - private val logs = mutableMapOf() + /** + * Keyed by the normalized path. That folds `a/./b` and `a/../a/b` together but does not resolve + * a relative path against the working directory, so callers must spell one file one way; every + * store here builds its paths from one directory. + */ + private val logs = mutableMapOf() - private fun stateFor(file: File): LogState = - logs.getOrPut(file.absolutePath) { + private fun stateFor(file: Path): LogState = + logs.getOrPut(file.normalized()) { val decoded = decodeFile(file) // A torn trailing segment is dropped from the FILE, not merely from @@ -105,9 +116,9 @@ class EncryptedAppendLog( // a record that parsing always stops at, so every later append is // written and then never read back — the log goes silently // write-only, for good. - if (decoded.headed && decoded.validLength < file.length()) { + if (decoded.headed && decoded.validLength < fileLength(file)) { try { - RandomAccessFile(file, "rw").use { it.setLength(decoded.validLength) } + fileSystem.openReadWrite(file).use { it.resize(decoded.validLength) } } catch (_: Exception) { // Best effort: the next fold rewrites the file wholesale and // resolves it anyway. @@ -125,17 +136,17 @@ class EncryptedAppendLog( } /** Every entry in [file], oldest first. */ - fun readAll(file: File): List = stateFor(file).entries.toList() + fun readAll(file: Path): List = stateFor(file).entries.toList() /** Whether [entry] is already in [file], without reading it back from disk. */ fun contains( - file: File, + file: Path, entry: String, ): Boolean = entry in stateFor(file).seen /** Append one entry. Constant time, apart from a periodic fold. */ fun append( - file: File, + file: Path, entry: String, ) { val state = stateFor(file) @@ -176,13 +187,13 @@ class EncryptedAppendLog( * between. */ private fun foldLooseTail( - file: File, + file: Path, state: LogState, ) { if (state.looseEntries == 0) return - val prefix = ByteArray(state.foldedLength.toInt()) - RandomAccessFile(file, "r").use { it.readFully(prefix) } + // Exactly foldedLength bytes, or an EOFException — what readFully did. + val prefix = fileSystem.read(file) { readByteArray(state.foldedLength) } val folded = encrypt(encodeEntries(state.entries.takeLast(state.looseEntries))) val out = ByteArray(prefix.size + 4 + folded.size) @@ -200,26 +211,28 @@ class EncryptedAppendLog( } private fun appendSegment( - file: File, + file: Path, entries: List, ) { - file.parentFile?.mkdirs() + file.parent?.let { fileSystem.createDirectories(it) } val segment = encrypt(encodeEntries(entries)) - FileOutputStream(file, true).use { out -> - out.write(lengthPrefix(segment.size)) - out.write(segment) + // Opened without truncating and written at its current end: an append. + fileSystem.openReadWrite(file).use { handle -> + val end = handle.size() + handle.write(end, lengthPrefix(segment.size), 0, 4) + handle.write(end + 4, segment, 0, segment.size) // An append that survives only in the page cache would lose a // message the UI has already shown as sent. - out.fd.sync() + handle.flush() } } /** Replace the whole log with [entries], as a single folded segment. */ fun rewrite( - file: File, + file: Path, entries: List, ) { - file.parentFile?.mkdirs() + file.parent?.let { fileSystem.createDirectories(it) } val segment = encrypt(encodeEntries(entries)) val out = ByteArray(HEADER_LENGTH + 4 + segment.size) @@ -230,7 +243,7 @@ class EncryptedAppendLog( atomicWrite(file, out) val state = - logs.getOrPut(file.absolutePath) { + logs.getOrPut(file.normalized()) { LogState(mutableListOf(), mutableSetOf(), headed = true, foldedLength = 0L, looseSegments = 0, looseEntries = 0) } state.entries.clear() @@ -244,8 +257,8 @@ class EncryptedAppendLog( } /** Drop the in-memory cache for [file]; call when the file is deleted. */ - fun forget(file: File) { - logs.remove(file.absolutePath) + fun forget(file: Path) { + logs.remove(file.normalized()) } private class Decoded( @@ -258,11 +271,11 @@ class EncryptedAppendLog( val looseEntries: Int, ) - private fun decodeFile(file: File): Decoded { + private fun decodeFile(file: Path): Decoded { // A file that does not exist yet has no header, so the first append has // to write one rather than tack a bare segment onto nothing. - if (!file.exists()) return Decoded(emptyList(), false, 0L, 0L, 0, 0) - val bytes = file.readBytes() + if (!fileSystem.exists(file)) return Decoded(emptyList(), false, 0L, 0L, 0, 0) + val bytes = fileSystem.read(file) { readByteArray() } if (!bytes.startsWithMagic() || bytes.size < HEADER_LENGTH) { // The older format: the file is one encrypted blob and nothing else. @@ -347,20 +360,22 @@ class EncryptedAppendLog( /** Write via a temp file and rename, so a crash can't leave a half-written log. */ private fun atomicWrite( - target: File, + target: Path, data: ByteArray, ) { - val tempFile = File(target.parentFile, "${target.name}.tmp") - FileOutputStream(tempFile).use { out -> - out.write(data) - out.fd.sync() - } - if (!tempFile.renameTo(target)) { - tempFile.copyTo(target, overwrite = true) - tempFile.delete() + val tempFile = target.sibling("${target.name}.tmp") + fileSystem.openReadWrite(tempFile).use { handle -> + // Truncated first, as opening a FileOutputStream did: a stale temp + // longer than [data] must not leave its tail behind. + handle.resize(0L) + handle.write(0L, data, 0, data.size) + handle.flush() } + fileSystem.moveOrCopy(tempFile, target) } + private fun fileLength(file: Path): Long = fileSystem.metadataOrNull(file)?.size ?: 0L + private fun ByteArray.startsWithMagic(): Boolean { if (size < MAGIC.size) return false for (i in MAGIC.indices) if (this[i] != MAGIC[i]) return false diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/tor/MoneyOpRelayRouting.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/tor/MoneyOpRelayRouting.kt new file mode 100644 index 0000000000..2b662250e6 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/tor/MoneyOpRelayRouting.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.tor + +import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl + +/** + * Puts the relays a payment talks to under the money-operations Tor preference for as long as the + * payment runs, rather than under the generic new-relay policy. Registrations are counted, so + * each [registerMoneyOpRelays] needs its own [unregisterMoneyOpRelays]. + */ +interface MoneyOpRelayRouting { + fun registerMoneyOpRelays(relays: Set) + + fun unregisterMoneyOpRelays(relays: Set) + + /** Routes nothing specially: for previews and hosts without Tor. */ + object None : MoneyOpRelayRouting { + override fun registerMoneyOpRelays(relays: Set) = Unit + + override fun unregisterMoneyOpRelays(relays: Set) = Unit + } +} diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/AmountFormat.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/AmountFormat.kt new file mode 100644 index 0000000000..ded4fca52b --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/AmountFormat.kt @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import com.vitorpamplona.quartz.utils.BigDecimal +import kotlin.math.abs +import kotlin.math.floor +import kotlin.math.round + +/** + * A zap amount in compact form: whole units below 10,000, then k, M and G. The amount is rounded + * half-up to a whole number of the unit before the unit is picked, so 999,500 reads "1.0M" rather + * than "1000k"; M and G below ten carry one decimal place ("3.0M"). Empty for null or for an + * amount that rounds to nothing. + */ +expect fun showAmount(amount: BigDecimal?): String + +/** [showAmount] without the decimal place on M and G ("3M"). */ +expect fun showAmountInteger(amount: BigDecimal?): String + +/** + * [showAmount] and [showAmountInteger] over a Double, for platforms without java.text. Exact for + * zap amounts: a tie only happens at an exact .5, which a Double holds exactly at this magnitude. + */ +internal fun compactAmount( + value: Double, + withDecimal: Boolean, + decimalSeparator: Char, +): String { + // <=, not <: the JVM's threshold is BigDecimal(0.01), built from the double, a hair above 0.01. + if (abs(value) <= 0.01) return "" + // DecimalFormat("#") rounds half-even. + if (value < 10_000) return round(value).toLong().toString() + + val kilos = roundHalfUp(value / 1_000) + if (kilos < 1_000) return "${kilos}k" + val megas = roundHalfUp(value / 1_000_000) + if (megas < 1_000) return if (withDecimal && megas < 10) "$megas${decimalSeparator}0M" else "${megas}M" + val gigas = roundHalfUp(value / 1_000_000_000) + return if (withDecimal && gigas < 10) "$gigas${decimalSeparator}0G" else "${gigas}G" +} + +private fun roundHalfUp(value: Double): Long = if (value >= 0) floor(value + 0.5).toLong() else -floor(-value + 0.5).toLong() diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/ConcurrentSet.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/ConcurrentSet.kt index 519a5e1aa3..d1e275aa11 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/ConcurrentSet.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/ConcurrentSet.kt @@ -42,7 +42,7 @@ expect class ConcurrentSet() { /** Adds [element]; returns true if it was not already present. */ fun add(element: E): Boolean - fun contains(element: E): Boolean + operator fun contains(element: E): Boolean /** Removes [element]; returns true if it was present. */ fun remove(element: E): Boolean @@ -50,4 +50,9 @@ expect class ConcurrentSet() { fun clear() val size: Int + + fun isEmpty(): Boolean + + /** A point-in-time copy — safe to iterate without a lock. */ + fun snapshot(): Set } diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/CountFormat.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/CountFormat.kt new file mode 100644 index 0000000000..41475c690a --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/CountFormat.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import kotlin.math.roundToInt + +/** A count in compact form (12k, 3M), or empty for none. */ +fun showCount(count: Int?): String { + if (count == null) return "" + if (count == 0) return "" + + return when { + count >= 1000000000 -> "${(count / 1000000000f).roundToInt()}G" + count >= 1000000 -> "${(count / 1000000f).roundToInt()}M" + count >= 10000 -> "${(count / 1000f).roundToInt()}k" + else -> "$count" + } +} diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/DecimalPatternFormatter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/DecimalPatternFormatter.kt new file mode 100644 index 0000000000..db2d8e9155 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/DecimalPatternFormatter.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +/** + * Formats numbers with a `java.text.DecimalFormat` pattern ("##.00", "###") in the default + * locale's symbols: "-1.25" in en-US, "-1,25" in de-DE. Not thread-safe; build one per caller. + */ +expect class DecimalPatternFormatter( + pattern: String, +) { + fun format(value: Double): String +} diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/EventPrettyJson.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/EventPrettyJson.kt new file mode 100644 index 0000000000..74280eaf87 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/EventPrettyJson.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import com.vitorpamplona.quartz.nip01Core.core.Event + +/** The event as indented JSON, for people to read (the "copy JSON" action), not for the wire. */ +expect fun Event.toPrettyJson(): String diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/FileSystemExt.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/FileSystemExt.kt new file mode 100644 index 0000000000..0348957608 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/FileSystemExt.kt @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import okio.FileSystem +import okio.IOException +import okio.Path +import okio.Path.Companion.toPath + +/* + * The java.io.File idioms that okio spells differently, for stores moving off + * File without changing what they do on failure. + * + * okio reports a failed delete or rename by throwing; File reported it by + * returning false, and the stores were written around that. These keep the + * File behaviour, so a port is a port and not a quiet change in error handling. + */ + +/** A file next to this one: `File(parentFile, name)`. */ +fun Path.sibling(name: String): Path = parent?.div(name) ?: name.toPath() + +/** + * Deletes a file or an empty directory, and never throws: `File.delete()`. + * + * @return true when [path] is gone, including when it never existed. + */ +fun FileSystem.deleteQuietly(path: Path): Boolean = + try { + delete(path) + true + } catch (e: IOException) { + !exists(path) + } + +/** + * Deletes [path] and everything under it, carrying on past anything it cannot + * delete: `File.deleteRecursively()`. + * + * One difference, deliberately kept: symlinks are deleted, never followed. + * `File.deleteRecursively` walks into a linked directory and empties it, which + * no store here ever wanted. + * + * @return true when nothing is left, including when [path] never existed. + */ +fun FileSystem.deleteRecursivelyQuietly(path: Path): Boolean { + var deleted = true + // metadataOrNull does not follow symlinks, so a link reads as a non-directory + // and is deleted itself rather than walked into. + if (metadataOrNull(path)?.isDirectory == true) { + // Listed one directory at a time, so a directory that cannot be listed + // costs only its own subtree: its siblings are still deleted, as + // File.deleteRecursively did. + val children = + try { + list(path) + } catch (e: IOException) { + deleted = false + emptyList() + } + for (child in children) deleted = deleteRecursivelyQuietly(child) && deleted + } + return deleteQuietly(path) && deleted +} + +/** + * Replaces [target] with [source]: an atomic rename, or, where the filesystem + * refuses one, a copy over [target] and a delete of [source]. + * + * The fallback is what `if (!temp.renameTo(file)) { temp.copyTo(file, true); temp.delete() }` + * did. It is not atomic, and is only here so that a filesystem without rename + * still gets written. + */ +fun FileSystem.moveOrCopy( + source: Path, + target: Path, +) { + try { + atomicMove(source, target) + } catch (e: IOException) { + copy(source, target) + deleteQuietly(source) + } +} diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/HttpUrlResolution.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/HttpUrlResolution.kt new file mode 100644 index 0000000000..51d1ca1149 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/HttpUrlResolution.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +/** The host of [url] when it parses as an absolute URL with a scheme the platform knows, else null. */ +expect fun absoluteUrlHost(url: String): String? + +/** + * Resolves [reference] against [base] as RFC 3986 §5 describes (any relative form, not only + * root-relative ones), and returns the result only when it is an absolute `http(s)` URL. A null + * or unparseable [base] leaves [reference] to stand on its own. + */ +expect fun resolveHttpUrl( + base: String?, + reference: String, +): String? diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/MeasurementSystem.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/MeasurementSystem.kt new file mode 100644 index 0000000000..8dcbcae6d0 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/MeasurementSystem.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +/** Countries that use miles for road distance (imperial / US customary). */ +internal val MILES_COUNTRIES = setOf("US", "GB", "LR", "MM") + +/** Whether the device's measurement preference favours miles for distance. */ +expect fun phonePrefersMiles(): Boolean diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/SpokenLanguages.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/SpokenLanguages.kt new file mode 100644 index 0000000000..011b6f1750 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/SpokenLanguages.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +/** + * The ISO 639 language codes (`en`, `pt`, …) of every language the user has configured on this + * device, in no particular order. New accounts default to not translating from these. + */ +expect fun getLanguagesSpokenByUser(): Set + +/** The ISO 639 code of the device's current language, the default target for translations. */ +expect fun getDefaultLanguageCode(): String diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/TimeDiffFormat.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/TimeDiffFormat.kt new file mode 100644 index 0000000000..73614975e8 --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/TimeDiffFormat.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import com.vitorpamplona.quartz.utils.TimeUtils + +fun timeDiffAgoLong(timeDifference: Int): String = + when { + timeDifference > TimeUtils.ONE_YEAR -> (timeDifference / TimeUtils.ONE_YEAR).toString() + " years" + timeDifference > TimeUtils.ONE_MONTH -> (timeDifference / TimeUtils.ONE_MONTH).toString() + " months" + timeDifference > TimeUtils.ONE_DAY -> (timeDifference / TimeUtils.ONE_DAY).toString() + " days" + timeDifference > TimeUtils.ONE_HOUR -> (timeDifference / TimeUtils.ONE_HOUR).toString() + " hours" + timeDifference > TimeUtils.ONE_MINUTE -> (timeDifference / TimeUtils.ONE_MINUTE).toString() + " minutes" + else -> "now" + } + +fun timeDiffAgoShortish(timeDifference: Int): String = + when { + timeDifference > TimeUtils.ONE_YEAR -> (timeDifference / TimeUtils.ONE_YEAR).toString() + " yrs" + timeDifference > TimeUtils.ONE_MONTH -> (timeDifference / TimeUtils.ONE_MONTH).toString() + " mos" + timeDifference > TimeUtils.ONE_DAY -> (timeDifference / TimeUtils.ONE_DAY).toString() + " days" + timeDifference > TimeUtils.ONE_HOUR -> (timeDifference / TimeUtils.ONE_HOUR).toString() + " hrs" + timeDifference > TimeUtils.ONE_MINUTE -> (timeDifference / TimeUtils.ONE_MINUTE).toString() + " mins" + else -> "now" + } diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/TimeFormatUtils.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/TimeFormatUtils.kt similarity index 90% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/TimeFormatUtils.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/TimeFormatUtils.kt index ce09af14e6..dbb83b7435 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/TimeFormatUtils.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/TimeFormatUtils.kt @@ -20,8 +20,6 @@ */ package com.vitorpamplona.amethyst.commons.util -import java.util.Locale - /** * Formats seconds into a human-readable time string (M:SS or MM:SS format). * @@ -32,8 +30,8 @@ fun formatSecondsToTime(seconds: Int): String { val minutes = seconds / 60 val secs = seconds % 60 return if (minutes > 0) { - String.format(Locale.getDefault(), "%d:%02d", minutes, secs) + "$minutes:${secs.toString().padStart(2, '0')}" } else { - String.format(Locale.getDefault(), "0:%02d", secs) + "0:${secs.toString().padStart(2, '0')}" } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/dal/VideoFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/video/dal/VideoFeedFilter.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/dal/VideoFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/video/dal/VideoFeedFilter.kt index 42dd92faf4..6756242124 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/dal/VideoFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/video/dal/VideoFeedFilter.kt @@ -18,11 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.video.dal +package com.vitorpamplona.amethyst.commons.video.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams import com.vitorpamplona.amethyst.commons.feeds.SupportedContent +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -30,8 +32,6 @@ import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.relayClient.video.SUPPORTED_VIDEO_FEED_MIME_TYPES_SET import com.vitorpamplona.amethyst.commons.richtext.RichTextParser -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip68Picture.PictureEvent import com.vitorpamplona.quartz.nip68Picture.PictureMeta diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountViewModelHost.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountViewModelHost.kt new file mode 100644 index 0000000000..d596783a8e --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountViewModelHost.kt @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.viewmodels + +import com.vitorpamplona.amethyst.commons.service.lnurl.LnurlHttpTransport +import com.vitorpamplona.amethyst.commons.service.pow.PoWJobFailure +import com.vitorpamplona.amethyst.commons.tor.MoneyOpRelayRouting +import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStats +import com.vitorpamplona.quartz.nip01Core.relay.sockets.WebsocketBuilder +import kotlinx.coroutines.flow.Flow + +/** + * What the account's ViewModel needs from the process it runs in: app-wide services that outlive + * any one account, and the few actions only the platform can perform. Android implements it over + * its app modules; previews pass a no-op. + */ +interface AccountViewModelHost { + /** Fires when memory is tight enough that feeds should drop the Notes they hold. */ + val memoryPressure: Flow + + /** Whether the local Blossom cache answers its probe. */ + val localBlossomCacheAvailable: Flow + + /** Background proof-of-work posts that could not be signed or sent. */ + val powPublishFailures: Flow + + /** Per-relay connection statistics, which order the relays a crawl visits. */ + val relayStats: RelayStats + + /** Opens sockets for the throwaway clients crawls use (Event Sync, Cashu discovery). */ + val websocketBuilder: WebsocketBuilder + + /** HTTP for LNURL-pay (zaps, invoices, melts), over the clients the app routes payments through. */ + val lnurlTransport: LnurlHttpTransport + + /** Routes a payment's relays under the money-operations Tor preference while it runs. */ + val moneyOpRelays: MoneyOpRelayRouting + + /** Public keys of every account saved on this device. */ + val savedAccounts: Flow> + + /** Removes the system notification posted for [eventId], if there is one. */ + fun dismissNotificationFor(eventId: HexKey) + + /** Hands a BOLT11 [invoice] to an installed wallet app. False when none could take it. */ + fun openLightningWallet(invoice: String): Boolean +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/webBookmarks/dal/WebBookmarkFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/webBookmarks/dal/WebBookmarkFeedFilter.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/webBookmarks/dal/WebBookmarkFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/webBookmarks/dal/WebBookmarkFeedFilter.kt index 24af3b3231..9e4dd6955c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/webBookmarks/dal/WebBookmarkFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/webBookmarks/dal/WebBookmarkFeedFilter.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.webBookmarks.dal +package com.vitorpamplona.amethyst.commons.webBookmarks.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nipB0WebBookmarks.WebBookmarkEvent class WebBookmarkFeedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/dal/WorkoutFeedFilter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/workouts/dal/WorkoutFeedFilter.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/dal/WorkoutFeedFilter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/workouts/dal/WorkoutFeedFilter.kt index 127553191b..6802306d50 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/dal/WorkoutFeedFilter.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/workouts/dal/WorkoutFeedFilter.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.dal +package com.vitorpamplona.amethyst.commons.workouts.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter import com.vitorpamplona.amethyst.commons.feeds.FilterByListParams +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.experimental.fitness.workout.WorkoutRecordEvent class WorkoutFeedFilter( diff --git a/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/ZoneMathTest.kt b/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/ZoneMathTest.kt index 9dd96efbcd..4de31b0c1c 100644 --- a/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/ZoneMathTest.kt +++ b/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/ZoneMathTest.kt @@ -108,6 +108,18 @@ class ZoneMathTest { assertEquals(1793505600L, ZoneMath.startOfDay(SearchDate(2026, 11, 1), havana)) } + @Test + fun anEpochDayCountsLocalDaysAcrossAClockChange() { + // 2026-03-08 is day 20520. Local midnight in New York is 05:00Z before the change. + assertEquals(20520L, ZoneMath.epochDayAt(1772946000L, newYork)) + assertEquals(20519L, ZoneMath.epochDayAt(1772945999L, newYork)) + // 23:59:59 EDT on 03-08 is 03:59:59Z the next UTC day: still 03-08 here. + assertEquals(20520L, ZoneMath.epochDayAt(1773028799L, newYork)) + assertEquals(20521L, ZoneMath.epochDayAt(1773028800L, newYork)) + // Before 1970 the day still floors, not truncates toward zero. + assertEquals(-1L, ZoneMath.epochDayAt(-1L, TestZone(0L))) + } + @Test fun anInstantNamesTheCivilDayItFallsOnHere() { // One second either side of local midnight in New York. diff --git a/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/util/ConcurrentSetTest.kt b/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/util/ConcurrentSetTest.kt index f6e2543476..0668079e00 100644 --- a/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/util/ConcurrentSetTest.kt +++ b/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/util/ConcurrentSetTest.kt @@ -60,4 +60,17 @@ class ConcurrentSetTest { assertEquals(0, set.size) assertFalse(set.contains("a")) } + + @Test + fun `snapshot is a copy that later writes do not touch`() { + val set = ConcurrentSet() + assertTrue(set.isEmpty()) + set.add("a") + val copy = set.snapshot() + set.add("b") + set.remove("a") + assertEquals(setOf("a"), copy) + assertTrue("b" in set) + assertFalse(set.isEmpty()) + } } diff --git a/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/podcasts/PreviewTextFetch.ios.kt b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/podcasts/PreviewTextFetch.ios.kt new file mode 100644 index 0000000000..96645c3bea --- /dev/null +++ b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/podcasts/PreviewTextFetch.ios.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.podcasts + +import com.vitorpamplona.amethyst.commons.service.http.IRoleBasedHttpClientBuilder + +actual suspend fun IRoleBasedHttpClientBuilder.fetchPreviewText(url: String): String? = null diff --git a/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/LocalClock.ios.kt b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/LocalClock.ios.kt index aaa6b68442..cfebd03c92 100644 --- a/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/LocalClock.ios.kt +++ b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/LocalClock.ios.kt @@ -67,6 +67,8 @@ actual object LocalClock { actual fun today(): SearchDate = ZoneMath.dayAt(currentTimeSeconds(), localZone) + actual fun epochDayCounter(): EpochDayCounter = EpochDayCounter { ZoneMath.epochDayAt(it, localZone) } + /** * Which weekday a week starts on here, 0 = Sunday. `firstWeekday` follows the reader's own * region setting — Sunday across most of the Americas and East Asia, Monday across Europe, diff --git a/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/service/VideoOnlineProbe.ios.kt b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/service/VideoOnlineProbe.ios.kt new file mode 100644 index 0000000000..ada112dd74 --- /dev/null +++ b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/service/VideoOnlineProbe.ios.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.service + +import com.vitorpamplona.amethyst.commons.service.http.IRoleBasedHttpClientBuilder + +actual suspend fun IRoleBasedHttpClientBuilder.isVideoOnline(url: String): Boolean = true diff --git a/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/service/http/IRoleBasedHttpClientBuilder.ios.kt b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/service/http/IRoleBasedHttpClientBuilder.ios.kt new file mode 100644 index 0000000000..f4b0dbc433 --- /dev/null +++ b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/service/http/IRoleBasedHttpClientBuilder.ios.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.service.http + +actual interface IRoleBasedHttpClientBuilder diff --git a/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/AmountFormat.ios.kt b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/AmountFormat.ios.kt new file mode 100644 index 0000000000..6b886d1dd0 --- /dev/null +++ b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/AmountFormat.ios.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import com.vitorpamplona.quartz.utils.BigDecimal +import com.vitorpamplona.quartz.utils.toDoubleValue +import platform.Foundation.NSLocale +import platform.Foundation.currentLocale +import platform.Foundation.decimalSeparator + +private fun localDecimalSeparator(): Char = NSLocale.currentLocale.decimalSeparator.firstOrNull() ?: '.' + +actual fun showAmount(amount: BigDecimal?): String = amount?.let { compactAmount(it.toDoubleValue(), withDecimal = true, localDecimalSeparator()) } ?: "" + +actual fun showAmountInteger(amount: BigDecimal?): String = amount?.let { compactAmount(it.toDoubleValue(), withDecimal = false, localDecimalSeparator()) } ?: "" diff --git a/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/ConcurrentSet.ios.kt b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/ConcurrentSet.ios.kt index 5fc7921153..0fbf392a5c 100644 --- a/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/ConcurrentSet.ios.kt +++ b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/ConcurrentSet.ios.kt @@ -29,11 +29,15 @@ actual class ConcurrentSet { actual fun add(element: E): Boolean = lock.withLock { set.add(element) } - actual fun contains(element: E): Boolean = lock.withLock { set.contains(element) } + actual operator fun contains(element: E): Boolean = lock.withLock { set.contains(element) } actual fun remove(element: E): Boolean = lock.withLock { set.remove(element) } actual fun clear() = lock.withLock { set.clear() } actual val size: Int get() = lock.withLock { set.size } + + actual fun isEmpty(): Boolean = lock.withLock { set.isEmpty() } + + actual fun snapshot(): Set = lock.withLock { HashSet(set) } } diff --git a/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/DecimalPatternFormatter.ios.kt b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/DecimalPatternFormatter.ios.kt new file mode 100644 index 0000000000..d3ad46c075 --- /dev/null +++ b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/DecimalPatternFormatter.ios.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import platform.Foundation.NSNumber +import platform.Foundation.NSNumberFormatter +import platform.Foundation.NSNumberFormatterRoundHalfEven +import platform.Foundation.numberWithDouble + +/** NSNumberFormatter reads the same pattern syntax and, like DecimalFormat, rounds half-even. */ +actual class DecimalPatternFormatter actual constructor( + pattern: String, +) { + private val formatter = + NSNumberFormatter().apply { + positiveFormat = pattern + roundingMode = NSNumberFormatterRoundHalfEven + } + + actual fun format(value: Double): String = formatter.stringFromNumber(NSNumber.numberWithDouble(value)) ?: value.toString() +} diff --git a/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/EventPrettyJson.ios.kt b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/EventPrettyJson.ios.kt new file mode 100644 index 0000000000..75dbbe389a --- /dev/null +++ b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/EventPrettyJson.ios.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import com.vitorpamplona.quartz.nip01Core.core.Event +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement + +private val prettyJson = Json { prettyPrint = true } + +actual fun Event.toPrettyJson(): String = prettyJson.encodeToString(JsonElement.serializer(), Json.parseToJsonElement(toJson())) diff --git a/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/HttpUrlResolution.ios.kt b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/HttpUrlResolution.ios.kt new file mode 100644 index 0000000000..325d6af833 --- /dev/null +++ b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/HttpUrlResolution.ios.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import platform.Foundation.NSURL + +actual fun absoluteUrlHost(url: String): String? = NSURL.URLWithString(url)?.takeIf { it.scheme != null }?.host + +actual fun resolveHttpUrl( + base: String?, + reference: String, +): String? { + val baseUrl = base?.let { NSURL.URLWithString(it) } + val resolved = NSURL.URLWithString(reference, relativeToURL = baseUrl)?.absoluteURL ?: return null + val scheme = resolved.scheme?.lowercase() + return if (scheme == "http" || scheme == "https") resolved.absoluteString else null +} diff --git a/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/MeasurementSystem.ios.kt b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/MeasurementSystem.ios.kt new file mode 100644 index 0000000000..20d6fdcca6 --- /dev/null +++ b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/MeasurementSystem.ios.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import platform.Foundation.NSLocale +import platform.Foundation.countryCode +import platform.Foundation.currentLocale + +/** By country, as on the other platforms: iOS reports the UK as metric, but its roads use miles. */ +actual fun phonePrefersMiles(): Boolean = NSLocale.currentLocale.countryCode?.uppercase() in MILES_COUNTRIES diff --git a/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/SpokenLanguages.ios.kt b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/SpokenLanguages.ios.kt new file mode 100644 index 0000000000..602a6a2dd3 --- /dev/null +++ b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/SpokenLanguages.ios.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import platform.Foundation.NSLocale +import platform.Foundation.currentLocale +import platform.Foundation.languageCode +import platform.Foundation.preferredLanguages + +// preferredLanguages holds BCP 47 tags ("pt-BR", "zh-Hans-CN"); the language code is the first subtag. +actual fun getLanguagesSpokenByUser(): Set = + NSLocale.preferredLanguages + .mapNotNull { (it as? String)?.substringBefore('-')?.lowercase() } + .filter { it.isNotEmpty() } + .toSet() + +actual fun getDefaultLanguageCode(): String = NSLocale.currentLocale.languageCode diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cashu/CashuWalletDiscovery.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cashu/CashuWalletDiscovery.kt index 772e18e7fb..71d2e6a214 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cashu/CashuWalletDiscovery.kt +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/cashu/CashuWalletDiscovery.kt @@ -56,7 +56,7 @@ import kotlin.coroutines.cancellation.CancellationException * events authored by the account. * * Modeled on - * [com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.eventsync.EventSync]: + * [com.vitorpamplona.amethyst.commons.relays.eventsync.EventSync]: * - queries up to [MAX_CONCURRENT_RELAYS] relays concurrently via a sliding * [Semaphore] window inside a [supervisorScope]; * - paginates each relay individually through Quartz's [fetchAllPages]; diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/marmot/EncryptedMarmotMessageStore.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/marmot/EncryptedMarmotMessageStore.kt index 0c0cc10d4b..5f3e144401 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/marmot/EncryptedMarmotMessageStore.kt +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/marmot/EncryptedMarmotMessageStore.kt @@ -29,6 +29,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext +import okio.Path.Companion.toOkioPath import java.io.File /** @@ -72,13 +73,13 @@ class EncryptedMarmotMessageStore( logMutex.withLock { try { val file = messagesFile(nostrGroupId) - if (log.contains(file, innerEventJson)) { + if (log.contains(file.toOkioPath(), innerEventJson)) { Log.d(TAG) { "appendMessage($nostrGroupId): duplicate entry skipped" } return@withLock } - log.append(file, innerEventJson) + log.append(file.toOkioPath(), innerEventJson) Log.d(TAG) { - "appendMessage($nostrGroupId): now ${log.readAll(file).size} message(s) persisted" + "appendMessage($nostrGroupId): now ${log.readAll(file.toOkioPath()).size} message(s) persisted" } } catch (e: Exception) { Log.e(TAG, "appendMessage($nostrGroupId) FAILED: ${e.message}", e) @@ -105,7 +106,7 @@ class EncryptedMarmotMessageStore( withContext(Dispatchers.IO) { logMutex.withLock { for (file in listOf(messagesFile(nostrGroupId), epochsFile(nostrGroupId), snapshotFile(nostrGroupId), expiriesFile(nostrGroupId), epochRetentionsFile(nostrGroupId))) { - log.forget(file) + log.forget(file.toOkioPath()) if (file.exists() && !file.delete()) { Log.w(TAG) { "delete($nostrGroupId): failed to remove ${file.absolutePath}" } } @@ -340,7 +341,7 @@ class EncryptedMarmotMessageStore( private fun readAll(nostrGroupId: String): List = readAllFrom(messagesFile(nostrGroupId)) - private fun readAllFrom(file: File): List = log.readAll(file) + private fun readAllFrom(file: File): List = log.readAll(file.toOkioPath()) private fun writeAll( nostrGroupId: String, @@ -350,7 +351,7 @@ class EncryptedMarmotMessageStore( private fun writeAllTo( file: File, messages: List, - ) = log.rewrite(file, messages) + ) = log.rewrite(file.toOkioPath(), messages) companion object { private const val TAG = "EncryptedMarmotMessageStore" diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/preferences/AccountSecrets.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/preferences/AccountSecrets.kt index 46769ead3d..0f27330d76 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/preferences/AccountSecrets.kt +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/preferences/AccountSecrets.kt @@ -152,33 +152,6 @@ fun readLegacyAccountSecrets(source: LegacyPreferenceSource) = legacyZapPaymentRequestServer = source.getString(LegacyAccountSecretNames.ZAP_PAYMENT_REQUEST_SERVER), ) -/** - * The account's location-chat identity: the seed its per-geohash throwaway keys - * come from, and the handle it posts under. - * - * # Why this is not two more fields on [AccountSecrets] - * - * Every account save mirrors a whole [AccountSecrets], built field by field from - * `AccountSettings` — which does not hold these, because they are owned by - * `GeohashChatIdentityState` rather than by the settings object. Folding them in - * would make each save write null over them, and the group save uses - * `putOrRemove`, so null *deletes*. The seed would vanish on the next unrelated - * save and every geohash identity the user has would silently change. A separate - * group with its own save path cannot be wiped by a save that does not know - * about it. - * - * # Why encrypted - * - * The whole point of the seed is that the identities derived from it are - * unlinkable to the npub. Anyone who can read it can link every cell the user - * has ever posted in, to each other and to the device, which is exactly what the - * feature exists to prevent. It was in an encrypted file before; it stays in one. - */ -data class GeohashIdentitySecrets( - val deviceSeed: String? = null, - val nickname: String? = null, -) - /** Keys for [GeohashIdentitySecrets] inside an [EncryptedDataStore]. */ internal object GeohashIdentityKeys { val deviceSeed = stringPreferencesKey(LegacyAccountSecretNames.GEOHASH_DEVICE_SEED) diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/podcasts/PreviewTextFetch.jvmAndroid.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/podcasts/PreviewTextFetch.jvmAndroid.kt new file mode 100644 index 0000000000..b5caa1240d --- /dev/null +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/podcasts/PreviewTextFetch.jvmAndroid.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.podcasts + +import com.vitorpamplona.amethyst.commons.service.http.IRoleBasedHttpClientBuilder + +actual suspend fun IRoleBasedHttpClientBuilder.fetchPreviewText(url: String): String? = PodcastRemoteContent.fetchText(url, okHttpClientForPreview(url)) diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11Retriever.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11Retriever.kt index a8ca53429d..b8f56a15b5 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11Retriever.kt +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11Retriever.kt @@ -31,20 +31,14 @@ import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.coroutines.executeAsync +/** The OkHttp [Nip11Fetcher]. */ class Nip11Retriever( val okHttpClient: (NormalizedRelayUrl) -> OkHttpClient, -) { - enum class ErrorCode { - FAIL_TO_ASSEMBLE_URL, - FAIL_TO_REACH_SERVER, - FAIL_TO_PARSE_RESULT, - FAIL_WITH_HTTP_STATUS, - } - - suspend fun loadRelayInfo( +) : Nip11Fetcher { + override suspend fun loadRelayInfo( relay: NormalizedRelayUrl, onInfo: (Nip11RelayInformation) -> Unit, - onError: (NormalizedRelayUrl, ErrorCode, String?) -> Unit, + onError: (NormalizedRelayUrl, Nip11ErrorCode, String?) -> Unit, ) = withContext(Dispatchers.IO) { val url = relay.toHttp() val request = @@ -57,7 +51,7 @@ class Nip11Retriever( } catch (e: Exception) { if (e is CancellationException) throw e Log.e("RelayInfoFail", "Invalid URL ${relay.url}", e) - onError(relay, ErrorCode.FAIL_TO_ASSEMBLE_URL, e.message) + onError(relay, Nip11ErrorCode.FAIL_TO_ASSEMBLE_URL, e.message) return@withContext } @@ -71,10 +65,10 @@ class Nip11Retriever( if (body.startsWith("{")) { onInfo(Nip11RelayInformation.fromJson(body)) } else { - onError(relay, ErrorCode.FAIL_TO_PARSE_RESULT, body) + onError(relay, Nip11ErrorCode.FAIL_TO_PARSE_RESULT, body) } } else { - onError(relay, ErrorCode.FAIL_WITH_HTTP_STATUS, response.code.toString()) + onError(relay, Nip11ErrorCode.FAIL_WITH_HTTP_STATUS, response.code.toString()) } } catch (e: Exception) { if (e is CancellationException) throw e @@ -83,13 +77,16 @@ class Nip11Retriever( "Resulting Message from Relay ${relay.url} in not parseable: $body", e, ) - onError(relay, ErrorCode.FAIL_TO_PARSE_RESULT, e.message) + onError(relay, Nip11ErrorCode.FAIL_TO_PARSE_RESULT, e.message) } } } catch (e: Exception) { if (e is CancellationException) throw e Log.e("RelayInfoFail", "Failed to fetch NIP-11 from ${relay.url}", e) - onError(relay, ErrorCode.FAIL_TO_REACH_SERVER, e.message ?: e::class.simpleName) + onError(relay, Nip11ErrorCode.FAIL_TO_REACH_SERVER, e.message ?: e::class.simpleName) } } } + +/** A [Nip11CachedRetriever] over OkHttp, the client picked per relay. */ +fun Nip11CachedRetriever(okHttpClient: (NormalizedRelayUrl) -> OkHttpClient): Nip11CachedRetriever = Nip11CachedRetriever(Nip11Retriever(okHttpClient)) diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/richtext/MediaLocalContent.jvmAndroid.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/richtext/MediaLocalContent.jvmAndroid.kt new file mode 100644 index 0000000000..e045e8c543 --- /dev/null +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/richtext/MediaLocalContent.jvmAndroid.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.richtext + +import java.io.File + +/** [MediaPreloadedContent.localFile] as a `java.io.File`, for the JVM image loaders and players. */ +val MediaPreloadedContent.localJavaFile: File? get() = localFile?.toFile() diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/LocalClock.jvmAndroid.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/LocalClock.jvmAndroid.kt index f7d0992b90..f7288c0cad 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/LocalClock.jvmAndroid.kt +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/LocalClock.jvmAndroid.kt @@ -20,6 +20,7 @@ */ package com.vitorpamplona.amethyst.commons.search.calendar +import java.time.Instant import java.time.LocalDate import java.time.ZoneId import java.time.format.DateTimeFormatter @@ -53,6 +54,12 @@ actual object LocalClock { SearchDate(it.year, it.monthValue, it.dayOfMonth) } + actual fun epochDayCounter(): EpochDayCounter { + val rules = zone().rules + val offsets = ZoneOffsets { rules.getOffset(Instant.ofEpochSecond(it)).totalSeconds.toLong() } + return EpochDayCounter { ZoneMath.epochDayAt(it, offsets) } + } + // WeekFields counts DayOfWeek 1..7 from Monday; this API counts 0..6 from Sunday. actual fun firstDayOfWeek(): Int = WeekFields.of(Locale.getDefault()).firstDayOfWeek.value % 7 diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/OnlineCheck.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/OnlineChecker.kt similarity index 71% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/OnlineCheck.kt rename to commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/OnlineChecker.kt index 834d011380..e7da69b76b 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/OnlineCheck.kt +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/OnlineChecker.kt @@ -20,11 +20,8 @@ */ package com.vitorpamplona.amethyst.commons.service -import androidx.collection.LruCache -import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.RandomInstance -import com.vitorpamplona.quartz.utils.TimeUtils import okhttp3.EventListener import okhttp3.OkHttpClient import okhttp3.Protocol @@ -33,45 +30,22 @@ import okhttp3.coroutines.executeAsync import okio.ByteString.Companion.toByteString import kotlin.coroutines.cancellation.CancellationException -@Immutable data class OnlineCheckResult( - val timeInSecs: Long, - val online: Boolean, -) - +/** Checks whether a stream URL answers, over OkHttp, recording the result in [OnlineStatusCache]. */ object OnlineChecker { - val checkOnlineCache = LruCache(100) + val checkOnlineCache get() = OnlineStatusCache.cache - fun isCachedAndOffline(url: String?): Boolean { - if (url.isNullOrBlank()) return false - val cached = checkOnlineCache.get(url) - return cached != null && !cached.online && cached.timeInSecs > TimeUtils.fiveMinutesAgo() - } + fun isCachedAndOffline(url: String?): Boolean = OnlineStatusCache.isCachedAndOffline(url) - fun isOnlineCached(url: String?): Boolean { - if (url.isNullOrBlank()) return false - val cached = checkOnlineCache.get(url) - if (cached != null && cached.timeInSecs > TimeUtils.fiveMinutesAgo()) { - return cached.online - } - return false - } + fun isOnlineCached(url: String?): Boolean = OnlineStatusCache.isOnlineCached(url) - fun resetIfOfflineToRetry(url: String) { - val cached = checkOnlineCache.get(url) - if (cached != null && !cached.online) { - checkOnlineCache.remove(url) - } - } + fun resetIfOfflineToRetry(url: String) = OnlineStatusCache.resetIfOfflineToRetry(url) suspend fun isOnline( url: String?, okHttpClient: (String) -> OkHttpClient, ): Boolean { if (url.isNullOrBlank()) return false - val cached = checkOnlineCache.get(url) - if (cached != null && cached.timeInSecs > TimeUtils.fiveMinutesAgo()) { - return cached.online - } + OnlineStatusCache.fresh(url)?.let { return it.online } return try { val result = @@ -109,11 +83,11 @@ object OnlineChecker { } } - checkOnlineCache.put(url, OnlineCheckResult(TimeUtils.now(), result)) + OnlineStatusCache.record(url, result) result } catch (e: Exception) { if (e is CancellationException) throw e - checkOnlineCache.put(url, OnlineCheckResult(TimeUtils.now(), false)) + OnlineStatusCache.record(url, false) Log.e("LiveActivities", "Failed to check streaming url $url", e) false } diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/VideoOnlineProbe.jvmAndroid.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/VideoOnlineProbe.jvmAndroid.kt new file mode 100644 index 0000000000..b87c9835e8 --- /dev/null +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/VideoOnlineProbe.jvmAndroid.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.service + +import com.vitorpamplona.amethyst.commons.service.http.IRoleBasedHttpClientBuilder +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +actual suspend fun IRoleBasedHttpClientBuilder.isVideoOnline(url: String): Boolean = + withContext(Dispatchers.IO) { + OnlineChecker.isOnline(url, ::okHttpClientForVideo) + } diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/http/LocalBlossomCacheRedirectInterceptor.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/http/LocalBlossomCacheRedirectInterceptor.kt index df52ddaf64..7cdabb641f 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/http/LocalBlossomCacheRedirectInterceptor.kt +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/http/LocalBlossomCacheRedirectInterceptor.kt @@ -187,9 +187,9 @@ class LocalBlossomCacheRedirectInterceptor( private val BLOSSOM_LAST_SEGMENT_REGEX = Regex("^([0-9a-fA-F]{64})(?:\\.[^./]+)?$") /** Marks a request as a media download the local cache may serve. Stripped before sending. */ - const val MEDIA_HEADER = "X-Amethyst-Local-Blossom" - const val MEDIA = "media" - const val PROFILE_PICTURE = "profile-picture" + const val MEDIA_HEADER = LocalBlossomCacheHeaders.MEDIA_HEADER + const val MEDIA = LocalBlossomCacheHeaders.MEDIA + const val PROFILE_PICTURE = LocalBlossomCacheHeaders.PROFILE_PICTURE } } diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/http/IRoleBasedHttpClientBuilder.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/http/RoleBasedOkHttpClients.kt similarity index 89% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/http/IRoleBasedHttpClientBuilder.kt rename to commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/http/RoleBasedOkHttpClients.kt index e4d3bea7e9..2b134144a8 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/http/IRoleBasedHttpClientBuilder.kt +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/http/RoleBasedOkHttpClients.kt @@ -22,7 +22,8 @@ package com.vitorpamplona.amethyst.commons.service.http import okhttp3.OkHttpClient -interface IRoleBasedHttpClientBuilder { +/** The JVM face of `IRoleBasedHttpClientBuilder`: one OkHttp client per role and URL. */ +interface RoleBasedOkHttpClients { fun proxyPortForVideo(url: String): Int? fun okHttpClientForNip05(url: String): OkHttpClient @@ -39,3 +40,5 @@ interface IRoleBasedHttpClientBuilder { fun okHttpClientForPushRegistration(url: String): OkHttpClient } + +actual typealias IRoleBasedHttpClientBuilder = RoleBasedOkHttpClients diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/OkHttpLnurlTransport.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/OkHttpLnurlTransport.kt new file mode 100644 index 0000000000..391d45ff34 --- /dev/null +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/OkHttpLnurlTransport.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.service.lnurl + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.coroutines.executeAsync + +/** [LnurlHttpTransport] over OkHttp. [okHttpClient] picks the client for each URL (Tor, proxies). */ +class OkHttpLnurlTransport( + private val okHttpClient: (String) -> OkHttpClient, +) : LnurlHttpTransport { + override suspend fun get(url: String): LnurlHttpResponse { + val request = Request.Builder().url(url).build() + return okHttpClient(url).newCall(request).executeAsync().use { response -> + withContext(Dispatchers.IO) { + LnurlHttpResponse(response.code, response.message, response.body.string()) + } + } + } +} diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/tor/TorRelayState.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/tor/TorRelayState.kt index 0c00f35f06..de97a3737d 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/tor/TorRelayState.kt +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/tor/TorRelayState.kt @@ -40,7 +40,7 @@ class TorRelayState( val okHttpClient: DualHttpClientManager, val torSettingsFlow: TorSettingsFlow, val scope: CoroutineScope, -) { +) : MoneyOpRelayRouting { val dmRelays = MutableStateFlow>(emptySet()) val trustedRelays = MutableStateFlow>(emptySet()) @@ -72,7 +72,7 @@ class TorRelayState( * Used by the CLINK offer/debit payers so a one-off payment relay honors the money-operations * Tor preference instead of being treated as a generic "new" relay. */ - fun registerMoneyOpRelays(relays: Set) { + override fun registerMoneyOpRelays(relays: Set) { if (relays.isEmpty()) return adHocMoneyOpCounts.update { current -> current.toMutableMap().apply { @@ -81,7 +81,7 @@ class TorRelayState( } } - fun unregisterMoneyOpRelays(relays: Set) { + override fun unregisterMoneyOpRelays(relays: Set) { if (relays.isEmpty()) return adHocMoneyOpCounts.update { current -> current.toMutableMap().apply { diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/ConcurrentSet.jvmAndroid.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/ConcurrentSet.jvmAndroid.kt index e91b7196f9..116cfce607 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/ConcurrentSet.jvmAndroid.kt +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/ConcurrentSet.jvmAndroid.kt @@ -28,11 +28,15 @@ actual class ConcurrentSet { actual fun add(element: E): Boolean = set.add(element) - actual fun contains(element: E): Boolean = set.contains(element) + actual operator fun contains(element: E): Boolean = set.contains(element) actual fun remove(element: E): Boolean = set.remove(element) actual fun clear() = set.clear() actual val size: Int get() = set.size + + actual fun isEmpty(): Boolean = set.isEmpty() + + actual fun snapshot(): Set = HashSet(set) } diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/DecimalPatternFormatter.jvmAndroid.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/DecimalPatternFormatter.jvmAndroid.kt new file mode 100644 index 0000000000..4443e37ccc --- /dev/null +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/DecimalPatternFormatter.jvmAndroid.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import java.text.DecimalFormat + +actual class DecimalPatternFormatter actual constructor( + pattern: String, +) { + private val formatter = DecimalFormat(pattern) + + actual fun format(value: Double): String = formatter.format(value) +} diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/EventPrettyJson.jvmAndroid.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/EventPrettyJson.jvmAndroid.kt new file mode 100644 index 0000000000..98822dae5d --- /dev/null +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/EventPrettyJson.jvmAndroid.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper + +actual fun Event.toPrettyJson(): String = JacksonMapper.toJsonPretty(this) diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/HttpUrlResolution.jvmAndroid.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/HttpUrlResolution.jvmAndroid.kt new file mode 100644 index 0000000000..bda5b0c2a9 --- /dev/null +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/HttpUrlResolution.jvmAndroid.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import java.net.URI + +actual fun absoluteUrlHost(url: String): String? = runCatching { URI(url).toURL().host }.getOrNull() + +actual fun resolveHttpUrl( + base: String?, + reference: String, +): String? = + runCatching { + val baseUri = base?.let { runCatching { URI(it).toURL().toURI() }.getOrNull() } + val resolved = if (baseUri != null) baseUri.resolve(reference) else URI(reference) + if (!resolved.scheme.equals("http", ignoreCase = true) && + !resolved.scheme.equals("https", ignoreCase = true) + ) { + null + } else { + resolved.toURL().toString() + } + }.getOrNull() diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/TimeAgoFormatter.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/TimeAgoFormatter.kt index 43f6d5270c..a5f190f558 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/TimeAgoFormatter.kt +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/TimeAgoFormatter.kt @@ -105,26 +105,6 @@ fun timeAgo( } } -fun timeDiffAgoLong(timeDifference: Int): String = - when { - timeDifference > TimeUtils.ONE_YEAR -> (timeDifference / TimeUtils.ONE_YEAR).toString() + " years" - timeDifference > TimeUtils.ONE_MONTH -> (timeDifference / TimeUtils.ONE_MONTH).toString() + " months" - timeDifference > TimeUtils.ONE_DAY -> (timeDifference / TimeUtils.ONE_DAY).toString() + " days" - timeDifference > TimeUtils.ONE_HOUR -> (timeDifference / TimeUtils.ONE_HOUR).toString() + " hours" - timeDifference > TimeUtils.ONE_MINUTE -> (timeDifference / TimeUtils.ONE_MINUTE).toString() + " minutes" - else -> "now" - } - -fun timeDiffAgoShortish(timeDifference: Int): String = - when { - timeDifference > TimeUtils.ONE_YEAR -> (timeDifference / TimeUtils.ONE_YEAR).toString() + " yrs" - timeDifference > TimeUtils.ONE_MONTH -> (timeDifference / TimeUtils.ONE_MONTH).toString() + " mos" - timeDifference > TimeUtils.ONE_DAY -> (timeDifference / TimeUtils.ONE_DAY).toString() + " days" - timeDifference > TimeUtils.ONE_HOUR -> (timeDifference / TimeUtils.ONE_HOUR).toString() + " hrs" - timeDifference > TimeUtils.ONE_MINUTE -> (timeDifference / TimeUtils.ONE_MINUTE).toString() + " mins" - else -> "now" - } - /** * Formats a Unix timestamp as a date string. * For recent dates (< 1 day), returns the provided today string. diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/ZapFormatter.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/ZapFormatter.kt index 1e32ae89c6..7866756547 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/ZapFormatter.kt +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/ZapFormatter.kt @@ -54,7 +54,7 @@ private val dfN = ThreadLocal.withInitial { DecimalFormat("#") } * - 2500000 -> "3.0M" * - 10000000000 -> "10G" */ -fun showAmount(amount: BigDecimal?): String { +actual fun showAmount(amount: BigDecimal?): String { if (amount == null) return "" if (amount.abs() < MinDisplayableAmount) return "" if (amount < TenKilo) return dfN.get()!!.format(amount) diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/ZapFormatterNoDecimals.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/ZapFormatterNoDecimals.kt index 8dc0ae07d1..cb69abebc4 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/ZapFormatterNoDecimals.kt +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/ZapFormatterNoDecimals.kt @@ -44,7 +44,7 @@ private val dfN = override fun initialValue() = DecimalFormat("#") } -fun showAmountInteger(amount: BigDecimal?): String { +actual fun showAmountInteger(amount: BigDecimal?): String { if (amount == null) return "" if (amount.abs() < MinDisplayableAmount) return "" if (amount < TenKilo) return dfN.get()?.format(amount) ?: "" diff --git a/commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/util/MeasurementSystem.jvm.kt b/commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/util/MeasurementSystem.jvm.kt new file mode 100644 index 0000000000..24c0b2e6ff --- /dev/null +++ b/commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/util/MeasurementSystem.jvm.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import java.util.Locale + +/** The `-u-ms-` locale extension when set, else the country of the default format locale. */ +actual fun phonePrefersMiles(): Boolean { + val locale = Locale.getDefault(Locale.Category.FORMAT) + + locale.getUnicodeLocaleType("ms")?.let { ms -> + return ms == "ussystem" || ms == "uksystem" + } + + return locale.country.uppercase(Locale.ROOT) in MILES_COUNTRIES +} diff --git a/commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/util/SpokenLanguages.jvm.kt b/commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/util/SpokenLanguages.jvm.kt new file mode 100644 index 0000000000..660709702d --- /dev/null +++ b/commons/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/util/SpokenLanguages.jvm.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import java.util.Locale + +// The JVM exposes one default locale, not the OS's ordered preference list. +actual fun getLanguagesSpokenByUser(): Set = setOf(Locale.getDefault().language) + +actual fun getDefaultLanguageCode(): String = Locale.getDefault().language diff --git a/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/cordn/CordnHandoffStateTest.kt b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/cordn/CordnHandoffStateTest.kt index f41b719896..9bb9bf80ef 100644 --- a/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/cordn/CordnHandoffStateTest.kt +++ b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/cordn/CordnHandoffStateTest.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.amethyst.commons.cordn import kotlinx.coroutines.test.runTest +import okio.Path.Companion.toOkioPath import org.junit.Assert.assertFalse import org.junit.Assert.assertThrows import org.junit.Assert.assertTrue @@ -106,5 +107,5 @@ class CordnHandoffStateTest { assertTrue(first.handedOff.value) } - private fun state() = CordnHandoffState(FileCordnHandoffStore(folder.root)) + private fun state() = CordnHandoffState(FileCordnHandoffStore(folder.root.toOkioPath())) } diff --git a/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/cordn/CordnMigrationStoresBase64Test.kt b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/cordn/CordnMigrationStoresBase64Test.kt new file mode 100644 index 0000000000..5075a16b85 --- /dev/null +++ b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/cordn/CordnMigrationStoresBase64Test.kt @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.cordn + +import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer +import kotlinx.coroutines.test.runTest +import okio.Path.Companion.toOkioPath +import java.util.Base64 +import kotlin.io.path.createTempDirectory +import kotlin.random.Random +import kotlin.test.AfterTest +import kotlin.test.Test +import kotlin.test.assertEquals + +/** + * A handoff snapshot's base64 must mean the same thing on both sides of an + * upgrade: a phone on an older build (which used `java.util.Base64`) hands off + * to one on this build, and the other way round. + * + * Every length mod 3, so every padding case, and each input both padded and + * unpadded, because `java.util.Base64.getDecoder()` accepted either. + */ +class CordnMigrationStoresBase64Test { + private object Identity : CordnBlobCipher { + override fun encrypt(bytes: ByteArray) = bytes + + override fun decrypt(bytes: ByteArray) = bytes + } + + private val rootFile = createTempDirectory("cordn-b64").toFile() + private val root = rootFile.toOkioPath() + private val account = "e".repeat(64) + private val coordinator = "b".repeat(64) + + @AfterTest + fun cleanUp() { + rootFile.deleteRecursively() + } + + @Test + fun `snapshot base64 is java util Base64 in both directions`() = + runTest { + val random = Random(7) + val blobs = (1..13).map { random.nextBytes(it) } + val javaEncoder = Base64.getEncoder() + val unpadded = Base64.getEncoder().withoutPadding() + + val snapshot = + CordnMigrationSnapshot( + accountPubKey = account, + groups = + blobs.mapIndexed { i, blob -> + CordnMigrationGroup( + coordinatorPubKey = coordinator, + coordinatorRelays = listOf("wss://coord.example"), + gid = "g" + i.toString().padStart(2, '0'), + clientStateBase64 = if (i % 2 == 0) javaEncoder.encodeToString(blob) else unpadded.encodeToString(blob), + cursor = 0, + ) + }, + ) + + CordnMigrationStores.write(root, account, Identity, snapshot) + val read = + CordnMigrationStores.read( + root, + account, + Identity, + listOf(CoordinatorConfig(coordinator, listOf(RelayUrlNormalizer.normalizeOrNull("wss://coord.example")!!))), + ) + + assertEquals( + blobs.map { javaEncoder.encodeToString(it) }, + read.groups.sortedBy { it.gid }.map { it.clientStateBase64 }, + ) + } +} diff --git a/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/cordn/CordnStorageFormatGoldenTest.kt b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/cordn/CordnStorageFormatGoldenTest.kt new file mode 100644 index 0000000000..f93c5b9aee --- /dev/null +++ b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/cordn/CordnStorageFormatGoldenTest.kt @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.cordn + +import com.vitorpamplona.amethyst.commons.storage.EncryptedAppendLog +import com.vitorpamplona.quartz.cordn.appMultiDevice.CordnCarriedKeyPackage +import com.vitorpamplona.quartz.cordn.spec02Envelopes.CordnDeliveredMessage +import com.vitorpamplona.quartz.cordn.spec02Envelopes.CordnDeliveredMessageCodec +import com.vitorpamplona.quartz.cordn.spec02Envelopes.CordnEnvelope +import com.vitorpamplona.quartz.cordn.sync.EchoState +import com.vitorpamplona.quartz.cordn.sync.GroupCursor +import com.vitorpamplona.quartz.cordn.sync.PendingEpochOperation +import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer +import kotlinx.coroutines.test.runTest +import okio.Path.Companion.toOkioPath +import java.io.ByteArrayOutputStream +import java.io.File +import java.util.Base64 +import kotlin.io.path.createTempDirectory +import kotlin.test.AfterTest +import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNull +import kotlin.test.assertTrue +import kotlin.test.fail + +/** + * The on-disk format of the cordn stores and of [EncryptedAppendLog], pinned + * byte for byte. + * + * These files hold a user's encrypted MLS group state and message history, and + * none of it can be re-derived from anywhere else on the device: a layout or + * framing change that the next build cannot read is a group the user has lost. + * So this drives every writer through a representative sequence — overwrites, + * deletes, dedup, appends, a fold, a legacy blob, a torn tail, a migration — + * and compares the resulting tree against constants captured from the + * implementation that shipped. It then goes the other way, laying those exact + * bytes down on a clean disk and reading them back, which is the direction an + * upgrade actually travels. + * + * The cipher is a deterministic stand-in (a tag byte plus XOR) so the bytes are + * stable; it also makes a segment's ciphertext one byte longer than its + * plaintext, so a length prefix that recorded the wrong one would show. + * + * If this fails, the format changed. Do not regenerate the constants to make it + * pass unless the change is deliberate and comes with a reader for the old one. + */ +class CordnStorageFormatGoldenTest { + /** Deterministic, reversible, and length-changing. */ + private class TaggedXorCipher : CordnBlobCipher { + override fun encrypt(bytes: ByteArray): ByteArray = byteArrayOf(TAG) + ByteArray(bytes.size) { (bytes[it].toInt() xor MASK).toByte() } + + override fun decrypt(bytes: ByteArray): ByteArray { + require(bytes.isNotEmpty() && bytes[0] == TAG) { "not ours" } + return ByteArray(bytes.size - 1) { (bytes[it + 1].toInt() xor MASK).toByte() } + } + + companion object { + const val TAG: Byte = 0x7C + const val MASK = 0x5A + } + } + + private val rootFile: File = createTempDirectory("cordn-golden").toFile() + private val cipher = TaggedXorCipher() + + private val account = "a".repeat(64) + private val coordinatorA = "b".repeat(64) + private val coordinatorB = "c".repeat(64) + private val handedBackAccount = "d".repeat(64) + private val migratedAccount = "e".repeat(64) + + // ---- Construction glue: the only part of this file that follows the stores' API. ---- + + private val root = rootFile.toOkioPath() + + private fun groupStore(coordinator: HexKey) = FileCordnGroupStore(CordnStorageLayout.directoryFor(root, account, coordinator), cipher) + + private fun keyPackageStore(coordinator: HexKey) = FileCordnKeyPackageStore(CordnStorageLayout.directoryFor(root, account, coordinator), cipher) + + private fun coordinatorStore() = FileCordnCoordinatorStore(CordnStorageLayout.accountDirectoryFor(root, account), cipher) + + private fun handoffStore(owner: HexKey) = FileCordnHandoffStore(CordnStorageLayout.accountDirectoryFor(root, owner)) + + private fun appendLog(compactAfterSegments: Int) = + EncryptedAppendLog( + encrypt = cipher::encrypt, + decrypt = { runCatching { cipher.decrypt(it) }.getOrNull() }, + compactAfterSegments = compactAfterSegments, + ) + + private fun logFile(name: String) = root / "logs" / name + + private suspend fun migrationWrite(snapshot: CordnMigrationSnapshot) = CordnMigrationStores.write(root, migratedAccount, cipher, snapshot) + + private suspend fun migrationRead(configs: List) = CordnMigrationStores.read(root, migratedAccount, cipher, configs) + + // ---- End of construction glue. ---- + + /** The test's own byte surgery, beneath the API under test. */ + private fun raw(relative: String) = File(rootFile, relative) + + @AfterTest + fun cleanUp() { + rootFile.deleteRecursively() + } + + private fun message( + content: String, + cursor: Long, + ) = CordnDeliveredMessage(CordnEnvelope.build("aa".repeat(32), 1_757_000_000L + cursor, 9, content = content), cursor = cursor) + + private val m1 = message("first", 1) + private val m2 = message("second ✓", 2) + private val m3 = message("third", 3) + + private fun relay(url: String) = RelayUrlNormalizer.normalizeOrNull(url)!! + + private val coordinators = + listOf( + CoordinatorConfig(coordinatorA, listOf(relay("wss://one.example.com")), CoordinatorConfig.Origin.MANUAL, "Work"), + CoordinatorConfig(coordinatorB, listOf(relay("wss://two.example.com"), relay("wss://three.example.com")), CoordinatorConfig.Origin.GROUP_REF), + ) + + private val room = CordnRoomState("héllo draft ✓", 42) + private val echoes = EchoState(listOf(PendingEpochOperation("c2VhbGVk", localStateApplied = false)), listOf(3L, 5L)) + + /** The pre-segment format: `uint32 count, (uint32 len, bytes)*`, encrypted as one blob. */ + private fun legacyPlain(vararg entries: String): ByteArray { + val out = ByteArrayOutputStream() + + fun int(v: Int) = out.write(byteArrayOf((v shr 24).toByte(), (v shr 16).toByte(), (v shr 8).toByte(), v.toByte())) + int(entries.size) + entries.forEach { + val bytes = it.encodeToByteArray() + int(bytes.size) + out.write(bytes) + } + return out.toByteArray() + } + + private fun b64(bytes: ByteArray) = Base64.getEncoder().encodeToString(bytes) + + private val migrationSnapshot = + CordnMigrationSnapshot( + accountPubKey = migratedAccount, + groups = + listOf( + CordnMigrationGroup( + coordinatorPubKey = coordinatorA, + coordinatorRelays = listOf("wss://coord.example"), + gid = "mg-1", + clientStateBase64 = b64("mls-state-1".encodeToByteArray()), + cursor = 77, + roomStateBase64 = b64(CordnRoomStateCodec.encode(CordnRoomState("migrated draft", 70))), + echoStateBase64 = b64(EchoStateCodec.encode(EchoState(ownMessageCursors = listOf(76L)))), + joinedViaRequest = true, + messages = listOf(CordnDeliveredMessageCodec.encode(m1), CordnDeliveredMessageCodec.encode(m2)), + ), + CordnMigrationGroup( + coordinatorPubKey = coordinatorB, + coordinatorRelays = listOf("wss://other.example"), + gid = "mg-2", + clientStateBase64 = b64(byteArrayOf(0, 1, 2, -1, -2)), + cursor = 0, + ), + ), + keyPackages = listOf(CordnCarriedKeyPackage(coordinatorA, "kp-ref", b64("bundle!".encodeToByteArray()))), + ) + + /** Every writer, through the paths that shape the tree: overwrite, delete, dedup, fold, repair. */ + private suspend fun drive() { + groupStore(coordinatorA).apply { + saveGroup("g1", "state-v1".encodeToByteArray()) + saveGroup("g1", "state-v2-longer".encodeToByteArray()) + saveCursor("g1", GroupCursor(fetchCursor = 0x0102030405060708L, lastCursor = 0x1112131415161718L)) + saveJoinedViaRequest("g1") + saveRoomState("g1", room) + saveEchoState("g1", echoes) + appendMessage("g1", m1) + appendMessage("g1", m2) + appendMessage("g1", m1) + appendMessage("g1", m3) + + saveGroup("../odd/gid ✓", byteArrayOf(9, 8, 7)) + + saveGroup("blanked", byteArrayOf(1)) + saveRoomState("blanked", room) + saveRoomState("blanked", CordnRoomState()) + saveEchoState("blanked", echoes) + saveEchoState("blanked", EchoState()) + + saveGroup("gone", byteArrayOf(2)) + saveCursor("gone", GroupCursor(5, 5)) + appendMessage("gone", m1) + deleteGroup("gone") + } + groupStore(coordinatorB).saveGroup("g1", "other-coordinator".encodeToByteArray()) + + keyPackageStore(coordinatorA).apply { + save("ref-1", "bundle-1".encodeToByteArray()) + save("ref/2", "bundle-2".encodeToByteArray()) + save("ref-3", "bundle-3".encodeToByteArray()) + delete("ref-3") + } + + coordinatorStore().save(coordinators) + + handoffStore(account).save(true) + handoffStore(handedBackAccount).save(true) + handoffStore(handedBackAccount).save(false) + + // Folding: a rewrite, three loose segments and a fold, then a restart + // that has to find the fold boundary in the header, not in memory. + appendLog(3).apply { (1..5).forEach { append(logFile("folding"), "e$it") } } + appendLog(3).apply { (6..7).forEach { append(logFile("folding"), "e$it") } } + + // Legacy: a headerless blob, rewritten into the segmented format by the next append. + raw("logs").mkdirs() + raw("logs/legacy").writeBytes(cipher.encrypt(legacyPlain("old-1", "old-2"))) + appendLog(200).append(logFile("legacy"), "new-1") + + // Torn tail: a half-written segment is cut off the file, and the next + // append lands after the last good one. + appendLog(200).apply { + append(logFile("torn"), "t1") + append(logFile("torn"), "t2") + } + raw("logs/torn").appendBytes(byteArrayOf(0, 0, 0, 0x40, 1, 2, 3)) + appendLog(200).apply { + assertEquals(listOf("t1", "t2"), readAll(logFile("torn"))) + append(logFile("torn"), "t3") + } + + appendLog(200).apply { + append(logFile("rewritten"), "r1") + append(logFile("rewritten"), "r2") + rewrite(logFile("rewritten"), listOf("x", "y")) + append(logFile("rewritten"), "z") + } + + // Migration: replaces the account's tree wholesale, stale files included. + raw("cordn/$migratedAccount/stale").apply { + parentFile.mkdirs() + writeBytes(byteArrayOf(1, 2, 3)) + } + val started = migrationWrite(migrationSnapshot) + assertEquals( + listOf( + CoordinatorConfig(coordinatorA, listOf(relay("wss://coord.example")), CoordinatorConfig.Origin.MANUAL), + CoordinatorConfig(coordinatorB, listOf(relay("wss://other.example")), CoordinatorConfig.Origin.MANUAL), + ), + started, + ) + } + + /** What every store reads back from the tree [drive] leaves — before an upgrade and after it. */ + private suspend fun assertReadsBack() { + groupStore(coordinatorA).apply { + assertEquals(listOf("../odd/gid ✓", "blanked", "g1"), listGroups().sorted()) + assertContentEquals("state-v2-longer".encodeToByteArray(), loadGroup("g1")) + assertEquals(GroupCursor(0x0102030405060708L, 0x1112131415161718L), loadCursor("g1")) + assertTrue(loadJoinedViaRequest("g1")) + assertEquals(room, loadRoomState("g1")) + assertEquals(echoes, loadEchoState("g1")) + assertEquals(listOf(m1, m2, m3), loadMessages("g1")) + assertEquals(CordnMessageSummary(m3, 3), loadMessageSummary("g1")) + assertContentEquals(byteArrayOf(9, 8, 7), loadGroup("../odd/gid ✓")) + assertFalse(loadJoinedViaRequest("blanked")) + assertEquals(CordnRoomState(), loadRoomState("blanked")) + assertEquals(EchoState(), loadEchoState("blanked")) + assertNull(loadGroup("gone")) + assertNull(loadCursor("gone")) + assertEquals(emptyList(), loadMessages("gone")) + } + assertEquals(listOf("g1"), groupStore(coordinatorB).listGroups()) + assertContentEquals("other-coordinator".encodeToByteArray(), groupStore(coordinatorB).loadGroup("g1")) + + keyPackageStore(coordinatorA).apply { + assertEquals(listOf("ref-1", "ref/2"), list().sorted()) + assertContentEquals("bundle-2".encodeToByteArray(), load("ref/2")) + assertNull(load("ref-3")) + } + + assertEquals(coordinators, coordinatorStore().load()) + assertTrue(handoffStore(account).load()) + assertFalse(handoffStore(handedBackAccount).load()) + + assertEquals((1..7).map { "e$it" }, appendLog(3).readAll(logFile("folding"))) + assertEquals(listOf("old-1", "old-2", "new-1"), appendLog(200).readAll(logFile("legacy"))) + assertEquals(listOf("t1", "t2", "t3"), appendLog(200).readAll(logFile("torn"))) + assertEquals(listOf("x", "y", "z"), appendLog(200).readAll(logFile("rewritten"))) + + // The migration document carries base64 of what the stores hold; the + // strings are pinned too, since another device decodes them. + val read = migrationRead(migrationSnapshot.groups.map { CoordinatorConfig(it.coordinatorPubKey, listOf(relay(it.coordinatorRelays.single()))) }) + assertEquals(migratedAccount, read.accountPubKey) + assertEquals( + listOf( + CordnMigrationGroup( + coordinatorPubKey = coordinatorA, + coordinatorRelays = listOf("wss://coord.example/"), + gid = "mg-1", + clientStateBase64 = "bWxzLXN0YXRlLTE=", + cursor = 77, + roomStateBase64 = "AAEADm1pZ3JhdGVkIGRyYWZ0AAAAAAAAAEY=", + echoStateBase64 = "AAEAAAAIAAAAAAAAAEw=", + joinedViaRequest = true, + messages = listOf(CordnDeliveredMessageCodec.encode(m1), CordnDeliveredMessageCodec.encode(m2)), + ), + CordnMigrationGroup( + coordinatorPubKey = coordinatorB, + coordinatorRelays = listOf("wss://other.example/"), + gid = "mg-2", + clientStateBase64 = "AAEC//4=", + cursor = 0, + roomStateBase64 = "AAEAAAAAAAAAAAAA", + echoStateBase64 = "AAEAAAAA", + joinedViaRequest = false, + messages = emptyList(), + ), + ), + read.groups.sortedBy { it.gid }, + ) + assertEquals(listOf(CordnCarriedKeyPackage(coordinatorA, "kp-ref", "YnVuZGxlIQ==")), read.keyPackages) + } + + @Test + fun `the stores write exactly the pinned files`() = + runTest { + drive() + val actual = tree(rootFile) + if (actual != EXPECTED) fail(mismatch(actual)) + assertReadsBack() + } + + @Test + fun `the pinned files read back as the values that wrote them`() = + runTest { + // The upgrade direction: files written by the build that shipped, + // read by this one. + EXPECTED.forEach { (path, hex) -> + val target = File(rootFile, path.removeSuffix("/")) + if (path.endsWith("/")) { + target.mkdirs() + } else { + target.parentFile.mkdirs() + target.writeBytes(hex.hexToByteArray()) + } + } + assertReadsBack() + } + + private fun tree(root: File): Map = + root + .walkTopDown() + .filter { it != root } + .associate { file -> + val relative = file.relativeTo(root).invariantSeparatorsPath + if (file.isDirectory) "$relative/" to "" else relative to file.readBytes().toHexString() + }.toSortedMap() + + /** The diff, plus the literal to paste if (and only if) the change is deliberate. */ + private fun mismatch(actual: Map): String = + buildString { + appendLine("the on-disk format changed") + (EXPECTED.keys - actual.keys).forEach { appendLine(" missing: $it") } + (actual.keys - EXPECTED.keys).forEach { appendLine(" unexpected: $it") } + actual.filter { (k, v) -> k in EXPECTED && EXPECTED[k] != v }.forEach { (k, _) -> appendLine(" bytes differ: $k") } + appendLine("---- actual ----") + actual.forEach { (path, hex) -> + appendLine(" \"$path\" to") + val chunks = hex.chunked(120).ifEmpty { listOf("") } + appendLine(chunks.joinToString(" +\n ", prefix = " ", postfix = ",") { "\"$it\"" }) + } + } + + companion object { + private val EXPECTED: Map = + sortedMapOf( + "cordn/" to + "", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/" to + "", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/" to + "", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/" to + "", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/Li4vb2RkL2dpZCDinJM/" to + "", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/Li4vb2RkL2dpZCDinJM/state" to + "7c53525d", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/YmxhbmtlZA/" to + "", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/YmxhbmtlZA/state" to + "7c5b", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/ZzE/" to + "", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/ZzE/cursor" to + "7c5b58595e5f5c5d524b48494e4f4c4d42", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/ZzE/echoes" to + "7c5a5b5a515a5239680c32381d0c315a5a4a5a5a5a5a5a5a5a595a5a5a5a5a5a5a5f", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/ZzE/messages" to + "4d524d544c4f47330000000000000101000000ed7c5a5a5a5b5a5a5abe21782c78606b76783978606b76783f78602178333e7860783b6b6b6d6d6a6c" + + "696a6f6b3e3b6e686d6c393c3f6262396e696a6f3f623c3f3e38626c3f623e3f3e6f6863396d6b6f6c3f3b6f3e3b383c626b696a383e6e3e3b787678" + + "2a2f38313f237860783b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b" + + "3b3b3b3b3b3b3b3b3b3b3b3b3b78767839283f3b2e3f3e053b2e78606b6d6f6d6a6a6a6a6a6b76783133343e78606376782e3b3d2978600107767839" + + "35342e3f342e7860783c3328292e782727000000f27c5a5a5a5b5a5a5ab321782c78606b76783978606876783f78602178333e78607838696b6d6f3b" + + "636e3c3e6e6e3c6f69696c3f6e3f3e39393868396e3b6b6c6d636938696b3f38626e623f3e69686f69636d6c3b6e3e39683b636239396c6b3c3b7876" + + "782a2f38313f237860783b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b" + + "3b3b3b3b3b3b3b3b3b3b3b3b3b3b78767839283f3b2e3f3e053b2e78606b6d6f6d6a6a6a6a6a6876783133343e78606376782e3b3d29786001077678" + + "3935342e3f342e786078293f3935343e7ab8c6c9782727000000ed7c5a5a5a5b5a5a5abe21782c78606b76783978606976783f78602178333e786078" + + "6838636f3c3c3f3f6d633c3f6a6f6b3963396a6f6c6f6363393c396e6d6c393b3b3e3e696d3c6e3c6b6e3b3c396b626a6a636a6c6a38396d3b386e63" + + "396e6c697876782a2f38313f237860783b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b" + + "3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b78767839283f3b2e3f3e053b2e78606b6d6f6d6a6a6a6a6a6976783133343e78606376782e3b3d29" + + "7860010776783935342e3f342e7860782e3233283e782727", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/ZzE/newest" to + "7c5a5b5a5a5a595abe21782c78606b76783978606976783f78602178333e7860786838636f3c3c3f3f6d633c3f6a6f6b3963396a6f6c6f6363393c39" + + "6e6d6c393b3b3e3e696d3c6e3c6b6e3b3c396b626a6a636a6c6a38396d3b386e63396e6c697876782a2f38313f237860783b3b3b3b3b3b3b3b3b3b3b" + + "3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b78767839283f3b" + + "2e3f3e053b2e78606b6d6f6d6a6a6a6a6a6976783133343e78606376782e3b3d297860010776783935342e3f342e7860782e3233283e782727", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/ZzE/room" to + "7c5a5b5a4a3299f33636357a3e283b3c2e7ab8c6c95a5a5a5a5a5a5a70", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/ZzE/state" to + "7c292e3b2e3f772c68773635343d3f28", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/ZzE/via-request" to + "", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/keypackages/" to + "", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/keypackages/cmVmLTE" to + "7c382f343e363f776b", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/keypackages/cmVmLzI" to + "7c382f343e363f7768", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/" to + "", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/groups/" to + "", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/groups/ZzE/" to + "", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/groups/ZzE/state" to + "7c352e323f2877393535283e33343b2e3528", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/coordinators" to + "7c5a5b5a585a1a3838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838" + + "38383838383838383838385a5c171b140f1b165a5e0d3528315a5b5a4c2d292960757535343f743f223b372a363f74393537755a1a39393939393939" + + "3939393939393939393939393939393939393939393939393939393939393939393939393939393939393939393939393939393939393939395a531d" + + "08150f0a05081f1c5a5a5a585a4c2d29296075752e2d35743f223b372a363f74393537755a422d29296075752e32283f3f743f223b372a363f743935" + + "3775", + "cordn/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/handed-off" to + "", + "cordn/dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd/" to + "", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/" to + "", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/" to + "", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/" to + "", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/bWctMQ/" to + "", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/bWctMQ/cursor" to + "7c5a5a5a5a5a5a5a175a5a5a5a5a5a5a17", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/bWctMQ/echoes" to + "7c5a5b5a5a5a525a5a5a5a5a5a5a16", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/bWctMQ/messages" to + "4d524d544c4f47330000000000000101000000ed7c5a5a5a5b5a5a5abe21782c78606b76783978606b76783f78602178333e7860783b6b6b6d6d6a6c" + + "696a6f6b3e3b6e686d6c393c3f6262396e696a6f3f623c3f3e38626c3f623e3f3e6f6863396d6b6f6c3f3b6f3e3b383c626b696a383e6e3e3b787678" + + "2a2f38313f237860783b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b" + + "3b3b3b3b3b3b3b3b3b3b3b3b3b78767839283f3b2e3f3e053b2e78606b6d6f6d6a6a6a6a6a6b76783133343e78606376782e3b3d2978600107767839" + + "35342e3f342e7860783c3328292e782727000000f27c5a5a5a5b5a5a5ab321782c78606b76783978606876783f78602178333e78607838696b6d6f3b" + + "636e3c3e6e6e3c6f69696c3f6e3f3e39393868396e3b6b6c6d636938696b3f38626e623f3e69686f69636d6c3b6e3e39683b636239396c6b3c3b7876" + + "782a2f38313f237860783b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b" + + "3b3b3b3b3b3b3b3b3b3b3b3b3b3b78767839283f3b2e3f3e053b2e78606b6d6f6d6a6a6a6a6a6876783133343e78606376782e3b3d29786001077678" + + "3935342e3f342e786078293f3935343e7ab8c6c9782727", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/bWctMQ/newest" to + "7c5a5b5a5a5a585ab321782c78606b76783978606876783f78602178333e78607838696b6d6f3b636e3c3e6e6e3c6f69696c3f6e3f3e39393868396e" + + "3b6b6c6d636938696b3f38626e623f3e69686f69636d6c3b6e3e39683b636239396c6b3c3b7876782a2f38313f237860783b3b3b3b3b3b3b3b3b3b3b" + + "3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b3b78767839283f3b" + + "2e3f3e053b2e78606b6d6f6d6a6a6a6a6a6876783133343e78606376782e3b3d297860010776783935342e3f342e786078293f3935343e7ab8c6c978" + + "2727", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/bWctMQ/room" to + "7c5a5b5a5437333d283b2e3f3e7a3e283b3c2e5a5a5a5a5a5a5a1c", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/bWctMQ/state" to + "7c37362977292e3b2e3f776b", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/groups/bWctMQ/via-request" to + "", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/keypackages/" to + "", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/keypackages/a3AtcmVm" to + "7c382f343e363f7b", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/" to + "", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/groups/" to + "", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/groups/bWctMg/" to + "", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/groups/bWctMg/cursor" to + "7c5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a", + "cordn/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/groups/bWctMg/state" to + "7c5a5b58a5a4", + "logs/" to + "", + "logs/folding" to + "4d524d544c4f473300000000000000550000000b7c5a5a5a5b5a5a5a583f6b000000177c5a5a5a595a5a5a583f685a5a5a583f695a5a5a583f6e0000" + + "00177c5a5a5a595a5a5a583f6f5a5a5a583f6c5a5a5a583f6d", + "logs/legacy" to + "4d524d544c4f47330000000000000034000000207c5a5a5a595a5a5a5f35363e776b5a5a5a5f35363e77685a5a5a5f343f2d776b", + "logs/rewritten" to + "4d524d544c4f473300000000000000230000000f7c5a5a5a585a5a5a5b225a5a5a5b230000000a7c5a5a5a5b5a5a5a5b20", + "logs/torn" to + "4d524d544c4f4733000000000000001f0000000b7c5a5a5a5b5a5a5a582e6b0000000b7c5a5a5a5b5a5a5a582e680000000b7c5a5a5a5b5a5a5a582e" + + "69", + ) + } +} diff --git a/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/cordn/FileCordnStoresTest.kt b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/cordn/FileCordnStoresTest.kt index a82edde651..a785bfe604 100644 --- a/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/cordn/FileCordnStoresTest.kt +++ b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/cordn/FileCordnStoresTest.kt @@ -27,6 +27,7 @@ import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.test.runTest import kotlinx.coroutines.withContext +import okio.Path.Companion.toOkioPath import java.io.File import kotlin.test.AfterTest import kotlin.test.Test @@ -70,16 +71,17 @@ class FileCordnStoresTest { it.delete() it.mkdirs() } + private val rootPath = root.toOkioPath() private val cipher = XorCipher() private val account = "a".repeat(64) private val coordinator = "b".repeat(64) - private fun dir() = CordnStorageLayout.directoryFor(root, account, coordinator) + private fun dir() = CordnStorageLayout.directoryFor(rootPath, account, coordinator) private fun groups() = FileCordnGroupStore(dir(), cipher) - private fun coordinators() = FileCordnCoordinatorStore(CordnStorageLayout.accountDirectoryFor(root, account), cipher) + private fun coordinators() = FileCordnCoordinatorStore(CordnStorageLayout.accountDirectoryFor(rootPath, account), cipher) private fun relay(url: String) = RelayUrlNormalizer.normalizeOrNull(url)!! @@ -110,7 +112,12 @@ class FileCordnStoresTest { val state = "ratchet-tree-and-epoch-secrets".encodeToByteArray() groups().saveGroup("g1", state) - val onDisk = dir().walkTopDown().filter { it.isFile }.toList() + val onDisk = + dir() + .toFile() + .walkTopDown() + .filter { it.isFile } + .toList() assertTrue(onDisk.isNotEmpty(), "nothing was written at all") onDisk.forEach { val raw = it.readBytes() @@ -138,7 +145,7 @@ class FileCordnStoresTest { val escaped = File(root, "cordn/etc").exists() || File(root.parentFile, "etc").exists() assertTrue(!escaped, "the write escaped the store directory") - assertTrue(dir().walkTopDown().any { it.isFile }, "it was not written anywhere at all") + assertTrue(dir().toFile().walkTopDown().any { it.isFile }, "it was not written anywhere at all") } @Test @@ -159,7 +166,7 @@ class FileCordnStoresTest { runTest { // The rule the layout exists for. Two coordinators can both serve // gid "shared" as unrelated groups with different ratchet trees. - val other = CordnStorageLayout.directoryFor(root, account, "c".repeat(64)) + val other = CordnStorageLayout.directoryFor(rootPath, account, "c".repeat(64)) FileCordnGroupStore(dir(), cipher).saveGroup("shared", byteArrayOf(1)) FileCordnGroupStore(other, cipher).saveGroup("shared", byteArrayOf(2)) @@ -170,7 +177,7 @@ class FileCordnStoresTest { @Test fun `two accounts on one device do not see each other`() = runTest { - val theirs = CordnStorageLayout.directoryFor(root, "d".repeat(64), coordinator) + val theirs = CordnStorageLayout.directoryFor(rootPath, "d".repeat(64), coordinator) groups().saveGroup("g1", byteArrayOf(1)) assertTrue(FileCordnGroupStore(theirs, cipher).listGroups().isEmpty()) @@ -179,8 +186,8 @@ class FileCordnStoresTest { @Test fun `a non-hex pubkey never becomes a directory`() { - assertFailsWith { CordnStorageLayout.directoryFor(root, "../escape", coordinator) } - assertFailsWith { CordnStorageLayout.directoryFor(root, account, "../escape") } + assertFailsWith { CordnStorageLayout.directoryFor(rootPath, "../escape", coordinator) } + assertFailsWith { CordnStorageLayout.directoryFor(rootPath, account, "../escape") } } @Test @@ -248,7 +255,7 @@ class FileCordnStoresTest { // encoding — swap it for something that passes names through and // this fails, which is the regression worth catching. keyPackages().save("ref1", byteArrayOf(1)) - File(dir(), "keypackages/${CordnStorageLayout.encodeKey("ref2")}.tmp").writeBytes(byteArrayOf(2)) + File(dir().toFile(), "keypackages/${CordnStorageLayout.encodeKey("ref2")}.tmp").writeBytes(byteArrayOf(2)) assertEquals(listOf("ref1"), keyPackages().list()) } @@ -259,8 +266,8 @@ class FileCordnStoresTest { // Ignoring one unreadable name is better than failing the listing // and hiding every real group behind it. groups().saveGroup("g1", byteArrayOf(1)) - File(dir(), "groups/not-base64-@@@").mkdirs() - File(dir(), "groups/not-base64-@@@/state").writeBytes(byteArrayOf(0)) + File(dir().toFile(), "groups/not-base64-@@@").mkdirs() + File(dir().toFile(), "groups/not-base64-@@@/state").writeBytes(byteArrayOf(0)) assertEquals(listOf("g1"), groups().listGroups()) } @@ -298,7 +305,7 @@ class FileCordnStoresTest { assertContentEquals(byteArrayOf(2, 2), store.loadGroup("g1")) assertTrue( - dir().walkTopDown().none { it.name.endsWith(".tmp") }, + dir().toFile().walkTopDown().none { it.name.endsWith(".tmp") }, "a temp file survived the rename", ) } @@ -314,7 +321,7 @@ class FileCordnStoresTest { coordinators().save(configs) assertEquals(configs, coordinators().load()) - val onDisk = File(CordnStorageLayout.accountDirectoryFor(root, account), "coordinators").readBytes() + val onDisk = File(CordnStorageLayout.accountDirectoryFor(rootPath, account).toFile(), "coordinators").readBytes() assertFalse(onDisk.decodeToString().contains(coordinator), "the pubkey went to disk in the clear") } @@ -340,7 +347,7 @@ class FileCordnStoresTest { fun `an unreadable list loses the coordinators rather than the login`() = runTest { coordinators().save(listOf(CoordinatorConfig(coordinator, listOf(relay("wss://one.example.com"))))) - File(CordnStorageLayout.accountDirectoryFor(root, account), "coordinators").writeBytes(byteArrayOf(9, 9, 9)) + File(CordnStorageLayout.accountDirectoryFor(rootPath, account).toFile(), "coordinators").writeBytes(byteArrayOf(9, 9, 9)) assertEquals(emptyList(), coordinators().load()) } @@ -350,8 +357,8 @@ class FileCordnStoresTest { runTest { // If it lived inside a coordinator's own directory, removing that // coordinator would delete the record of every other one with it. - val listFile = File(CordnStorageLayout.accountDirectoryFor(root, account), "coordinators") - assertEquals(dir().parentFile, listFile.parentFile) + val listFile = File(CordnStorageLayout.accountDirectoryFor(rootPath, account).toFile(), "coordinators") + assertEquals(dir().toFile().parentFile, listFile.parentFile) } @Test @@ -363,15 +370,15 @@ class FileCordnStoresTest { // same gid and deleting a level too high takes both. val other = "e".repeat(64) groups().saveGroup("shared-gid", byteArrayOf(1, 2, 3)) - FileCordnGroupStore(CordnStorageLayout.directoryFor(root, account, other), cipher) + FileCordnGroupStore(CordnStorageLayout.directoryFor(rootPath, account, other), cipher) .saveGroup("shared-gid", byteArrayOf(4, 5, 6)) - CordnStorageLayout.directoryFor(root, account, coordinator).deleteRecursively() + CordnStorageLayout.directoryFor(rootPath, account, coordinator).toFile().deleteRecursively() assertNull(groups().loadGroup("shared-gid")) assertContentEquals( byteArrayOf(4, 5, 6), - FileCordnGroupStore(CordnStorageLayout.directoryFor(root, account, other), cipher).loadGroup("shared-gid"), + FileCordnGroupStore(CordnStorageLayout.directoryFor(rootPath, account, other), cipher).loadGroup("shared-gid"), ) } @@ -385,7 +392,7 @@ class FileCordnStoresTest { coordinators().save(listOf(CoordinatorConfig(coordinator, listOf(relay("wss://one.example.com"))))) groups().saveGroup("gid", byteArrayOf(1)) - CordnStorageLayout.directoryFor(root, account, coordinator).deleteRecursively() + CordnStorageLayout.directoryFor(rootPath, account, coordinator).toFile().deleteRecursively() assertEquals(1, coordinators().load().size) } @@ -415,7 +422,7 @@ class FileCordnStoresTest { store.saveRoomState("gid", CordnRoomState(draft = "the secret plan", lastReadCursor = 7)) assertEquals(CordnRoomState("the secret plan", 7), store.loadRoomState("gid")) - val onDisk = File(dir(), "groups/${CordnStorageLayout.encodeKey("gid")}/room").readBytes() + val onDisk = File(dir().toFile(), "groups/${CordnStorageLayout.encodeKey("gid")}/room").readBytes() assertFalse(onDisk.decodeToString().contains("the secret plan"), "a draft went to disk in the clear") } @@ -430,7 +437,7 @@ class FileCordnStoresTest { store.saveRoomState("gid", CordnRoomState(draft = "typed")) store.saveRoomState("gid", CordnRoomState()) - assertFalse(File(dir(), "groups/${CordnStorageLayout.encodeKey("gid")}/room").exists()) + assertFalse(File(dir().toFile(), "groups/${CordnStorageLayout.encodeKey("gid")}/room").exists()) assertEquals(CordnRoomState(), store.loadRoomState("gid")) } @@ -440,7 +447,7 @@ class FileCordnStoresTest { val store = groups() store.saveGroup("gid", byteArrayOf(1)) store.saveRoomState("gid", CordnRoomState(draft = "typed", lastReadCursor = 3)) - File(dir(), "groups/${CordnStorageLayout.encodeKey("gid")}/room").writeBytes(byteArrayOf(7, 7, 7)) + File(dir().toFile(), "groups/${CordnStorageLayout.encodeKey("gid")}/room").writeBytes(byteArrayOf(7, 7, 7)) assertEquals(CordnRoomState(), store.loadRoomState("gid")) assertNotNull(store.loadGroup("gid")) diff --git a/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11RetrieverTest.kt b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11RetrieverTest.kt index 73a11a6335..7ea2fed847 100644 --- a/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11RetrieverTest.kt +++ b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/relays/nip11RelayInfo/Nip11RetrieverTest.kt @@ -40,13 +40,13 @@ class Nip11RetrieverTest { } val relay = NormalizedRelayUrl("ws://127.0.0.1:14591/") - var errorCode: Nip11Retriever.ErrorCode? = null + var errorCode: Nip11ErrorCode? = null retriever.loadRelayInfo( relay = relay, onInfo = { fail("Expected an error, got relay info") }, onError = { _, code, _ -> errorCode = code }, ) - assertEquals(Nip11Retriever.ErrorCode.FAIL_TO_REACH_SERVER, errorCode) + assertEquals(Nip11ErrorCode.FAIL_TO_REACH_SERVER, errorCode) } } diff --git a/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/EpochDayCounterTest.kt b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/EpochDayCounterTest.kt new file mode 100644 index 0000000000..671978fe58 --- /dev/null +++ b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/search/calendar/EpochDayCounterTest.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.search.calendar + +import java.time.Instant +import java.time.ZoneId +import java.util.TimeZone +import kotlin.test.Test +import kotlin.test.assertEquals + +/** [LocalClock.epochDayCounter] against the java.time chain notification cards used to call. */ +class EpochDayCounterTest { + private val zones = listOf("America/New_York", "Asia/Kathmandu", "America/Santiago", "Pacific/Chatham", "UTC") + + // Around New York's 2026 changes, Santiago's midnight change, the epoch and before it. + private val instants = + listOf( + -86401L, + -1L, + 0L, + 1L, + 1772945999L, + 1772946000L, + 1773028799L, + 1773028800L, + 1788667199L, + 1788667200L, + 1793509199L, + 1793509200L, + 1793512800L, + ) + (0 until 400).map { 1767225600L + it * 21_613L } + + @Test + fun matchesJavaTimeInEveryZone() { + val saved = TimeZone.getDefault() + try { + for (id in zones) { + TimeZone.setDefault(TimeZone.getTimeZone(id)) + val zone = ZoneId.of(id) + val counter = LocalClock.epochDayCounter() + for (t in instants) { + val expected = + Instant + .ofEpochSecond(t) + .atZone(zone) + .toLocalDate() + .toEpochDay() + assertEquals(expected, counter.epochDay(t), "$id at $t") + } + } + } finally { + TimeZone.setDefault(saved) + } + } +} diff --git a/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/storage/EncryptedAppendLogTest.kt b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/storage/EncryptedAppendLogTest.kt index 87629543b7..60748a11d8 100644 --- a/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/storage/EncryptedAppendLogTest.kt +++ b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/storage/EncryptedAppendLogTest.kt @@ -20,6 +20,7 @@ */ package com.vitorpamplona.amethyst.commons.storage +import okio.Path.Companion.toOkioPath import java.io.File import java.nio.file.Files import kotlin.test.Test @@ -61,39 +62,39 @@ class EncryptedAppendLogTest { fun `entries survive a round trip through a fresh reader`() { val file = tempFile() val writer = cipher() - writer.append(file, "first") - writer.append(file, "second") - writer.append(file, "third") + writer.append(file.toOkioPath(), "first") + writer.append(file.toOkioPath(), "second") + writer.append(file.toOkioPath(), "third") // A second instance reads only what reached the disk. - assertContentEquals(listOf("first", "second", "third"), cipher().readAll(file)) + assertContentEquals(listOf("first", "second", "third"), cipher().readAll(file.toOkioPath())) } @Test fun `an empty log reads as empty rather than failing`() { - assertContentEquals(emptyList(), cipher().readAll(tempFile())) + assertContentEquals(emptyList(), cipher().readAll(tempFile().toOkioPath())) } @Test fun `contains answers without reading the file back`() { val file = tempFile() val log = cipher() - log.append(file, "hello") + log.append(file.toOkioPath(), "hello") - assertTrue(log.contains(file, "hello")) - assertFalse(log.contains(file, "goodbye")) + assertTrue(log.contains(file.toOkioPath(), "hello")) + assertFalse(log.contains(file.toOkioPath(), "goodbye")) } @Test fun `a rewrite replaces the whole log`() { val file = tempFile() val log = cipher() - log.append(file, "a") - log.append(file, "b") - log.rewrite(file, listOf("b")) + log.append(file.toOkioPath(), "a") + log.append(file.toOkioPath(), "b") + log.rewrite(file.toOkioPath(), listOf("b")) - assertContentEquals(listOf("b"), cipher().readAll(file)) - assertFalse(cipher().contains(file, "a")) + assertContentEquals(listOf("b"), cipher().readAll(file.toOkioPath())) + assertFalse(cipher().contains(file.toOkioPath(), "a")) } @Test @@ -101,9 +102,9 @@ class EncryptedAppendLogTest { val file = tempFile() val log = cipher(compactAfter = 4) val written = (1..20).map { "entry-$it" } - written.forEach { log.append(file, it) } + written.forEach { log.append(file.toOkioPath(), it) } - assertContentEquals(written, cipher().readAll(file)) + assertContentEquals(written, cipher().readAll(file.toOkioPath())) // Folding every four appends leaves ~5 segments rather than 20, which is // the bound on read cost that matters here. assertTrue(file.length() < 20 * SEGMENT_OVERHEAD_CEILING, "log should have been compacted, was ${file.length()} bytes") @@ -116,10 +117,10 @@ class EncryptedAppendLogTest { // The first append lays the header down; the next four are the loose run // that the fourth of them collapses. - (1..5).forEach { log.append(file, "first-run-$it") } + (1..5).forEach { log.append(file.toOkioPath(), "first-run-$it") } val afterFirstFold = file.readBytes() - (1..4).forEach { log.append(file, "second-run-$it") } + (1..4).forEach { log.append(file.toOkioPath(), "second-run-$it") } val afterSecondFold = file.readBytes() // The SEGMENTS the first fold produced must survive verbatim. If they @@ -135,7 +136,7 @@ class EncryptedAppendLogTest { afterSecondFold.copyOfRange(HEADER_LEN, afterFirstFold.size).toList(), "folding the tail must copy the already-folded segments as ciphertext", ) - assertContentEquals((1..5).map { "first-run-$it" } + (1..4).map { "second-run-$it" }, cipher().readAll(file)) + assertContentEquals((1..5).map { "first-run-$it" } + (1..4).map { "second-run-$it" }, cipher().readAll(file.toOkioPath())) } @Test @@ -145,7 +146,7 @@ class EncryptedAppendLogTest { // Exactly what the old writer produced: one encrypted blob, no magic. file.writeBytes(legacyBlob(listOf("old-one", "old-two"))) - assertContentEquals(listOf("old-one", "old-two"), cipher().readAll(file)) + assertContentEquals(listOf("old-one", "old-two"), cipher().readAll(file.toOkioPath())) } @Test @@ -155,9 +156,9 @@ class EncryptedAppendLogTest { file.writeBytes(legacyBlob(listOf("old-one", "old-two"))) val log = cipher() - log.append(file, "new-one") + log.append(file.toOkioPath(), "new-one") - assertContentEquals(listOf("old-one", "old-two", "new-one"), cipher().readAll(file)) + assertContentEquals(listOf("old-one", "old-two", "new-one"), cipher().readAll(file.toOkioPath())) // and the upgraded file is in the new format, so the next append is cheap assertTrue(file.readBytes().decodeToString().startsWith("MRMTLOG3")) } @@ -166,31 +167,31 @@ class EncryptedAppendLogTest { fun `a torn final append costs only the torn entry`() { val file = tempFile() val log = cipher() - log.append(file, "kept-one") - log.append(file, "kept-two") + log.append(file.toOkioPath(), "kept-one") + log.append(file.toOkioPath(), "kept-two") // Simulate process death partway through writing the third segment. val intact = file.readBytes() - log.append(file, "lost") + log.append(file.toOkioPath(), "lost") val torn = file.readBytes() file.writeBytes(torn.copyOfRange(0, intact.size + 6)) - assertContentEquals(listOf("kept-one", "kept-two"), cipher().readAll(file)) + assertContentEquals(listOf("kept-one", "kept-two"), cipher().readAll(file.toOkioPath())) } @Test fun `a segment that cannot be decrypted does not hide the rest`() { val file = tempFile() val log = cipher() - log.append(file, "before") - log.append(file, "after") + log.append(file.toOkioPath(), "before") + log.append(file.toOkioPath(), "after") // Corrupt the first segment's nonce marker so decrypt returns null for it. val bytes = file.readBytes() bytes[HEADER_LEN + 4] = 0 file.writeBytes(bytes) - assertContentEquals(listOf("after"), cipher().readAll(file)) + assertContentEquals(listOf("after"), cipher().readAll(file.toOkioPath())) } @Test @@ -201,21 +202,21 @@ class EncryptedAppendLogTest { // writes and never read one back again — silently write-only, for good. val file = tempFile() val log = cipher() - log.append(file, "kept-one") - log.append(file, "kept-two") + log.append(file.toOkioPath(), "kept-one") + log.append(file.toOkioPath(), "kept-two") val intact = file.readBytes() - log.append(file, "lost") + log.append(file.toOkioPath(), "lost") val torn = file.readBytes() file.writeBytes(torn.copyOfRange(0, intact.size + 6)) val reopened = cipher() - assertContentEquals(listOf("kept-one", "kept-two"), reopened.readAll(file)) + assertContentEquals(listOf("kept-one", "kept-two"), reopened.readAll(file.toOkioPath())) - reopened.append(file, "three") + reopened.append(file.toOkioPath(), "three") assertContentEquals( listOf("kept-one", "kept-two", "three"), - cipher().readAll(file), + cipher().readAll(file.toOkioPath()), "an append after a torn tail must be readable by the next reader", ) } @@ -230,11 +231,11 @@ class EncryptedAppendLogTest { repeat(12) { session -> // A fresh instance per session, as a cold process gets. val log = cipher(compactAfter = 4) - repeat(3) { log.append(file, "s$session-m$it") } + repeat(3) { log.append(file.toOkioPath(), "s$session-m$it") } } val expected = (0 until 12).flatMap { session -> (0 until 3).map { "s$session-m$it" } } - assertContentEquals(expected, cipher().readAll(file)) + assertContentEquals(expected, cipher().readAll(file.toOkioPath())) // 36 entries at a fold every 4 appends: a handful of segments, not 36. assertTrue( @@ -256,8 +257,8 @@ class EncryptedAppendLogTest { decrypt = { null }, ) - runCatching { log.append(file, "never-written") } - assertFalse(log.contains(file, "never-written"), "a write that failed must not count as persisted") + runCatching { log.append(file.toOkioPath(), "never-written") } + assertFalse(log.contains(file.toOkioPath(), "never-written"), "a write that failed must not count as persisted") } @Test @@ -265,9 +266,9 @@ class EncryptedAppendLogTest { val file = tempFile() val log = cipher() val awkward = listOf("", "emoji 👩‍👧 here", "a\nb\tc", "\"quoted\": {\"json\": 1}") - awkward.forEach { log.append(file, it) } + awkward.forEach { log.append(file.toOkioPath(), it) } - assertEquals(awkward, cipher().readAll(file)) + assertEquals(awkward, cipher().readAll(file.toOkioPath())) } /** The pre-segment on-disk shape: `encrypt(uint32 count, (uint32 len, bytes)*)`. */ diff --git a/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/util/AmountFormatTest.kt b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/util/AmountFormatTest.kt new file mode 100644 index 0000000000..b985a694c8 --- /dev/null +++ b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/util/AmountFormatTest.kt @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import java.math.BigDecimal +import java.text.DecimalFormatSymbols +import kotlin.test.Test +import kotlin.test.assertEquals + +/** The Double-based [compactAmount] other platforms use, against the JVM's DecimalFormat actuals. */ +class AmountFormatTest { + private val separator = DecimalFormatSymbols.getInstance().decimalSeparator + + private val samples: List = + buildList { + (0L..20_000L step 7).forEach { add(BigDecimal(it)) } + listOf( + 0L, + 1L, + 9_999L, + 10_000L, + 10_499L, + 10_500L, + 12_500L, + 13_500L, + 999_499L, + 999_500L, + 1_000_000L, + 1_499_999L, + 1_500_000L, + 9_499_999L, + 9_500_000L, + 9_999_999L, + 10_000_000L, + 999_499_999L, + 999_500_000L, + 1_500_000_000L, + 9_500_000_000L, + 10_000_000_000L, + 2_100_000_000_000_000L, + ).forEach { add(BigDecimal(it)) } + // Millisat precision: three decimals, ties included. + listOf("0.005", "0.01", "0.5", "1.5", "2.5", "2.501", "9999.499", "9999.5", "10499.999", "12345.678").forEach { add(BigDecimal(it)) } + var x = 1L + while (x < 1_000_000_000_000_000L) { + add(BigDecimal(x * 3 + 17)) + x *= 7 + } + } + + @Test + fun matchesShowAmount() { + samples.forEach { assertEquals(showAmount(it), compactAmount(it.toDouble(), withDecimal = true, separator), "$it") } + } + + @Test + fun matchesShowAmountInteger() { + samples.forEach { assertEquals(showAmountInteger(it), compactAmount(it.toDouble(), withDecimal = false, separator), "$it") } + } +} diff --git a/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/util/FileSystemExtTest.kt b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/util/FileSystemExtTest.kt new file mode 100644 index 0000000000..3f0d16a473 --- /dev/null +++ b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/util/FileSystemExtTest.kt @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import okio.FileSystem +import okio.ForwardingFileSystem +import okio.IOException +import okio.Path +import okio.Path.Companion.toOkioPath +import java.nio.file.Files +import kotlin.test.AfterTest +import kotlin.test.Test +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class FileSystemExtTest { + private val root = Files.createTempDirectory("fs-ext-test").toFile() + + @AfterTest + fun cleanup() { + root.deleteRecursively() + } + + /** Refuses to list one directory, as an unreadable or concurrently removed one would. */ + private class UnlistableDirFileSystem( + private val unlistable: Path, + ) : ForwardingFileSystem(FileSystem.SYSTEM) { + override fun list(dir: Path): List { + if (dir == unlistable) throw IOException("cannot list $dir") + return super.list(dir) + } + } + + private fun write( + relative: String, + text: String = "x", + ) { + val file = root.resolve(relative) + file.parentFile.mkdirs() + file.writeText(text) + } + + @Test + fun deletesAWholeTree() { + write("a/b/c.txt") + write("a/d.txt") + val dir = root.resolve("a").toOkioPath() + + assertTrue(FileSystem.SYSTEM.deleteRecursivelyQuietly(dir)) + assertFalse(FileSystem.SYSTEM.exists(dir)) + } + + @Test + fun missingPathCountsAsDeleted() { + assertTrue(FileSystem.SYSTEM.deleteRecursivelyQuietly(root.resolve("never").toOkioPath())) + } + + @Test + fun carriesOnPastADirectoryItCannotList() { + // File.deleteRecursively removed everything it could reach and reported false for the + // rest. One unlistable subdirectory must not stop its siblings from being deleted. + write("g/stuck/inner.txt") + write("g/sibling/messages", "plaintext") + write("g/state") + val dir = root.resolve("g").toOkioPath() + val fs = UnlistableDirFileSystem(dir / "stuck") + + assertFalse(fs.deleteRecursivelyQuietly(dir)) + assertFalse(root.resolve("g/sibling/messages").exists()) + assertFalse(root.resolve("g/state").exists()) + assertTrue(root.resolve("g/stuck/inner.txt").exists()) + } + + @Test + fun deletesASymlinkWithoutEmptyingItsTarget() { + write("outside/keep.txt") + write("h/own.txt") + Files.createSymbolicLink(root.resolve("h/link").toPath(), root.resolve("outside").toPath()) + val dir = root.resolve("h").toOkioPath() + + assertTrue(FileSystem.SYSTEM.deleteRecursivelyQuietly(dir)) + assertFalse(root.resolve("h").exists()) + assertTrue(root.resolve("outside/keep.txt").exists()) + } +} diff --git a/commonsUI/ARCHITECTURE.md b/commonsUI/ARCHITECTURE.md index 8a091c05f7..5ad5d36090 100644 --- a/commonsUI/ARCHITECTURE.md +++ b/commonsUI/ARCHITECTURE.md @@ -17,11 +17,30 @@ therefore useless to the headless `cli`: its `LazyListState`, `ChatNewMessageState` with `TextFieldValue`, `EmojiSuggestionState` with `TextFieldState`). +Its end state is **the whole app UI**: every screen, the navigation host and the +navigation chrome for every window size (bottom bar, rail, permanent drawer), with +`amethyst` and a new JVM `desktopApp` as thin shims around it. Screens still in +`amethyst/` are waiting on their own app-only helpers and the app root, not staying +there by design. `AccountViewModel` lives here (`commons.viewmodels`) rather than in +`commons` because it toasts through compose-resources strings; it reaches the +platform through `AccountViewModelHost`. See `commons/plans/2026-09-27-one-ui-android-desktop.md`. + It depends on `:commons` (and `:quartz`) as **`api`**, so a consumer that adds `:commonsUI` sees the headless layer transitively. `amethyst`, `desktopApp`, `nappletHost` and `benchmark` depend on it; `cli`, `geode`, `marmotBench` must never. +## Platform slots + +Shared composables that need something only a front end can draw or do get it from a +CompositionLocal the front end installs at its root (Android in `AmethystTheme`): +`LocalRichTextPlatform` (rich-text leaves, markdown), `LocalInlineQuoteRenderer`, +`LocalTranslationPlatform`, and `LocalNotePlatform` (media players, map, platform-engine note +types, reactions/zap row, post editor; call it through the same-named shims in +`commons.ui.note.platform`). Each default draws nothing or plain text, so previews and a front +end still wiring its pieces never crash. Small platform verbs are expect/actuals instead: +`rememberTextSharer`, `rememberShortNotice`, `rememberBlossomUriOpener`, `rememberViewModel`. + ## Same packages as `commons` Every file keeps its `com.vitorpamplona.amethyst.commons.*` package. The split diff --git a/commonsUI/build.gradle.kts b/commonsUI/build.gradle.kts index 87e9b9a0ea..5073bc8d30 100644 --- a/commonsUI/build.gradle.kts +++ b/commonsUI/build.gradle.kts @@ -116,13 +116,24 @@ kotlin { // JVM-only and lives in jvmAndroid; iOS will pull coil-ktor // when that target wires its actual. implementation(libs.coil.compose) + // NetworkHeaders on avatar requests (the local Blossom cache marker). Multiplatform, + // Apache-2.0; already on the JVM classpath through coil-network-okhttp. + implementation(libs.coil.network.core) // LruCache (KMP-ready) implementation(libs.androidx.collection) + // Charts (Vico 3, Compose Multiplatform, Apache-2.0): the notification + // summary builds its chart model off the main thread. `api` because the + // model is part of that state holder's public surface. + api(libs.vico.charts.compose) + // Immutable collections api(libs.kotlinx.collections.immutable) + // JSON trees for the LNURL-pay replies the payment stack reads. + implementation(libs.kotlinx.serialization.json) + // Compose Multiplatform Resources (strings, fonts, napplet shell files) implementation(libs.jetbrains.compose.components.resources) @@ -146,6 +157,8 @@ kotlin { // artifact jvmMain already uses, and it rasterises in software, // so it needs no display. implementation(compose.desktop.currentOs) + // RouteForPointerTest stubs an Account (already the app's and androidHostTest's mock lib). + implementation(libs.mockk) } } diff --git a/commonsUI/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/ArgbImageBitmap.android.kt b/commonsUI/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/ArgbImageBitmap.android.kt new file mode 100644 index 0000000000..7690ed370d --- /dev/null +++ b/commonsUI/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/ArgbImageBitmap.android.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.service.image + +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.asImageBitmap +import androidx.core.graphics.createBitmap + +actual fun argbPixelsToImageBitmap( + pixels: IntArray, + width: Int, + height: Int, +): ImageBitmap = + createBitmap(width, height) + .apply { setPixels(pixels, 0, width, 0, 0, width, height) } + .asImageBitmap() diff --git a/commonsUI/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ShortNotice.android.kt b/commonsUI/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ShortNotice.android.kt new file mode 100644 index 0000000000..24d16cd38a --- /dev/null +++ b/commonsUI/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ShortNotice.android.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import android.widget.Toast +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalContext + +@Composable +actual fun rememberShortNotice(): ShortNotice { + val context = LocalContext.current + return remember(context) { ShortNotice { message -> Toast.makeText(context, message, Toast.LENGTH_SHORT).show() } } +} diff --git a/commonsUI/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TextSharer.android.kt b/commonsUI/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TextSharer.android.kt new file mode 100644 index 0000000000..5f2498a71c --- /dev/null +++ b/commonsUI/src/androidMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TextSharer.android.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import android.content.Intent +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalContext + +@Composable +actual fun rememberTextSharer(): TextSharer { + val context = LocalContext.current + return remember(context) { + TextSharer { text, title, chooserTitle -> + val sendIntent = + Intent().apply { + action = Intent.ACTION_SEND + type = "text/plain" + putExtra(Intent.EXTRA_TEXT, text) + if (title != null) putExtra(Intent.EXTRA_TITLE, title) + } + context.startActivity(Intent.createChooser(sendIntent, chooserTitle)) + } + } +} diff --git a/amethyst/src/main/res/drawable-hdpi/ic_compose.png b/commonsUI/src/commonMain/composeResources/drawable-hdpi/ic_compose.png similarity index 100% rename from amethyst/src/main/res/drawable-hdpi/ic_compose.png rename to commonsUI/src/commonMain/composeResources/drawable-hdpi/ic_compose.png diff --git a/amethyst/src/main/res/drawable-hdpi/ic_dm.png b/commonsUI/src/commonMain/composeResources/drawable-hdpi/ic_dm.png similarity index 100% rename from amethyst/src/main/res/drawable-hdpi/ic_dm.png rename to commonsUI/src/commonMain/composeResources/drawable-hdpi/ic_dm.png diff --git a/commonsUI/src/commonMain/composeResources/drawable-hdpi/ic_qrcode.png b/commonsUI/src/commonMain/composeResources/drawable-hdpi/ic_qrcode.png new file mode 100644 index 0000000000..31b0439c91 Binary files /dev/null and b/commonsUI/src/commonMain/composeResources/drawable-hdpi/ic_qrcode.png differ diff --git a/amethyst/src/main/res/drawable-mdpi/ic_compose.png b/commonsUI/src/commonMain/composeResources/drawable-mdpi/ic_compose.png similarity index 100% rename from amethyst/src/main/res/drawable-mdpi/ic_compose.png rename to commonsUI/src/commonMain/composeResources/drawable-mdpi/ic_compose.png diff --git a/amethyst/src/main/res/drawable-mdpi/ic_dm.png b/commonsUI/src/commonMain/composeResources/drawable-mdpi/ic_dm.png similarity index 100% rename from amethyst/src/main/res/drawable-mdpi/ic_dm.png rename to commonsUI/src/commonMain/composeResources/drawable-mdpi/ic_dm.png diff --git a/commonsUI/src/commonMain/composeResources/drawable-mdpi/ic_qrcode.png b/commonsUI/src/commonMain/composeResources/drawable-mdpi/ic_qrcode.png new file mode 100644 index 0000000000..ff1e891620 Binary files /dev/null and b/commonsUI/src/commonMain/composeResources/drawable-mdpi/ic_qrcode.png differ diff --git a/amethyst/src/main/res/drawable-xhdpi/ic_compose.png b/commonsUI/src/commonMain/composeResources/drawable-xhdpi/ic_compose.png similarity index 100% rename from amethyst/src/main/res/drawable-xhdpi/ic_compose.png rename to commonsUI/src/commonMain/composeResources/drawable-xhdpi/ic_compose.png diff --git a/amethyst/src/main/res/drawable-xhdpi/ic_dm.png b/commonsUI/src/commonMain/composeResources/drawable-xhdpi/ic_dm.png similarity index 100% rename from amethyst/src/main/res/drawable-xhdpi/ic_dm.png rename to commonsUI/src/commonMain/composeResources/drawable-xhdpi/ic_dm.png diff --git a/commonsUI/src/commonMain/composeResources/drawable-xhdpi/ic_qrcode.png b/commonsUI/src/commonMain/composeResources/drawable-xhdpi/ic_qrcode.png new file mode 100644 index 0000000000..e6f4bb4531 Binary files /dev/null and b/commonsUI/src/commonMain/composeResources/drawable-xhdpi/ic_qrcode.png differ diff --git a/amethyst/src/main/res/drawable-xxhdpi/ic_compose.png b/commonsUI/src/commonMain/composeResources/drawable-xxhdpi/ic_compose.png similarity index 100% rename from amethyst/src/main/res/drawable-xxhdpi/ic_compose.png rename to commonsUI/src/commonMain/composeResources/drawable-xxhdpi/ic_compose.png diff --git a/amethyst/src/main/res/drawable-xxhdpi/ic_dm.png b/commonsUI/src/commonMain/composeResources/drawable-xxhdpi/ic_dm.png similarity index 100% rename from amethyst/src/main/res/drawable-xxhdpi/ic_dm.png rename to commonsUI/src/commonMain/composeResources/drawable-xxhdpi/ic_dm.png diff --git a/commonsUI/src/commonMain/composeResources/drawable-xxhdpi/ic_qrcode.png b/commonsUI/src/commonMain/composeResources/drawable-xxhdpi/ic_qrcode.png new file mode 100644 index 0000000000..c35c205d45 Binary files /dev/null and b/commonsUI/src/commonMain/composeResources/drawable-xxhdpi/ic_qrcode.png differ diff --git a/amethyst/src/main/res/drawable-xxxhdpi/ic_compose.png b/commonsUI/src/commonMain/composeResources/drawable-xxxhdpi/ic_compose.png similarity index 100% rename from amethyst/src/main/res/drawable-xxxhdpi/ic_compose.png rename to commonsUI/src/commonMain/composeResources/drawable-xxxhdpi/ic_compose.png diff --git a/amethyst/src/main/res/drawable-xxxhdpi/ic_dm.png b/commonsUI/src/commonMain/composeResources/drawable-xxxhdpi/ic_dm.png similarity index 100% rename from amethyst/src/main/res/drawable-xxxhdpi/ic_dm.png rename to commonsUI/src/commonMain/composeResources/drawable-xxxhdpi/ic_dm.png diff --git a/commonsUI/src/commonMain/composeResources/drawable-xxxhdpi/ic_qrcode.png b/commonsUI/src/commonMain/composeResources/drawable-xxxhdpi/ic_qrcode.png new file mode 100644 index 0000000000..bffe18dc1e Binary files /dev/null and b/commonsUI/src/commonMain/composeResources/drawable-xxxhdpi/ic_qrcode.png differ diff --git a/amethyst/src/main/res/drawable-xxxhdpi/profile_banner.webp b/commonsUI/src/commonMain/composeResources/drawable-xxxhdpi/profile_banner.webp similarity index 100% rename from amethyst/src/main/res/drawable-xxxhdpi/profile_banner.webp rename to commonsUI/src/commonMain/composeResources/drawable-xxxhdpi/profile_banner.webp diff --git a/commonsUI/src/commonMain/composeResources/drawable/github.xml b/commonsUI/src/commonMain/composeResources/drawable/github.xml new file mode 100644 index 0000000000..e3e4918508 --- /dev/null +++ b/commonsUI/src/commonMain/composeResources/drawable/github.xml @@ -0,0 +1,4 @@ + + + diff --git a/commonsUI/src/commonMain/composeResources/drawable/ic_tor.xml b/commonsUI/src/commonMain/composeResources/drawable/ic_tor.xml new file mode 100644 index 0000000000..7a8f25b5eb --- /dev/null +++ b/commonsUI/src/commonMain/composeResources/drawable/ic_tor.xml @@ -0,0 +1,9 @@ + + + diff --git a/amethyst/src/main/res/drawable/nip_05.xml b/commonsUI/src/commonMain/composeResources/drawable/nip_05.xml similarity index 100% rename from amethyst/src/main/res/drawable/nip_05.xml rename to commonsUI/src/commonMain/composeResources/drawable/nip_05.xml diff --git a/amethyst/src/main/res/drawable/original.xml b/commonsUI/src/commonMain/composeResources/drawable/original.xml similarity index 100% rename from amethyst/src/main/res/drawable/original.xml rename to commonsUI/src/commonMain/composeResources/drawable/original.xml diff --git a/commonsUI/src/commonMain/composeResources/drawable/relays.xml b/commonsUI/src/commonMain/composeResources/drawable/relays.xml new file mode 100644 index 0000000000..2ec03a2c22 --- /dev/null +++ b/commonsUI/src/commonMain/composeResources/drawable/relays.xml @@ -0,0 +1,4 @@ + + + diff --git a/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/audio/RecordingIndicators.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/audio/RecordingIndicators.kt similarity index 100% rename from commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/audio/RecordingIndicators.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/audio/RecordingIndicators.kt diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoveryFilterAssembler.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoveryFilterAssembler.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoveryFilterAssembler.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoveryFilterAssembler.kt index d69d5d71ff..5074174801 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoveryFilterAssembler.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoveryFilterAssembler.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource +package com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource import androidx.compose.runtime.Stable +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountFeedContentStates +import com.vitorpamplona.amethyst.commons.viewmodels.AccountFeedContentStates import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import kotlinx.coroutines.CoroutineScope diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoverySubAssembler.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoverySubAssembler.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoverySubAssembler.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoverySubAssembler.kt index d4d8353db7..743ea256a1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoverySubAssembler.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoverySubAssembler.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource +package com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -41,6 +41,7 @@ import com.vitorpamplona.quartz.nip29RelayGroups.metadata.GroupAdminsEvent import com.vitorpamplona.quartz.nip29RelayGroups.metadata.GroupMembersEvent import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.sample diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/TopNavFilterState.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/feeds/TopNavFilterState.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/TopNavFilterState.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/feeds/TopNavFilterState.kt index 5e1b5da3ff..c370932351 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/TopNavFilterState.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/feeds/TopNavFilterState.kt @@ -18,11 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen +package com.vitorpamplona.amethyst.commons.feeds import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip51Lists.interestSets.InterestSet import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter @@ -38,8 +40,6 @@ import com.vitorpamplona.amethyst.commons.resources.follow_list_mine import com.vitorpamplona.amethyst.commons.resources.follow_list_mute_list import com.vitorpamplona.amethyst.commons.resources.follow_list_teleport import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl @@ -54,6 +54,7 @@ import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine @@ -294,7 +295,7 @@ class TopNavFilterState( livePeopleListsFlow, liveInterestFlows, ) { peopleLists, interests -> - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() emit( listOf( listOf(allFollows, userFollows, kind3Follows, aroundMe, teleport, globalFollow), @@ -307,7 +308,7 @@ class TopNavFilterState( private val _badgeRoutes = livePeopleListsFlow.transform { peopleLists -> - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() emit( listOf( listOf(allFollows, userFollows, kind3Follows, globalFollow, mineFollow), @@ -319,7 +320,7 @@ class TopNavFilterState( private val _communityRoutes = livePeopleListsFlow.transform { peopleLists -> - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() emit( listOf( listOf(allFollows, userFollows, kind3Follows, globalFollow, mineFollow), @@ -334,7 +335,7 @@ class TopNavFilterState( livePeopleListsFlow, liveInterestFlows, ) { peopleLists, interests -> - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() emit( listOf( // Same content-style catalog as kind3GlobalPeopleRoutes, plus "Mine" so the @@ -352,7 +353,7 @@ class TopNavFilterState( livePeopleListsFlow, liveInterestFlows, ) { peopleLists, interests -> - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() emit( listOf( // Git repository announcements can be narrowed by author, hashtag and geohash, @@ -370,7 +371,7 @@ class TopNavFilterState( livePeopleListsFlow, liveInterestFlows, ) { peopleLists, interests -> - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() emit( listOf( // Workout records can be narrowed by author, hashtag and geohash, so this @@ -388,7 +389,7 @@ class TopNavFilterState( livePeopleListsFlow, liveInterestFlows, ) { peopleLists, interests -> - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() emit( listOf( // Highlights can be narrowed by author, hashtag and geohash, so this mirrors @@ -407,7 +408,7 @@ class TopNavFilterState( liveInterestFlows, account.relayGroupList.liveRelayGroupServers, ) { peopleLists, interests, joinedServers -> - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() // A relay chip per host relay of every group the user joined (kind-10009), so they can // browse the OTHER groups on those relays without first having to Favorite them. Deduped // against relays that are already chips because they were favorited (kind-10012, already @@ -441,7 +442,7 @@ class TopNavFilterState( livePeopleListsFlow, liveInterestFlows, ) { peopleLists, interests -> - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() emit( listOf( // Same content-style catalog as kind3GlobalPeopleRoutes, plus "Mine" so the @@ -456,7 +457,7 @@ class TopNavFilterState( private val _kind3GlobalPeople = livePeopleListsFlow.transform { peopleLists -> - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() emit( listOf( listOf(allFollows, userFollows, kind3Follows, aroundMe, teleport, globalFollow), @@ -472,7 +473,7 @@ class TopNavFilterState( // and AroundMe — none of which can match a tag-less manifest — are deliberately left out. private val _authorOnlyRoutes = livePeopleListsFlow.transform { peopleLists -> - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() emit( listOf( listOf(allFollows, userFollows, kind3Follows, globalFollow, mineFollow), @@ -484,7 +485,7 @@ class TopNavFilterState( private val _notificationLists = livePeopleListsFlow.transform { peopleLists -> - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() emit( listOf( listOf(allFollows, userFollows, kind3Follows, aroundMe, teleport, selectedFollow, globalFollow), @@ -555,7 +556,7 @@ class TopNavFilterState( .stateIn(scope, SharingStarted.Eagerly, persistentListOf(allFollows, userFollows, kind3Follows, aroundMe, teleport, globalFollow, mineFollow, muteListFollow)) fun destroy() { - Log.d("Init") { "OnCleared: ${this.javaClass.simpleName}" } + Log.d("Init") { "OnCleared: ${this::class.simpleName}" } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/MediaAspectRatioCache.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/MediaAspectRatioCache.kt similarity index 89% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/MediaAspectRatioCache.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/MediaAspectRatioCache.kt index 5057f55847..2823e33686 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/MediaAspectRatioCache.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/MediaAspectRatioCache.kt @@ -18,11 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model +package com.vitorpamplona.amethyst.commons.model import androidx.collection.LruCache import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf +import com.vitorpamplona.amethyst.commons.util.KmpLock +import com.vitorpamplona.amethyst.commons.util.withLock interface MutableMediaAspectRatioCache { fun get(url: String): Float? @@ -51,8 +53,9 @@ object MediaAspectRatioCache : MutableMediaAspectRatioCache { // get-then-put has to be atomic, so the compound op is guarded even though LruCache is itself // thread-safe. A miss still stores a slot: that empty slot is what the caller observes until // add() fills it in. - @Synchronized - private fun entry(url: String): MutableState = cache.get(url) ?: mutableStateOf(null).also { cache.put(url, it) } + private val lock = KmpLock() + + private fun entry(url: String): MutableState = lock.withLock { cache.get(url) ?: mutableStateOf(null).also { cache.put(url, it) } } override fun get(url: String): Float? = entry(url).value diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip11RelayInfo/LoadRelayInfo.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip11RelayInfo/LoadRelayInfo.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip11RelayInfo/LoadRelayInfo.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip11RelayInfo/LoadRelayInfo.kt index 86a39afb05..baf2abc572 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip11RelayInfo/LoadRelayInfo.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip11RelayInfo/LoadRelayInfo.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip11RelayInfo +package com.vitorpamplona.amethyst.commons.model.nip11RelayInfo import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State import androidx.compose.runtime.produceState -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relays.nip11RelayInfo.Nip11CachedRetriever import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip11RelayInfo.Nip11RelayInformation @@ -33,7 +33,7 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch @Composable -fun loadRelayInfo(relay: NormalizedRelayUrl): State = loadRelayInfo(relay, Amethyst.instance.nip11Cache) +fun loadRelayInfo(relay: NormalizedRelayUrl): State = loadRelayInfo(relay, LocalCache.appHost.nip11Cache) /** * Eagerly warms the NIP-11 cache for a whole set of [relays] **in parallel** (each fetch on its own @@ -48,7 +48,7 @@ fun WarmNip11( relays: Collection, onEachLoaded: () -> Unit = {}, ) { - val cache = Amethyst.instance.nip11Cache + val cache = LocalCache.appHost.nip11Cache LaunchedEffect(relays) { coroutineScope { relays.forEach { relay -> diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/datasource/NestRoomFilterAssembler.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nests/datasource/NestRoomFilterAssembler.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/datasource/NestRoomFilterAssembler.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nests/datasource/NestRoomFilterAssembler.kt index ca4c53d621..94e9456b02 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/datasource/NestRoomFilterAssembler.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nests/datasource/NestRoomFilterAssembler.kt @@ -18,11 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.datasource +package com.vitorpamplona.amethyst.commons.nests.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager @@ -31,8 +32,7 @@ import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFil import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.nests.admin.AdminCommandEvent import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/datasource/NestRoomLivenessProbeAssembler.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nests/datasource/NestRoomLivenessProbeAssembler.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/datasource/NestRoomLivenessProbeAssembler.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nests/datasource/NestRoomLivenessProbeAssembler.kt index 3444375053..206ac82e11 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/datasource/NestRoomLivenessProbeAssembler.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nests/datasource/NestRoomLivenessProbeAssembler.kt @@ -18,11 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.datasource +package com.vitorpamplona.amethyst.commons.nests.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager @@ -31,8 +32,7 @@ import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFil import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/activity/NestBridge.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nests/room/activity/NestBridge.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/activity/NestBridge.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nests/room/activity/NestBridge.kt index b8db586f78..f9cd4ead6a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/activity/NestBridge.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nests/room/activity/NestBridge.kt @@ -18,14 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.activity +package com.vitorpamplona.amethyst.commons.nests.room.activity -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import kotlin.concurrent.Volatile /** * Process-level singleton that hands the active [AccountViewModel] from the * main activity to [NestActivity]. Mirrors the - * [com.vitorpamplona.amethyst.service.call.CallSessionBridge] pattern so a + * [com.vitorpamplona.amethyst.commons.service.call.CallSessionBridge] pattern so a * separately-tasked Activity in the same process can reach the logged-in * account without serialising a `NostrSigner` through an Intent extra. * diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nip52Calendar/ui/CalendarScaffoldPadding.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nip52Calendar/ui/CalendarScaffoldPadding.kt index 1f79082ba3..9a9856a7bc 100644 --- a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nip52Calendar/ui/CalendarScaffoldPadding.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nip52Calendar/ui/CalendarScaffoldPadding.kt @@ -27,7 +27,7 @@ import androidx.compose.ui.composed import com.vitorpamplona.amethyst.commons.ui.layouts.LocalDisappearingScaffoldPadding /** - * Applies the surrounding [com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold]'s reserved + * Applies the surrounding [com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold]'s reserved * top/bottom space as padding. The scaffold places content at y=0 by design — it lets feeds * scroll *behind* the disappearing bar — but the month/week/day views are static-headered grids, * so without this modifier the grid header would render under the top app bar. Outside a diff --git a/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/nip53LiveActivities/ui/StreamingStatusFlags.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nip53LiveActivities/ui/StreamingStatusFlags.kt similarity index 93% rename from commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/nip53LiveActivities/ui/StreamingStatusFlags.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nip53LiveActivities/ui/StreamingStatusFlags.kt index cfc643fb71..4ec874e85f 100644 --- a/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/nip53LiveActivities/ui/StreamingStatusFlags.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/nip53LiveActivities/ui/StreamingStatusFlags.kt @@ -37,13 +37,12 @@ import com.vitorpamplona.amethyst.commons.resources.live_stream_live_tag import com.vitorpamplona.amethyst.commons.resources.live_stream_offline_tag import com.vitorpamplona.amethyst.commons.resources.live_stream_planned_tag import com.vitorpamplona.amethyst.commons.resources.live_stream_private_tag +import com.vitorpamplona.amethyst.commons.ui.note.DateTimeStyle +import com.vitorpamplona.amethyst.commons.ui.note.formatDateTime import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.SmallBorder import com.vitorpamplona.amethyst.commons.ui.theme.liveStreamTag import com.vitorpamplona.quartz.utils.TimeUtils -import java.text.DateFormat -import java.text.SimpleDateFormat -import java.util.Date @Composable fun LiveFlag() { @@ -117,11 +116,7 @@ fun ScheduledFlag(starts: Long?) { remember(starts) { starts?.let { if (it > TimeUtils.now()) { - SimpleDateFormat - .getDateTimeInstance( - DateFormat.SHORT, - DateFormat.SHORT, - ).format(Date(starts * 1000)) + formatDateTime(starts * 1000, DateTimeStyle.SHORT, DateTimeStyle.SHORT) } else { null } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSummaryState.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/notifications/NotificationSummaryState.kt similarity index 86% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSummaryState.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/notifications/NotificationSummaryState.kt index 3eb9bfd2ae..5dd59a4eb6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSummaryState.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/notifications/NotificationSummaryState.kt @@ -18,21 +18,23 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications +package com.vitorpamplona.amethyst.commons.notifications import androidx.compose.runtime.Stable import com.patrykandpatrick.vico.compose.cartesian.data.CartesianChartModel import com.patrykandpatrick.vico.compose.cartesian.data.LineCartesianLayerModel import com.patrykandpatrick.vico.compose.common.data.ExtraStore import com.patrykandpatrick.vico.compose.common.data.MutableExtraStore +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.search.calendar.EpochDayCounter +import com.vitorpamplona.amethyst.commons.search.calendar.LocalClock +import com.vitorpamplona.amethyst.commons.search.calendar.SearchDate import com.vitorpamplona.amethyst.commons.service.BundledInsert import com.vitorpamplona.amethyst.commons.util.showAmountInteger -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.ui.note.showCount +import com.vitorpamplona.amethyst.commons.util.showCount import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent @@ -42,17 +44,16 @@ import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent import com.vitorpamplona.quartz.nipB1Bolt12Zaps.zap.Bolt12ZapEvent import com.vitorpamplona.quartz.nipBCOnchainZaps.zap.OnchainZapEvent +import com.vitorpamplona.quartz.utils.BigDecimal import com.vitorpamplona.quartz.utils.Log +import com.vitorpamplona.quartz.utils.plus +import com.vitorpamplona.quartz.utils.toDoubleValue import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map -import java.math.BigDecimal -import java.time.Instant -import java.time.LocalDateTime -import java.time.ZoneId -import java.time.format.DateTimeFormatter val ShowDecimals = ExtraStore.Key() val BottomAxisLabelKey = ExtraStore.Key>() @@ -72,22 +73,25 @@ class NotificationSummaryState( val chartModel = _chartModel.asStateFlow() private var takenIntoAccount = setOf() - private val sdf = DateTimeFormatter.ofPattern("yyyy-MM-dd") // SimpleDateFormat() val todaysReplyCount = replies.map { showCount(it[today()]) }.distinctUntilChanged() val todaysBoostCount = boosts.map { showCount(it[today()]) }.distinctUntilChanged() val todaysReactionCount = reactions.map { showCount(it[today()]) }.distinctUntilChanged() val todaysZapAmount = zaps.map { showAmountInteger(it[today()]) }.distinctUntilChanged() - fun formatDate(createAt: Long): String = - sdf.format( - Instant.ofEpochSecond(createAt).atZone(ZoneId.systemDefault()).toLocalDateTime(), - ) + // Buckets are local calendar days, keyed yyyy-MM-dd. [days] is built once per pass: it reads + // the zone rules once, and a pass buckets every notification in the cache. + private fun formatDate( + createAt: Long, + days: EpochDayCounter, + ): String = SearchDate.civilFromDays(days.epochDay(createAt)).ymd() - fun today(): String = sdf.format(LocalDateTime.now()) + fun today(): String = LocalClock.today().ymd() suspend fun initializeSuspend() { - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() + + val days = LocalClock.epochDayCounter() val currentUser = user.pubkeyHex @@ -103,7 +107,7 @@ class NotificationSummaryState( when { noteEvent is ReactionEvent -> { if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) { - val netDate = formatDate(noteEvent.createdAt) + val netDate = formatDate(noteEvent.createdAt, days) reactions[netDate] = (reactions[netDate] ?: 0) + 1 takenIntoAccount.add(noteEvent.id) } @@ -111,7 +115,7 @@ class NotificationSummaryState( noteEvent is RepostEvent || noteEvent is GenericRepostEvent -> { if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) { - val netDate = formatDate(noteEvent.createdAt) + val netDate = formatDate(noteEvent.createdAt, days) boosts[netDate] = (boosts[netDate] ?: 0) + 1 takenIntoAccount.add(noteEvent.id) } @@ -120,8 +124,8 @@ class NotificationSummaryState( noteEvent is ZapReceiptEvent -> { // the user might be sending his own receipts noteEvent.pubKey != currentUser if (noteEvent.isTaggedUser(currentUser)) { - val netDate = formatDate(noteEvent.createdAt) - zaps[netDate] = (zaps[netDate] ?: BigDecimal.ZERO) + (noteEvent.amount ?: BigDecimal.ZERO) + val netDate = formatDate(noteEvent.createdAt, days) + zaps[netDate] = (zaps[netDate] ?: BigDecimal(0)) + (noteEvent.amount ?: BigDecimal(0)) takenIntoAccount.add(noteEvent.id) } } @@ -130,8 +134,8 @@ class NotificationSummaryState( if (noteEvent.isTaggedUser(currentUser)) { val amount = noteEvent.claimedAmountInSats() if (amount != null) { - val netDate = formatDate(noteEvent.createdAt) - zaps[netDate] = (zaps[netDate] ?: BigDecimal.ZERO) + BigDecimal.valueOf(amount) + val netDate = formatDate(noteEvent.createdAt, days) + zaps[netDate] = (zaps[netDate] ?: BigDecimal(0)) + BigDecimal(amount) takenIntoAccount.add(noteEvent.id) } } @@ -141,8 +145,8 @@ class NotificationSummaryState( if (noteEvent.isTaggedUser(currentUser)) { val amount = noteEvent.amount() if (amount != null) { - val netDate = formatDate(noteEvent.createdAt) - zaps[netDate] = (zaps[netDate] ?: BigDecimal.ZERO) + BigDecimal.valueOf(amount / 1000) + val netDate = formatDate(noteEvent.createdAt, days) + zaps[netDate] = (zaps[netDate] ?: BigDecimal(0)) + BigDecimal(amount / 1000) takenIntoAccount.add(noteEvent.id) } } @@ -156,7 +160,7 @@ class NotificationSummaryState( LocalCache.getNoteIfExists(it)?.author?.pubkeyHex == currentUser } - val netDate = formatDate(noteEvent.createdAt) + val netDate = formatDate(noteEvent.createdAt, days) if (isCitation) { boosts[netDate] = (boosts[netDate] ?: 0) + 1 } else { @@ -178,7 +182,9 @@ class NotificationSummaryState( } suspend fun addToStatsSuspend(newBlockNotes: Set>) { - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() + + val days = LocalClock.epochDayCounter() val currentUser = user.pubkeyHex @@ -196,7 +202,7 @@ class NotificationSummaryState( when { noteEvent is ReactionEvent -> { if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) { - val netDate = formatDate(noteEvent.createdAt) + val netDate = formatDate(noteEvent.createdAt, days) reactions[netDate] = (reactions[netDate] ?: 0) + 1 takenIntoAccount.add(noteEvent.id) hasNewElements = true @@ -205,7 +211,7 @@ class NotificationSummaryState( noteEvent is RepostEvent || noteEvent is GenericRepostEvent -> { if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) { - val netDate = formatDate(noteEvent.createdAt) + val netDate = formatDate(noteEvent.createdAt, days) boosts[netDate] = (boosts[netDate] ?: 0) + 1 takenIntoAccount.add(noteEvent.id) hasNewElements = true @@ -215,8 +221,8 @@ class NotificationSummaryState( noteEvent is ZapReceiptEvent -> { if (noteEvent.isTaggedUser(currentUser)) { // && noteEvent.pubKey != currentUser User might be sending his own receipts - val netDate = formatDate(noteEvent.createdAt) - zaps[netDate] = (zaps[netDate] ?: BigDecimal.ZERO) + (noteEvent.amount ?: BigDecimal.ZERO) + val netDate = formatDate(noteEvent.createdAt, days) + zaps[netDate] = (zaps[netDate] ?: BigDecimal(0)) + (noteEvent.amount ?: BigDecimal(0)) takenIntoAccount.add(noteEvent.id) hasNewElements = true } @@ -226,8 +232,8 @@ class NotificationSummaryState( if (noteEvent.isTaggedUser(currentUser)) { val amount = noteEvent.claimedAmountInSats() if (amount != null) { - val netDate = formatDate(noteEvent.createdAt) - zaps[netDate] = (zaps[netDate] ?: BigDecimal.ZERO) + BigDecimal.valueOf(amount) + val netDate = formatDate(noteEvent.createdAt, days) + zaps[netDate] = (zaps[netDate] ?: BigDecimal(0)) + BigDecimal(amount) takenIntoAccount.add(noteEvent.id) hasNewElements = true } @@ -238,8 +244,8 @@ class NotificationSummaryState( if (noteEvent.isTaggedUser(currentUser)) { val amount = noteEvent.amount() if (amount != null) { - val netDate = formatDate(noteEvent.createdAt) - zaps[netDate] = (zaps[netDate] ?: BigDecimal.ZERO) + BigDecimal.valueOf(amount / 1000) + val netDate = formatDate(noteEvent.createdAt, days) + zaps[netDate] = (zaps[netDate] ?: BigDecimal(0)) + BigDecimal(amount / 1000) takenIntoAccount.add(noteEvent.id) hasNewElements = true } @@ -254,7 +260,7 @@ class NotificationSummaryState( LocalCache.getNoteIfExists(it)?.author?.pubkeyHex == currentUser } - val netDate = formatDate(noteEvent.createdAt) + val netDate = formatDate(noteEvent.createdAt, days) if (isCitation) { boosts[netDate] = (boosts[netDate] ?: 0) + 1 } else { @@ -280,12 +286,12 @@ class NotificationSummaryState( } private suspend fun refreshChartModel() { - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() - val now = LocalDateTime.now() + val today = LocalClock.today() val dataAxisLabelIndexes = listOf(-6, -5, -4, -3, -2, -1, 0) - val dataAxisLabels = dataAxisLabelIndexes.map { sdf.format(now.plusDays(it.toLong())) } + val dataAxisLabels = dataAxisLabelIndexes.map { today.plusDays(it).ymd() } val chart1 = LineCartesianLayerModel.build { @@ -296,7 +302,7 @@ class NotificationSummaryState( val chart2 = LineCartesianLayerModel.build { - series(dataAxisLabelIndexes, dataAxisLabels.map { zaps.value[it]?.toFloat() ?: 0f }) + series(dataAxisLabelIndexes, dataAxisLabels.map { zaps.value[it]?.toDoubleValue()?.toFloat() ?: 0f }) } val model = CartesianChartModel(chart1, chart2) @@ -315,9 +321,9 @@ class NotificationSummaryState( ): Boolean { val step = (max - min) / 8 - var previous = showAmountInteger(min.toBigDecimal()) + var previous = showAmountInteger(BigDecimal(min.toString())) for (i in 1..7) { - val current = showAmountInteger((min + (i * step)).toBigDecimal()) + val current = showAmountInteger(BigDecimal((min + (i * step)).toString())) if (previous == current) { return true } @@ -335,6 +341,6 @@ class NotificationSummaryState( fun destroy() { bundlerInsert.cancel() - Log.d("Init") { "OnCleared: ${this.javaClass.simpleName}" } + Log.d("Init") { "OnCleared: ${this::class.simpleName}" } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/EventObservers.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/event/AccountEventObservers.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/EventObservers.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/event/AccountEventObservers.kt index 33e77422c6..e3260d73bb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/EventObservers.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/event/AccountEventObservers.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.event +package com.vitorpamplona.amethyst.commons.relayClient.event import androidx.compose.runtime.Composable import androidx.compose.runtime.State import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.amethyst.commons.relayClient.event.observeCommunityApprovalNeedStatus as sharedObserveCommunityApprovalNeedStatus import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote as sharedObserveNote diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/RelaySubscriptionsCoordinator.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/RelaySubscriptionsCoordinator.kt similarity index 86% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/RelaySubscriptionsCoordinator.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/RelaySubscriptionsCoordinator.kt index 7291d8e943..ca03818de5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/RelaySubscriptionsCoordinator.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/RelaySubscriptionsCoordinator.kt @@ -18,10 +18,27 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand +import com.vitorpamplona.amethyst.commons.chats.privateDM.datasource.ChatroomFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.concord.datasource.ConcordChannelFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.concord.datasource.ConcordChannelHistoryFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.BuzzDmJoinedChatTailFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupJoinedChatTailFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupJoinedStateFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupOpenChatHistoryFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupOpenChatTailFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupOpenThreadsHistoryFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupsDiscoveryFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupsOnRelayFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.rooms.datasource.ChatroomListFilterAssembler +import com.vitorpamplona.amethyst.commons.followPacks.feed.datasource.FollowPackFeedFilterAssembler +import com.vitorpamplona.amethyst.commons.hashtag.datasource.HashtagFilterAssembler import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cachedDvmAnnouncements +import com.vitorpamplona.amethyst.commons.nests.datasource.NestRoomFilterAssembler +import com.vitorpamplona.amethyst.commons.nests.datasource.NestRoomLivenessAssembler import com.vitorpamplona.amethyst.commons.relayClient.apps.recommendations.ProfileAppRecommendationsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.articles.ArticlesFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.assemblers.CashuMintDirectoryFilterAssembler @@ -65,6 +82,10 @@ import com.vitorpamplona.amethyst.commons.relayClient.profile.UserProfileFilterA import com.vitorpamplona.amethyst.commons.relayClient.publicChats.PublicChatsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.relay.RelayFeedFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.relays.RelayInfoNip66FilterAssembler +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountFilterAssembler +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountForegroundFilterAssembler +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.ChannelFinderFilterAssemblyGroup +import com.vitorpamplona.amethyst.commons.relayClient.searchCommand.SearchFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.shorts.ShortsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.softwareapps.SoftwareAppsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.thread.ThreadFilterAssembler @@ -73,27 +94,6 @@ import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderFilterAssem import com.vitorpamplona.amethyst.commons.relayClient.video.VideoFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.wallet.OnchainZapsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.workouts.WorkoutsFilterAssembler -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountFilterAssembler -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountForegroundFilterAssembler -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.ChannelFinderFilterAssemblyGroup -import com.vitorpamplona.amethyst.service.relayClient.searchCommand.SearchFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.datasource.ChatroomFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelHistoryFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.BuzzDmJoinedChatTailFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupJoinedChatTailFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupJoinedStateFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupOpenChatHistoryFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupOpenChatTailFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupOpenThreadsHistoryFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupsDiscoveryFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupsOnRelayFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource.ChatroomListFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.feed.datasource.FollowPackFeedFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.datasource.HashtagFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.datasource.NestRoomFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.datasource.NestRoomLivenessAssembler import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.RelayOfflineTracker import com.vitorpamplona.quartz.nip01Core.relay.client.auth.IAuthStatus diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountFilterAssembler.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/AccountFilterAssembler.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountFilterAssembler.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/AccountFilterAssembler.kt index f8941ca69d..bd87241b3a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountFilterAssembler.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/AccountFilterAssembler.kt @@ -18,24 +18,24 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account import androidx.compose.runtime.Stable +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.relayClient.AccountScopedQuery import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.buzz.BuzzMembershipEoseManager -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.drafts.AccountDraftsEoseManager -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.marmot.MarmotGroupEventsEoseManager -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.metadata.AccountMetadataEoseManager -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip01Notifications.AccountNotificationsEoseFromInboxRelaysManager -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip01Notifications.AccountNotificationsHistoryEoseManager -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip47WalletConnect.NwcNotificationsEoseManager -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip59GiftWraps.AccountGiftWrapsEoseManager -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip59GiftWraps.AccountGiftWrapsHistoryEoseManager -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip60Cashu.CashuWalletEoseManager -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip60Cashu.CashuWalletHistoryEoseManager -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountFeedContentStates +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.buzz.BuzzMembershipEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.drafts.AccountDraftsEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.marmot.MarmotGroupEventsEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.metadata.AccountMetadataEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip01Notifications.AccountNotificationsEoseFromInboxRelaysManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip01Notifications.AccountNotificationsHistoryEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip47WalletConnect.NwcNotificationsEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip59GiftWraps.AccountGiftWrapsEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip59GiftWraps.AccountGiftWrapsHistoryEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip60Cashu.CashuWalletEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip60Cashu.CashuWalletHistoryEoseManager +import com.vitorpamplona.amethyst.commons.viewmodels.AccountFeedContentStates import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient @@ -55,7 +55,7 @@ open class AccountQueryState( * background accounts. * * The only always-on reader is - * [com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip01Notifications.AccountNotificationsEoseFromInboxRelaysManager], + * [com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip01Notifications.AccountNotificationsEoseFromInboxRelaysManager], * which reads it as a cold-start `since` floor via `lastNoteCreatedAtIfFilled()`. * That floor only arms once the feed holds a full page, and nothing fills a * feed that has no UI — so for a background account it could only ever diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountForegroundFilterAssembler.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/AccountForegroundFilterAssembler.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountForegroundFilterAssembler.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/AccountForegroundFilterAssembler.kt index 90491de091..0d70826ee3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountForegroundFilterAssembler.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/AccountForegroundFilterAssembler.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.follows.AccountFollowsLoaderSubAssembler -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip01Notifications.AccountNotificationsEoseFromRandomRelaysManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.follows.AccountFollowsLoaderSubAssembler +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip01Notifications.AccountNotificationsEoseFromRandomRelaysManager import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.RelayOfflineTracker import com.vitorpamplona.quartz.nip01Core.relay.client.auth.IAuthStatus diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountObservers.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/AccountObservers.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountObservers.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/AccountObservers.kt index 92b28d4ea0..15364b5df0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/AccountObservers.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/AccountObservers.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.model.Account import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/buzz/BuzzMembershipEoseManager.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/buzz/BuzzMembershipEoseManager.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/buzz/BuzzMembershipEoseManager.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/buzz/BuzzMembershipEoseManager.kt index f383407aa9..c10e1323a6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/buzz/BuzzMembershipEoseManager.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/buzz/BuzzMembershipEoseManager.kt @@ -18,35 +18,28 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.buzz +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.buzz import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.model.buzz.MembershipNotificationKinds import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthDecision import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.quartz.buzz.dvDmVisibility.DmVisibilityEvent -import com.vitorpamplona.quartz.buzz.notifications.MemberAddedNotificationEvent -import com.vitorpamplona.quartz.buzz.notifications.MemberRemovedNotificationEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch -/** The relay's membership verdicts addressed to me: 44100 "you were added", 44101 "you were removed". */ -val MembershipNotificationKinds = - listOf( - MemberAddedNotificationEvent.KIND, - MemberRemovedNotificationEvent.KIND, - ) - /** * Everything the workspace relay addresses to me personally: the membership verdicts plus the kind-30622 * snapshot of which DMs I have hidden. One filter class — `#p` = me, channel-less, workspace relay — so @@ -97,7 +90,7 @@ fun filterWorkspaceInboxToPubkey( * so there is no `#h` to scope it with. `block/buzz` downgrades any subscription carrying a channel-less * (or multi-channel) filter to "global", a class that by design never receives channel-scoped events; * that is exactly why NIP-29 group activity was moved out of - * [com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip01Notifications.AccountNotificationsEoseFromInboxRelaysManager] + * [com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip01Notifications.AccountNotificationsEoseFromInboxRelaysManager] * and onto the per-channel tails. Global is the correct class for 44100/44101 — they are stored globally * so their target can find them — but only as long as nothing channel-scoped shares the subscription. So * these ride a manager of their own rather than joining the inbox notification filters. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/drafts/AccountDraftsEoseManager.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/drafts/AccountDraftsEoseManager.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/drafts/AccountDraftsEoseManager.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/drafts/AccountDraftsEoseManager.kt index e99116d43b..4ff9a702ab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/drafts/AccountDraftsEoseManager.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/drafts/AccountDraftsEoseManager.kt @@ -18,18 +18,19 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.drafts +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.drafts import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.relayClient.account.drafts.filterDraftsFromKey import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/follows/AccountFollowsLoaderSubAssembler.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/follows/AccountFollowsLoaderSubAssembler.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/follows/AccountFollowsLoaderSubAssembler.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/follows/AccountFollowsLoaderSubAssembler.kt index 20558e89bd..9cc723bba0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/follows/AccountFollowsLoaderSubAssembler.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/follows/AccountFollowsLoaderSubAssembler.kt @@ -18,18 +18,18 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.follows +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.follows +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.IEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountUiQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose import com.vitorpamplona.amethyst.commons.relays.EOSEAccountFast import com.vitorpamplona.amethyst.commons.service.BundledUpdate -import com.vitorpamplona.amethyst.isDebug -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountUiQueryState +import com.vitorpamplona.amethyst.commons.util.isDebug import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.RelayOfflineTracker @@ -46,6 +46,7 @@ import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collectLatest diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/marmot/MarmotGroupEventsEoseManager.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/marmot/MarmotGroupEventsEoseManager.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/marmot/MarmotGroupEventsEoseManager.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/marmot/MarmotGroupEventsEoseManager.kt index 2081b2add3..977648af71 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/marmot/MarmotGroupEventsEoseManager.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/marmot/MarmotGroupEventsEoseManager.kt @@ -18,21 +18,22 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.marmot +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.marmot import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.launchChatFeedToggleObserver +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.launchChatFeedToggleObserver -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/AccountMetadataEoseManager.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/metadata/AccountMetadataEoseManager.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/AccountMetadataEoseManager.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/metadata/AccountMetadataEoseManager.kt index 4543f53330..215f01dabc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/AccountMetadataEoseManager.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/metadata/AccountMetadataEoseManager.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.metadata +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.metadata import com.vitorpamplona.amethyst.commons.defaults.Constants import com.vitorpamplona.amethyst.commons.model.User @@ -28,13 +28,14 @@ import com.vitorpamplona.amethyst.commons.relayClient.account.metadata.filterFol import com.vitorpamplona.amethyst.commons.relayClient.account.metadata.filterLastPostsFromKey import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.MergedAuthorTracker import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.SingleSubEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromInboxRelaysManager.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromInboxRelaysManager.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromInboxRelaysManager.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromInboxRelaysManager.kt index 9e4530da0f..42eec095f9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromInboxRelaysManager.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromInboxRelaysManager.kt @@ -18,20 +18,21 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip01Notifications +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip01Notifications import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.relayClient.account.nip01Notifications.filterNotificationsToPubkeys import com.vitorpamplona.amethyst.commons.relayClient.account.nip01Notifications.filterSummaryNotificationsToPubkeys import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.MergedAuthorTracker import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.SingleSubEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.sample @@ -51,11 +52,11 @@ import kotlinx.coroutines.launch * Gift wraps deliberately do **not** merge this way. They are unsolicited and their content is opaque * to the relay, so it cannot rate-limit them per recipient; a merged query would let one spammed * account consume the shared `limit` and starve every other account's DMs. Each account keeps its own - * budget there — see [com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip59GiftWraps.AccountGiftWrapsEoseManager]. + * budget there — see [com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip59GiftWraps.AccountGiftWrapsEoseManager]. * * ## The `limit` here is shared, and deliberately not scaled * - * [com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.metadata.AccountMetadataEoseManager] + * [com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.metadata.AccountMetadataEoseManager] * multiplies its limits by the number of merged accounts; this one does not, and the difference is the * kind of event. Metadata is replaceable, so the limit is a safety bound and widening it costs nothing. * Notifications are a stream, so the limit is a page size: scaling it by four accounts would ask four diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromRandomRelaysManager.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromRandomRelaysManager.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromRandomRelaysManager.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromRandomRelaysManager.kt index c8abad2128..2db53a0765 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromRandomRelaysManager.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromRandomRelaysManager.kt @@ -18,18 +18,19 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip01Notifications +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip01Notifications import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.relayClient.account.nip01Notifications.filterJustTheLatestNotificationsToPubkeyFromRandomRelays import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountUiQueryState import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountUiQueryState import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collectLatest @@ -37,6 +38,7 @@ import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.sample import kotlinx.coroutines.isActive import kotlinx.coroutines.launch +import kotlin.concurrent.Volatile class AccountNotificationsEoseFromRandomRelaysManager( client: INostrClient, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsHistoryEoseManager.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsHistoryEoseManager.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsHistoryEoseManager.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsHistoryEoseManager.kt index ccefa9f47a..6845a59dce 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsHistoryEoseManager.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsHistoryEoseManager.kt @@ -18,8 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip01Notifications +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip01Notifications +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.buzz.BuzzDmChannels import com.vitorpamplona.amethyst.commons.model.buzz.BuzzDmRegistry @@ -28,9 +29,8 @@ import com.vitorpamplona.amethyst.commons.relayClient.account.nip01Notifications import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager import com.vitorpamplona.amethyst.commons.relayClient.paging.BackwardRelayPager import com.vitorpamplona.amethyst.commons.relayClient.paging.PagingStatus +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter @@ -43,6 +43,7 @@ import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collectLatest diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip47WalletConnect/NwcNotificationsEoseManager.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip47WalletConnect/NwcNotificationsEoseManager.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip47WalletConnect/NwcNotificationsEoseManager.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip47WalletConnect/NwcNotificationsEoseManager.kt index 73d5bf6034..fbfc35f70a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip47WalletConnect/NwcNotificationsEoseManager.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip47WalletConnect/NwcNotificationsEoseManager.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip47WalletConnect +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip47WalletConnect import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.ExplainedFilter import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.SubPurpose import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient @@ -36,17 +36,18 @@ import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip47WalletConnect.events.NwcNotificationEvent import com.vitorpamplona.quartz.utils.TimeUtils +import com.vitorpamplona.quartz.utils.concurrent.ConcurrentSet import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.sample import kotlinx.coroutines.launch -import java.util.concurrent.ConcurrentHashMap /** * Always-on subscription for NIP-47 wallet notifications (kind 23197/23196), - * grouped in [com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountFilterAssembler] + * grouped in [com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountFilterAssembler] * so it shares the exact lifecycle of the account's zap/notification inbox * subscription: open while logged in, kept warm in the background by * `NotificationRelayService`, torn down on logout. @@ -64,7 +65,7 @@ class NwcNotificationsEoseManager( allKeys: () -> Set, ) : PerUserEoseManager(client, allKeys) { private val startSince = TimeUtils.now() - private val seen = ConcurrentHashMap.newKeySet() + private val seen = ConcurrentSet() private val userJobMap = mutableMapOf>() override fun user(key: AccountQueryState) = key.account.userProfile() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip59GiftWraps/AccountGiftWrapsEoseManager.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip59GiftWraps/AccountGiftWrapsEoseManager.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip59GiftWraps/AccountGiftWrapsEoseManager.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip59GiftWraps/AccountGiftWrapsEoseManager.kt index 278bcd24c8..6102f636b6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip59GiftWraps/AccountGiftWrapsEoseManager.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip59GiftWraps/AccountGiftWrapsEoseManager.kt @@ -18,19 +18,19 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip59GiftWraps +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip59GiftWraps import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType import com.vitorpamplona.amethyst.commons.model.privateChats.DmHistoryTuning +import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.DmRelayLog import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.launchChatFeedToggleObserver import com.vitorpamplona.amethyst.commons.relayClient.nip17Dm.filterGiftWrapsToPubkey import com.vitorpamplona.amethyst.commons.relayClient.paging.WindowLoadTracker import com.vitorpamplona.amethyst.commons.relayClient.paging.trackingListener +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.DmRelayLog -import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.launchChatFeedToggleObserver -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription @@ -38,6 +38,7 @@ import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collectLatest diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip59GiftWraps/AccountGiftWrapsHistoryEoseManager.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip59GiftWraps/AccountGiftWrapsHistoryEoseManager.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip59GiftWraps/AccountGiftWrapsHistoryEoseManager.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip59GiftWraps/AccountGiftWrapsHistoryEoseManager.kt index 99a2bbb90b..76b4efbbdb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip59GiftWraps/AccountGiftWrapsHistoryEoseManager.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip59GiftWraps/AccountGiftWrapsHistoryEoseManager.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip59GiftWraps +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip59GiftWraps import com.vitorpamplona.amethyst.commons.model.chats.ChatFeedType +import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.DmRelayLog import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager import com.vitorpamplona.amethyst.commons.relayClient.nip17Dm.filterGiftWrapsToPubkey import com.vitorpamplona.amethyst.commons.relayClient.paging.BackwardRelayPager import com.vitorpamplona.amethyst.commons.relayClient.paging.PagingStatus +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.DmRelayLog -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip60Cashu/CashuWalletEoseManager.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip60Cashu/CashuWalletEoseManager.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip60Cashu/CashuWalletEoseManager.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip60Cashu/CashuWalletEoseManager.kt index 95f3c1ece7..591d1d7598 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip60Cashu/CashuWalletEoseManager.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip60Cashu/CashuWalletEoseManager.kt @@ -18,19 +18,20 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip60Cashu +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip60Cashu import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.relayClient.assemblers.CashuWalletQueryState import com.vitorpamplona.amethyst.commons.relayClient.assemblers.cashuWalletFilters import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.sample @@ -41,13 +42,13 @@ import kotlinx.coroutines.launch * * This used to run from a collector inside `CashuWalletState`, on the account's own scope, which made * the wallet the only account-level subscription whose lifetime was decided by the model rather than - * by a mount. It ran for every [com.vitorpamplona.amethyst.model.Account] object that happened to be + * by a mount. It ran for every [com.vitorpamplona.amethyst.commons.model.Account] object that happened to be * resident — including accounts loaded purely so pushed gift wraps could be decrypted, which have no * wallet anyone is looking at — and the attempt to fix that bolted a "is this pubkey subscribed * anywhere" flow onto the model, so a model object was reading the relay layer's bookkeeping to * decide whether to talk to relays. * - * As a manager in [com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountFilterAssembler]'s + * As a manager in [com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountFilterAssembler]'s * group it starts and stops with every other account-level loader: the screen's mount for the account * on show, the registry for the rest, and whatever the foreground/background rule becomes without this * having to know about it. Exactly how NWC already worked. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip60Cashu/CashuWalletHistoryEoseManager.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip60Cashu/CashuWalletHistoryEoseManager.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip60Cashu/CashuWalletHistoryEoseManager.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip60Cashu/CashuWalletHistoryEoseManager.kt index a8afd11566..b0a6df59e2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip60Cashu/CashuWalletHistoryEoseManager.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/account/nip60Cashu/CashuWalletHistoryEoseManager.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.nip60Cashu +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.nip60Cashu +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.relayClient.account.nip60Cashu.filterCashuHistoryToPubkey import com.vitorpamplona.amethyst.commons.relayClient.eoseManagers.PerUserEoseManager import com.vitorpamplona.amethyst.commons.relayClient.paging.BackwardRelayPager import com.vitorpamplona.amethyst.commons.relayClient.paging.PagingStatus +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.amethyst.commons.relays.SincePerRelayMap -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountQueryState import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter @@ -39,6 +39,7 @@ import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collectLatest diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/ChannelFinderFilterAssemblySubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/ChannelFinderFilterAssemblySubscription.kt similarity index 84% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/ChannelFinderFilterAssemblySubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/ChannelFinderFilterAssemblySubscription.kt index 3bc756a125..be09d6fe0b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/ChannelFinderFilterAssemblySubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/ChannelFinderFilterAssemblySubscription.kt @@ -18,14 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Channel +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.ChannelFinderFilterAssemblyGroup +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.ChannelFinderQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun ChannelFinderFilterAssemblerSubscription( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/ChannelObservers.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/ChannelObservers.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/ChannelObservers.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/ChannelObservers.kt index d83de98e94..f1a8955c0a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/ChannelObservers.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/channel/ChannelObservers.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel import androidx.compose.runtime.Composable import androidx.compose.runtime.State @@ -30,7 +30,7 @@ import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.collections.immutable.ImmutableList @@ -38,6 +38,7 @@ import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.mapLatest diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/EventFinderShims.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/event/EventFinderShims.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/EventFinderShims.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/event/EventFinderShims.kt index 351a8b0eee..e9ae669074 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/EventFinderShims.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/reqCommand/event/EventFinderShims.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.event +package com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.relayClient.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Android convenience overload: pulls the account + shared event-finder data source diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/searchCommand/UserSearchDataSourceSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/searchCommand/UserSearchDataSourceSubscription.kt similarity index 84% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/searchCommand/UserSearchDataSourceSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/searchCommand/UserSearchDataSourceSubscription.kt index f0cf9f2485..16e201bdb3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/searchCommand/UserSearchDataSourceSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/searchCommand/UserSearchDataSourceSubscription.kt @@ -18,12 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.searchCommand +package com.vitorpamplona.amethyst.commons.relayClient.searchCommand import androidx.compose.runtime.Composable +import com.vitorpamplona.amethyst.commons.relayClient.searchCommand.SearchFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun UserSearchDataSourceSubscription( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/UserFinderFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/user/AccountUserFinderSubscription.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/UserFinderFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/user/AccountUserFinderSubscription.kt index 3002e75f48..7c567372b7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/UserFinderFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/user/AccountUserFinderSubscription.kt @@ -18,20 +18,19 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.user +package com.vitorpamplona.amethyst.commons.relayClient.user -import android.annotation.SuppressLint import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderQueryState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderFilterAssemblerSubscription as SharedUserFinderSubscription -@SuppressLint("StateFlowValueCalledInComposition") +@Suppress("StateFlowValueCalledInComposition") @Composable fun UserFinderFilterAssemblerSubscription( user: User, @@ -47,7 +46,7 @@ fun UserFinderFilterAssemblerSubscription( * So that we load their relay lists and find posts * cited in this event. */ -@SuppressLint("StateFlowValueCalledInComposition") +@Suppress("StateFlowValueCalledInComposition") @Composable fun UserFinderByParentFilterAssemblerSubscription( note: Note, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/UserObservers.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/user/AccountUserObservers.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/UserObservers.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/user/AccountUserObservers.kt index 54d6667e67..34f6acbc28 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/UserObservers.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/relayClient/user/AccountUserObservers.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.relayClient.reqCommand.user +package com.vitorpamplona.amethyst.commons.relayClient.user -import android.annotation.SuppressLint import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.User @@ -32,8 +32,7 @@ import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel import com.vitorpamplona.amethyst.commons.model.nip01Core.UserInfo import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.commons.model.nip85TrustedAssertions.Nickname -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent import com.vitorpamplona.quartz.nip51Lists.PinListEvent @@ -44,6 +43,7 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn @@ -309,7 +309,7 @@ fun observeUserIsFollowing( ) } -@SuppressLint("StateFlowValueCalledInComposition") +@Suppress("StateFlowValueCalledInComposition") @OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class) @Composable fun observeUserIsFollowingHashtag( @@ -331,7 +331,7 @@ fun observeUserIsFollowingHashtag( return flow.collectAsStateWithLifecycle(hashtag in accountViewModel.account.interestList.flow.value) } -@SuppressLint("StateFlowValueCalledInComposition") +@Suppress("StateFlowValueCalledInComposition") @OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class) @Composable fun observeUserIsMutingHashtag( @@ -358,7 +358,7 @@ fun observeUserIsMutingHashtag( ) } -@SuppressLint("StateFlowValueCalledInComposition") +@Suppress("StateFlowValueCalledInComposition") @OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class) @Composable fun observeUserIsFollowingGeohash( @@ -379,7 +379,7 @@ fun observeUserIsFollowingGeohash( return flow.collectAsStateWithLifecycle(geohash in accountViewModel.account.geohashList.flow.value) } -@SuppressLint("StateFlowValueCalledInComposition") +@Suppress("StateFlowValueCalledInComposition") @OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class) @Composable fun observeUserIsFollowingRelay( @@ -422,7 +422,7 @@ fun observeUserIsFollowingChannel( .flowOn(Dispatchers.IO) } - @SuppressLint("StateFlowValueCalledInComposition") + @Suppress("StateFlowValueCalledInComposition") return flow.collectAsStateWithLifecycle(channel.idHex in account.publicChatList.flowSet.value) } @@ -448,7 +448,7 @@ fun observeUserIsFollowingChannel( .flowOn(Dispatchers.IO) } - @SuppressLint("StateFlowValueCalledInComposition") + @Suppress("StateFlowValueCalledInComposition") return flow.collectAsStateWithLifecycle(channel.roomId in account.ephemeralChatList.liveEphemeralChatList.value) } @@ -506,7 +506,7 @@ fun observeUserStatuses( }.flowOn(Dispatchers.IO) } - @SuppressLint("StateFlowValueCalledInComposition") + @Suppress("StateFlowValueCalledInComposition") return flow.collectAsStateWithLifecycle(user.statusState().statuses.value) } @@ -526,6 +526,6 @@ fun observeUserRelayIntoList( .flowOn(Dispatchers.IO) } - @SuppressLint("StateFlowValueCalledInComposition") + @Suppress("StateFlowValueCalledInComposition") return flow.collectAsStateWithLifecycle(relayUrl in accountViewModel.account.trustedRelays.flow.value) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/HttpStatusMessages.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/HttpStatusMessages.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/HttpStatusMessages.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/HttpStatusMessages.kt index 03932cd6e7..a6766ec081 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/HttpStatusMessages.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/HttpStatusMessages.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service +package com.vitorpamplona.amethyst.commons.service import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.http_status_400 diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/V4VPaymentHandler.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/V4VPaymentHandler.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/V4VPaymentHandler.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/V4VPaymentHandler.kt index 9a8bd71f10..d7d2e40810 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/V4VPaymentHandler.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/V4VPaymentHandler.kt @@ -18,10 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service +package com.vitorpamplona.amethyst.commons.service -import android.content.Context +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.model.nip47WalletConnect.NwcSignerState import com.vitorpamplona.amethyst.commons.model.payments.PaymentSource import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.clink_debit_no_response @@ -32,12 +33,12 @@ import com.vitorpamplona.amethyst.commons.resources.podcast_value_error_title import com.vitorpamplona.amethyst.commons.resources.podcast_value_keysend_not_supported import com.vitorpamplona.amethyst.commons.resources.podcast_value_keysend_requires_nwc import com.vitorpamplona.amethyst.commons.resources.podcast_value_no_recipients +import com.vitorpamplona.amethyst.commons.service.lnurl.LightningInvoiceResolver +import com.vitorpamplona.amethyst.commons.service.lnurl.LnurlHttpTransport +import com.vitorpamplona.amethyst.commons.service.nwc.nwcFailureDetail +import com.vitorpamplona.amethyst.commons.service.nwc.nwcTimeoutMessage +import com.vitorpamplona.amethyst.commons.tor.MoneyOpRelayRouting import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.nip47WalletConnect.NwcSignerState -import com.vitorpamplona.amethyst.service.lnurl.LightningAddressResolver -import com.vitorpamplona.amethyst.ui.nwc.nwcFailureDetail -import com.vitorpamplona.amethyst.ui.nwc.nwcTimeoutMessage import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip47WalletConnect.rpc.NwcMethod import com.vitorpamplona.quartz.nip47WalletConnect.rpc.PayKeysendMethod @@ -51,10 +52,10 @@ import com.vitorpamplona.quartz.podcasts.PodcastValueShare import com.vitorpamplona.quartz.utils.mapNotNullAsync import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeoutOrNull -import okhttp3.OkHttpClient /** * Executes a Podcasting-2.0 value-for-value (V4V) split: takes a [PodcastValue] block and a total @@ -77,6 +78,7 @@ import okhttp3.OkHttpClient */ class V4VPaymentHandler( val account: Account, + private val moneyOpRelays: MoneyOpRelayRouting, ) { /** A resolved lnaddress share ready to pay: the share plus the BOLT-11 fetched for it. */ class InvoicePayable( @@ -89,8 +91,7 @@ class V4VPaymentHandler( totalMilliSats: Long, boostagram: PodcastBoostagram, zappedNote: Note?, - context: Context, - okHttpClient: (String) -> OkHttpClient, + lnurl: LnurlHttpTransport, onError: (title: String, message: String) -> Unit, onProgress: (percent: Float) -> Unit, onPayInvoicesViaIntent: (invoices: List) -> Unit, @@ -115,7 +116,7 @@ class V4VPaymentHandler( if (nodeShares.isNotEmpty()) { if (account.nip47SignerState.hasWalletConnectSetup()) { if (defaultWalletMayKeysend()) { - payNodeSharesViaKeysend(nodeShares, boostagram, context, onError) + payNodeSharesViaKeysend(nodeShares, boostagram, onError) } else { onError( loadStringRes(Res.string.podcast_value_error_title), @@ -138,12 +139,11 @@ class V4VPaymentHandler( asZap = asZap, zapType = zapType, zappedNote = zappedNote, - okHttpClient = okHttpClient, - context = context, + lnurl = lnurl, onError = onError, onProgress = { onProgress(it * 0.6f + 0.1f) }, ) - payInvoices(payables, zappedNote, context, onError, onPayInvoicesViaIntent) { + payInvoices(payables, zappedNote, onError, onPayInvoicesViaIntent) { onProgress(it * 0.25f + 0.7f) } } @@ -169,7 +169,6 @@ class V4VPaymentHandler( private suspend fun payNodeSharesViaKeysend( shares: List, boostagram: PodcastBoostagram, - context: Context, onError: (String, String) -> Unit, ) { val metadataTlv = TlvRecord(PodcastValue.PODCAST_TLV_RECORD, hexTlv(boostagram.toJson())) @@ -215,8 +214,7 @@ class V4VPaymentHandler( asZap: Boolean, zapType: ZapReceiptEvent.ZapType, zappedNote: Note?, - okHttpClient: (String) -> OkHttpClient, - context: Context, + lnurl: LnurlHttpTransport, onError: (String, String) -> Unit, onProgress: (percent: Float) -> Unit, ): List { @@ -248,19 +246,17 @@ class V4VPaymentHandler( } val invoice = - LightningAddressResolver().lnAddressInvoice( + LightningInvoiceResolver(lnurl).lnAddressInvoice( lnAddress = lnAddress, milliSats = share.amountMilliSats, message = message, nostrRequest = nostrRequest, - okHttpClient = okHttpClient, onProgress = {}, - context = context, ) progress += 1f / shares.size onProgress(progress) InvoicePayable(share, invoice) - } catch (e: LightningAddressResolver.LightningAddressError) { + } catch (e: LightningInvoiceResolver.LightningAddressError) { onError(e.title, e.msg) null } catch (e: Exception) { @@ -277,7 +273,6 @@ class V4VPaymentHandler( private suspend fun payInvoices( payables: List, zappedNote: Note?, - context: Context, onError: (String, String) -> Unit, onPayInvoicesViaIntent: (List) -> Unit, onProgress: (percent: Float) -> Unit, @@ -312,7 +307,7 @@ class V4VPaymentHandler( is PaymentSource.ClinkDebit -> { var done = 0 payables.forEach { payable -> - val response = ClinkDebitPayer.payInvoice(account, source.wallet.pointer, payable.invoice) + val response = ClinkDebitPayer.payInvoice(account, moneyOpRelays, source.wallet.pointer, payable.invoice) if (response?.isOk() != true) { onError( loadStringRes(Res.string.error_dialog_pay_invoice_error), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/ZapPaymentHandler.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/ZapPaymentHandler.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/ZapPaymentHandler.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/ZapPaymentHandler.kt index 6c8a9e667c..ec73a67887 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/ZapPaymentHandler.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/ZapPaymentHandler.kt @@ -18,10 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service +package com.vitorpamplona.amethyst.commons.service -import android.content.Context import androidx.compose.runtime.Immutable +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.model.Bolt12ZapFailure import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -29,6 +30,8 @@ import com.vitorpamplona.amethyst.commons.model.payments.PaymentSource import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.bolt12_payment_failed import com.vitorpamplona.amethyst.commons.resources.bolt12_zap_error +import com.vitorpamplona.amethyst.commons.resources.bolt12_zap_invalid_receipt +import com.vitorpamplona.amethyst.commons.resources.bolt12_zap_paid_no_receipt import com.vitorpamplona.amethyst.commons.resources.clink_debit_no_response import com.vitorpamplona.amethyst.commons.resources.error_dialog_pay_invoice_error import com.vitorpamplona.amethyst.commons.resources.error_dialog_zap_error @@ -38,11 +41,12 @@ import com.vitorpamplona.amethyst.commons.resources.unable_to_create_a_lightning import com.vitorpamplona.amethyst.commons.resources.user_does_not_have_a_lightning_address_setup_to_receive_sats import com.vitorpamplona.amethyst.commons.resources.user_x_does_not_have_a_lightning_address_setup_to_receive_sats import com.vitorpamplona.amethyst.commons.resources.wallet_connect_pay_invoice_error_error +import com.vitorpamplona.amethyst.commons.service.lnurl.LightningInvoiceResolver +import com.vitorpamplona.amethyst.commons.service.lnurl.LnurlHttpTransport +import com.vitorpamplona.amethyst.commons.service.nwc.nwcFailureDetail +import com.vitorpamplona.amethyst.commons.service.nwc.nwcTimeoutMessage +import com.vitorpamplona.amethyst.commons.tor.MoneyOpRelayRouting import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.lnurl.LightningAddressResolver -import com.vitorpamplona.amethyst.ui.nwc.nwcFailureDetail -import com.vitorpamplona.amethyst.ui.nwc.nwcTimeoutMessage import com.vitorpamplona.quartz.experimental.clink.pointers.NDebit import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip47WalletConnect.rpc.NwcErrorCode @@ -61,15 +65,18 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import okhttp3.OkHttpClient import org.jetbrains.compose.resources.StringResource -import java.util.concurrent.atomic.AtomicInteger +import kotlin.concurrent.atomics.AtomicInt +import kotlin.concurrent.atomics.ExperimentalAtomicApi +import kotlin.concurrent.atomics.incrementAndFetch import kotlin.math.round class ZapPaymentHandler( val account: Account, + private val moneyOpRelays: MoneyOpRelayRouting, ) { @Immutable data class Payable( @@ -116,9 +123,8 @@ class ZapPaymentHandler( amountMilliSats: Long, pollOption: Int?, message: String, - context: Context, showErrorIfNoLnAddress: Boolean, - okHttpClient: (String) -> OkHttpClient, + lnurl: LnurlHttpTransport, onError: (String, String, User?) -> Unit, onProgress: (percent: Float) -> Unit, onPayViaIntent: (ImmutableList) -> Unit, @@ -257,11 +263,10 @@ class ZapPaymentHandler( zapType = zapType, totalAmountMilliSats = amountMilliSats, totalWeight = totalWeight, - okHttpClient = okHttpClient, + lnurl = lnurl, onError = onError, onProgress = onProgress, onPayViaIntent = onPayViaIntent, - context = context, ) } @@ -275,11 +280,10 @@ class ZapPaymentHandler( totalWeight = totalWeight, message = message, zapType = zapType, - okHttpClient = okHttpClient, + lnurl = lnurl, onError = onError, onProgress = { onProgress(it * 0.25f + 0.75f) }, onPayViaIntent = onPayViaIntent, - context = context, ) } @@ -300,11 +304,10 @@ class ZapPaymentHandler( zapType: ZapReceiptEvent.ZapType, totalAmountMilliSats: Long, totalWeight: Double, - okHttpClient: (String) -> OkHttpClient, + lnurl: LnurlHttpTransport, onError: (String, String, User?) -> Unit, onProgress: (percent: Float) -> Unit, onPayViaIntent: (ImmutableList) -> Unit, - context: Context, ) { val splitZapRequests = signAllZapRequests(note, pollOption, message, zapType, zapsToSend, totalAmountMilliSats, totalWeight) if (splitZapRequests.isEmpty()) return @@ -316,10 +319,9 @@ class ZapPaymentHandler( requests = splitZapRequests, totalAmountMilliSats = totalAmountMilliSats, message = message, - okHttpClient = okHttpClient, + lnurl = lnurl, onError = onError, onProgress = { onProgress(it * 0.7f + 0.05f) }, - context = context, totalWeight = totalWeight, ) if (payables.isEmpty()) return @@ -333,13 +335,13 @@ class ZapPaymentHandler( is PaymentSource.ClinkDebit -> { payViaClinkDebit(payables, source.wallet.pointer, onError = onError, onProgress = { onProgress(it * 0.25f + 0.75f) - }, context) + }) } is PaymentSource.Nwc -> { payViaNWC(payables, note, onError = onError, onProgress = { onProgress(it * 0.25f + 0.75f) // keeps within range. - }, context) + }) } null -> { @@ -411,10 +413,9 @@ class ZapPaymentHandler( requests: List, totalAmountMilliSats: Long, message: String, - okHttpClient: (String) -> OkHttpClient, + lnurl: LnurlHttpTransport, onError: (String, String, User?) -> Unit, onProgress: (percent: Float) -> Unit, - context: Context, // Shared across the lightning + BOLT12 lanes so a mixed split stays proportional. totalWeight: Double = requests.sumOf { it.inputSetup.weight }, ): List { @@ -428,14 +429,13 @@ class ZapPaymentHandler( nostrZapRequest = splitZapRequestPair.zapRequest, zapValue = calculateZapValue(totalAmountMilliSats, splitZapRequestPair.inputSetup.weight, totalWeight), message = message, - okHttpClient = okHttpClient, + lnurl = lnurl, onProgressStep = { percentStepForThisPayment -> progressAllPayments += percentStepForThisPayment / requests.size onProgress(progressAllPayments) }, - context = context, ) - } catch (e: LightningAddressResolver.LightningAddressError) { + } catch (e: LightningInvoiceResolver.LightningAddressError) { onError(e.title, e.msg, splitZapRequestPair.inputSetup.user) null } catch (e: Exception) { @@ -465,7 +465,6 @@ class ZapPaymentHandler( note: Note, onError: (String, String, User?) -> Unit, onProgress: (percent: Float) -> Unit, - context: Context, ): List { val progress = PaymentProgress(payables.size, onProgress) @@ -536,11 +535,10 @@ class ZapPaymentHandler( totalWeight: Double, message: String, zapType: ZapReceiptEvent.ZapType, - okHttpClient: (String) -> OkHttpClient, + lnurl: LnurlHttpTransport, onError: (String, String, User?) -> Unit, onProgress: (percent: Float) -> Unit, onPayViaIntent: (ImmutableList) -> Unit, - context: Context, ) { val progress = PaymentProgress(recipients.size, onProgress) @@ -560,7 +558,7 @@ class ZapPaymentHandler( amountMillisats = calculateZapValue(totalAmountMilliSats, recipient.weight, totalWeight), message = message, zapType = zapType, - onError = { msgRes, detail -> account.scope.launch { reportBolt12Error(msgRes, detail) } }, + onError = { failure -> account.scope.launch { reportBolt12Error(failure.messageRes(), null) } }, onNotPaid = { code, detail -> val lnAddress = recipient.lnAddress if (lnAddress != null && Bolt12LightningFallback.shouldRetry(code)) { @@ -574,13 +572,12 @@ class ZapPaymentHandler( zapType = zapType, totalAmountMilliSats = totalAmountMilliSats, totalWeight = totalWeight, - okHttpClient = okHttpClient, + lnurl = lnurl, onError = onError, // The zap's own progress finished when the BOLT12 request was // dispatched; the retry settles in the background like NWC does. onProgress = {}, onPayViaIntent = onPayViaIntent, - context = context, ) } catch (e: CancellationException) { throw e @@ -618,14 +615,15 @@ class ZapPaymentHandler( * The counter is atomic because `mapNotNullAsync` runs the payables concurrently and the * response half-step fires from an async callback, so plain `+=` would lose updates. */ + @OptIn(ExperimentalAtomicApi::class) private class PaymentProgress( payableCount: Int, private val onProgress: (percent: Float) -> Unit, ) { private val totalSteps = (payableCount * 2).coerceAtLeast(1) - private val done = AtomicInteger(0) + private val done = AtomicInt(0) - fun step() = onProgress(done.incrementAndGet().toFloat() / totalSteps) + fun step() = onProgress(done.incrementAndFetch().toFloat() / totalSteps) } /** @@ -642,7 +640,6 @@ class ZapPaymentHandler( pointer: NDebit, onError: (String, String, User?) -> Unit, onProgress: (percent: Float) -> Unit, - context: Context, ): List { val progress = PaymentProgress(payables.size, onProgress) @@ -650,7 +647,7 @@ class ZapPaymentHandler( items = payables, runRequestFor = { payable: Payable -> account.scope.launch { - val response = ClinkDebitPayer.payInvoice(account, pointer, payable.invoice) + val response = ClinkDebitPayer.payInvoice(account, moneyOpRelays, pointer, payable.invoice) progress.step() if (response?.isOk() != true) { onError( @@ -675,9 +672,8 @@ class ZapPaymentHandler( nostrZapRequest: ZapRequestEvent?, zapValue: Long, message: String, - okHttpClient: (String) -> OkHttpClient, + lnurl: LnurlHttpTransport, onProgressStep: (percent: Float) -> Unit, - context: Context, ): Payable { var progressThisPayment = 0.00f @@ -686,18 +682,16 @@ class ZapPaymentHandler( var sentZapRequest: ZapRequestEvent? = null val invoice = - LightningAddressResolver().lnAddressInvoice( + LightningInvoiceResolver(lnurl).lnAddressInvoice( lnAddress = lud16, milliSats = zapValue, message = message, nostrRequest = nostrZapRequest, - okHttpClient = okHttpClient, onProgress = { val step = it - progressThisPayment progressThisPayment = it onProgressStep(step) }, - context = context, onZapRequestSent = { sentZapRequest = it }, ) @@ -712,3 +706,9 @@ class ZapPaymentHandler( ) } } + +private fun Bolt12ZapFailure.messageRes(): StringResource = + when (this) { + Bolt12ZapFailure.PaidNoReceipt -> Res.string.bolt12_zap_paid_no_receipt + Bolt12ZapFailure.InvalidReceipt -> Res.string.bolt12_zap_invalid_receipt + } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallSessionBridge.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/call/CallSessionBridge.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallSessionBridge.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/call/CallSessionBridge.kt index d476f6820f..613c78ca2c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallSessionBridge.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/call/CallSessionBridge.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.call +package com.vitorpamplona.amethyst.commons.service.call +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.nipACWebRtcCalls.CallManager import com.vitorpamplona.amethyst.commons.nipACWebRtcCalls.CallState -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Process-level singleton that bridges the active [CallManager] and diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/cashu/melt/MeltProcessor.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/cashu/melt/MeltProcessor.kt similarity index 87% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/cashu/melt/MeltProcessor.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/cashu/melt/MeltProcessor.kt index 6956104ffc..c0e171dc59 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/cashu/melt/MeltProcessor.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/cashu/melt/MeltProcessor.kt @@ -18,22 +18,22 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.cashu.melt +package com.vitorpamplona.amethyst.commons.service.cashu.melt -import android.content.Context import com.vitorpamplona.amethyst.commons.cashu.melt.MeltResult import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.cashu_failed_redemption import com.vitorpamplona.amethyst.commons.resources.cashu_failed_redemption_explainer_error_msg import com.vitorpamplona.amethyst.commons.resources.cashu_unsafe_mint_url import com.vitorpamplona.amethyst.commons.resources.cashu_unsafe_mint_url_explainer +import com.vitorpamplona.amethyst.commons.service.lnurl.LightningInvoiceResolver +import com.vitorpamplona.amethyst.commons.service.lnurl.LnurlHttpTransport import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.service.lnurl.LightningAddressResolver import com.vitorpamplona.quartz.nip60Cashu.mintApi.CashuMintOperations import com.vitorpamplona.quartz.nip60Cashu.mintApi.MintHttpClient +import com.vitorpamplona.quartz.nip60Cashu.mintApi.MintHttpTransport import com.vitorpamplona.quartz.nip60Cashu.mintApi.MintUrlException import com.vitorpamplona.quartz.nip60Cashu.token.CashuToken -import okhttp3.OkHttpClient import kotlin.coroutines.cancellation.CancellationException /** @@ -61,13 +61,13 @@ class MeltProcessor { suspend fun melt( token: CashuToken, lud16: String, - okHttpClient: (String) -> OkHttpClient, - context: Context, + mintTransport: MintHttpTransport, + lnurl: LnurlHttpTransport, knownWalletMints: Set = emptySet(), ): MeltResult { try { val isOwnMint = knownWalletMints.any { it.trim().trimEnd('/').equals(token.mint.trim().trimEnd('/'), ignoreCase = true) } - val ops = CashuMintOperations(MintHttpClient(token.mint, userConfigured = isOwnMint, okHttpClient = okHttpClient)) + val ops = CashuMintOperations(MintHttpClient(token.mint, userConfigured = isOwnMint, transport = mintTransport)) val proofs = token.proofs // A Lightning address must commit to an amount before we know the @@ -75,20 +75,18 @@ class MeltProcessor { // the LN fee_reserve, then add the NUT-02 input fee the mint // charges on these proofs. val probeInvoice = - LightningAddressResolver().lnAddressInvoice( + LightningInvoiceResolver(lnurl).lnAddressInvoice( lnAddress = lud16, milliSats = token.totalAmount * 1000, message = "Calculate Fees for Cashu", - okHttpClient = okHttpClient, onProgress = {}, - context = context, ) val probeQuote = ops.requestMeltQuote(probeInvoice) val fees = probeQuote.feeReserve + ops.inputFeeFor(proofs) val sendable = token.totalAmount - fees if (sendable <= 0) { - throw LightningAddressResolver.LightningAddressError( + throw LightningInvoiceResolver.LightningAddressError( loadStringRes(Res.string.cashu_failed_redemption), loadStringRes( Res.string.cashu_failed_redemption_explainer_error_msg, @@ -101,13 +99,11 @@ class MeltProcessor { // requesting change — there is no wallet to hold leftover proofs, // so the unused fee_reserve stays with the mint. val invoice = - LightningAddressResolver().lnAddressInvoice( + LightningInvoiceResolver(lnurl).lnAddressInvoice( lnAddress = lud16, milliSats = sendable * 1000, message = "Redeem Cashu", - okHttpClient = okHttpClient, onProgress = {}, - context = context, ) val quote = ops.requestMeltQuote(invoice) ops.meltProofs(quote, proofs, requestChange = false) @@ -119,16 +115,16 @@ class MeltProcessor { ) } catch (e: Exception) { if (e is CancellationException) throw e - if (e is LightningAddressResolver.LightningAddressError) throw e + if (e is LightningInvoiceResolver.LightningAddressError) throw e // The mint URL was refused before any request went out: this is OUR // message, not the mint's, so don't dress it up as "the mint said". if (e is MintUrlException) { - throw LightningAddressResolver.LightningAddressError( + throw LightningInvoiceResolver.LightningAddressError( loadStringRes(Res.string.cashu_unsafe_mint_url), loadStringRes(Res.string.cashu_unsafe_mint_url_explainer, e.message), ) } - throw LightningAddressResolver.LightningAddressError( + throw LightningInvoiceResolver.LightningAddressError( loadStringRes(Res.string.cashu_failed_redemption), loadStringRes(Res.string.cashu_failed_redemption_explainer_error_msg, e.message), ) diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/ArgbImageBitmap.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/ArgbImageBitmap.kt new file mode 100644 index 0000000000..27674aa677 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/ArgbImageBitmap.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.service.image + +import androidx.compose.ui.graphics.ImageBitmap + +/** An [ImageBitmap] of [width] × [height] from row-major ARGB (0xAARRGGBB) [pixels]. */ +expect fun argbPixelsToImageBitmap( + pixels: IntArray, + width: Int, + height: Int, +): ImageBitmap diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/BlurHashFetcher.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/BlurHashFetcher.kt index ec1405df9f..8250bb5f08 100644 --- a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/BlurHashFetcher.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/BlurHashFetcher.kt @@ -30,10 +30,6 @@ import coil3.key.Keyer import coil3.request.Options import com.vitorpamplona.amethyst.commons.blurhash.BlurHashDecoder -data class BlurhashWrapper( - val blurhash: String, -) - @Stable class BlurHashFetcher( private val options: Options, diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/ThumbHashFetcher.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/ThumbHashFetcher.kt index 9dddd1b976..d98a7b867f 100644 --- a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/ThumbHashFetcher.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/ThumbHashFetcher.kt @@ -30,10 +30,6 @@ import coil3.key.Keyer import coil3.request.Options import com.vitorpamplona.amethyst.commons.thumbhash.ThumbHashDecoder -data class ThumbhashWrapper( - val thumbhash: String, -) - @Stable class ThumbHashFetcher( private val options: Options, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/LightningInvoiceResolver.kt similarity index 69% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/LightningInvoiceResolver.kt index 9056561530..e2501d307e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/LightningInvoiceResolver.kt @@ -18,10 +18,8 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.lnurl +package com.vitorpamplona.amethyst.commons.service.lnurl -import android.content.Context -import com.fasterxml.jackson.databind.ObjectMapper import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.callback_url_not_found_in_the_user_s_lightning_address_server_configuration_with_user import com.vitorpamplona.amethyst.commons.resources.could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup @@ -34,26 +32,31 @@ import com.vitorpamplona.amethyst.commons.resources.incorrect_invoice_amount_sat import com.vitorpamplona.amethyst.commons.resources.the_receiver_s_lightning_service_at_is_not_available_it_was_calculated_from_the_lightning_address_error_check_if_the_server_is_up_and_if_the_lightning_address_is_correct import com.vitorpamplona.amethyst.commons.resources.unable_to_create_a_lightning_invoice_before_sending_the_zap_element_pr_not_found_in_the_resulting_json_with_user import com.vitorpamplona.amethyst.commons.resources.unable_to_create_a_lightning_invoice_before_sending_the_zap_the_receiver_s_lightning_wallet_sent_the_following_error_with_user +import com.vitorpamplona.amethyst.commons.service.HttpStatusMessages +import com.vitorpamplona.amethyst.commons.service.lnurl.LnurlHttpResponse +import com.vitorpamplona.amethyst.commons.service.lnurl.LnurlHttpTransport import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.service.HttpStatusMessages import com.vitorpamplona.quartz.lightning.LnInvoiceUtil import com.vitorpamplona.quartz.lightning.Lud06 import com.vitorpamplona.quartz.nip57Zaps.ZapRequestEvent import com.vitorpamplona.quartz.nip57Zaps.validate.LnurlEndpointCache import com.vitorpamplona.quartz.nip57Zaps.validate.LnurlEndpointInfo import com.vitorpamplona.quartz.utils.Log -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import okhttp3.coroutines.executeAsync -import java.math.BigDecimal -import java.math.RoundingMode -import java.net.URLEncoder +import com.vitorpamplona.quartz.utils.UrlEncoder +import com.vitorpamplona.quartz.utils.toLongValue +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonNull +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.booleanOrNull +import kotlinx.serialization.json.longOrNull import kotlin.coroutines.cancellation.CancellationException -class LightningAddressResolver { +/** LNURL-pay (LUD-06/16) for zaps and payments, over whatever [transport] the platform supplies. */ +class LightningInvoiceResolver( + private val transport: LnurlHttpTransport, +) { fun assembleUrl(lnAddress: String): String? { val parts = lnAddress.split("@") @@ -73,42 +76,27 @@ class LightningAddressResolver { val msg: String, ) : Exception(msg) - private suspend fun fetchLightningAddressJson( - lnAddress: String, - okHttpClient: (String) -> OkHttpClient, - context: Context, - ): String { + private suspend fun fetchLightningAddressJson(lnAddress: String): String { val url = assembleUrl(lnAddress) ?: throw LightningAddressError( loadStringRes(Res.string.error_unable_to_fetch_invoice), loadStringRes(Res.string.could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup, lnAddress), ) - val client = okHttpClient(url) - return try { - val request: Request = - Request - .Builder() - .url(url) - .build() - - client.newCall(request).executeAsync().use { response -> - withContext(Dispatchers.IO) { - if (response.isSuccessful) { - response.body.string() - } else { - throw LightningAddressError( - loadStringRes(Res.string.error_unable_to_fetch_invoice), - loadStringRes( - Res.string.the_receiver_s_lightning_service_at_is_not_available_it_was_calculated_from_the_lightning_address_error_check_if_the_server_is_up_and_if_the_lightning_address_is_correct, - url, - lnAddress, - errorMessage(response, context), - ), - ) - } - } + val response = transport.get(url) + if (response.isSuccessful) { + response.body + } else { + throw LightningAddressError( + loadStringRes(Res.string.error_unable_to_fetch_invoice), + loadStringRes( + Res.string.the_receiver_s_lightning_service_at_is_not_available_it_was_calculated_from_the_lightning_address_error_check_if_the_server_is_up_and_if_the_lightning_address_is_correct, + url, + lnAddress, + errorMessage(response), + ), + ) } } catch (e: Exception) { if (e is CancellationException) throw e @@ -129,63 +117,43 @@ class LightningAddressResolver { milliSats: Long, message: String, nostrRequest: ZapRequestEvent? = null, - okHttpClient: (String) -> OkHttpClient, - context: Context, ): String { - @Suppress("BlockingMethodInNonBlockingContext") // URLEncoder.encode is CPU-only, not I/O blocking - val encodedMessage = URLEncoder.encode(message, "utf-8") + val encodedMessage = UrlEncoder.encode(message) val urlBinder = if (lnCallback.contains("?")) "&" else "?" var url = "$lnCallback${urlBinder}amount=$milliSats&comment=$encodedMessage" if (nostrRequest != null) { - @Suppress("BlockingMethodInNonBlockingContext") // URLEncoder.encode is CPU-only, not I/O blocking - val encodedNostrRequest = URLEncoder.encode(nostrRequest.toJson(), "utf-8") + val encodedNostrRequest = UrlEncoder.encode(nostrRequest.toJson()) url += "&nostr=$encodedNostrRequest" } - val client = okHttpClient(url) - - val request: Request = - Request - .Builder() - .url(url) - .build() - - return client.newCall(request).executeAsync().use { response -> - withContext(Dispatchers.IO) { - if (response.isSuccessful) { - response.body.string() - } else { - throw LightningAddressError( - loadStringRes(Res.string.error_unable_to_fetch_invoice), - loadStringRes(Res.string.could_not_fetch_invoice_from_details, lnCallback, errorMessage(response, context)), - ) - } - } + val response = transport.get(url) + return if (response.isSuccessful) { + response.body + } else { + throw LightningAddressError( + loadStringRes(Res.string.error_unable_to_fetch_invoice), + loadStringRes(Res.string.could_not_fetch_invoice_from_details, lnCallback, errorMessage(response)), + ) } } - suspend fun errorMessage( - response: Response, - context: Context, - ): String { - val body = response.body.string() + suspend fun errorMessage(response: LnurlHttpResponse): String { + val body = response.body val errorMessage = - runCatching { - ObjectMapper().readTree(body) - }.getOrNull()?.let { tree -> - val errorNode = tree.get("error") - val messageNode = tree.get("message") - val statusNode = tree.get("status") + (parseJson(body) as? JsonObject)?.let { tree -> + val errorNode = tree["error"] + val messageNode = tree["message"] + val statusNode = tree["status"] - if (tree.get("error") != null && - tree.get("error").isBoolean && + if (errorNode != null && + errorNode.isBoolean() && messageNode != null && errorNode.asBoolean() ) { - return messageNode.asText() + messageNode.asText()?.let { return it } } val status = statusNode?.asText() @@ -194,18 +162,18 @@ class LightningAddressResolver { if (status == "error" && message != null) { message } else { - tree.get("error")?.get("message")?.asText() + (errorNode as? JsonObject)?.get("message")?.asText() } } if (errorMessage == null) { - Log.d("LightningAddressResolver") { "Error parsing LNResponse: $body" } + Log.d("LightningInvoiceResolver") { "Error parsing LNResponse: $body" } } return errorMessage - ?: HttpStatusMessages.resourceIdFor(response.code)?.let { loadStringRes(it) } - ?: response.message.ifBlank { null } - ?: response.code.toString() + ?: HttpStatusMessages.resourceIdFor(response.status)?.let { loadStringRes(it) } + ?: response.reason.ifBlank { null } + ?: response.status.toString() } /** @@ -220,27 +188,19 @@ class LightningAddressResolver { milliSats: Long, message: String, nostrRequest: ZapRequestEvent? = null, - okHttpClient: (String) -> OkHttpClient, onProgress: (percent: Float) -> Unit, - context: Context, onZapRequestSent: (ZapRequestEvent?) -> Unit = {}, ): String { - val mapper = ObjectMapper() - val lnurlpUrl = assembleUrl(lnAddress) val lnAddressJson = - fetchLightningAddressJson( - lnAddress, - okHttpClient, - context, - ) + fetchLightningAddressJson(lnAddress) onProgress(0.4f) val lnurlp = try { - mapper.readTree(lnAddressJson) + Json.parseToJsonElement(lnAddressJson) as? JsonObject } catch (t: Throwable) { if (t is CancellationException) throw t throw LightningAddressError( @@ -264,8 +224,8 @@ class LightningAddressResolver { ) } - val allowsNostr = lnurlp.get("allowsNostr")?.asBoolean() ?: false - val nostrPubkey = lnurlp.get("nostrPubkey")?.asText()?.ifBlank { null } + val allowsNostr = lnurlp["allowsNostr"]?.asBoolean() ?: false + val nostrPubkey = lnurlp["nostrPubkey"]?.asText()?.ifBlank { null } // Prime the receipt-validation cache so incoming zap receipts can be // checked against this provider's nostrPubkey (NIP-57 Appendix F) @@ -290,15 +250,13 @@ class LightningAddressResolver { milliSats = milliSats, message = message, nostrRequest = sentZapRequest, - okHttpClient = okHttpClient, - context = context, ) onProgress(0.6f) val lnInvoice = try { - mapper.readTree(invoice) + Json.parseToJsonElement(invoice) as? JsonObject } catch (t: Throwable) { if (t is CancellationException) throw t throw LightningAddressError( @@ -337,18 +295,17 @@ class LightningAddressResolver { } // Forces LN Invoice amount to be the requested amount. - val expectedAmountInSats = - BigDecimal(milliSats).divide(BigDecimal(1000), RoundingMode.HALF_UP).toLong() + val expectedAmountInSats = roundHalfUpToSats(milliSats) val invoiceAmount = LnInvoiceUtil.getAmountInSats(pr) - if (invoiceAmount.toLong() != expectedAmountInSats) { + if (invoiceAmount.toLongValue() != expectedAmountInSats) { onProgress(0.0f) throw LightningAddressError( loadStringRes(Res.string.error_unable_to_fetch_invoice), loadStringRes( Res.string.incorrect_invoice_amount_sats_from_it_should_have_been, - invoiceAmount.toLong().toString(), + invoiceAmount.toLongValue().toString(), lnAddress, expectedAmountInSats.toString(), ), @@ -360,3 +317,34 @@ class LightningAddressResolver { return pr } } + +/** Millisats to sats, rounding a half sat up, as `BigDecimal.divide(1000, HALF_UP)` did. */ +internal fun roundHalfUpToSats(milliSats: Long): Long = if (milliSats >= 0) (milliSats + 500) / 1000 else -((-milliSats + 500) / 1000) + +private fun parseJson(body: String): JsonElement? = + try { + Json.parseToJsonElement(body) + } catch (e: Exception) { + if (e is CancellationException) throw e + null + } + +// Jackson's JsonNode readers, which LNURL servers' loosely-typed replies were written against: +// asText() gives a scalar's text and "" for a container; asBoolean() reads true, a non-zero +// number or the text "true". JSON null reads as absent rather than as the text "null". + +private fun JsonElement.asText(): String? = + when (this) { + is JsonNull -> null + is JsonPrimitive -> content + else -> "" + } + +private fun JsonElement.isBoolean(): Boolean = this is JsonPrimitive && !isString && booleanOrNull != null + +private fun JsonElement.asBoolean(): Boolean = + when { + this !is JsonPrimitive || this is JsonNull -> false + isString -> content.trim() == "true" + else -> booleanOrNull ?: longOrNull?.let { it != 0L } ?: false + } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/nwc/NwcResponseMessages.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/nwc/NwcResponseMessages.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/nwc/NwcResponseMessages.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/nwc/NwcResponseMessages.kt index bca605aace..87b82b3fe6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/nwc/NwcResponseMessages.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/nwc/NwcResponseMessages.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.nwc +package com.vitorpamplona.amethyst.commons.service.nwc +import com.vitorpamplona.amethyst.commons.model.nip47WalletConnect.NwcSignerState import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.error_parsing_error_message import com.vitorpamplona.amethyst.commons.resources.wallet_connect_no_response_error import com.vitorpamplona.amethyst.commons.resources.wallet_connect_unreadable_response_error import com.vitorpamplona.amethyst.commons.ui.loadPluralStringRes import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.model.nip47WalletConnect.NwcSignerState import com.vitorpamplona.quartz.nip47WalletConnect.rpc.IErrorResponseLike import com.vitorpamplona.quartz.nip47WalletConnect.rpc.Response diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/pow/PowKindLabel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/pow/PowKindLabel.kt new file mode 100644 index 0000000000..fa065c6e70 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/service/pow/PowKindLabel.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.service.pow + +import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.boost +import com.vitorpamplona.amethyst.commons.resources.post +import com.vitorpamplona.amethyst.commons.resources.pow_kind_chat_message +import com.vitorpamplona.amethyst.commons.resources.pow_kind_report +import com.vitorpamplona.amethyst.commons.resources.private_message +import com.vitorpamplona.amethyst.commons.resources.reaction +import com.vitorpamplona.amethyst.commons.resources.voice_post +import com.vitorpamplona.amethyst.commons.resources.voice_reply +import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent +import com.vitorpamplona.quartz.nip18Reposts.RepostEvent +import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent +import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent +import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessageEvent +import com.vitorpamplona.quartz.nip56Reports.ReportEvent +import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent +import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceEvent +import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceReplyEvent +import org.jetbrains.compose.resources.StringResource + +/** + * The one user-facing label for "what is being mined": shared by the + * broadcast banner, the mining foreground notification, and failure toasts + * so a job is described the same way everywhere it appears. + */ +fun powKindLabelRes(kind: Int): StringResource = + when (kind) { + ReactionEvent.KIND -> Res.string.reaction + RepostEvent.KIND, GenericRepostEvent.KIND -> Res.string.boost + VoiceEvent.KIND -> Res.string.voice_post + VoiceReplyEvent.KIND -> Res.string.voice_reply + ReportEvent.KIND -> Res.string.pow_kind_report + GiftWrapEvent.KIND -> Res.string.private_message + ChannelMessageEvent.KIND, LiveActivitiesChatMessageEvent.KIND -> Res.string.pow_kind_chat_message + else -> Res.string.post + } diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/PainterRes.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/PainterRes.kt new file mode 100644 index 0000000000..f0790beeb5 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/PainterRes.kt @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui + +import androidx.collection.LruCache +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.painter.Painter +import org.jetbrains.compose.resources.DrawableResource +import org.jetbrains.compose.resources.painterResource + +// Caches the few bitmaps and vectors every feed row draws, so a scroll does not reload them. +private val iconCache = LruCache>(30) + +/** + * The Compose-resources twin of the Android app's `painterRes`: [painterResource] behind a cache + * keyed by resource and [sizeReference]. A cached painter can be the only copy on the screen, so + * callers drawing it at different sizes pass different references. + */ +@Composable +fun painterRes( + resource: DrawableResource, + sizeReference: Int, +): Painter { + val bySize = iconCache[resource] + bySize?.get(sizeReference)?.let { return it } + + val loaded = painterResource(resource) + + val sizes = bySize ?: LruCache(10).also { iconCache.put(resource, it) } + sizes.put(sizeReference, loaded) + + return loaded +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/bud10/OpenBlossomUriAsIntent.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/BlossomUriOpener.kt similarity index 58% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/bud10/OpenBlossomUriAsIntent.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/BlossomUriOpener.kt index 5319b2fc89..f35735139c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/bud10/OpenBlossomUriAsIntent.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/BlossomUriOpener.kt @@ -18,29 +18,38 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.service.uploads.blossom.bud10 +package com.vitorpamplona.amethyst.commons.ui.components -import android.content.Context -import android.content.Intent -import androidx.core.net.toUri +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalUriHandler import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.no_blossom_apps_found_description import com.vitorpamplona.amethyst.commons.resources.no_blossom_apps_found_title import org.jetbrains.compose.resources.StringResource import kotlin.coroutines.cancellation.CancellationException -fun openBlossomUriAsIntent( - context: Context, - blossomUri: String, - onError: (StringResource, StringResource) -> Unit, -) { - try { - val intent = Intent(Intent.ACTION_VIEW, blossomUri.toUri()) - intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK +/** Opens a `blossom:` URI in whichever installed app handles it. */ +fun interface BlossomUriOpener { + /** Opens [blossomUri], or reports through [onError] that no app can. */ + fun open( + blossomUri: String, + onError: (StringResource, StringResource) -> Unit, + ) +} - context.startActivity(intent) - } catch (e: Exception) { - if (e is CancellationException) throw e - onError(Res.string.no_blossom_apps_found_title, Res.string.no_blossom_apps_found_description) +/** A [BlossomUriOpener] over the platform's URI handler (a `VIEW` intent on Android). */ +@Composable +fun rememberBlossomUriOpener(): BlossomUriOpener { + val uriHandler = LocalUriHandler.current + return remember(uriHandler) { + BlossomUriOpener { blossomUri, onError -> + try { + uriHandler.openUri(blossomUri) + } catch (e: Exception) { + if (e is CancellationException) throw e + onError(Res.string.no_blossom_apps_found_title, Res.string.no_blossom_apps_found_description) + } + } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableRoute.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableRoute.kt index 91d448980f..784fae2dd7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableRoute.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.components +package com.vitorpamplona.amethyst.commons.ui.components import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -46,19 +46,19 @@ import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserDisplayNickname +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.concord_invite_naddr_label import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.richtext.ClickableInLineIconRenderer import com.vitorpamplona.amethyst.commons.ui.richtext.CreateClickableTextWithEmoji import com.vitorpamplona.amethyst.commons.ui.richtext.CustomEmojiChecker import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.util.njumpLink -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserDisplayNickname -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.concord.cord05Invites.bundle.ConcordInviteBundleEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableUrl.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableUrlOrBlossom.kt similarity index 87% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableUrl.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableUrlOrBlossom.kt index 230631cdf1..f8b6c8e499 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableUrl.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableUrlOrBlossom.kt @@ -18,15 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.components +package com.vitorpamplona.amethyst.commons.ui.components import androidx.compose.material3.LocalTextStyle import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextOverflow import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary -import com.vitorpamplona.amethyst.service.uploads.blossom.bud10.openBlossomUriAsIntent +import com.vitorpamplona.amethyst.commons.ui.components.rememberBlossomUriOpener import org.jetbrains.compose.resources.StringResource import com.vitorpamplona.amethyst.commons.ui.components.ClickableUrl as SharedClickableUrl @@ -37,20 +36,20 @@ import com.vitorpamplona.amethyst.commons.ui.components.ClickableUrl as SharedCl * stays here. Touch front end, so no underline. */ @Composable -fun ClickableUrl( +fun ClickableUrlOrBlossom( urlText: String, url: String, style: TextStyle = LocalTextStyle.current, onError: (StringResource, StringResource) -> Unit = { _, _ -> }, ) { if (url.startsWith("blossom:")) { - val context = LocalContext.current + val blossomOpener = rememberBlossomUriOpener() ClickableTextPrimary( text = urlText, style = style, maxLines = 1, overflow = TextOverflow.MiddleEllipsis, - onClick = { openBlossomUriAsIntent(context, url, onError) }, + onClick = { blossomOpener.open(url, onError) }, ) } else { SharedClickableUrl(url = url, displayText = urlText, style = style) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ConcordInviteCard.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ConcordInviteCard.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ConcordInviteCard.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ConcordInviteCard.kt index 714fc0af02..ee4aecd238 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ConcordInviteCard.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ConcordInviteCard.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.components +package com.vitorpamplona.amethyst.commons.ui.components import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement @@ -54,7 +54,7 @@ import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncIma import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.concord.cord05Invites.CommunityInvite import com.vitorpamplona.amethyst.commons.icons.symbols.Icon as SymbolIcon @@ -63,7 +63,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon as SymbolIcon * NIP-29's `RelayGroupCard`. Tapping the card opens the redeem/join flow * ([Route.ConcordInvite], which keeps the full URL so the fragment token * survives). It fetches + unlocks the kind-33301 bundle in the background (via - * [com.vitorpamplona.amethyst.model.Account.peekConcordInvite]) to fill in the + * [com.vitorpamplona.amethyst.commons.model.Account.peekConcordInvite]) to fill in the * community name; until then it shows a stable placeholder so layout never jumps. * * Degrades to [ClickableConcordInviteLink] (a plain link) if the URL doesn't parse. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ExpandableRichTextViewer.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ExpandableRichTextViewer.kt index b3884e3038..149b57b045 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ExpandableRichTextViewer.kt @@ -18,9 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.components +package com.vitorpamplona.amethyst.commons.ui.components -import android.util.LruCache +import androidx.collection.LruCache import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -43,13 +43,14 @@ import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.show_more import com.vitorpamplona.amethyst.commons.richtext.ExpandableTextCutOffCalculator +import com.vitorpamplona.amethyst.commons.ui.components.RichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.getGradient import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.commons.ui.theme.ButtonPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdTopPadding -import com.vitorpamplona.amethyst.ui.note.getGradient -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel object ShowFullTextCache { val cache = LruCache(10) diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/InlineQuoteRenderer.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/InlineQuoteRenderer.kt new file mode 100644 index 0000000000..1e00429e14 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/InlineQuoteRenderer.kt @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.ui.graphics.Color +import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.util.toShortDisplay +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel + +/** + * Strategy for rendering a note quoted inline in another note's text (a + * `nostr:nevent1...`/`nostr:note1...` mention with preview budget left, or a + * legacy `#[index]` event tag). + * + * Both rich-text paths (plain and markdown) funnel through [DisplayFullNote], + * which reads [LocalInlineQuoteRenderer], so providing a different renderer + * re-skins inline quotes for a whole subtree without threading a parameter + * through the parser stack. Chat bubbles use this to keep a quoted chat + * message in the chat reply design instead of the default quoted-note card + * (see `chatInlineQuoteRenderer`). + * + * A renderer draws only the quoted note itself; any leftover characters + * around the mention stay with the caller ([DisplayFullNote]). + */ +fun interface InlineQuoteRenderer { + @Composable + fun Render( + note: Note, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) +} + +/** + * A link to the quoted note, for front ends that install no card renderer of their own (Android + * installs its quoted-note card in its theme root). + */ +val PlainInlineQuoteRenderer = + InlineQuoteRenderer { note, _, _, accountViewModel, nav -> + ClickableTextPrimary( + text = "@${note.idNote().toShortDisplay()}", + onClick = { routeFor(note, accountViewModel.account)?.let { nav.nav(it) } }, + ) + } + +val LocalInlineQuoteRenderer = compositionLocalOf { PlainInlineQuoteRenderer } diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/MediaPlaceholders.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/MediaPlaceholders.kt new file mode 100644 index 0000000000..3452842e2c --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/MediaPlaceholders.kt @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.AnimatedVisibilityScope +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp +import coil3.compose.AsyncImage +import com.vitorpamplona.amethyst.commons.richtext.BaseMediaContent +import com.vitorpamplona.amethyst.commons.richtext.MediaUrlContent +import com.vitorpamplona.amethyst.commons.service.image.placeholderModel +import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation +import com.vitorpamplona.amethyst.commons.ui.components.rememberBlossomUriOpener +import com.vitorpamplona.amethyst.commons.ui.note.DownloadForOfflineIcon +import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp +import com.vitorpamplona.amethyst.commons.ui.theme.Size24dp +import kotlinx.coroutines.delay +import org.jetbrains.compose.resources.StringResource + +@Composable +fun ImageUrlWithDownloadButton( + url: String, + showImage: MutableState, +) { + val uri = LocalUriHandler.current + + val primary = MaterialTheme.colorScheme.primary + val background = MaterialTheme.colorScheme.onBackground + + val regularText = remember { SpanStyle(color = background) } + val clickableTextStyle = remember { SpanStyle(color = primary) } + + val annotatedTermsString = + remember { + buildAnnotatedString { + withStyle(clickableTextStyle) { + pushStringAnnotation("routeToImage", "") + append("$url ") + pop() + } + + withStyle(clickableTextStyle) { + pushStringAnnotation("routeToImage", "") + pop() + } + + withStyle(regularText) { append(" ") } + } + } + + val pressIndicator = + remember { + Modifier + .fillMaxWidth() + .clickable { runCatching { uri.openUri(url) } } + } + + Row( + modifier = + Modifier + .width(IntrinsicSize.Max), + horizontalArrangement = Arrangement.spacedBy(2.dp), + ) { + Text( + text = annotatedTermsString, + modifier = + pressIndicator + .weight(1f, fill = false), + overflow = TextOverflow.Ellipsis, + maxLines = 1, + ) + InlineDownloadIcon(showImage) + } +} + +@Composable +private fun InlineDownloadIcon(showImage: MutableState) = + IconButton( + modifier = Modifier.size(Size20dp), + onClick = { showImage.value = true }, + ) { + DownloadForOfflineIcon(Size24dp) + } + +@Composable +fun WaitAndDisplay(content: @Composable (AnimatedVisibilityScope.() -> Unit)) { + val visible = remember { mutableStateOf(false) } + + LaunchedEffect(Unit) { + delay(200) + visible.value = true + } + + AnimatedVisibility( + visible = visible.value, + enter = fadeIn(), + exit = fadeOut(), + content = content, + ) +} + +@Composable +fun DisplayUrlWithLoadingSymbol( + content: BaseMediaContent, + onError: (StringResource, StringResource) -> Unit = { _, _ -> }, +) { + val uri = LocalUriHandler.current + + val primary = MaterialTheme.colorScheme.primary + val background = MaterialTheme.colorScheme.onBackground + + val regularText = remember { SpanStyle(color = background) } + val clickableTextStyle = remember { SpanStyle(color = primary) } + + val blossomOpener = rememberBlossomUriOpener() + + val annotatedTermsString = + remember { + buildAnnotatedString { + if (content is MediaUrlContent) { + withStyle(clickableTextStyle) { + pushStringAnnotation("routeToImage", "") + append(content.url + " ") + pop() + } + } else { + withStyle(regularText) { append("Loading content...") } + } + + withStyle(clickableTextStyle) { + pushStringAnnotation("routeToImage", "") + pop() + } + + withStyle(regularText) { append(" ") } + } + } + + val pressIndicator = + remember { + if (content is MediaUrlContent) { + Modifier.clickable { + if (content.url.startsWith("blossom:")) { + blossomOpener.open(content.url, onError) + } else { + runCatching { uri.openUri(content.url) } + } + } + } else { + Modifier + } + } + + Row( + modifier = + Modifier + .width(IntrinsicSize.Max), + horizontalArrangement = Arrangement.spacedBy(2.dp), + ) { + Text( + text = annotatedTermsString, + modifier = pressIndicator.weight(1f, fill = false), + overflow = TextOverflow.MiddleEllipsis, + maxLines = 1, + ) + InlineLoadingIcon() + } +} + +@Composable +fun DisplayUrlWithLoadingSymbol( + url: String, + onError: (StringResource, StringResource) -> Unit = { _, _ -> }, +) { + val uri = LocalUriHandler.current + + val primary = MaterialTheme.colorScheme.primary + val annotatedTermsString = + remember { + buildAnnotatedString { + withStyle(SpanStyle(color = primary)) { + pushStringAnnotation("routeToImage", "") + append("$url ") + pop() + } + } + } + + val blossomOpener = rememberBlossomUriOpener() + + val pressIndicator = + remember { + Modifier.clickable { + if (url.startsWith("blossom:")) { + blossomOpener.open(url, onError) + } else { + runCatching { + uri.openUri(url) + } + } + } + } + + Row( + modifier = Modifier.width(IntrinsicSize.Max), + horizontalArrangement = Arrangement.spacedBy(2.dp), + ) { + Text( + text = annotatedTermsString, + modifier = pressIndicator.weight(1f, fill = false), + overflow = TextOverflow.Ellipsis, + maxLines = 1, + ) + InlineLoadingIcon() + } +} + +@Composable +private fun InlineLoadingIcon() = LoadingAnimation() + +@Composable +fun DisplayBlurHash( + blurhash: String?, + description: String?, + contentScale: ContentScale, + modifier: Modifier, + thumbhash: String? = null, +) { + val model = + placeholderModel(thumbhash, blurhash) ?: return + + AsyncImage( + model = model, + contentDescription = description, + contentScale = contentScale, + modifier = modifier, + ) +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/MyAsyncImage.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/MyAsyncImage.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/MyAsyncImage.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/MyAsyncImage.kt index a549723619..b6e25c689e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/MyAsyncImage.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/MyAsyncImage.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.components +package com.vitorpamplona.amethyst.commons.ui.components import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.aspectRatio @@ -37,15 +37,16 @@ import androidx.compose.ui.layout.ContentScale import coil3.compose.AsyncImagePainter import coil3.compose.SubcomposeAsyncImage import coil3.compose.SubcomposeAsyncImageContent +import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.commons.richtext.isAnimatedMediaUrl import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation import com.vitorpamplona.amethyst.commons.ui.note.DownloadForOfflineIcon +import com.vitorpamplona.amethyst.commons.ui.note.platform.GifVideoView import com.vitorpamplona.amethyst.commons.ui.theme.Size40dp import com.vitorpamplona.amethyst.commons.ui.theme.Size6dp import com.vitorpamplona.amethyst.commons.ui.theme.Size75dp -import com.vitorpamplona.amethyst.model.MediaAspectRatioCache -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun MyAsyncImage( @@ -115,7 +116,7 @@ fun MyAsyncImage( } } } else { - ClickableUrl(urlText = imageUrl, url = imageUrl) + ClickableUrlOrBlossom(urlText = imageUrl, url = imageUrl) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/NonlazyGridPreview.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/NonlazyGridPreview.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/NonlazyGridPreview.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/NonlazyGridPreview.kt index c9917b3936..0a50505cb6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/NonlazyGridPreview.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/NonlazyGridPreview.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.components +package com.vitorpamplona.amethyst.commons.ui.components import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement.spacedBy @@ -33,10 +33,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview -import com.google.common.math.IntMath.sqrt import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp -import java.math.RoundingMode import kotlin.math.ceil +import kotlin.math.sqrt @Composable fun GridPreviewTemplate(count: Int) { @@ -93,7 +92,7 @@ fun AutoNonlazyGrid( content: @Composable (Int) -> Unit, ) { if (itemCount > 0) { - NonlazyGrid(sqrt(itemCount, RoundingMode.UP), itemCount, modifier, content) + NonlazyGrid(ceil(sqrt(itemCount.toDouble())).toInt(), itemCount, modifier, content) } } diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RememberViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RememberViewModel.kt new file mode 100644 index 0000000000..5902d14fb1 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RememberViewModel.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.runtime.Composable +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import kotlin.reflect.KClass + +/** + * The [ViewModel] of [modelClass] scoped to the nearest ViewModel store owner (the screen or + * dialog), built by [factory] the first time. Android and Desktop use lifecycle's `viewModel()`; + * iOS, where that artifact is not published, keeps it for as long as the composition does. + */ +@Composable +expect fun rememberViewModel( + modelClass: KClass, + key: String?, + factory: () -> VM, +): VM + +/** [rememberViewModel] built through an existing [ViewModelProvider.Factory]. */ +@Composable +expect fun rememberViewModel( + modelClass: KClass, + key: String?, + factory: ViewModelProvider.Factory, +): VM + +@Composable +inline fun rememberViewModel( + key: String? = null, + factory: ViewModelProvider.Factory, +): VM = rememberViewModel(VM::class, key, factory) + +@Composable +inline fun rememberViewModel( + key: String? = null, + noinline factory: () -> VM, +): VM = rememberViewModel(VM::class, key, factory) diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RichTextViewer.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RichTextViewer.kt new file mode 100644 index 0000000000..c95a05d178 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RichTextViewer.kt @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.text.InlineTextContent +import androidx.compose.foundation.text.appendInlineContent +import androidx.compose.material3.Icon +import androidx.compose.material3.LocalTextStyle +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalFontFamilyResolver +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.TextMeasurer +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.em +import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists +import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserDisplayNickname +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo +import com.vitorpamplona.amethyst.commons.richtext.CachedRichTextParser +import com.vitorpamplona.amethyst.commons.richtext.HashIndexEventSegment +import com.vitorpamplona.amethyst.commons.richtext.HashIndexUserSegment +import com.vitorpamplona.amethyst.commons.richtext.HashTagSegment +import com.vitorpamplona.amethyst.commons.richtext.ParagraphState +import com.vitorpamplona.amethyst.commons.richtext.RichTextViewerState +import com.vitorpamplona.amethyst.commons.richtext.Segment +import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary +import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.components.LocalInlineQuoteRenderer +import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.richtext.CreateClickableTextWithEmoji +import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji +import com.vitorpamplona.amethyst.commons.ui.richtext.HashtagIcon +import com.vitorpamplona.amethyst.commons.ui.richtext.LocalRichTextInteractions +import com.vitorpamplona.amethyst.commons.ui.richtext.LocalRichTextPlatform +import com.vitorpamplona.amethyst.commons.ui.richtext.LocalRichTextSegmentRenderer +import com.vitorpamplona.amethyst.commons.ui.richtext.RichTextInteractions +import com.vitorpamplona.amethyst.commons.ui.richtext.RichTextSegmentRenderer +import com.vitorpamplona.amethyst.commons.ui.richtext.checkForHashtagWithIcon +import com.vitorpamplona.amethyst.commons.ui.state.produceCachedState +import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn +import com.vitorpamplona.amethyst.commons.ui.theme.inlinePlaceholder +import com.vitorpamplona.amethyst.commons.util.toShortDisplay +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent +import com.vitorpamplona.amethyst.commons.ui.richtext.RichTextViewer as CommonsRichTextViewer + +/** + * Renders Nostr rich text. Markdown goes to the front end's renderer; plain rich text is parsed + * once ([CachedRichTextParser]) and laid out by the shared [CommonsRichTextViewer] core, which + * renders text, emoji, hashtags and mentions itself and hands every platform segment (media, + * LaTeX, payments, link previews) to the [RichTextSegmentRenderer] the front end's + * [LocalRichTextPlatform] builds for this call. + */ +@Composable +fun RichTextViewer( + content: String, + canPreview: Boolean, + quotesLeft: Int, + modifier: Modifier, + tags: ImmutableListOfLists, + backgroundColor: MutableState, + callbackUri: String? = null, + authorPubKey: String? = null, + accountViewModel: AccountViewModel, + nav: INav, +) { + val platform = LocalRichTextPlatform.current + + Column(modifier = modifier) { + if (remember(content) { CachedRichTextParser.isMarkdown(content) }) { + platform.Markdown(content, tags, canPreview, quotesLeft, backgroundColor, callbackUri, accountViewModel, nav) + return@Column + } + + val state by remember(content, tags) { + mutableStateOf(CachedRichTextParser.parseText(content, tags, callbackUri, authorPubKey)) + } + + val renderer = + remember(platform, accountViewModel, nav, backgroundColor, callbackUri, canPreview) { + platform.segmentRenderer(accountViewModel, nav, backgroundColor, callbackUri, canPreview) + } + + val interactions = + remember(nav) { + RichTextInteractions( + onClickHashtag = { nav.nav(Route.Hashtag(it.lowercase())) }, + ) + } + + CompositionLocalProvider( + LocalRichTextSegmentRenderer provides renderer, + LocalRichTextInteractions provides interactions, + ) { + CommonsRichTextViewer( + state = state, + canPreview = canPreview, + quotesLeft = quotesLeft, + ) + } + } +} + +@Composable +fun RenderTextParagraph( + paragraph: ParagraphState, + spaceWidth: Dp, + modifier: Modifier, + renderWord: @Composable (word: Segment) -> Unit, +) { + FlowRow( + modifier = modifier, + horizontalArrangement = Arrangement.spacedBy(spaceWidth), + // Center items on the cross axis so a taller item (an equation, whose image + // is taller than a text line) sits centered on the line instead of hanging + // below the baseline. No-op for the common all-text row. + itemVerticalAlignment = Alignment.CenterVertically, + ) { + paragraph.words.forEach { word -> + renderWord(word) + } + } +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +fun RenderRegular( + content: String, + tags: ImmutableListOfLists, + callbackUri: String? = null, + authorPubKey: String? = null, + renderParagraph: @Composable (ParagraphState, state: RichTextViewerState, Dp, modifier: Modifier) -> Unit, +) { + val state by remember(content, tags) { mutableStateOf(CachedRichTextParser.parseText(content, tags, callbackUri, authorPubKey)) } + + val spaceWidth = measureSpaceWidth(LocalTextStyle.current) + + val currentTextStyle = LocalTextStyle.current + + val textStyle = + remember(currentTextStyle) { + currentTextStyle.copy( + lineHeight = 1.3.em, + ) + } + + Column { + // FlowRow doesn't work well with paragraphs. So we need to split them + state.paragraphs.forEach { paragraph -> + CompositionLocalProvider( + LocalLayoutDirection provides + if (paragraph.isRTL) { + LayoutDirection.Rtl + } else { + LayoutDirection.Ltr + }, + LocalTextStyle provides textStyle, + ) { + renderParagraph( + paragraph, + state, + spaceWidth, + Modifier.align(if (paragraph.isRTL) Alignment.End else Alignment.Start), + ) + } + } + } +} + +@Composable +fun measureSpaceWidth(textStyle: TextStyle): Dp { + val fontFamilyResolver = LocalFontFamilyResolver.current + val density = LocalDensity.current + val layoutDirection = LocalLayoutDirection.current + + return remember(fontFamilyResolver, density, layoutDirection, textStyle) { + val widthPx = + TextMeasurer(fontFamilyResolver, density, layoutDirection, 1) + .measure(" ", textStyle) + .size + .width + with(density) { widthPx.toDp() } + } +} + +@Composable +fun RenderCustomEmoji( + word: String, + state: RichTextViewerState, +) { + CreateTextWithEmoji( + text = word, + emojis = state.customEmoji, + ) +} + +@Composable +fun BechLink( + word: String, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) { + val loadedLink by produceCachedState(cache = accountViewModel.bechLinkCache, key = word) + + val baseNote = loadedLink?.baseNote + + // Preload the placeholder's author NIP-65 outbox so a missing quoted event can be fetched from there. + baseNote?.author?.let { author -> + UserFinderFilterAssemblerSubscription(author, accountViewModel) + } + + if (canPreview && quotesLeft > 0 && baseNote != null) { + Row { + DisplayFullNote( + note = baseNote, + extraChars = loadedLink?.nip19?.additionalChars?.ifBlank { null }, + quotesLeft = quotesLeft, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, + ) + } + } else if (loadedLink?.nip19 != null) { + ClickableRoute(word, loadedLink?.nip19!!, accountViewModel, nav) + } else { + val text = + remember(word) { + if (word.length > 16) { + word.replaceRange(8, word.length - 8, ":") + } else { + word + } + } + + Text(text = text, maxLines = 1) + } +} + +@Composable +fun DisplayFullNote( + note: Note, + extraChars: String?, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) { + LocalInlineQuoteRenderer.current.Render(note, quotesLeft, backgroundColor, accountViewModel, nav) + + extraChars?.let { Text(it) } +} + +@Composable +fun HashTag( + segment: HashTagSegment, + nav: INav, +) { + val primary = MaterialTheme.colorScheme.primary + val background = MaterialTheme.colorScheme.onBackground + val hashtagIcon: HashtagIcon? = checkForHashtagWithIcon(segment.hashtag) + + val annotatedTermsString = + remember(segment.segmentText) { + buildAnnotatedString { + withStyle(SpanStyle(color = primary)) { + pushStringAnnotation("routeToHashtag", "") + append("#${segment.hashtag}") + pop() + } + + if (hashtagIcon != null) { + withStyle(SpanStyle(color = primary)) { + pushStringAnnotation("routeToHashtag", "") + appendInlineContent("inlineContent", "[icon]") + pop() + } + } + + segment.extras?.let { withStyle(SpanStyle(color = background)) { append(it) } } + } + } + + Text( + text = annotatedTermsString, + modifier = + remember { + Modifier.clickable { + nav.nav(Route.Hashtag(segment.hashtag.lowercase())) + } + }, + inlineContent = + if (hashtagIcon != null) { + mapOf("inlineContent" to inlineIcon(hashtagIcon)) + } else { + emptyMap() + }, + ) +} + +@Composable +private fun inlineIcon(hashtagIcon: HashtagIcon) = + InlineTextContent(inlinePlaceholder) { + Icon( + imageVector = hashtagIcon.icon, + contentDescription = hashtagIcon.description, + tint = Color.Unspecified, + modifier = hashtagIcon.modifier, + ) + } + +@Composable +fun TagLink( + word: HashIndexUserSegment, + accountViewModel: AccountViewModel, + nav: INav, +) { + LoadUser(baseUserHex = word.hex) { + if (it == null) { + Text(text = word.segmentText) + } else { + Row { + DisplayUserFromTag(it, accountViewModel, nav) + word.extras?.let { it2 -> + Text(text = it2) + } + } + } + } +} + +@Composable +fun LoadNote( + baseNoteHex: String, + content: @Composable (Note?) -> Unit, +) { + var note by + remember(baseNoteHex) { mutableStateOf(LocalCache.getNoteIfExists(baseNoteHex)) } + + if (note == null) { + LaunchedEffect(key1 = baseNoteHex) { + note = LocalCache.checkGetOrCreateNote(baseNoteHex) + } + } + + content(note) +} + +@Composable +fun TagLink( + word: HashIndexEventSegment, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) { + LoadNote(baseNoteHex = word.hex) { + if (it == null) { + Text(text = remember { word.segmentText.toShortDisplay() }) + } else { + Row { + DisplayNoteFromTag( + it, + word.extras, + canPreview, + quotesLeft, + accountViewModel, + backgroundColor, + nav, + ) + } + } + } +} + +@Preview +@Composable +fun DisplayNoteFromTagPreview() { + val dummyPost = + TextNoteEvent( + id = "0b6d941c46411a95edb1c93da7ad6ca26370497d8c7b7d621f5cb59f48841bad", + pubKey = "6dd3b72e325da7383b275eef1c66131ba4664326e162bc060527509b4e33ae43", + createdAt = 1753988264, + tags = emptyArray(), + content = "test", + sig = "ec39e60722a083cccbd2d82d2827e13f5499fa7cbcedac5b76011a844c077473adb629d50d01fab147835ac6c8a3d5ba9aaddd87d6723f0c3c864b9119fc4356", + ) + + LocalCache.justConsume(dummyPost, null, true) + val note = LocalCache.getOrCreateNote(dummyPost.id) + + ThemeComparisonColumn( + toPreview = { + ClickableTextPrimary( + text = "@${note.idNote().toShortDisplay()}", + onClick = { }, + ) + }, + ) +} + +@Composable +private fun DisplayNoteFromTag( + baseNote: Note, + addedChars: String?, + canPreview: Boolean, + quotesLeft: Int, + accountViewModel: AccountViewModel, + backgroundColor: MutableState, + nav: INav, +) { + if (canPreview && quotesLeft > 0) { + LocalInlineQuoteRenderer.current.Render(baseNote, quotesLeft, backgroundColor, accountViewModel, nav) + } else { + ClickableTextPrimary( + text = "@${baseNote.idNote().toShortDisplay()}", + onClick = { routeFor(baseNote, accountViewModel.account)?.let { nav.nav(it) } }, + ) + } + + addedChars?.ifBlank { null }?.let { Text(text = it) } +} + +@Composable +private fun DisplayUserFromTag( + baseUser: User, + accountViewModel: AccountViewModel, + nav: INav, +) { + val meta by observeUserInfo(baseUser, accountViewModel) + val nickname by observeUserDisplayNickname(baseUser, accountViewModel) + val petName = nickname?.petName + + CrossfadeIfEnabled(targetState = meta, label = "DisplayUserFromTag") { + Row { + CreateClickableTextWithEmoji( + clickablePart = remember(meta, petName) { petName ?: it?.info?.bestName() ?: baseUser.pubkeyDisplayHex() }, + maxLines = 1, + route = remember(baseUser) { routeFor(baseUser) }, + nav = nav, + tags = if (petName != null) nickname?.tags else it?.tags, + ) + } + } +} diff --git a/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RobohashAsyncImage.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RobohashAsyncImage.kt similarity index 98% rename from commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RobohashAsyncImage.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RobohashAsyncImage.kt index ff55834b65..11b112799d 100644 --- a/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RobohashAsyncImage.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RobohashAsyncImage.kt @@ -47,7 +47,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.icons.symbols.rememberMaterialSymbolPainter import com.vitorpamplona.amethyst.commons.richtext.isAnimatedMediaUrl import com.vitorpamplona.amethyst.commons.robohash.CachedRobohash -import com.vitorpamplona.amethyst.commons.service.http.LocalBlossomCacheRedirectInterceptor +import com.vitorpamplona.amethyst.commons.service.http.LocalBlossomCacheHeaders import com.vitorpamplona.amethyst.commons.ui.theme.isLight import com.vitorpamplona.amethyst.commons.ui.theme.onBackgroundColorFilter import coil3.Image as CoilImage @@ -221,7 +221,7 @@ fun GifProfilePicture( .httpHeaders( NetworkHeaders .Builder() - .set(LocalBlossomCacheRedirectInterceptor.MEDIA_HEADER, LocalBlossomCacheRedirectInterceptor.PROFILE_PICTURE) + .set(LocalBlossomCacheHeaders.MEDIA_HEADER, LocalBlossomCacheHeaders.PROFILE_PICTURE) .build(), ).build() } else { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/SensitivityWarning.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/SensitivityWarning.kt index fabeb56dd5..7cfb3e1bd1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/SensitivityWarning.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.components +package com.vitorpamplona.amethyst.commons.ui.components import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -49,14 +49,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import coil3.imageLoader +import coil3.SingletonImageLoader +import coil3.compose.LocalPlatformContext import coil3.request.ImageRequest import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -73,7 +73,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.commons.ui.theme.ButtonPadding import com.vitorpamplona.amethyst.commons.ui.theme.PaddingHorizontal12Modifier import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip36SensitiveContent.ContentWarningTag import com.vitorpamplona.quartz.nip36SensitiveContent.contentWarningReason @@ -144,11 +144,11 @@ fun ContentWarningGate( var showContentWarningNote by remember(accountState) { mutableStateOf(accountState.value != true) } if (showContentWarningNote && preloadUrls.isNotEmpty()) { - val context = LocalContext.current + val context = LocalPlatformContext.current LaunchedEffect(preloadUrls) { preloadUrls.forEach { url -> runCatching { - context.imageLoader.enqueue(ImageRequest.Builder(context).data(url).build()) + SingletonImageLoader.get(context).enqueue(ImageRequest.Builder(context).data(url).build()) } } } diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ShortNotice.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ShortNotice.kt new file mode 100644 index 0000000000..afcf42777d --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ShortNotice.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.runtime.Composable + +/** A brief, non-blocking confirmation ("Copied to clipboard"). */ +fun interface ShortNotice { + fun show(message: String) +} + +/** + * The platform's brief confirmation: an Android toast. Desktop and iOS have no system toast + * wired yet and only log the message. + */ +@Composable +expect fun rememberShortNotice(): ShortNotice diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TextSharer.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TextSharer.kt new file mode 100644 index 0000000000..cb555403ba --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TextSharer.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.runtime.Composable + +/** Hands a piece of text to the platform's share sheet. */ +fun interface TextSharer { + /** + * Shares [text], labelled [title] where the target shows one, behind a chooser titled + * [chooserTitle] where the platform has a chooser. + */ + fun share( + text: String, + title: String?, + chooserTitle: String, + ) +} + +/** + * The platform's share sheet: Android's `ACTION_SEND` chooser. Desktop and iOS have no system + * share sheet wired yet and put the text on the clipboard instead. + */ +@Composable +expect fun rememberTextSharer(): TextSharer diff --git a/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TranslatableRichTextViewer.kt similarity index 62% rename from amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TranslatableRichTextViewer.kt index bcd01f5071..43f1f8e9ca 100644 --- a/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TranslatableRichTextViewer.kt @@ -18,18 +18,17 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.components +package com.vitorpamplona.amethyst.commons.ui.components import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists +import com.vitorpamplona.amethyst.commons.ui.components.LocalTranslationPlatform import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.MaxWidthPaddingTop5dp -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun TranslatableRichTextViewer( @@ -44,19 +43,27 @@ fun TranslatableRichTextViewer( authorPubKey: String? = null, accountViewModel: AccountViewModel, nav: INav, -) = ExpandableRichTextViewer( - content, - canPreview, - quotesLeft, - modifier, - tags, - backgroundColor, - id, - callbackUri, - authorPubKey, - accountViewModel, - nav, -) +) { + TranslatableRichTextViewer( + content = content, + id = id, + accountViewModel = accountViewModel, + ) { + ExpandableRichTextViewer( + it, + canPreview, + quotesLeft, + modifier, + tags, + backgroundColor, + id, + callbackUri, + authorPubKey, + accountViewModel, + nav, + ) + } +} @Composable fun TranslatableRichTextViewer( @@ -65,11 +72,17 @@ fun TranslatableRichTextViewer( translationMessageModifier: Modifier = MaxWidthPaddingTop5dp, accountViewModel: AccountViewModel, displayText: @Composable (String) -> Unit, -) = displayText(content) +) = LocalTranslationPlatform.current.Translatable(content, id, translationMessageModifier, accountViewModel, displayText) -/** No translation service in this flavor, so the content is always its own "translation". */ +/** + * The translation of [content] under the current language settings, or [content] unchanged when + * no translation applies. Same machinery and cache as [TranslatableRichTextViewer] but without + * the status bar, for callers that already render one and need a second string translated in + * step with it — e.g. a NIP-84 highlight, which must translate the quoted passage alongside the + * context in order to keep locating the passage inside it. + */ @Composable fun rememberTranslation( content: String, accountViewModel: AccountViewModel, -): String = content +): String = LocalTranslationPlatform.current.rememberTranslation(content, accountViewModel) diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TranslationPlatform.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TranslationPlatform.kt new file mode 100644 index 0000000000..6b8ebfb71b --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TranslationPlatform.kt @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.Modifier +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel + +/** + * The on-device translator behind every translatable text, supplied by the platform through + * [LocalTranslationPlatform]. Android's Play build installs its ML Kit translator; builds and + * platforms without one fall back to [None], which shows the text as written. + */ +@Stable +interface TranslationPlatform { + /** + * Renders [content] through [displayText], translated when the account's language settings + * ask for it, with the platform's "translated from" bar under it. + */ + @Composable + fun Translatable( + content: String, + id: String, + translationMessageModifier: Modifier, + accountViewModel: AccountViewModel, + displayText: @Composable (String) -> Unit, + ) + + /** The translation of [content] under the current settings, or [content] when none applies. */ + @Composable + fun rememberTranslation( + content: String, + accountViewModel: AccountViewModel, + ): String + + /** + * The already-computed translation of [content] under the current settings, or null when + * none occurred or none is cached. Cache-only: it backs "Copy Translated", which applies + * to text on screen, and rendering that text through [Translatable] filled the cache. + */ + fun cachedTranslation( + content: String, + accountViewModel: AccountViewModel, + ): String? = null + + /** No translator: the content is always its own translation. */ + object None : TranslationPlatform { + @Composable + override fun Translatable( + content: String, + id: String, + translationMessageModifier: Modifier, + accountViewModel: AccountViewModel, + displayText: @Composable (String) -> Unit, + ) = displayText(content) + + @Composable + override fun rememberTranslation( + content: String, + accountViewModel: AccountViewModel, + ): String = content + } +} + +val LocalTranslationPlatform = staticCompositionLocalOf { TranslationPlatform.None } diff --git a/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/ui/components/UrlPreviewCard.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/UrlPreviewCard.kt similarity index 99% rename from commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/ui/components/UrlPreviewCard.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/UrlPreviewCard.kt index 95ff1c5d00..a084cb0edf 100644 --- a/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/ui/components/UrlPreviewCard.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/UrlPreviewCard.kt @@ -133,7 +133,7 @@ fun UrlPreviewCard( verticalAlignment = Alignment.CenterVertically, ) { Text( - text = previewInfo.verifiedUrl?.host ?: previewInfo.url, + text = previewInfo.verifiedHost ?: previewInfo.url, style = MaterialTheme.typography.bodySmall, modifier = Modifier.weight(1f, fill = false), color = Color.Gray, diff --git a/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/ui/components/UrlPreviewState.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/UrlPreviewState.kt similarity index 100% rename from commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/ui/components/UrlPreviewState.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/UrlPreviewState.kt diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/VideoOnlineCheck.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/VideoOnlineCheck.kt new file mode 100644 index 0000000000..773aaa1afb --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/VideoOnlineCheck.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.produceState +import com.vitorpamplona.amethyst.commons.service.OnlineStatusCache +import com.vitorpamplona.amethyst.commons.service.isVideoOnline +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel + +@Composable +fun CheckIfVideoIsOnline( + url: String, + accountViewModel: AccountViewModel, + whenOnline: @Composable (Boolean) -> Unit, +) { + val online by produceState( + initialValue = OnlineStatusCache.isOnlineCached(url), + key1 = url, + ) { + val isOnline = accountViewModel.httpClientBuilder.isVideoOnline(url) + if (value != isOnline) { + value = isOnline + } + } + + whenOnline(online) +} + +@Composable +fun CrossfadeCheckIfVideoIsOnline( + url: String, + accountViewModel: AccountViewModel, + whenOnline: @Composable () -> Unit, +) { + val online by produceState( + initialValue = OnlineStatusCache.isOnlineCached(url), + key1 = url, + ) { + val isOnline = accountViewModel.httpClientBuilder.isVideoOnline(url) + if (value != isOnline) { + value = isOnline + } + } + + CrossfadeIfEnabled( + targetState = online, + label = "CheckIfUrlIsOnline", + ) { + if (it) { + whenOnline() + } + } +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedContentStateView.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/FeedContentStateView.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedContentStateView.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/FeedContentStateView.kt index 85dc9c6610..1c15d4a865 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedContentStateView.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/FeedContentStateView.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.feeds +package com.vitorpamplona.amethyst.commons.ui.feeds import androidx.compose.animation.core.tween import androidx.compose.foundation.lazy.LazyListState @@ -40,7 +40,7 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverLazyGridState import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverLazyListState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun RefresheableFeedContentStateView( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedLoaded.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/FeedLoaded.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedLoaded.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/FeedLoaded.kt index 54577fcee5..09bbcade92 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedLoaded.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/FeedLoaded.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.feeds +package com.vitorpamplona.amethyst.commons.ui.feeds import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Row @@ -34,10 +34,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @OptIn(ExperimentalFoundationApi::class) @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/PrefetchFeedMedia.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/PrefetchFeedMedia.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/PrefetchFeedMedia.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/PrefetchFeedMedia.kt index c13a8124a8..d32ca1ee26 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/PrefetchFeedMedia.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/PrefetchFeedMedia.kt @@ -18,9 +18,8 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.feeds +package com.vitorpamplona.amethyst.commons.ui.feeds -import android.content.Context import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.runtime.Composable @@ -29,12 +28,14 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.snapshotFlow -import androidx.compose.ui.platform.LocalContext import androidx.lifecycle.compose.collectAsStateWithLifecycle -import coil3.imageLoader +import coil3.PlatformContext +import coil3.SingletonImageLoader +import coil3.compose.LocalPlatformContext import coil3.request.ImageRequest import coil3.request.SuccessResult import com.vitorpamplona.amethyst.commons.feeds.FeedState +import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists import com.vitorpamplona.amethyst.commons.richtext.CachedRichTextParser @@ -43,9 +44,10 @@ 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.model.MediaAspectRatioCache -import com.vitorpamplona.amethyst.model.UrlCachedPreviewer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.note.platform.LocalNotePlatform +import com.vitorpamplona.amethyst.commons.ui.note.platform.NotePlatform +import com.vitorpamplona.amethyst.commons.util.ConcurrentSet +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip14Subject.subject @@ -63,7 +65,6 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.withContext -import java.util.concurrent.ConcurrentHashMap /** How many notes on each side of the viewport to warm. */ private const val PREFETCH_RADIUS = 3 @@ -130,16 +131,17 @@ private fun PrefetchVisibleMedia( accountViewModel: AccountViewModel, radius: Int, ) { - val context = LocalContext.current + val context = LocalPlatformContext.current + val platform = LocalNotePlatform.current val currentNotes by rememberUpdatedState(notes) - val warmed = remember(stateKey) { ConcurrentHashMap.newKeySet() } + val warmed = remember(stateKey) { ConcurrentSet() } LaunchedEffect(stateKey, accountViewModel) { visibleEnds.collectLatest { ends -> withContext(Dispatchers.Default) { currentNotes.notesAround(ends, radius).forEach { note -> if (note.idHex !in warmed) { - note.warm(context, accountViewModel) + note.warm(context, platform, accountViewModel) warmed.add(note.idHex) } } @@ -220,19 +222,18 @@ private fun List.notesAfter( /** Prefetches this note's media into Coil and warms its link previews, honoring the data-saver gates. */ private fun Note.warm( - context: Context, + context: PlatformContext, + platform: NotePlatform, accountViewModel: AccountViewModel, ) { val targets = collectWarmTargets() ?: return if (accountViewModel.settings.showImages()) { - targets.forEachImage(context::prefetchImage) + targets.forEachImage { url, videoUrlForDims -> context.prefetchImage(url, videoUrlForDims) } } if (accountViewModel.settings.showUrlPreview()) { targets.links.forEach { url -> - if (UrlCachedPreviewer.cache.get(url) == null) { - accountViewModel.urlPreview(url) {} - } + platform.warmUrlPreview(url, accountViewModel) } } } @@ -245,7 +246,7 @@ private class WarmTargets { val links = LinkedHashSet() fun image(url: String) { - images.putIfAbsent(url, null) + if (url !in images) images[url] = null } /** A video poster: warmed as an image, and its decoded ratio also seeds [videoUrl]'s box (if non-null). */ @@ -392,12 +393,12 @@ private fun Note.warmRenderCache(ev: Event): RichTextViewerState? { } /** Enqueues an image prefetch that also records its decoded aspect ratio. */ -private fun Context.prefetchImage( +private fun PlatformContext.prefetchImage( url: String, videoUrlForDims: String?, ) { runCatching { - imageLoader.enqueue( + SingletonImageLoader.get(this).enqueue( ImageRequest .Builder(this) .data(url) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/DisappearingScaffold.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/layouts/AccountDisappearingScaffold.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/DisappearingScaffold.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/layouts/AccountDisappearingScaffold.kt index 83f0fb31cb..ee1e5179b8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/DisappearingScaffold.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/layouts/AccountDisappearingScaffold.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.layouts +package com.vitorpamplona.amethyst.commons.ui.layouts import androidx.compose.foundation.layout.PaddingValues import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.ui.layouts.LocalScreenLayout -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold as SharedDisappearingScaffold /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/RouteMaker.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/navigation/routes/RouteMaker.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/RouteMaker.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/navigation/routes/RouteMaker.kt index 9cfc9b9ab6..c7b1038649 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/RouteMaker.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/navigation/routes/RouteMaker.kt @@ -18,8 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.navigation.routes +package com.vitorpamplona.amethyst.commons.ui.navigation.routes +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -31,8 +32,7 @@ import com.vitorpamplona.amethyst.commons.model.navigation.minichatRouteFor import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.buzz.notifications.MemberAddedNotificationEvent import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.application.SoftwareApplicationEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/topbars/FeedFilterSpinner.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/navigation/topbars/FeedFilterSpinner.kt similarity index 81% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/topbars/FeedFilterSpinner.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/navigation/topbars/FeedFilterSpinner.kt index e5a5d737fb..f9ddc64ffe 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/topbars/FeedFilterSpinner.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/navigation/topbars/FeedFilterSpinner.kt @@ -18,9 +18,8 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.navigation.topbars +package com.vitorpamplona.amethyst.commons.ui.navigation.topbars -import android.Manifest import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource @@ -42,7 +41,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.produceState @@ -51,7 +49,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.onClick @@ -63,14 +60,22 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.google.accompanist.permissions.ExperimentalPermissionsApi -import com.google.accompanist.permissions.isGranted -import com.google.accompanist.permissions.rememberPermissionState -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.feeds.CommunityName +import com.vitorpamplona.amethyst.commons.feeds.FavoriteAlgoFeedName +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.GeoHashName +import com.vitorpamplona.amethyst.commons.feeds.HashtagName +import com.vitorpamplona.amethyst.commons.feeds.InterestSetName +import com.vitorpamplona.amethyst.commons.feeds.Name +import com.vitorpamplona.amethyst.commons.feeds.NoteBackedName +import com.vitorpamplona.amethyst.commons.feeds.PeopleListName +import com.vitorpamplona.amethyst.commons.feeds.RelayName +import com.vitorpamplona.amethyst.commons.feeds.ResourceName import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserIsFollowingGeohash import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.dvm_offline import com.vitorpamplona.amethyst.commons.resources.feed_filter_select_an_option @@ -84,8 +89,6 @@ import com.vitorpamplona.amethyst.commons.resources.feed_group_lists import com.vitorpamplona.amethyst.commons.resources.feed_group_locations import com.vitorpamplona.amethyst.commons.resources.feed_group_relays import com.vitorpamplona.amethyst.commons.resources.follow_geohash -import com.vitorpamplona.amethyst.commons.resources.lack_location_permissions -import com.vitorpamplona.amethyst.commons.resources.loading_location import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_be_able_to_follow import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_be_able_to_unfollow import com.vitorpamplona.amethyst.commons.resources.open_dropdown_menu @@ -93,34 +96,20 @@ import com.vitorpamplona.amethyst.commons.resources.read_only_user import com.vitorpamplona.amethyst.commons.resources.select_an_option import com.vitorpamplona.amethyst.commons.resources.unfollow_geohash import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation +import com.vitorpamplona.amethyst.commons.ui.note.platform.LoadCityName +import com.vitorpamplona.amethyst.commons.ui.platform.AroundMeLocationLabel +import com.vitorpamplona.amethyst.commons.ui.platform.GeohashLocationPickerDialog +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.dvms.rememberDvmHeartbeatFresh import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Font12SP import com.vitorpamplona.amethyst.commons.ui.theme.Font14SP import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.location.LocationState -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsFollowingGeohash -import com.vitorpamplona.amethyst.ui.note.creators.location.GeohashLocationPickerDialog -import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName -import com.vitorpamplona.amethyst.ui.screen.CommunityName -import com.vitorpamplona.amethyst.ui.screen.FavoriteAlgoFeedName -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.GeoHashName -import com.vitorpamplona.amethyst.ui.screen.HashtagName -import com.vitorpamplona.amethyst.ui.screen.InterestSetName -import com.vitorpamplona.amethyst.ui.screen.Name -import com.vitorpamplona.amethyst.ui.screen.NoteBackedName -import com.vitorpamplona.amethyst.ui.screen.PeopleListName -import com.vitorpamplona.amethyst.ui.screen.RelayName -import com.vitorpamplona.amethyst.ui.screen.ResourceName -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.rememberDvmHeartbeatFresh +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.collections.immutable.ImmutableList import org.jetbrains.compose.resources.StringResource -@OptIn(ExperimentalPermissionsApi::class) @Composable fun FeedFilterSpinner( placeholderCode: TopFilter, @@ -132,7 +121,6 @@ fun FeedFilterSpinner( ) { var optionsShowing by remember { mutableStateOf(false) } - val context = LocalContext.current val selectAnOption = stringRes(id = Res.string.select_an_option) val selected = @@ -220,70 +208,7 @@ fun FeedFilterSpinner( } if (filter is TopFilter.AroundMe) { - val locationPermissionState = rememberPermissionState(Manifest.permission.ACCESS_COARSE_LOCATION) - if (!locationPermissionState.status.isGranted) { - LaunchedEffect(locationPermissionState) { locationPermissionState.launchPermissionRequest() } - - Text( - text = stringRes(Res.string.lack_location_permissions), - fontSize = Font12SP, - lineHeight = 12.sp, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - } else { - val location by Amethyst.instance.locationManager.geohashStateFlow - .collectAsStateWithLifecycle() - - when (val myLocation = location) { - is LocationState.LocationResult.Success -> { - LoadCityName( - geohashStr = myLocation.geoHash.toString(), - onLoading = { - Row { - Text( - text = "(${myLocation.geoHash})", - fontSize = Font12SP, - lineHeight = 12.sp, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - Spacer(modifier = StdHorzSpacer) - LoadingAnimation(indicatorSize = 12.dp, circleWidth = 2.dp) - } - }, - ) { cityName -> - Text( - text = "($cityName)", - fontSize = Font12SP, - lineHeight = 12.sp, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - } - } - - LocationState.LocationResult.LackPermission -> { - Text( - text = stringRes(Res.string.lack_location_permissions), - fontSize = Font12SP, - lineHeight = 12.sp, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - } - - LocationState.LocationResult.Loading -> { - Text( - text = stringRes(Res.string.loading_location), - fontSize = Font12SP, - lineHeight = 12.sp, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - } - } - } + AroundMeLocationLabel() } } @@ -402,7 +327,6 @@ fun RenderOption( option: Name, accountViewModel: AccountViewModel, ) { - val context = LocalContext.current when (option) { is GeoHashName -> { LoadCityName(option.geoHashTag) { @@ -574,7 +498,6 @@ private fun GroupSection( onSelect: (FeedDefinition) -> Unit, onRenderItem: @Composable (FeedDefinition) -> Unit, ) { - val context = LocalContext.current Surface( modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp), shape = RoundedCornerShape(16.dp), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/topbars/UserDrawerSearchTopBar.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/navigation/topbars/UserDrawerSearchTopBar.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/topbars/UserDrawerSearchTopBar.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/navigation/topbars/UserDrawerSearchTopBar.kt index 4b3a56e022..03f2630e3f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/topbars/UserDrawerSearchTopBar.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/navigation/topbars/UserDrawerSearchTopBar.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.navigation.topbars +package com.vitorpamplona.amethyst.commons.ui.navigation.topbars import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -33,6 +33,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserPicture import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.your_profile_image import com.vitorpamplona.amethyst.commons.search.SearchQuery @@ -47,8 +48,7 @@ import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.HeaderPictureModifier import com.vitorpamplona.amethyst.commons.ui.theme.Size22Modifier import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * The standard root top bar: the drawer avatar (or a back arrow), the screen's own title slot, @@ -130,7 +130,7 @@ fun TopBarNavigationIcon( } @Composable -internal fun LoggedInUserPictureDrawer( +fun LoggedInUserPictureDrawer( accountViewModel: AccountViewModel, onClick: () -> Unit, ) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/AuthorGalleryRenderContext.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/AuthorGalleryRenderContext.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/AuthorGalleryRenderContext.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/AuthorGalleryRenderContext.kt index 702d846009..205a4a3435 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/AuthorGalleryRenderContext.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/AuthorGalleryRenderContext.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable @@ -26,7 +26,7 @@ import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * The notification galleries (reactions, zaps, nutzaps, boosts) render up to 30 diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/BlankNote.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/BlankNote.kt index f8cfd136af..986006b4b1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/BlankNote.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -45,14 +45,16 @@ import com.vitorpamplona.amethyst.commons.resources.post_was_hidden_due_to_too_m import com.vitorpamplona.amethyst.commons.resources.show_anyway import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteAuthorPicture +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.commons.ui.theme.ButtonPadding import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.persistentSetOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BlockReportChecker.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/BlockReportChecker.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BlockReportChecker.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/BlockReportChecker.kt index 27ae7eb985..58dbb20e7e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BlockReportChecker.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/BlockReportChecker.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -28,7 +28,7 @@ import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun CheckHiddenFeedWatchBlockAndReport( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/CopyNoteText.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/CopyNoteText.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/CopyNoteText.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/CopyNoteText.kt index a247124776..9c63a61caa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/CopyNoteText.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/CopyNoteText.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable @@ -32,14 +32,14 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.copy_text import com.vitorpamplona.amethyst.commons.resources.copy_text_original import com.vitorpamplona.amethyst.commons.resources.copy_text_translated +import com.vitorpamplona.amethyst.commons.ui.components.LocalTranslationPlatform import com.vitorpamplona.amethyst.commons.ui.components.M3ActionDialog import com.vitorpamplona.amethyst.commons.ui.components.M3ActionRow import com.vitorpamplona.amethyst.commons.ui.components.M3ActionSection import com.vitorpamplona.amethyst.commons.ui.components.util.setText +import com.vitorpamplona.amethyst.commons.ui.note.types.displayedNoteText import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.components.cachedTranslation -import com.vitorpamplona.amethyst.ui.note.types.displayedNoteText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.coroutines.launch /** Both texts of a translated note, held while the user picks which one to copy. */ @@ -80,6 +80,7 @@ fun copyNoteTextAction( onDismiss: () -> Unit, ): (note: Note, versionShown: Note) -> Unit { val clipboardManager = LocalClipboard.current + val translator = LocalTranslationPlatform.current val scope = rememberCoroutineScope() val choice = remember { mutableStateOf(null) } @@ -113,7 +114,7 @@ fun copyNoteTextAction( onDismiss() } else { val original = displayedNoteText(note, decrypted) - val translated = cachedTranslation(original, accountViewModel) + val translated = translator.cachedTranslation(original, accountViewModel) if (translated == null) { copy(original) } else { diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/DateTimeStyle.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/DateTimeStyle.kt new file mode 100644 index 0000000000..c69a4c4133 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/DateTimeStyle.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.note + +/** The locale's predefined date or time lengths, as `java.text.DateFormat` and `NSDateFormatter` name them. */ +enum class DateTimeStyle { NONE, SHORT, MEDIUM, LONG } + +/** + * Formats an instant in the default locale and time zone with the locale's predefined [date] and + * [time] styles ("Sep 28, 2026, 2:32:10 PM" for MEDIUM/MEDIUM in en-US). A NONE side is left out; + * both NONE formats nothing. Safe to call from any thread. + */ +expect fun formatDateTime( + epochMillis: Long, + date: DateTimeStyle, + time: DateTimeStyle, +): String diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/DisplayAuthorBanner.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/DisplayAuthorBanner.kt similarity index 89% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/DisplayAuthorBanner.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/DisplayAuthorBanner.kt index 5f78f383a7..97065e3941 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/DisplayAuthorBanner.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/DisplayAuthorBanner.kt @@ -18,17 +18,17 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.note.elements.BannerImage import com.vitorpamplona.amethyst.commons.ui.theme.SimpleImageBorder -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.note.elements.BannerImage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun DisplayAuthorBanner( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ErrorMessageDialog.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/ErrorMessageDialog.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ErrorMessageDialog.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/ErrorMessageDialog.kt index 0fc5563865..b62810ad9e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ErrorMessageDialog.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/ErrorMessageDialog.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.PaddingValues @@ -39,17 +39,17 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -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.resources.Res import com.vitorpamplona.amethyst.commons.resources.error_dialog_button_ok import com.vitorpamplona.amethyst.commons.resources.error_dialog_talk_to_user +import com.vitorpamplona.amethyst.commons.resources.ic_dm +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size16dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.painterRes @Composable @Preview @@ -84,7 +84,7 @@ fun ErrorMessageDialog( onClickStartMessage?.let { TextButton(onClick = onClickStartMessage) { Icon( - painter = painterRes(R.drawable.ic_dm, 3), + painter = painterRes(Res.drawable.ic_dm, 3), contentDescription = null, ) Spacer(StdHorzSpacer) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Gallery.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/Gallery.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Gallery.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/Gallery.kt index b60440f8c1..38724de8f4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Gallery.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/Gallery.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -39,9 +39,11 @@ import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.navigation.routeForUser import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.util.showCount +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import kotlinx.collections.immutable.ImmutableList diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/LoadUser.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/LoadUser.kt new file mode 100644 index 0000000000..d26f63734d --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/LoadUser.kt @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.note + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache + +/** The cached [User] for [baseUserHex], creating it off the first frame when it isn't cached yet. */ +@Composable +fun LoadUser( + baseUserHex: String, + content: @Composable (User?) -> Unit, +) { + var user by + remember(baseUserHex) { mutableStateOf(LocalCache.getUserIfExists(baseUserHex)) } + + if (user == null) { + LaunchedEffect(key1 = baseUserHex) { + user = LocalCache.checkGetOrCreateUser(baseUserHex) + } + } + + content(user) +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Loaders.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/Loaders.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Loaders.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/Loaders.kt index ad119a36a4..5d17af4a18 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Loaders.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/Loaders.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -31,7 +31,6 @@ import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -39,12 +38,13 @@ import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel import com.vitorpamplona.amethyst.commons.model.nip03Timestamp.earliestOtsVerifiedTime import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteOts import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteOts -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId import com.vitorpamplona.quartz.nip01Core.core.Address import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext import kotlin.coroutines.CoroutineContext @@ -122,7 +122,7 @@ fun LoadOts( val target = noteStatus?.note ?: note val newOts = withContext(Dispatchers.IO) { - target.earliestOtsVerifiedTime(Amethyst.instance.otsResolverBuilder.build()) + target.earliestOtsVerifiedTime(accountViewModel.account.otsResolverBuilder()) } earliestDate = diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/MultiSetCompose.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/MultiSetCompose.kt index 651a79a79b..17cf26f941 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/MultiSetCompose.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background @@ -41,7 +41,6 @@ import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.Immutable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue @@ -67,26 +66,40 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.emojicoder.EmojiCoder import com.vitorpamplona.amethyst.commons.hashtags.Cashu import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons +import com.vitorpamplona.amethyst.commons.model.CombinedZap import com.vitorpamplona.amethyst.commons.model.EmptyTagList import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.model.ZapAmountCommentNotification import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.authorRouteFor import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.notifications.MultiSetCard +import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserAssertionsScore +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserPicture import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.nutzap import com.vitorpamplona.amethyst.commons.resources.profile_image import com.vitorpamplona.amethyst.commons.richtext.CachedRichTextParser import com.vitorpamplona.amethyst.commons.ui.components.AnimatedBorderTextCornerRadius +import com.vitorpamplona.amethyst.commons.ui.components.ExpandableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.DisplayBlankAuthor import com.vitorpamplona.amethyst.commons.ui.note.FollowingIcon import com.vitorpamplona.amethyst.commons.ui.note.LikedIcon import com.vitorpamplona.amethyst.commons.ui.note.RepostedIcon import com.vitorpamplona.amethyst.commons.ui.note.ScoreTagSmall +import com.vitorpamplona.amethyst.commons.ui.note.WatchAuthorWithBlank +import com.vitorpamplona.amethyst.commons.ui.note.WatchUserFollows import com.vitorpamplona.amethyst.commons.ui.note.ZappedIcon +import com.vitorpamplona.amethyst.commons.ui.note.elements.NoteDropDownMenu import com.vitorpamplona.amethyst.commons.ui.richtext.InLineIconRenderer +import com.vitorpamplona.amethyst.commons.ui.richtext.LocalRichTextPlatform import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange @@ -106,24 +119,16 @@ import com.vitorpamplona.amethyst.commons.ui.theme.bitcoinColor import com.vitorpamplona.amethyst.commons.ui.theme.overPictureBackground import com.vitorpamplona.amethyst.commons.ui.theme.profile35dpModifier import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.UserFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserAssertionsScore -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserPicture -import com.vitorpamplona.amethyst.ui.components.CoreSecretMessage -import com.vitorpamplona.amethyst.ui.components.ExpandableRichTextViewer -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.elements.NoteDropDownMenu -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.CombinedZap -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.MultiSetCard +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip30CustomEmoji.CustomEmoji import com.vitorpamplona.quartz.nip61Nutzaps.nutzap.NutzapEvent import com.vitorpamplona.quartz.nip61Nutzaps.nutzap.claimedSatsTotal +import com.vitorpamplona.quartz.utils.BigDecimal import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.launch import kotlin.time.ExperimentalTime @@ -390,7 +395,7 @@ fun DisplaySecretEmojiAsReaction( ) { Surface(Modifier.padding(10.dp)) { val color = remember { mutableStateOf(Color.Transparent) } - CoreSecretMessage(localSecretContent, null, 3, color, accountViewModel, nav) + LocalRichTextPlatform.current.SecretMessage(localSecretContent, null, 3, color, accountViewModel, nav) } } } @@ -453,7 +458,7 @@ fun RenderNutzapGallery( ZapAmountCommentNotification( user = note.author, comment = event?.content?.ifBlank { null }, - amount = showAmount(java.math.BigDecimal(sats)), + amount = showAmount(BigDecimal(sats)), zapNote = note, ) }.toImmutableList() @@ -557,16 +562,6 @@ fun AuthorGalleryZaps( } } -@Immutable -data class ZapAmountCommentNotification( - val user: User?, - val comment: String?, - val amount: String?, - // The zap receipt (kind 9735) note, when available, so the chip can offer - // actions that target the zap itself (e.g. replying to it). - val zapNote: Note? = null, -) - @Composable private fun ParseAuthorCommentAndAmount( zapRequest: Note, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/NIP05VerificationDisplay.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/NIP05VerificationDisplay.kt index 208b2c4ba1..eb314f4e77 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/NIP05VerificationDisplay.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -41,7 +41,6 @@ import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons import com.vitorpamplona.amethyst.commons.hashtags.Tunestr import com.vitorpamplona.amethyst.commons.icons.symbols.Icon @@ -53,13 +52,23 @@ import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.navigation.routeForUser import com.vitorpamplona.amethyst.commons.model.nip05DnsIdentifiers.Nip05State import com.vitorpamplona.amethyst.commons.model.nip05DnsIdentifiers.Nip05VerifState +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserStatuses import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.nip05_checking import com.vitorpamplona.amethyst.commons.resources.nip05_failed import com.vitorpamplona.amethyst.commons.resources.nip05_verified +import com.vitorpamplona.amethyst.commons.resources.nip_05 import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.WatchAuthor +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Font14SP @@ -70,14 +79,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.lessImportantLink import com.vitorpamplona.amethyst.commons.ui.theme.nip05 import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserStatuses -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.tags.aTag.firstTaggedAddress import com.vitorpamplona.quartz.nip01Core.tags.events.ETag @@ -482,7 +484,7 @@ fun RenderNIP05VerifiedSymbol( is Nip05VerifState.Verified -> { Icon( - painter = painterRes(R.drawable.nip_05, compositionSizeReference), + painter = painterRes(Res.drawable.nip_05, compositionSizeReference), contentDescription = stringRes(id = Res.string.nip05_verified), modifier = modifier, tint = MaterialTheme.colorScheme.nip05, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/NoteCompose.kt similarity index 85% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/NoteCompose.kt index 6a1d1c0089..b15ce3709b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/NoteCompose.kt @@ -20,7 +20,7 @@ */ @file:Suppress("DEPRECATION") -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background @@ -52,7 +52,6 @@ import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.birdstar.ui.RenderBirdDetection @@ -72,6 +71,10 @@ import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChann import com.vitorpamplona.amethyst.commons.model.replyingDirectlyTo import com.vitorpamplona.amethyst.commons.model.textNoteModifications import com.vitorpamplona.amethyst.commons.nipC0CodeSnippets.ui.RenderCodeSnippetEvent +import com.vitorpamplona.amethyst.commons.relayClient.event.observeCommunityApprovalNeedStatus +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteModifications +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannelPicture import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.approve import com.vitorpamplona.amethyst.commons.resources.draft @@ -90,16 +93,188 @@ import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncIma import com.vitorpamplona.amethyst.commons.ui.layouts.GenericRepostLayout import com.vitorpamplona.amethyst.commons.ui.layouts.NoteComposeLayout import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeEditDraftTo +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.DateTimeStyle import com.vitorpamplona.amethyst.commons.ui.note.HeaderPill +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.LoadPublicChatChannel +import com.vitorpamplona.amethyst.commons.ui.note.NoteAuthorPicture +import com.vitorpamplona.amethyst.commons.ui.note.NoteUsernameDisplay 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.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.DisplayZapSplits +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayEditStatus +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayFollowingCommunityInPost +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayFollowingHashtagsInPost +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayLocation +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayOts +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayPoW +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayReward +import com.vitorpamplona.amethyst.commons.ui.note.elements.MoreOptionsButton +import com.vitorpamplona.amethyst.commons.ui.note.elements.Reward +import com.vitorpamplona.amethyst.commons.ui.note.elements.ShowForkInformation import com.vitorpamplona.amethyst.commons.ui.note.elements.StaleRelayHint import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgo import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgoStyle +import com.vitorpamplona.amethyst.commons.ui.note.formatDateTime +import com.vitorpamplona.amethyst.commons.ui.note.platform.ReactionsRow +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderAudioHeader +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderAudioTrack +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderCalendarRSVPEvent +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderChessGame +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderGitIssueEvent +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderGitPatchEvent +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderGitPullRequestEvent +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderGitPullRequestUpdateEvent +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderGitRepositoryEvent +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderLiveChessChallenge +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderLiveChessGameEnd +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderMeetingRoomEvent +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderMeetingRoomPresence +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderMeetingSpaceEvent +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderMusicTrack +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderNamedNappletEvent +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderNamedSiteEvent +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderRootNappletEvent +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderRootSiteEvent +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderVoiceTrack import com.vitorpamplona.amethyst.commons.ui.note.timeAheadNoDot +import com.vitorpamplona.amethyst.commons.ui.note.types.BadgeDisplay +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayBlockedRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayBroadcastRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayContactList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayDMRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayFavoriteRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayIndexerRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayNIP65RelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayPeopleList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayProxyRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayRelaySet +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplaySearchRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayStarterPack +import com.vitorpamplona.amethyst.commons.ui.note.types.DisplayTrustedRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.EditState +import com.vitorpamplona.amethyst.commons.ui.note.types.EmptyState +import com.vitorpamplona.amethyst.commons.ui.note.types.FileMetadataDisplay +import com.vitorpamplona.amethyst.commons.ui.note.types.FileStorageHeaderDisplay +import com.vitorpamplona.amethyst.commons.ui.note.types.PictureDisplay +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderAppDefinition +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderAppRecommendation +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderAttestation +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderAttestationRequest +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderAttestorProficiency +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderAttestorRecommendation +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderBadgeAward +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderBlossomPieceIndex +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderBolt12Zap +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderBookshelfDirectory +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderCalendarCollectionEvent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderCalendarDateSlotEvent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderCalendarTimeSlotEvent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderChannelInvite +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderChannelMessage +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderChat +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderChatMessage +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderChatMessageEncryptedFile +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderCitation +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderClassifieds +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderCommunity +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderCyberspaceBag +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderDvmContentDiscoveryResponse +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderDvmStatus +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderEmojiPack +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderEntityRating +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderExternalReaction +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderFhirResource +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderFundraiser +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderGeocache +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderGeocacheFoundLog +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderGoal +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderHighlight +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderInteractiveStory +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderLearningResource +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderLiveActivityChatMessage +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderLiveActivityEvent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderLongFormContent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderMusicPlaylist +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderNipContent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderNutzap +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderOnchainZap +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPinListEvent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPodcastEpisode +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPodcastMetadata +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPoll +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPostApproval +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPrivateMessage +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderProfileCard +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPs1Save +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPublicMessage +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPublicationIndex +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderPublicationSection +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderReaction +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRelayAddMember +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRelayDiscovery +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRelayGroupMessage +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRelayJoinRequest +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRelayLeaveRequest +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRelayMembershipList +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRelayRemoveMember +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRelayReview +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderReport +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRoadEventConfirmation +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderRoadEventReport +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderSnoAvatar +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderSnoObject +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderSnoShard +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderSoftwareApplication +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderSoftwareAsset +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderSoftwareRelease +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderTextEvent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderTextModificationEvent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderThread +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderTorrent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderTorrentComment +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderVideoCollaboration +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderVideoCurationSet +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderWikiContent +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderWikiMergeAcceptance +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderWikiMergeRequest +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderWikiRedirect +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderZapPoll +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderZapReceipt +import com.vitorpamplona.amethyst.commons.ui.note.types.ReplyRenderType +import com.vitorpamplona.amethyst.commons.ui.note.types.VideoDisplay +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderAppCurationSet +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderArticleCurationSet +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderBookmarkList +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderBookmarkSet +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderFavoriteAlgoFeedsList +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderGeohashList +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderGitAuthorList +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderGitRepositoryList +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderGoodWikiAuthorList +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderGoodWikiRelayList +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderInterestList +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderInterestSet +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderKindMuteSet +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderMediaFollowList +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderMediaStarterPack +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderMuteList +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderOldBookmarkList +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderPictureCurationSet +import com.vitorpamplona.amethyst.commons.ui.note.types.lists.RenderSimpleGroupList +import com.vitorpamplona.amethyst.commons.ui.note.types.observeZapSender import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.RenderChatClip +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.RenderPublicChatChannelHeader +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts.PodcastTrailerListItem +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts.ExerciseTemplateDisplay +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts.WorkoutDisplay import com.vitorpamplona.amethyst.commons.ui.state.produceCachedStateAsync import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer @@ -119,173 +294,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.newItemBackgroundColor import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannelPicture -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeCommunityApprovalNeedStatus -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteModifications -import com.vitorpamplona.amethyst.ui.navigation.routes.routeEditDraftTo -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.DisplayZapSplits -import com.vitorpamplona.amethyst.ui.note.elements.DisplayEditStatus -import com.vitorpamplona.amethyst.ui.note.elements.DisplayFollowingCommunityInPost -import com.vitorpamplona.amethyst.ui.note.elements.DisplayFollowingHashtagsInPost -import com.vitorpamplona.amethyst.ui.note.elements.DisplayLocation -import com.vitorpamplona.amethyst.ui.note.elements.DisplayOts -import com.vitorpamplona.amethyst.ui.note.elements.DisplayPoW -import com.vitorpamplona.amethyst.ui.note.elements.DisplayReward -import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton -import com.vitorpamplona.amethyst.ui.note.elements.Reward -import com.vitorpamplona.amethyst.ui.note.elements.ShowForkInformation -import com.vitorpamplona.amethyst.ui.note.types.BadgeDisplay -import com.vitorpamplona.amethyst.ui.note.types.DisplayBlockedRelayList -import com.vitorpamplona.amethyst.ui.note.types.DisplayBroadcastRelayList -import com.vitorpamplona.amethyst.ui.note.types.DisplayContactList -import com.vitorpamplona.amethyst.ui.note.types.DisplayDMRelayList -import com.vitorpamplona.amethyst.ui.note.types.DisplayFavoriteRelayList -import com.vitorpamplona.amethyst.ui.note.types.DisplayIndexerRelayList -import com.vitorpamplona.amethyst.ui.note.types.DisplayNIP65RelayList -import com.vitorpamplona.amethyst.ui.note.types.DisplayPeopleList -import com.vitorpamplona.amethyst.ui.note.types.DisplayProxyRelayList -import com.vitorpamplona.amethyst.ui.note.types.DisplayRelaySet -import com.vitorpamplona.amethyst.ui.note.types.DisplaySearchRelayList -import com.vitorpamplona.amethyst.ui.note.types.DisplayStarterPack -import com.vitorpamplona.amethyst.ui.note.types.DisplayTrustedRelayList -import com.vitorpamplona.amethyst.ui.note.types.EditState -import com.vitorpamplona.amethyst.ui.note.types.EmptyState -import com.vitorpamplona.amethyst.ui.note.types.FileMetadataDisplay -import com.vitorpamplona.amethyst.ui.note.types.FileStorageHeaderDisplay -import com.vitorpamplona.amethyst.ui.note.types.PictureDisplay -import com.vitorpamplona.amethyst.ui.note.types.RenderAppDefinition -import com.vitorpamplona.amethyst.ui.note.types.RenderAppRecommendation -import com.vitorpamplona.amethyst.ui.note.types.RenderAttestation -import com.vitorpamplona.amethyst.ui.note.types.RenderAttestationRequest -import com.vitorpamplona.amethyst.ui.note.types.RenderAttestorProficiency -import com.vitorpamplona.amethyst.ui.note.types.RenderAttestorRecommendation -import com.vitorpamplona.amethyst.ui.note.types.RenderAudioHeader -import com.vitorpamplona.amethyst.ui.note.types.RenderAudioTrack -import com.vitorpamplona.amethyst.ui.note.types.RenderBadgeAward -import com.vitorpamplona.amethyst.ui.note.types.RenderBlossomPieceIndex -import com.vitorpamplona.amethyst.ui.note.types.RenderBolt12Zap -import com.vitorpamplona.amethyst.ui.note.types.RenderBookshelfDirectory -import com.vitorpamplona.amethyst.ui.note.types.RenderCalendarCollectionEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderCalendarDateSlotEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderCalendarRSVPEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderCalendarTimeSlotEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderChannelInvite -import com.vitorpamplona.amethyst.ui.note.types.RenderChannelMessage -import com.vitorpamplona.amethyst.ui.note.types.RenderChat -import com.vitorpamplona.amethyst.ui.note.types.RenderChatMessage -import com.vitorpamplona.amethyst.ui.note.types.RenderChatMessageEncryptedFile -import com.vitorpamplona.amethyst.ui.note.types.RenderChessGame -import com.vitorpamplona.amethyst.ui.note.types.RenderCitation -import com.vitorpamplona.amethyst.ui.note.types.RenderClassifieds -import com.vitorpamplona.amethyst.ui.note.types.RenderCommunity -import com.vitorpamplona.amethyst.ui.note.types.RenderCyberspaceBag -import com.vitorpamplona.amethyst.ui.note.types.RenderDvmContentDiscoveryResponse -import com.vitorpamplona.amethyst.ui.note.types.RenderDvmStatus -import com.vitorpamplona.amethyst.ui.note.types.RenderEmojiPack -import com.vitorpamplona.amethyst.ui.note.types.RenderEntityRating -import com.vitorpamplona.amethyst.ui.note.types.RenderExternalReaction -import com.vitorpamplona.amethyst.ui.note.types.RenderFhirResource -import com.vitorpamplona.amethyst.ui.note.types.RenderFundraiser -import com.vitorpamplona.amethyst.ui.note.types.RenderGeocache -import com.vitorpamplona.amethyst.ui.note.types.RenderGeocacheFoundLog -import com.vitorpamplona.amethyst.ui.note.types.RenderGitIssueEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderGitPatchEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderGitPullRequestEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderGitPullRequestUpdateEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderGitRepositoryEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderGoal -import com.vitorpamplona.amethyst.ui.note.types.RenderHighlight -import com.vitorpamplona.amethyst.ui.note.types.RenderInteractiveStory -import com.vitorpamplona.amethyst.ui.note.types.RenderLearningResource -import com.vitorpamplona.amethyst.ui.note.types.RenderLiveActivityChatMessage -import com.vitorpamplona.amethyst.ui.note.types.RenderLiveActivityEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderLiveChessChallenge -import com.vitorpamplona.amethyst.ui.note.types.RenderLiveChessGameEnd -import com.vitorpamplona.amethyst.ui.note.types.RenderLongFormContent -import com.vitorpamplona.amethyst.ui.note.types.RenderMeetingRoomEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderMeetingSpaceEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderMusicPlaylist -import com.vitorpamplona.amethyst.ui.note.types.RenderMusicTrack -import com.vitorpamplona.amethyst.ui.note.types.RenderNamedNappletEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderNamedSiteEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderNipContent -import com.vitorpamplona.amethyst.ui.note.types.RenderNutzap -import com.vitorpamplona.amethyst.ui.note.types.RenderOnchainZap -import com.vitorpamplona.amethyst.ui.note.types.RenderPinListEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderPodcastEpisode -import com.vitorpamplona.amethyst.ui.note.types.RenderPodcastMetadata -import com.vitorpamplona.amethyst.ui.note.types.RenderPoll -import com.vitorpamplona.amethyst.ui.note.types.RenderPostApproval -import com.vitorpamplona.amethyst.ui.note.types.RenderPrivateMessage -import com.vitorpamplona.amethyst.ui.note.types.RenderProfileCard -import com.vitorpamplona.amethyst.ui.note.types.RenderPs1Save -import com.vitorpamplona.amethyst.ui.note.types.RenderPublicMessage -import com.vitorpamplona.amethyst.ui.note.types.RenderPublicationIndex -import com.vitorpamplona.amethyst.ui.note.types.RenderPublicationSection -import com.vitorpamplona.amethyst.ui.note.types.RenderReaction -import com.vitorpamplona.amethyst.ui.note.types.RenderRelayAddMember -import com.vitorpamplona.amethyst.ui.note.types.RenderRelayDiscovery -import com.vitorpamplona.amethyst.ui.note.types.RenderRelayGroupMessage -import com.vitorpamplona.amethyst.ui.note.types.RenderRelayJoinRequest -import com.vitorpamplona.amethyst.ui.note.types.RenderRelayLeaveRequest -import com.vitorpamplona.amethyst.ui.note.types.RenderRelayMembershipList -import com.vitorpamplona.amethyst.ui.note.types.RenderRelayRemoveMember -import com.vitorpamplona.amethyst.ui.note.types.RenderRelayReview -import com.vitorpamplona.amethyst.ui.note.types.RenderReport -import com.vitorpamplona.amethyst.ui.note.types.RenderRoadEventConfirmation -import com.vitorpamplona.amethyst.ui.note.types.RenderRoadEventReport -import com.vitorpamplona.amethyst.ui.note.types.RenderRootNappletEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderRootSiteEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderSnoAvatar -import com.vitorpamplona.amethyst.ui.note.types.RenderSnoObject -import com.vitorpamplona.amethyst.ui.note.types.RenderSnoShard -import com.vitorpamplona.amethyst.ui.note.types.RenderSoftwareApplication -import com.vitorpamplona.amethyst.ui.note.types.RenderSoftwareAsset -import com.vitorpamplona.amethyst.ui.note.types.RenderSoftwareRelease -import com.vitorpamplona.amethyst.ui.note.types.RenderTextEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderTextModificationEvent -import com.vitorpamplona.amethyst.ui.note.types.RenderThread -import com.vitorpamplona.amethyst.ui.note.types.RenderTorrent -import com.vitorpamplona.amethyst.ui.note.types.RenderTorrentComment -import com.vitorpamplona.amethyst.ui.note.types.RenderVideoCollaboration -import com.vitorpamplona.amethyst.ui.note.types.RenderVideoCurationSet -import com.vitorpamplona.amethyst.ui.note.types.RenderVoiceTrack -import com.vitorpamplona.amethyst.ui.note.types.RenderWikiContent -import com.vitorpamplona.amethyst.ui.note.types.RenderWikiMergeAcceptance -import com.vitorpamplona.amethyst.ui.note.types.RenderWikiMergeRequest -import com.vitorpamplona.amethyst.ui.note.types.RenderWikiRedirect -import com.vitorpamplona.amethyst.ui.note.types.RenderZapPoll -import com.vitorpamplona.amethyst.ui.note.types.RenderZapReceipt -import com.vitorpamplona.amethyst.ui.note.types.ReplyRenderType -import com.vitorpamplona.amethyst.ui.note.types.VideoDisplay -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderAppCurationSet -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderArticleCurationSet -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderBookmarkList -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderBookmarkSet -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderFavoriteAlgoFeedsList -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderGeohashList -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderGitAuthorList -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderGitRepositoryList -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderGoodWikiAuthorList -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderGoodWikiRelayList -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderInterestList -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderInterestSet -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderKindMuteSet -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderMediaFollowList -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderMediaStarterPack -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderMuteList -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderOldBookmarkList -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderPictureCurationSet -import com.vitorpamplona.amethyst.ui.note.types.lists.RenderSimpleGroupList -import com.vitorpamplona.amethyst.ui.note.types.observeZapSender -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderChatClip -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.RenderPublicChatChannelHeader -import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.PodcastTrailerListItem -import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.ExerciseTemplateDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.WorkoutDisplay +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.buzz.notifications.MemberAddedNotificationEvent import com.vitorpamplona.quartz.buzz.stream.StreamMessageV2Event import com.vitorpamplona.quartz.cyberspace.CyberspaceBagEvent @@ -402,6 +411,7 @@ import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessa import com.vitorpamplona.quartz.nip53LiveActivities.clip.LiveActivitiesClipEvent import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingRoomEvent import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent +import com.vitorpamplona.quartz.nip53LiveActivities.presence.MeetingRoomPresenceEvent import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent import com.vitorpamplona.quartz.nip54Wiki.WikiArticleEvent import com.vitorpamplona.quartz.nip54Wiki.WikiMergeAcceptanceEvent @@ -457,10 +467,9 @@ import com.vitorpamplona.quartz.nipXXPodcasting20.metadata.Podcasting20PodcastMe import com.vitorpamplona.quartz.nipXXPodcasting20.trailer.Podcasting20TrailerEvent import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.delay import kotlinx.coroutines.withContext -import java.text.SimpleDateFormat -import java.util.Date @Composable fun NoteCompose( @@ -1312,9 +1321,8 @@ private fun RenderNoteRow( RenderMeetingRoomEvent(baseNote, accountViewModel, nav) } - is com.vitorpamplona.quartz.nip53LiveActivities.presence.MeetingRoomPresenceEvent -> { - com.vitorpamplona.amethyst.ui.note.types - .RenderMeetingRoomPresence(baseNote, accountViewModel, nav) + is MeetingRoomPresenceEvent -> { + RenderMeetingRoomPresence(baseNote, accountViewModel, nav) } is GitRepositoryEvent -> { @@ -2103,7 +2111,6 @@ fun DisplayExpiration( expirationDate: Long, accountViewModel: AccountViewModel, ) { - val context = LocalContext.current // Beyond a year timeAheadNoDot switches to a full date, which is too wide // for the pill: clamp it. val text = @@ -2120,7 +2127,7 @@ fun DisplayExpiration( accountViewModel.toastManager.toast( Res.string.expiration_date_label, Res.string.expiration_info_description, - SimpleDateFormat.getDateTimeInstance().format(Date(expirationDate * 1000)), + formatDateTime(expirationDate * 1000, DateTimeStyle.MEDIUM, DateTimeStyle.MEDIUM), ) }, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/NoteQuickActionMenu.kt similarity index 89% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/NoteQuickActionMenu.kt index c0bbf9a613..b91cc98f9f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/NoteQuickActionMenu.kt @@ -18,10 +18,8 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note -import android.content.Intent -import android.widget.Toast import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -55,14 +53,11 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalClipboard -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Popup -import androidx.core.graphics.ColorUtils import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -102,9 +97,13 @@ import com.vitorpamplona.amethyst.commons.resources.quick_action_unfollow import com.vitorpamplona.amethyst.commons.resources.quick_action_unmute_thread import com.vitorpamplona.amethyst.commons.resources.report_dialog_block_hide_user_btn import com.vitorpamplona.amethyst.commons.resources.report_dialog_blocking_a_user +import com.vitorpamplona.amethyst.commons.ui.components.rememberShortNotice +import com.vitorpamplona.amethyst.commons.ui.components.rememberTextSharer import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeEditDraftTo +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.report.ReportNoteDialog import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.LightRedColor import com.vitorpamplona.amethyst.commons.ui.theme.QuickActionPopupShadow @@ -112,27 +111,45 @@ import com.vitorpamplona.amethyst.commons.ui.theme.SmallestBorder import com.vitorpamplona.amethyst.commons.ui.theme.isLight import com.vitorpamplona.amethyst.commons.ui.theme.secondaryButtonBackground import com.vitorpamplona.amethyst.commons.util.njumpLink -import com.vitorpamplona.amethyst.ui.navigation.routes.routeEditDraftTo -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.report.ReportNoteDialog +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.bounties.bountyBaseReward import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent import com.vitorpamplona.quartz.nip51Lists.followSet.FollowSetEvent import com.vitorpamplona.quartz.nip51Lists.starterPack.StarterPackEvent import kotlinx.coroutines.launch import org.jetbrains.compose.resources.StringResource +import kotlin.math.abs +/** [color] with its HSL lightness raised by [amount], opaque, as `ColorUtils` computed it. */ private fun lightenColor( color: Color, amount: Float, ): Color { - var argb = color.toArgb() - val hslOut = floatArrayOf(0f, 0f, 0f) - ColorUtils.colorToHSL(argb, hslOut) - hslOut[2] += amount - argb = ColorUtils.HSLToColor(hslOut) - return Color(argb) + val r = color.red + val g = color.green + val b = color.blue + val max = maxOf(r, g, b) + val min = minOf(r, g, b) + val delta = max - min + val lightness = (max + min) / 2f + + var hue = 0f + var saturation = 0f + if (delta != 0f) { + hue = + when (max) { + r -> ((g - b) / delta).mod(6f) + g -> (b - r) / delta + 2f + else -> (r - g) / delta + 4f + } * 60f + saturation = delta / (1f - abs(2f * lightness - 1f)) + } + + return Color.hsl( + hue = hue.mod(360f), + saturation = saturation.coerceIn(0f, 1f), + lightness = (lightness + amount).coerceIn(0f, 1f), + ) } val externalLinkForUser = { user: User -> @@ -289,19 +306,15 @@ fun CardBody( ) { val quickActionShareBrowserLinkStr = stringRes(Res.string.quick_action_share_browser_link) val quickActionShareStr = stringRes(Res.string.quick_action_share) - val context = LocalContext.current + val notice = rememberShortNotice() + val sharer = rememberTextSharer() val primaryLight = lightenColor(MaterialTheme.colorScheme.primary, 0.1f) val clipboardManager = LocalClipboard.current val scope = rememberCoroutineScope() val showToast = { stringRes: StringResource -> scope.launch { - Toast - .makeText( - context, - loadStringRes(stringRes), - Toast.LENGTH_SHORT, - ).show() + notice.show(loadStringRes(stringRes)) } } @@ -492,26 +505,7 @@ fun CardBody( icon = MaterialSymbols.Share, label = stringRes(Res.string.quick_action_share), ) { - val sendIntent = - Intent().apply { - action = Intent.ACTION_SEND - type = "text/plain" - putExtra( - Intent.EXTRA_TEXT, - externalLinkForNote(note), - ) - putExtra( - Intent.EXTRA_TITLE, - quickActionShareBrowserLinkStr, - ) - } - - val shareIntent = - Intent.createChooser( - sendIntent, - quickActionShareStr, - ) - context.startActivity(shareIntent) + sharer.share(externalLinkForNote(note), quickActionShareBrowserLinkStr, quickActionShareStr) onDismiss() } } @@ -675,35 +669,6 @@ fun QuickActionAlertDialog( ) } -@Composable -fun QuickActionAlertDialog( - title: String, - textContent: String, - buttonIconResource: Int, - buttonIconReference: Int, - buttonText: String, - buttonColors: ButtonColors = ButtonDefaults.buttonColors(), - onClickDoOnce: () -> Unit, - onClickDontShowAgain: () -> Unit, - onDismiss: () -> Unit, -) { - QuickActionAlertDialog( - title = title, - textContent = textContent, - icon = { - Icon( - painter = painterRes(buttonIconResource, buttonIconReference), - contentDescription = null, - ) - }, - buttonText = buttonText, - buttonColors = buttonColors, - onClickDoOnce = onClickDoOnce, - onClickDontShowAgain = onClickDontShowAgain, - onDismiss = onDismiss, - ) -} - @Composable fun QuickActionAlertDialog( title: String, @@ -774,33 +739,6 @@ fun QuickActionAlertDialogOneButton( ) } -@Composable -fun QuickActionAlertDialogOneButton( - title: String, - textContent: String, - buttonIconResource: Int, - buttonIconReference: Int, - buttonText: String, - buttonColors: ButtonColors = ButtonDefaults.buttonColors(), - onClickDoOnce: () -> Unit, - onDismiss: () -> Unit, -) { - QuickActionAlertDialogOneButton( - title = title, - textContent = textContent, - icon = { - Icon( - painter = painterRes(buttonIconResource, buttonIconReference), - contentDescription = null, - ) - }, - buttonText = buttonText, - buttonColors = buttonColors, - onClickDoOnce = onClickDoOnce, - onDismiss = onDismiss, - ) -} - @Composable fun QuickActionAlertDialogOneButton( title: String, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/RelayCompose.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/RelayCompose.kt index 3e683cb40e..760d6ee3a4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/RelayCompose.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -33,7 +33,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -49,8 +48,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.ButtonPadding import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.MyRelayInfo -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl @Composable @@ -61,8 +60,6 @@ fun RelayCompose( onRemoveRelay: () -> Unit, onClick: (() -> Unit)? = null, ) { - val context = LocalContext.current - Row( modifier = StdPadding.then(if (onClick != null) Modifier.clickable(onClick = onClick) else Modifier), verticalAlignment = Alignment.CenterVertically, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/RelayListBox.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/RelayListBox.kt index 6dfd2b8037..c91175fbb4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListBox.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/RelayListBox.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -57,7 +57,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.ShowMoreRelaysButtonBoxModife import com.vitorpamplona.amethyst.commons.ui.theme.Size17Modifier import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.distinctUntilChanged diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/RelayListRow.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/RelayListRow.kt index bb7b302840..f04d028d13 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayListRow.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/RelayListRow.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background @@ -51,6 +51,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.expand_relay_list import com.vitorpamplona.amethyst.commons.resources.relay_info @@ -72,8 +73,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.redColorOnSecondSurface import com.vitorpamplona.amethyst.commons.ui.theme.relayIconModifier import com.vitorpamplona.amethyst.commons.ui.theme.ripple24dp import com.vitorpamplona.amethyst.commons.ui.theme.warningColorOnSecondSurface -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.launch diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/RenderReaction.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/RenderReaction.kt new file mode 100644 index 0000000000..72c6e1bc4b --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/RenderReaction.kt @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.note + +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.unit.sp +import com.vitorpamplona.amethyst.commons.emojicoder.EmojiCoder +import com.vitorpamplona.amethyst.commons.ui.components.AnimatedBorderTextCornerRadius +import com.vitorpamplona.amethyst.commons.ui.note.LikedIcon +import com.vitorpamplona.amethyst.commons.ui.richtext.InLineIconRenderer +import com.vitorpamplona.amethyst.commons.ui.theme.Size28Modifier +import com.vitorpamplona.quartz.nip30CustomEmoji.CustomEmoji +import kotlinx.collections.immutable.persistentListOf + +@Composable +fun RenderReaction(reactionType: String) { + if (reactionType.startsWith(":")) { + val noStartColon = reactionType.removePrefix(":") + val url = noStartColon.substringAfter(":") + + InLineIconRenderer( + persistentListOf( + CustomEmoji.ImageUrlType(url), + ), + style = SpanStyle(color = MaterialTheme.colorScheme.onBackground), + maxLines = 1, + fontSize = 22.sp, + ) + } else { + when (reactionType) { + "+" -> { + LikedIcon(modifier = Size28Modifier) + } + + "-" -> { + Text( + text = "\uD83D\uDC4E", + color = MaterialTheme.colorScheme.onBackground, + maxLines = 1, + fontSize = 22.sp, + ) + } + + else -> { + if (EmojiCoder.isCoded(reactionType)) { + AnimatedBorderTextCornerRadius( + reactionType, + color = MaterialTheme.colorScheme.onBackground, + fontSize = 20.sp, + ) + } else { + Text( + reactionType, + color = MaterialTheme.colorScheme.onBackground, + maxLines = 1, + fontSize = 22.sp, + ) + } + } + } + } +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/UserCompose.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/UserCompose.kt index f002b59bef..e9ba32bd5c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/UserCompose.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -38,6 +38,9 @@ import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.profile.ui.FollowButton import com.vitorpamplona.amethyst.commons.profile.ui.ListButton import com.vitorpamplona.amethyst.commons.profile.ui.UnfollowButton +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.observeAccountIsHiddenUser +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserAboutMe +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserIsFollowing import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.follow import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_be_able_to_follow @@ -45,15 +48,14 @@ import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_ import com.vitorpamplona.amethyst.commons.resources.read_only_user import com.vitorpamplona.amethyst.commons.ui.layouts.listItem.SlimListItem import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.note.ShowUserButton +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.observeAccountIsHiddenUser -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserAboutMe -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsFollowing -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun UserCompose( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/UserProfilePicture.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/UserProfilePicture.kt index a5af97da5f..ce4b21c4af 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/UserProfilePicture.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.clickable @@ -40,6 +40,8 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserAssertionsScore +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.profile_image import com.vitorpamplona.amethyst.commons.resources.profile_image_of_user @@ -47,17 +49,14 @@ import com.vitorpamplona.amethyst.commons.resources.unknown_author import com.vitorpamplona.amethyst.commons.ui.components.RobohashAsyncImage import com.vitorpamplona.amethyst.commons.ui.components.UserAvatar import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.note.FollowingIcon +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser import com.vitorpamplona.amethyst.commons.ui.note.ScoreTag import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserAssertionsScore -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey @@ -442,7 +441,6 @@ private const val PREVIEW_USER_NAME = "vitor" @Preview @Composable fun ScoreTag55Preview() { - val accountViewModel = mockAccountViewModel() ThemeComparisonColumn { Row { var size = 75.dp diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UsernameDisplay.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/UsernameDisplay.kt similarity index 69% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UsernameDisplay.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/UsernameDisplay.kt index fbf94432b4..88fd33691e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UsernameDisplay.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/UsernameDisplay.kt @@ -18,33 +18,22 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note -import android.content.Context -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.compose.LocalLifecycleOwner import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserDisplayNickname +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled -import com.vitorpamplona.amethyst.commons.ui.note.PlayIcon import com.vitorpamplona.amethyst.commons.ui.note.UserNameText -import com.vitorpamplona.amethyst.commons.ui.theme.StdButtonSizeModifier -import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserDisplayNickname -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.service.tts.TextToSpeechHelper -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.quartz.utils.Log +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun NoteUsernameDisplay( @@ -120,30 +109,3 @@ fun UsernameDisplay( ) } } - -@Composable -fun DrawPlayName(name: String) { - val context = LocalContext.current - val lifecycleOwner = LocalLifecycleOwner.current - - IconButton(onClick = { speak(name, context, lifecycleOwner) }, modifier = StdButtonSizeModifier) { - PlayIcon( - modifier = StdButtonSizeModifier, - tint = MaterialTheme.colorScheme.placeholderText, - ) - } -} - -private fun speak( - message: String, - context: Context, - owner: LifecycleOwner, -) { - TextToSpeechHelper - .getInstance(context) - .registerLifecycle(owner) - .speak(message) - .highlight() - .onDone { Log.d("TextToSpeak", "speak: done") } - .onError { Log.d("TextToSpeak") { "speak error: $it" } } -} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/WatchNoteEvent.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/WatchNoteEvent.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/WatchNoteEvent.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/WatchNoteEvent.kt index cb435bf6d0..f1ed9fcc5c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/WatchNoteEvent.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/WatchNoteEvent.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.combinedClickable @@ -27,11 +27,11 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteHasEvent +import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderByParentFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteHasEvent -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.UserFinderByParentFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @OptIn(ExperimentalFoundationApi::class) @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapPollNote.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/ZapPollNote.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapPollNote.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/ZapPollNote.kt index e476f5e5df..eed14dbbde 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapPollNote.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/ZapPollNote.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween @@ -60,7 +60,6 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.clipRect -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.semantics.Role import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -69,7 +68,6 @@ import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Popup import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.EmptyTagList @@ -79,6 +77,7 @@ import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteZaps import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.error_dialog_zap_error import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_be_able_to_send_zaps @@ -89,9 +88,13 @@ import com.vitorpamplona.amethyst.commons.resources.poll_is_closed_explainer import com.vitorpamplona.amethyst.commons.resources.poll_unable_to_vote import com.vitorpamplona.amethyst.commons.resources.read_only_user import com.vitorpamplona.amethyst.commons.resources.zaps +import com.vitorpamplona.amethyst.commons.service.ZapPaymentHandler +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel import com.vitorpamplona.amethyst.commons.ui.components.toasts.StringToastMsg import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeToMessage import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.BigPadding import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange @@ -106,17 +109,15 @@ import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.ripple24dp import com.vitorpamplona.amethyst.commons.ui.theme.subtleBorder import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.service.ZapPaymentHandler -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteZaps -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.navigation.routes.routeToMessage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockVitorAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockVitorAccountViewModel import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent +import com.vitorpamplona.quartz.utils.BigDecimal import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext @@ -256,7 +257,7 @@ fun ZapPollNote( accountViewModel: AccountViewModel, nav: INav, ) { - val pollViewModel: PollNoteViewModel = viewModel(key = "PollNoteViewModel${baseNote.idHex}") + val pollViewModel: PollNoteViewModel = rememberViewModel(key = "PollNoteViewModel${baseNote.idHex}") { PollNoteViewModel() } pollViewModel.init(accountViewModel.account) pollViewModel.load(baseNote) @@ -544,7 +545,6 @@ fun ZapVote( var showErrorMessageDialog by remember { mutableStateOf(null) } - val context = LocalContext.current val scope = rememberCoroutineScope() nonClickablePrepend() @@ -595,7 +595,6 @@ fun ZapVote( accountViewModel.zapAmountChoices().first() * 1000, poolOption.option, "", - context, onError = { title, message, user -> zappingProgress = 0f showErrorMessageDialog = StringToastMsg(title, message) @@ -604,9 +603,9 @@ fun ZapVote( onPayViaIntent = { if (it.size == 1) { val payable = it.first() - payViaIntent(payable.invoice, context, noWalletFoundStr, { }) { error -> + if (!accountViewModel.host.openLightningWallet(payable.invoice)) { zappingProgress = 0f - showErrorMessageDialog = StringToastMsg(errorDialogZapErrorStr, error) + showErrorMessageDialog = StringToastMsg(errorDialogZapErrorStr, noWalletFoundStr) } } else { val uid = Uuid.random().toString() @@ -625,7 +624,6 @@ fun ZapVote( ), ) { if (wantsToZap) { - val context = LocalContext.current FilteredZapAmountChoicePopup( baseNote, accountViewModel, @@ -645,9 +643,9 @@ fun ZapVote( onPayViaIntent = { if (it.size == 1) { val payable = it.first() - payViaIntent(payable.invoice, context, noWalletFoundStr, { }) { error -> + if (!accountViewModel.host.openLightningWallet(payable.invoice)) { zappingProgress = 0f - showErrorMessageDialog = StringToastMsg(errorDialogZapErrorStr, error) + showErrorMessageDialog = StringToastMsg(errorDialogZapErrorStr, noWalletFoundStr) } } else { val uid = Uuid.random().toString() @@ -729,8 +727,6 @@ fun FilteredZapAmountChoicePopup( onProgress: (percent: Float) -> Unit, onPayViaIntent: (ImmutableList) -> Unit, ) { - val context = LocalContext.current - // TODO: Move this to the viewModel val zapPaymentChoices by accountViewModel.account.settings.syncedSettings.zaps.zapAmountChoices .collectAsStateWithLifecycle() @@ -747,7 +743,7 @@ fun FilteredZapAmountChoicePopup( ) { FlowRow(horizontalArrangement = Arrangement.Center) { sortedOptions.forEach { amountInSats -> - val zapAmount = remember { "⚡ ${showAmount(amountInSats.toBigDecimal().setScale(1))}" } + val zapAmount = remember { "⚡ ${showAmount(BigDecimal(amountInSats))}" } Button( modifier = Modifier.padding(horizontal = 3.dp), @@ -758,7 +754,6 @@ fun FilteredZapAmountChoicePopup( amountInSats * 1000, pollOption, zapMessage, - context, true, onError, onProgress, @@ -785,7 +780,6 @@ fun FilteredZapAmountChoicePopup( amountInSats * 1000, pollOption, zapMessage, - context, true, onError, onProgress, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapPollNoteViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/ZapPollNoteViewModel.kt similarity index 80% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapPollNoteViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/ZapPollNoteViewModel.kt index d8970b6b23..40c227567b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapPollNoteViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/ZapPollNoteViewModel.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note +package com.vitorpamplona.amethyst.commons.ui.note import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable @@ -26,23 +26,28 @@ import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent import com.vitorpamplona.quartz.nip57Zaps.ZapRequestEvent +import com.vitorpamplona.quartz.utils.BigDecimal import com.vitorpamplona.quartz.utils.TimeUtils +import com.vitorpamplona.quartz.utils.plus +import com.vitorpamplona.quartz.utils.toDoubleValue import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.launch -import java.math.BigDecimal -import java.math.RoundingMode +import kotlin.math.roundToLong + +private val ZERO = BigDecimal(0) @Stable data class PollOption( val option: Int, val descriptor: String, - var zappedValue: MutableState = mutableStateOf(BigDecimal.ZERO), + var zappedValue: MutableState = mutableStateOf(ZERO), var tally: MutableState = mutableFloatStateOf(0f), var consensusThreadhold: MutableState = mutableStateOf(false), var zappedByLoggedIn: MutableState = mutableStateOf(false), @@ -57,13 +62,11 @@ class PollNoteViewModel : ViewModel() { private var pollOptions: Map? = null private var valueMaximum: Long? = null private var valueMinimum: Long? = null - private var valueMaximumBD: BigDecimal? = null - private var valueMinimumBD: BigDecimal? = null private var closedAt: Long? = null - private var consensusThreshold: BigDecimal? = null + private var consensusThreshold: Double? = null - private var totalZapped: BigDecimal = BigDecimal.ZERO + private var totalZapped: BigDecimal = ZERO private var wasZappedByLoggedInAccount: Boolean = false var canZap = mutableStateOf(false) @@ -80,12 +83,10 @@ class PollNoteViewModel : ViewModel() { pollOptions = pollEvent?.pollOptions() valueMaximum = pollEvent?.maxAmount() valueMinimum = pollEvent?.minAmount() - valueMinimumBD = valueMinimum?.let { BigDecimal(it) } - valueMaximumBD = valueMaximum?.let { BigDecimal(it) } - consensusThreshold = pollEvent?.consensusThreshold()?.toBigDecimal() + consensusThreshold = pollEvent?.consensusThreshold() closedAt = pollEvent?.closedAt() - totalZapped = BigDecimal.ZERO + totalZapped = ZERO wasZappedByLoggedInAccount = false canZap.value = checkIfCanZap() @@ -108,16 +109,18 @@ class PollNoteViewModel : ViewModel() { tallies.forEach { val zappedValue = zappedPollOptionAmount(it.option) + val total = totalZapped.toDoubleValue() + // The share, rounded to two decimals. val tallyValue = - if (totalZapped > BigDecimal.ZERO) { - zappedValue.divide(totalZapped, 2, RoundingMode.HALF_UP) + if (total > 0) { + (zappedValue.toDoubleValue() / total * 100).roundToLong() / 100.0 } else { - BigDecimal.ZERO + 0.0 } it.zappedValue.value = zappedValue it.tally.value = tallyValue.toFloat() - it.consensusThreadhold.value = consensusThreshold != null && tallyValue >= consensusThreshold!! + it.consensusThreadhold.value = consensusThreshold?.let { threshold -> tallyValue >= threshold } == true it.zappedByLoggedIn.value = account.userProfile().let { it1 -> cachedIsPollOptionZappedBy(it.option, it1) } } } @@ -157,36 +160,16 @@ class PollNoteViewModel : ViewModel() { } fun isValidInputVoteAmount(amount: BigDecimal?): Boolean { - when { - amount == null -> { - return false - } - - valueMinimum == null && valueMaximum == null -> { - if (amount > BigDecimal.ZERO) { - return true - } - } - - valueMinimum == null -> { - if (amount > BigDecimal.ZERO && amount <= valueMaximumBD!!) { - return true - } - } - - valueMaximum == null -> { - if (amount >= valueMinimumBD!!) { - return true - } - } - - else -> { - if ((valueMinimumBD!! <= amount) && (amount <= valueMaximumBD!!)) { - return true - } - } + if (amount == null) return false + val sats = amount.toDoubleValue() + val min = valueMinimum + val max = valueMaximum + return when { + min == null && max == null -> sats > 0 + min == null -> sats > 0 && sats <= max!! + max == null -> sats >= min + else -> min <= sats && sats <= max } - return false } fun isValidInputVoteAmount(amount: Long?): Boolean { @@ -243,32 +226,32 @@ class PollNoteViewModel : ViewModel() { } private fun zappedPollOptionAmount(option: Int): BigDecimal = - pollNote?.zaps?.values?.sumOf { + pollNote?.zaps?.values?.fold(ZERO) { acc, it -> val event = it?.event as? ZapReceiptEvent - val zapAmount = event?.amount ?: BigDecimal.ZERO + val zapAmount = event?.amount ?: ZERO val isValidAmount = isValidInputVoteAmount(event?.amount) if (isValidAmount && event?.zappedPollOption() == option) { - zapAmount + acc + zapAmount } else { - BigDecimal.ZERO + acc } } - ?: BigDecimal.ZERO + ?: ZERO private fun totalZapped(): BigDecimal = - pollNote?.zaps?.values?.sumOf { + pollNote?.zaps?.values?.fold(ZERO) { acc, it -> val zapEvent = (it?.event as? ZapReceiptEvent) - val zapAmount = zapEvent?.amount ?: BigDecimal.ZERO + val zapAmount = zapEvent?.amount ?: ZERO val isValidAmount = isValidInputVoteAmount(zapEvent?.amount) if (isValidAmount && zapEvent?.zappedPollOption() != null) { - zapAmount + acc + zapAmount } else { - BigDecimal.ZERO + acc } } - ?: BigDecimal.ZERO + ?: ZERO fun createZapOptionsThatMatchThePollingParameters(zapPaymentChoices: List): List { val options = diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/ShowUserSuggestionList.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/creators/userSuggestions/ShowUserSuggestionList.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/ShowUserSuggestionList.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/creators/userSuggestions/ShowUserSuggestionList.kt index ee8e180270..eb380d73c8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/ShowUserSuggestionList.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/creators/userSuggestions/ShowUserSuggestionList.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.creators.userSuggestions +package com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -51,21 +51,22 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip05DnsIdentifiers.Nip05State +import com.vitorpamplona.amethyst.commons.relayClient.searchCommand.UserSearchDataSourceSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.user_suggestion_in_this_chat import com.vitorpamplona.amethyst.commons.ui.layouts.listItem.SlimListItem +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.ObserveAndRenderNIP05VerifiedSymbol +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.Font14SP import com.vitorpamplona.amethyst.commons.ui.theme.NIP05IconSize import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp import com.vitorpamplona.amethyst.commons.ui.theme.nip05 -import com.vitorpamplona.amethyst.service.relayClient.searchCommand.UserSearchDataSourceSubscription -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.ObserveAndRenderNIP05VerifiedSymbol -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.launch /** The dropdown's breathing room under the composer it floats over. */ diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/UserSuggestionState.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/creators/userSuggestions/UserSuggestionState.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/UserSuggestionState.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/creators/userSuggestions/UserSuggestionState.kt index 764d734442..826aa95971 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/UserSuggestionState.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/creators/userSuggestions/UserSuggestionState.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.creators.userSuggestions +package com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.runtime.Stable import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.input.TextFieldValue +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.relayClient.search.SearchQueryState -import com.vitorpamplona.amethyst.logTime -import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.commons.util.logTime import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.normalizeRelayUrlOrNull @@ -42,6 +42,7 @@ import com.vitorpamplona.quartz.utils.Hex import com.vitorpamplona.quartz.utils.startsWithAny import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.debounce diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/zapsplits/DisplayZapSplits.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/creators/zapsplits/DisplayZapSplits.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/zapsplits/DisplayZapSplits.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/creators/zapsplits/DisplayZapSplits.kt index 4c95a30a66..8976881979 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/zapsplits/DisplayZapSplits.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/creators/zapsplits/DisplayZapSplits.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.creators.zapsplits +package com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow @@ -29,12 +29,12 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.ZapSplitIcon import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip57Zaps.splits.ZapSplitSetup import com.vitorpamplona.quartz.nip57Zaps.splits.ZapSplitSetupLnAddress diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddHashtagLabelDialog.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/AddHashtagLabelDialog.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddHashtagLabelDialog.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/AddHashtagLabelDialog.kt index 4200433286..514074fd46 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/AddHashtagLabelDialog.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/AddHashtagLabelDialog.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.elements +package com.vitorpamplona.amethyst.commons.ui.note.elements import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.nip32Labeling.ui.HashtagLabelDialog -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * NIP-32: lets the user tag any post with a hashtag by publishing a kind 1985 label diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DefaultImageHeader.kt similarity index 89% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DefaultImageHeader.kt index e8e1698377..bb994411ee 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DefaultImageHeader.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DefaultImageHeader.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.elements +package com.vitorpamplona.amethyst.commons.ui.note.elements import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box @@ -28,23 +28,22 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.blur import androidx.compose.ui.layout.ContentScale -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserBanner import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for import com.vitorpamplona.amethyst.commons.resources.profile_banner +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage +import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.WatchAuthor +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.SimpleHeaderImage import com.vitorpamplona.amethyst.commons.ui.theme.Size16dp import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp import com.vitorpamplona.amethyst.commons.ui.theme.authorNotePictureForImageHeader -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserBanner -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.note.BaseUserPicture -import com.vitorpamplona.amethyst.ui.note.WatchAuthor -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun DefaultImageHeader( @@ -145,7 +144,7 @@ fun DefaultProfileBanner( sizeReference: Int, ) { Image( - painter = painterRes(R.drawable.profile_banner, sizeReference), + painter = painterRes(Res.drawable.profile_banner, sizeReference), contentDescription = stringRes(Res.string.profile_banner), contentScale = ContentScale.Crop, modifier = modifier, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayCommunity.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayCommunity.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayCommunity.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayCommunity.kt index 8a852796b3..2e127de7e2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayCommunity.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayCommunity.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.elements +package com.vitorpamplona.amethyst.commons.ui.note.elements import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -30,11 +30,11 @@ import androidx.compose.ui.text.style.TextOverflow import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextColor import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.lessImportantLink -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip72ModCommunities.communityAddress import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayEditStatus.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayEditStatus.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayEditStatus.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayEditStatus.kt index 8e048031cf..980832adbc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayEditStatus.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayEditStatus.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.elements +package com.vitorpamplona.amethyst.commons.ui.note.elements import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -26,8 +26,8 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.edited import com.vitorpamplona.amethyst.commons.resources.original import com.vitorpamplona.amethyst.commons.ui.note.QuietMark +import com.vitorpamplona.amethyst.commons.ui.note.types.EditState import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.note.types.EditState /** * Pencil marking an edited note; tapping cycles through the versions. The diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayHashtags.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayHashtags.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayHashtags.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayHashtags.kt index a695bb79e1..e20aea6b16 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayHashtags.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayHashtags.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.elements +package com.vitorpamplona.amethyst.commons.ui.note.elements import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -31,7 +31,7 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.FollowedHashtagLabel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.hashtags.firstIsTaggedHashes import com.vitorpamplona.quartz.nip22Comments.CommentEvent import com.vitorpamplona.quartz.nip73ExternalIds.topics.HashtagId diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayLocation.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayLocation.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayLocation.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayLocation.kt index 6701595a34..7d32d7def7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayLocation.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayLocation.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.elements +package com.vitorpamplona.amethyst.commons.ui.note.elements import androidx.compose.foundation.layout.widthIn import androidx.compose.runtime.Composable @@ -28,8 +28,8 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.HeaderPill -import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.note.platform.LoadCityName +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Compact pill showing the geohash a note is scoped to, resolved to a city diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayOts.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayOts.kt similarity index 89% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayOts.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayOts.kt index 40de13910d..64dcc8a61c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayOts.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayOts.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.elements +package com.vitorpamplona.amethyst.commons.ui.note.elements import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -28,13 +28,13 @@ import com.vitorpamplona.amethyst.commons.resources.ots_info_description import com.vitorpamplona.amethyst.commons.resources.ots_info_pending_description import com.vitorpamplona.amethyst.commons.resources.ots_info_title import com.vitorpamplona.amethyst.commons.resources.timestamp_pending_short +import com.vitorpamplona.amethyst.commons.ui.note.DateTimeStyle import com.vitorpamplona.amethyst.commons.ui.note.HeaderPill +import com.vitorpamplona.amethyst.commons.ui.note.LoadOts +import com.vitorpamplona.amethyst.commons.ui.note.formatDateTime import com.vitorpamplona.amethyst.commons.ui.note.timeAgoNoDot import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.note.LoadOts -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import java.text.SimpleDateFormat -import java.util.Date +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Compact pill showing the note's NIP-03 OpenTimestamps proof: how long ago @@ -60,7 +60,7 @@ fun DisplayOts( accountViewModel.toastManager.toast( Res.string.ots_info_title, Res.string.ots_info_description, - SimpleDateFormat.getDateTimeInstance().format(Date(unixtimestamp * 1000)), + formatDateTime(unixtimestamp * 1000, DateTimeStyle.MEDIUM, DateTimeStyle.MEDIUM), ) }, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayPoW.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayPoW.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayPoW.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayPoW.kt index 25c0870a11..01d67009af 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayPoW.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayPoW.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.elements +package com.vitorpamplona.amethyst.commons.ui.note.elements import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.pow_info_description import com.vitorpamplona.amethyst.commons.resources.pow_settings_title import com.vitorpamplona.amethyst.commons.ui.note.ProofOfWorkPill -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** Entry: the shared [ProofOfWorkPill], explaining the number in a toast when tapped. */ @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayReward.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayReward.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayReward.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayReward.kt index 50e02948d5..1b7c4ea8c0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayReward.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayReward.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.elements +package com.vitorpamplona.amethyst.commons.ui.note.elements import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -52,12 +52,14 @@ import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteReplies import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.bounty_label import com.vitorpamplona.amethyst.commons.resources.pledge_amount_in_sats +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel import com.vitorpamplona.amethyst.commons.ui.note.HeaderPill import com.vitorpamplona.amethyst.commons.ui.note.buttons.CloseButton import com.vitorpamplona.amethyst.commons.ui.note.buttons.PostButton @@ -65,12 +67,12 @@ import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteReplies -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.quartz.utils.BigDecimal +import com.vitorpamplona.quartz.utils.parseBigDecimalOrNull import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.launch -import java.math.BigDecimal @Stable data class Reward( val amount: BigDecimal, @@ -150,7 +152,7 @@ class AddBountyAmountViewModel : ViewModel() { } fun sendPost() { - val newValue = nextAmount.text.trim().toBigDecimalOrNull() + val newValue = parseBigDecimalOrNull(nextAmount.text.trim()) if (newValue != null) { viewModelScope.launch(Dispatchers.IO) { @@ -181,7 +183,7 @@ fun AddBountyAmountDialog( accountViewModel: AccountViewModel, onClose: () -> Unit, ) { - val postViewModel: AddBountyAmountViewModel = viewModel() + val postViewModel: AddBountyAmountViewModel = rememberViewModel { AddBountyAmountViewModel() } postViewModel.load(accountViewModel.account, bounty) val scope = rememberCoroutineScope() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayUncitedHashtags.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayUncitedHashtags.kt index 6669563d50..d7fb6836fc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DisplayUncitedHashtags.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.elements +package com.vitorpamplona.amethyst.commons.ui.note.elements import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow @@ -34,7 +34,7 @@ import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextColor import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.HalfTopPadding import com.vitorpamplona.amethyst.commons.ui.theme.lessImportantLink -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DropDownMenu.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DropDownMenu.kt index 313da6e77e..6e33b82272 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DropDownMenu.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/DropDownMenu.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.elements +package com.vitorpamplona.amethyst.commons.ui.note.elements import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable @@ -40,20 +40,21 @@ import com.vitorpamplona.amethyst.commons.ui.components.M3ActionDialog import com.vitorpamplona.amethyst.commons.ui.components.M3ActionRow import com.vitorpamplona.amethyst.commons.ui.components.M3ActionSection import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeEditDraftTo +import com.vitorpamplona.amethyst.commons.ui.note.QuickActionAlertDialog import com.vitorpamplona.amethyst.commons.ui.note.VerticalDotsIcon +import com.vitorpamplona.amethyst.commons.ui.note.deletionRequestBody +import com.vitorpamplona.amethyst.commons.ui.note.platform.EditPostView +import com.vitorpamplona.amethyst.commons.ui.note.types.EditState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.report.ReportNoteDialog import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size24Modifier -import com.vitorpamplona.amethyst.ui.actions.EditPostView -import com.vitorpamplona.amethyst.ui.navigation.routes.routeEditDraftTo -import com.vitorpamplona.amethyst.ui.note.QuickActionAlertDialog -import com.vitorpamplona.amethyst.ui.note.deletionRequestBody -import com.vitorpamplona.amethyst.ui.note.types.EditState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.report.ReportNoteDialog +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.aTag.isTaggedAddressableNote import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent import com.vitorpamplona.quartz.nip36SensitiveContent.isSensitiveOrNSFW import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.onStart diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ForkInfo.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/ForkInfo.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ForkInfo.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/ForkInfo.kt index 943141e3ee..04ad29dadd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ForkInfo.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/ForkInfo.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.elements +package com.vitorpamplona.amethyst.commons.ui.note.elements import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -27,16 +27,16 @@ import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.forked_from +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.note.QuietMark import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.forks.IForkableEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/NoteActionSections.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/NoteActionSections.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/NoteActionSections.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/NoteActionSections.kt index 7d6719b11b..ee96d5b253 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/NoteActionSections.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/NoteActionSections.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.elements +package com.vitorpamplona.amethyst.commons.ui.note.elements import androidx.compose.material3.ButtonDefaults import androidx.compose.runtime.Composable @@ -72,18 +72,19 @@ import com.vitorpamplona.amethyst.commons.resources.unfollow import com.vitorpamplona.amethyst.commons.resources.unpin_from_profile import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.QuickActionAlertDialogOneButton +import com.vitorpamplona.amethyst.commons.ui.note.copyNoteTextAction import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.LightRedColor -import com.vitorpamplona.amethyst.ui.note.QuickActionAlertDialogOneButton -import com.vitorpamplona.amethyst.ui.note.copyNoteTextAction -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.util.toPrettyJson +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.music.track.MusicTrackEvent -import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip23LongContent.LongFormContentEvent import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -210,7 +211,7 @@ fun noteActionSections( val event = note.event if (event != null) { scope.launch { - val json = withContext(Dispatchers.Default) { JacksonMapper.toJsonPretty(event) } + val json = withContext(Dispatchers.Default) { event.toPrettyJson() } clipboardManager.setText(json) handlers.onDismiss() } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ShareActions.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/ShareActions.kt similarity index 85% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ShareActions.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/ShareActions.kt index 7a9b54fd06..0acba72e70 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ShareActions.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/ShareActions.kt @@ -18,11 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.elements +package com.vitorpamplona.amethyst.commons.ui.note.elements -import android.content.Intent import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note @@ -34,9 +32,10 @@ import com.vitorpamplona.amethyst.commons.resources.share_as_image import com.vitorpamplona.amethyst.commons.resources.share_as_image_url import com.vitorpamplona.amethyst.commons.resources.share_as_qr import com.vitorpamplona.amethyst.commons.ui.components.M3ActionRow +import com.vitorpamplona.amethyst.commons.ui.components.rememberTextSharer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.externalLinkForNote import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.note.externalLinkForNote /** * The shared Share rows used by the [ShareOptionsBottomSheet] drawer (opened @@ -59,21 +58,13 @@ fun ShareActionRows( ) { val quickActionShareBrowserLinkStr = stringRes(Res.string.quick_action_share_browser_link) val quickActionShareStr = stringRes(Res.string.quick_action_share) - val actContext = LocalContext.current + val sharer = rememberTextSharer() // AddressableNotes are shared by their replaceable address; everything else // by event id. The two image routes resolve the note from this same id. val shareId = if (note is AddressableNote) note.address.toValue() else note.idHex M3ActionRow(icon = MaterialSymbols.Share, text = stringRes(Res.string.quick_action_share)) { - val sendIntent = - Intent().apply { - action = Intent.ACTION_SEND - type = "text/plain" - putExtra(Intent.EXTRA_TEXT, externalLinkForNote(note)) - putExtra(Intent.EXTRA_TITLE, quickActionShareBrowserLinkStr) - } - val shareIntent = Intent.createChooser(sendIntent, quickActionShareStr) - actContext.startActivity(shareIntent) + sharer.share(externalLinkForNote(note), quickActionShareBrowserLinkStr, quickActionShareStr) onDismiss() } M3ActionRow(icon = MaterialSymbols.Image, text = stringRes(Res.string.share_as_image)) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ShareOptionsBottomSheet.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/ShareOptionsBottomSheet.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ShareOptionsBottomSheet.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/ShareOptionsBottomSheet.kt index d19adb6045..08d2069ff8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ShareOptionsBottomSheet.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/elements/ShareOptionsBottomSheet.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.elements +package com.vitorpamplona.amethyst.commons.ui.note.elements import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/DisplayCommentScope.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/nip22Comments/DisplayCommentScope.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/DisplayCommentScope.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/nip22Comments/DisplayCommentScope.kt index f1bdd4f091..4cb10e9b39 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/DisplayCommentScope.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/nip22Comments/DisplayCommentScope.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.nip22Comments +package com.vitorpamplona.amethyst.commons.ui.note.nip22Comments import androidx.compose.foundation.layout.Spacer import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip22Comments.CommentEvent import com.vitorpamplona.quartz.nip72ModCommunities.topLevelCommunityAddress import com.vitorpamplona.quartz.nip73ExternalIds.scope diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/DisplayCommunityScope.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/nip22Comments/DisplayCommunityScope.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/DisplayCommunityScope.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/nip22Comments/DisplayCommunityScope.kt index 2d652edbab..2b4925c359 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/DisplayCommunityScope.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/nip22Comments/DisplayCommunityScope.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.nip22Comments +package com.vitorpamplona.amethyst.commons.ui.note.nip22Comments import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.padding @@ -29,9 +29,9 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.types.ShortCommunityHeaderNoActions import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.note.types.ShortCommunityHeaderNoActions -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/DisplayExternalId.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/nip22Comments/DisplayExternalId.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/DisplayExternalId.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/nip22Comments/DisplayExternalId.kt index 5f1e9b9626..bede6f558a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/DisplayExternalId.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/nip22Comments/DisplayExternalId.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.nip22Comments +package com.vitorpamplona.amethyst.commons.ui.note.nip22Comments import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -48,11 +48,11 @@ import com.vitorpamplona.amethyst.commons.resources.external_url_scope import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewCard import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.platform.rememberUrlPreviewState import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.components.rememberUrlPreviewState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip73ExternalIds.ExternalId import com.vitorpamplona.quartz.nip73ExternalIds.location.GeohashId import com.vitorpamplona.quartz.nip73ExternalIds.topics.HashtagId diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/DisplayGeoHashExternalId.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/nip22Comments/DisplayGeoHashExternalId.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/DisplayGeoHashExternalId.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/nip22Comments/DisplayGeoHashExternalId.kt index 47c11a2e53..50940cb536 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/DisplayGeoHashExternalId.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/nip22Comments/DisplayGeoHashExternalId.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.nip22Comments +package com.vitorpamplona.amethyst.commons.ui.note.nip22Comments import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -42,11 +42,11 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.geohash_exclusive import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.platform.LoadCityName import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip73ExternalIds.location.GeohashId @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/DisplayHashtagExternalId.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/nip22Comments/DisplayHashtagExternalId.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/DisplayHashtagExternalId.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/nip22Comments/DisplayHashtagExternalId.kt index 1166fa439b..7540b060bc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/DisplayHashtagExternalId.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/nip22Comments/DisplayHashtagExternalId.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.nip22Comments +package com.vitorpamplona.amethyst.commons.ui.note.nip22Comments import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.nip73ExternalIds.ui.HashtagExternalIdCard import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip73ExternalIds.topics.HashtagId @Composable diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/platform/NotePlatform.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/platform/NotePlatform.kt new file mode 100644 index 0000000000..ab6e88a774 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/platform/NotePlatform.kt @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.note.platform + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.Stable +import androidx.compose.runtime.State +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Rect +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.TextUnit +import com.vitorpamplona.amethyst.commons.audio.WaveformData +import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.richtext.BaseMediaContent +import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable +import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewState +import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.CalendarRsvpCard +import com.vitorpamplona.amethyst.commons.ui.note.types.EditState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.quartz.nip52Calendar.rsvp.CalendarRSVPEvent +import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag +import com.vitorpamplona.quartz.podcasts.PodcastAudio +import kotlinx.collections.immutable.ImmutableList + +/** + * The platform halves of the shared note renderer: what a note card needs that only the front end + * can draw or do. Media players and the zoomable viewer, maps and reverse geocoding, the note types + * built on a platform engine (audio players, chess, the git browser, meeting rooms, napplets), the + * reactions/zap row with its wallet hand-offs, and the post editor. + * + * The shared note code calls these through [LocalNotePlatform]; a front end installs its own at the + * composition root (Android does in its theme). Every member defaults to drawing nothing, so a + * preview, or a front end still wiring a piece, gets an empty slot rather than a crash. + */ +@Stable +interface NotePlatform { + // Media + + @Composable + fun ZoomableContentView( + content: BaseMediaContent, + images: ImmutableList, + roundedCorner: Boolean, + contentScale: ContentScale, + accountViewModel: AccountViewModel, + ) {} + + @Composable + fun ZoomableImageDialog( + imageUrl: BaseMediaContent, + allImages: ImmutableList, + sourceBounds: Rect?, + onDismiss: () -> Unit, + accountViewModel: AccountViewModel, + ) {} + + @Composable + fun GifVideoView( + videoUri: String, + contentDescription: String?, + dimensions: DimensionTag?, + blurhash: String?, + roundedCorner: Boolean, + contentScale: ContentScale, + onDialog: (() -> Unit)?, + accountViewModel: AccountViewModel, + thumbhash: String?, + ) {} + + @Composable + fun VideoView( + videoUri: String, + mimeType: String?, + title: String?, + artworkUri: String?, + authorName: String?, + roundedCorner: Boolean, + contentScale: ContentScale, + nostrUriCallback: String?, + isLiveStream: Boolean, + accountViewModel: AccountViewModel, + ) {} + + /** The link card for [url]: OpenGraph preview, inline media, or a plain link. */ + @Composable + fun UrlPreview( + url: String, + urlText: String, + callbackUri: String?, + accountViewModel: AccountViewModel, + nav: INav?, + ) {} + + /** The OpenGraph preview of [url], starting from the platform's cache. */ + @Composable + fun rememberUrlPreviewState( + url: String, + accountViewModel: AccountViewModel, + ): UrlPreviewState = UrlPreviewState.Loading + + /** + * Starts loading the OpenGraph preview of [url] into the platform's cache ahead of display, + * unless it is already there. Not composable: feed prefetchers call it from a coroutine. + */ + fun warmUrlPreview( + url: String, + accountViewModel: AccountViewModel, + ) {} + + // Places + + @Composable + fun LocationPreviewMap( + latitude: Double, + longitude: Double, + aspectRatio: Float, + pinColor: Color?, + pinEmoji: String?, + pinAlpha: Float, + ) {} + + /** Resolves [geohashStr] to a place name for [content], showing [onLoading] meanwhile. */ + @Composable + fun LoadCityName( + geohashStr: String, + onLoading: (@Composable () -> Unit)?, + content: @Composable (String) -> Unit, + ) {} + + // Audio + + @Composable + fun RenderAudioHeader( + note: Note, + contentScale: ContentScale, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun RenderAudioTrack( + note: Note, + contentScale: ContentScale, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun RenderMusicTrack( + note: Note, + makeItShort: Boolean, + canPreview: Boolean, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun PodcastEpisodeAudioPlayer( + audio: PodcastAudio, + note: Note, + title: String?, + image: String?, + borderModifier: Modifier, + accountViewModel: AccountViewModel, + ) {} + + @Composable + fun RenderVoiceTrack( + note: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun RenderAudioFromIMeta( + note: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun RenderAudioWithWaveform( + mediaUrl: String, + title: String?, + mimeType: String?, + waveform: WaveformData?, + note: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + // Chess + + @Composable + fun RenderChessGame( + note: Note, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun RenderLiveChessChallenge( + note: Note, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun RenderLiveChessGameEnd( + note: Note, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + // Git + + @Composable + fun RenderGitRepositoryEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun RenderGitPatchEvent( + baseNote: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun RenderGitIssueEvent( + baseNote: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun RenderGitPullRequestEvent( + baseNote: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun RenderGitPullRequestUpdateEvent( + baseNote: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + // Calendar + + /** + * A NIP-52 RSVP with the appointment it answers merged into its frame. Draws the bare + * [com.vitorpamplona.amethyst.commons.ui.note.CalendarRsvpCard] by default: the appointment + * half still uses the platform's calendar formatting. + */ + @Composable + fun RenderCalendarRSVPEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) { + val event = baseNote.event as? CalendarRSVPEvent ?: return + CalendarRsvpCard(event) + } + + // Meeting rooms (audio spaces) + + @Composable + fun RenderMeetingSpaceEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun RenderMeetingRoomEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun RenderMeetingRoomPresence( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + // Napplets and nsites + + @Composable + fun RenderRootNappletEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun RenderNamedNappletEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun RenderRootSiteEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun RenderNamedSiteEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + // Reactions, zaps and editing + + @Composable + fun ReactionsRow( + baseNote: Note, + showReactionDetail: Boolean, + addPadding: Boolean, + editState: State>?, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + @Composable + fun LikeReaction( + baseNote: Note, + grayTint: Color, + accountViewModel: AccountViewModel, + nav: INav, + iconSize: Dp, + heartSizeModifier: Modifier, + iconFontSize: TextUnit, + showCounter: Boolean, + ) {} + + @Composable + fun ZapReaction( + baseNote: Note, + grayTint: Color, + accountViewModel: AccountViewModel, + iconSize: Dp, + iconSizeModifier: Modifier, + animationModifier: Modifier, + showCounter: Boolean, + nav: INav, + ) {} + + /** The editor for a new version of [edit], shown while [versionLookingAt] is on screen. */ + @Composable + fun EditPostView( + onClose: () -> Unit, + edit: Note, + versionLookingAt: Note?, + accountViewModel: AccountViewModel, + nav: INav, + ) {} + + /** Draws nothing: previews, and front ends still wiring their pieces. */ + object None : NotePlatform +} + +/** The front end's [NotePlatform]. Static: it is set once at the root and never changes. */ +val LocalNotePlatform = staticCompositionLocalOf { NotePlatform.None } diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/platform/NotePlatformCalls.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/platform/NotePlatformCalls.kt new file mode 100644 index 0000000000..00b25ef085 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/platform/NotePlatformCalls.kt @@ -0,0 +1,564 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.note.platform + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.State +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Rect +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.TextUnit +import com.vitorpamplona.amethyst.commons.audio.WaveformData +import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.richtext.BaseMediaContent +import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable +import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewState +import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.types.EditState +import com.vitorpamplona.amethyst.commons.ui.theme.Font14SP +import com.vitorpamplona.amethyst.commons.ui.theme.Size14Modifier +import com.vitorpamplona.amethyst.commons.ui.theme.Size18Modifier +import com.vitorpamplona.amethyst.commons.ui.theme.Size18dp +import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier +import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag +import com.vitorpamplona.quartz.podcasts.PodcastAudio +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf + +// Call-site shims for [NotePlatform]: the same names and defaults the app's own composables have, +// so shared note code reads as it did and only its imports point here. + +@Composable +fun ZoomableContentView( + content: BaseMediaContent, + images: ImmutableList = remember(content) { persistentListOf(content) }, + roundedCorner: Boolean, + contentScale: ContentScale, + accountViewModel: AccountViewModel, +) = LocalNotePlatform.current.ZoomableContentView( + content = content, + images = images, + roundedCorner = roundedCorner, + contentScale = contentScale, + accountViewModel = accountViewModel, +) + +@Composable +fun ZoomableImageDialog( + imageUrl: BaseMediaContent, + allImages: ImmutableList = remember(imageUrl) { persistentListOf(imageUrl) }, + sourceBounds: Rect? = null, + onDismiss: () -> Unit, + accountViewModel: AccountViewModel, +) = LocalNotePlatform.current.ZoomableImageDialog( + imageUrl = imageUrl, + allImages = allImages, + sourceBounds = sourceBounds, + onDismiss = onDismiss, + accountViewModel = accountViewModel, +) + +@Composable +fun GifVideoView( + videoUri: String, + contentDescription: String?, + dimensions: DimensionTag?, + blurhash: String?, + roundedCorner: Boolean, + contentScale: ContentScale, + onDialog: (() -> Unit)? = null, + accountViewModel: AccountViewModel, + thumbhash: String? = null, +) = LocalNotePlatform.current.GifVideoView( + videoUri = videoUri, + contentDescription = contentDescription, + dimensions = dimensions, + blurhash = blurhash, + roundedCorner = roundedCorner, + contentScale = contentScale, + onDialog = onDialog, + accountViewModel = accountViewModel, + thumbhash = thumbhash, +) + +@Composable +fun VideoView( + videoUri: String, + mimeType: String?, + title: String? = null, + artworkUri: String? = null, + authorName: String? = null, + roundedCorner: Boolean, + contentScale: ContentScale, + nostrUriCallback: String? = null, + isLiveStream: Boolean = false, + accountViewModel: AccountViewModel, +) = LocalNotePlatform.current.VideoView( + videoUri = videoUri, + mimeType = mimeType, + title = title, + artworkUri = artworkUri, + authorName = authorName, + roundedCorner = roundedCorner, + contentScale = contentScale, + nostrUriCallback = nostrUriCallback, + isLiveStream = isLiveStream, + accountViewModel = accountViewModel, +) + +@Composable +fun LoadUrlPreview( + url: String, + urlText: String, + callbackUri: String? = null, + accountViewModel: AccountViewModel, + nav: INav? = null, +) = LocalNotePlatform.current.UrlPreview( + url = url, + urlText = urlText, + callbackUri = callbackUri, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun LocationPreviewMap( + latitude: Double, + longitude: Double, + aspectRatio: Float = 1f, + pinColor: Color? = null, + pinEmoji: String? = null, + pinAlpha: Float = 1f, +) = LocalNotePlatform.current.LocationPreviewMap( + latitude = latitude, + longitude = longitude, + aspectRatio = aspectRatio, + pinColor = pinColor, + pinEmoji = pinEmoji, + pinAlpha = pinAlpha, +) + +@Composable +fun LoadCityName( + geohashStr: String, + onLoading: (@Composable () -> Unit)? = null, + content: @Composable (String) -> Unit, +) = LocalNotePlatform.current.LoadCityName( + geohashStr = geohashStr, + onLoading = onLoading, + content = content, +) + +@Composable +fun RenderAudioTrack( + note: Note, + contentScale: ContentScale, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderAudioTrack( + note = note, + contentScale = contentScale, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderMusicTrack( + note: Note, + makeItShort: Boolean, + canPreview: Boolean, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderMusicTrack( + note = note, + makeItShort = makeItShort, + canPreview = canPreview, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun PodcastEpisodeAudioPlayer( + audio: PodcastAudio, + note: Note, + title: String?, + image: String?, + borderModifier: Modifier, + accountViewModel: AccountViewModel, +) = LocalNotePlatform.current.PodcastEpisodeAudioPlayer( + audio = audio, + note = note, + title = title, + image = image, + borderModifier = borderModifier, + accountViewModel = accountViewModel, +) + +@Composable +fun RenderVoiceTrack( + note: Note, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderVoiceTrack( + note = note, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderAudioFromIMeta( + note: Note, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderAudioFromIMeta( + note = note, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderAudioWithWaveform( + mediaUrl: String, + title: String?, + mimeType: String?, + waveform: WaveformData?, + note: Note, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderAudioWithWaveform( + mediaUrl = mediaUrl, + title = title, + mimeType = mimeType, + waveform = waveform, + note = note, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderChessGame( + note: Note, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderChessGame( + note = note, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderLiveChessChallenge( + note: Note, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderLiveChessChallenge( + note = note, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderLiveChessGameEnd( + note: Note, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderLiveChessGameEnd( + note = note, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderGitRepositoryEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderGitRepositoryEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderGitPatchEvent( + baseNote: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderGitPatchEvent( + baseNote = baseNote, + makeItShort = makeItShort, + canPreview = canPreview, + quotesLeft = quotesLeft, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderGitIssueEvent( + baseNote: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderGitIssueEvent( + baseNote = baseNote, + makeItShort = makeItShort, + canPreview = canPreview, + quotesLeft = quotesLeft, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderGitPullRequestEvent( + baseNote: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderGitPullRequestEvent( + baseNote = baseNote, + makeItShort = makeItShort, + canPreview = canPreview, + quotesLeft = quotesLeft, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderGitPullRequestUpdateEvent( + baseNote: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderGitPullRequestUpdateEvent( + baseNote = baseNote, + makeItShort = makeItShort, + canPreview = canPreview, + quotesLeft = quotesLeft, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderCalendarRSVPEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderCalendarRSVPEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderMeetingSpaceEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderMeetingSpaceEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderMeetingRoomEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderMeetingRoomEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderMeetingRoomPresence( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderMeetingRoomPresence( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderRootNappletEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderRootNappletEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderNamedNappletEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderNamedNappletEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderRootSiteEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderRootSiteEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun RenderNamedSiteEvent( + baseNote: Note, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderNamedSiteEvent( + baseNote = baseNote, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun ReactionsRow( + baseNote: Note, + showReactionDetail: Boolean, + addPadding: Boolean, + editState: State>?, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.ReactionsRow( + baseNote = baseNote, + showReactionDetail = showReactionDetail, + addPadding = addPadding, + editState = editState, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun LikeReaction( + baseNote: Note, + grayTint: Color, + accountViewModel: AccountViewModel, + nav: INav, + iconSize: Dp = Size18dp, + heartSizeModifier: Modifier = Size18Modifier, + iconFontSize: TextUnit = Font14SP, + showCounter: Boolean = true, +) = LocalNotePlatform.current.LikeReaction( + baseNote = baseNote, + grayTint = grayTint, + accountViewModel = accountViewModel, + nav = nav, + iconSize = iconSize, + heartSizeModifier = heartSizeModifier, + iconFontSize = iconFontSize, + showCounter = showCounter, +) + +@Composable +fun ZapReaction( + baseNote: Note, + grayTint: Color, + accountViewModel: AccountViewModel, + iconSize: Dp = Size20dp, + iconSizeModifier: Modifier = Size20Modifier, + animationModifier: Modifier = Size14Modifier, + showCounter: Boolean = true, + nav: INav, +) = LocalNotePlatform.current.ZapReaction( + baseNote = baseNote, + grayTint = grayTint, + accountViewModel = accountViewModel, + iconSize = iconSize, + iconSizeModifier = iconSizeModifier, + animationModifier = animationModifier, + showCounter = showCounter, + nav = nav, +) + +@Composable +fun EditPostView( + onClose: () -> Unit, + edit: Note, + versionLookingAt: Note?, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.EditPostView( + onClose = onClose, + edit = edit, + versionLookingAt = versionLookingAt, + accountViewModel = accountViewModel, + nav = nav, +) + +@Composable +fun rememberUrlPreviewState( + url: String, + accountViewModel: AccountViewModel, +): UrlPreviewState = LocalNotePlatform.current.rememberUrlPreviewState(url, accountViewModel) + +@Composable +fun RenderAudioHeader( + note: Note, + contentScale: ContentScale, + accountViewModel: AccountViewModel, + nav: INav, +) = LocalNotePlatform.current.RenderAudioHeader(note, contentScale, accountViewModel, nav) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/AppDefinition.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/AppDefinition.kt index 2369f4f58f..a08fbba7dc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/AppDefinition.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image @@ -77,11 +77,11 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil3.compose.AsyncImage -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.EmptyTagList import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_definition_available_on import com.vitorpamplona.amethyst.commons.resources.app_definition_by @@ -102,25 +102,24 @@ import com.vitorpamplona.amethyst.commons.resources.profile_banner import com.vitorpamplona.amethyst.commons.resources.profile_image import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture import com.vitorpamplona.amethyst.commons.ui.note.LinkIcon +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.platform.ZoomableImageDialog +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.KindChip +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.kindDisplayName import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size16Modifier import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.components.ZoomableImageDialog -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.BaseUserPicture -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser -import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.KindChip -import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.kindDisplayName +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.application.SoftwareApplicationEvent import com.vitorpamplona.quartz.experimental.nipsOnNostr.NipTextEvent import com.vitorpamplona.quartz.kinds.KindNames @@ -134,6 +133,7 @@ import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppMetadata import com.vitorpamplona.quartz.nip89AppHandlers.definition.tags.SupportedNipTag import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -193,7 +193,7 @@ fun RenderAppDefinition( } } else { Image( - painter = painterRes(R.drawable.profile_banner, 6), + painter = painterRes(Res.drawable.profile_banner, 6), contentDescription = stringRes(id = Res.string.profile_banner), contentScale = ContentScale.FillWidth, modifier = diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppRecommendation.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/AppRecommendation.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppRecommendation.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/AppRecommendation.kt index 9d11acf61e..ebc75e57df 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppRecommendation.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/AppRecommendation.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -38,15 +38,15 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.profile_app_recommendations_title import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.profile.header.apps.AppRecommendationChip +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.KindChip import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header.apps.AppRecommendationChip -import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.KindChip +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip89AppHandlers.recommendation.AppRecommendationEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Attestation.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Attestation.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Attestation.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Attestation.kt index 9b891d7f10..7088cfd7c8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Attestation.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Attestation.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -44,7 +44,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -69,22 +68,23 @@ import com.vitorpamplona.amethyst.commons.resources.attestation_valid_to import com.vitorpamplona.amethyst.commons.resources.attestor_proficiency import com.vitorpamplona.amethyst.commons.resources.attestor_recommendation import com.vitorpamplona.amethyst.commons.resources.attestor_recommendation_for_kinds +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.DateTimeStyle +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.note.UserCompose +import com.vitorpamplona.amethyst.commons.ui.note.formatDateTime +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.KindChip import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.note.UserCompose -import com.vitorpamplona.amethyst.ui.note.formatMediumDate -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.KindChip +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.experimental.attestations.attestation.AttestationEvent import com.vitorpamplona.quartz.experimental.attestations.attestation.tags.AttestationStatus import com.vitorpamplona.quartz.experimental.attestations.proficiency.AttestorProficiencyEvent @@ -199,19 +199,18 @@ fun RenderAttestation( } if (validFrom != null || validTo != null) { - val context = LocalContext.current Spacer(modifier = DoubleVertSpacer) Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { validFrom?.let { Text( - text = stringRes(Res.string.attestation_valid_from, formatMediumDate(it, context)), + text = stringRes(Res.string.attestation_valid_from, formatDateTime(it * 1000, DateTimeStyle.MEDIUM, DateTimeStyle.NONE)), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) } validTo?.let { Text( - text = stringRes(Res.string.attestation_valid_to, formatMediumDate(it, context)), + text = stringRes(Res.string.attestation_valid_to, formatDateTime(it * 1000, DateTimeStyle.MEDIUM, DateTimeStyle.NONE)), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/AudioMetaExt.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/AudioMetaExt.kt new file mode 100644 index 0000000000..d55302fb24 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/AudioMetaExt.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.note.types + +import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.quartz.nip92IMeta.imetas +import com.vitorpamplona.quartz.nipA0VoiceMessages.AudioMeta + +/** + * Extracts AudioMeta from an event's IMeta tags if it has audio content with waveform. + * Returns the first audio IMeta that has a waveform, or null if none found. + */ +fun Event.getAudioMetaWithWaveform(): AudioMeta? { + val audioMetas = imetas().map { AudioMeta.parse(it) } + return audioMetas.firstOrNull { meta -> + meta.waveform != null && + (meta.mimeType == null || meta.mimeType?.startsWith("audio/") == true) + } +} + +/** + * Checks if the event content is primarily an audio attachment (content is just the audio URL). + */ +fun Event.isAudioOnlyContent(): Boolean { + val audioMeta = getAudioMetaWithWaveform() ?: return false + return content.trim() == audioMeta.url +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Badge.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Badge.kt index d90b4644cc..a5fbe331e0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Badge.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -64,6 +64,7 @@ import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.accept_badge import com.vitorpamplona.amethyst.commons.resources.award_badge @@ -77,13 +78,12 @@ import com.vitorpamplona.amethyst.commons.resources.reject_badge import com.vitorpamplona.amethyst.commons.resources.unaccept_badge import com.vitorpamplona.amethyst.commons.ui.components.RobohashAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size30dp import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip58Badges.accepted.AcceptedBadgeSetEvent import com.vitorpamplona.quartz.nip58Badges.award.BadgeAwardEvent import com.vitorpamplona.quartz.nip58Badges.definition.BadgeDefinitionEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Bolt12ZapEvent.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Bolt12ZapEvent.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Bolt12ZapEvent.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Bolt12ZapEvent.kt index 0decfa1fa6..13bf7db86b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Bolt12ZapEvent.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Bolt12ZapEvent.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.size import androidx.compose.material3.MaterialTheme @@ -33,15 +33,15 @@ import com.vitorpamplona.amethyst.commons.ui.note.ActivityAmountRow import com.vitorpamplona.amethyst.commons.ui.note.ActivityBadge import com.vitorpamplona.amethyst.commons.ui.note.ActivityCardFrame import com.vitorpamplona.amethyst.commons.ui.note.ActivityHeaderRow +import com.vitorpamplona.amethyst.commons.ui.note.CrossfadeToDisplayComment +import com.vitorpamplona.amethyst.commons.ui.note.DisplayBlankAuthor +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.note.ZapIcon import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp import com.vitorpamplona.amethyst.commons.ui.theme.bitcoinColor -import com.vitorpamplona.amethyst.ui.note.CrossfadeToDisplayComment -import com.vitorpamplona.amethyst.ui.note.DisplayBlankAuthor -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.util.PlatformNumberFormatter +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nipB1Bolt12Zaps.zap.Bolt12ZapEvent -import java.text.NumberFormat /** * Standalone card for a NIP-B1 BOLT12 zap (kind 9736), styled like the NIP-57 @@ -91,7 +91,7 @@ fun RenderBolt12Zap( RenderZappedPost(note, quotesLeft, cardBackground, accountViewModel, nav) - amountSats?.let { ActivityAmountRow(NumberFormat.getNumberInstance().format(it), orange) } + amountSats?.let { ActivityAmountRow(PlatformNumberFormatter().format(it), orange) } comment?.let { CrossfadeToDisplayComment(it, cardBackground, nav, accountViewModel) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CalendarCollectionRender.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/CalendarCollectionRender.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CalendarCollectionRender.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/CalendarCollectionRender.kt index 22b1fa72c6..53989e371a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CalendarCollectionRender.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/CalendarCollectionRender.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.CalendarCollectionCard -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip52Calendar.calendar.CalendarCollectionEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CalendarEvent.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/CalendarEvent.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CalendarEvent.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/CalendarEvent.kt index 6bd57addf6..3b51535a6f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CalendarEvent.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/CalendarEvent.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -40,22 +40,21 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.DateTimeStyle +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeader +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeaderBackground +import com.vitorpamplona.amethyst.commons.ui.note.formatDateTime import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeaderBackground -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip52Calendar.appt.day.CalendarDateSlotEvent import com.vitorpamplona.quartz.nip52Calendar.appt.time.CalendarTimeSlotEvent -import java.text.DateFormat -import java.text.SimpleDateFormat -import java.util.Date @Composable fun RenderCalendarTimeSlotEvent( @@ -239,11 +238,9 @@ private fun formatTimestampRange( end: Long?, ): String? { if (start == null) return null - val formatter = SimpleDateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT) - val startStr = formatter.format(Date(start * 1000)) + val startStr = formatDateTime(start * 1000, DateTimeStyle.MEDIUM, DateTimeStyle.SHORT) return if (end != null && end != start) { - val endFormatter = SimpleDateFormat.getTimeInstance(DateFormat.SHORT) - "$startStr – ${endFormatter.format(Date(end * 1000))}" + "$startStr – ${formatDateTime(end * 1000, DateTimeStyle.NONE, DateTimeStyle.SHORT)}" } else { startStr } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CalendarRsvpRow.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/CalendarRsvpRow.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CalendarRsvpRow.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/CalendarRsvpRow.kt index b3b9a80dd7..e9dc798b5e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CalendarRsvpRow.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/CalendarRsvpRow.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -26,7 +26,7 @@ import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.nip52Calendar.ui.CalendarRsvpButtons -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.events.ETag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChannelInvite.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ChannelInvite.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChannelInvite.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ChannelInvite.kt index de7e2355be..a61db6bb9e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChannelInvite.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ChannelInvite.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -53,9 +53,11 @@ import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil3.compose.AsyncImage import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.model.buzz.toMembershipNotice import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.add_to_messages import com.vitorpamplona.amethyst.commons.resources.channel_invite_added_you @@ -66,16 +68,14 @@ import com.vitorpamplona.amethyst.commons.resources.relay_group_badge_invite_onl import com.vitorpamplona.amethyst.commons.resources.relay_group_badge_private import com.vitorpamplona.amethyst.commons.resources.relay_group_member_count import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.ObserveAndDrawInnerUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size22dp import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.model.buzz.toMembershipNotice -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.ui.note.ObserveAndDrawInnerUserPicture -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import com.vitorpamplona.quartz.nip29RelayGroups.GroupId @@ -87,7 +87,7 @@ private val RosterFaceSize = 19.dp /** * The body of a "somebody added you to a channel" row (kind 44100). * - * Only the body: the row itself is an ordinary [com.vitorpamplona.amethyst.ui.note.NoteCompose], so the + * Only the body: the row itself is an ordinary [com.vitorpamplona.amethyst.commons.ui.note.NoteCompose], so the * author header, overflow menu, reaction bar, last-read background and click-through all come from the * same code every other notification uses. * diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChannelMessage.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ChannelMessage.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChannelMessage.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ChannelMessage.kt index bc048ea0f5..c504d1f42b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChannelMessage.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ChannelMessage.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding @@ -32,10 +32,10 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.PublicChatChannelHeader import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.PublicChatChannelHeader +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Chat.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Chat.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Chat.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Chat.kt index 55e2bcc6a9..5127725c1e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Chat.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Chat.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -34,14 +34,14 @@ import com.vitorpamplona.amethyst.commons.model.EmptyTagList import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.nip92IMeta.appendMissingImetaUrls import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.ReplyNoteComposition +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayUncitedHashtags import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.note.ReplyNoteComposition -import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags import com.vitorpamplona.quartz.nip10Notes.BaseNoteEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChatMessage.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ChatMessage.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChatMessage.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ChatMessage.kt index 28615c3db0..05a6f9de6a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChatMessage.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ChatMessage.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding @@ -35,11 +35,11 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.privateDM.header.ChatroomHeader import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.header.ChatroomHeader +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChatMessageEncryptedFile.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ChatMessageEncryptedFile.kt similarity index 87% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChatMessageEncryptedFile.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ChatMessageEncryptedFile.kt index e0ee74d808..ef8faf2f54 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ChatMessageEncryptedFile.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ChatMessageEncryptedFile.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Spacer @@ -35,15 +35,15 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.RenderEncryptedFile +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.privateDM.header.ChatroomHeader import com.vitorpamplona.amethyst.commons.ui.theme.HalfVertPadding import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.RenderEncryptedFile -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.header.ChatroomHeader +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Citation.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Citation.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Citation.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Citation.kt index d324734c97..668f9c04b9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Citation.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Citation.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -43,15 +43,15 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.ui.components.ClickableUrlOrBlossom +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.richtext.LocalRichTextPlatform import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.components.ClickableUrl -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.components.markdown.RenderContentAsMarkdown -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.citations.CitationEvent import com.vitorpamplona.quartz.experimental.citations.ExternalCitationEvent import com.vitorpamplona.quartz.experimental.citations.HardcopyCitationEvent @@ -126,7 +126,7 @@ fun RenderCitation( url?.let { Spacer(Modifier.padding(top = Size5dp)) - ClickableUrl(urlText = it, url = it) + ClickableUrlOrBlossom(urlText = it, url = it) } } @@ -137,7 +137,7 @@ fun RenderCitation( // A prompt citation's body is the prompt itself, which the reference implementation // renders as Markdown; the other two carry a plain note. if (noteEvent is PromptCitationEvent) { - RenderContentAsMarkdown( + LocalRichTextPlatform.current.Markdown( content = noteEvent.content, tags = tags, canPreview = canPreview && !makeItShort, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Classifieds.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Classifieds.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Classifieds.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Classifieds.kt index 6c4e230095..83c58773fa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Classifieds.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Classifieds.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.border import androidx.compose.foundation.layout.Column @@ -40,17 +40,18 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage +import com.vitorpamplona.amethyst.commons.ui.components.AutoNonlazyGrid import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeader +import com.vitorpamplona.amethyst.commons.ui.note.platform.ZoomableContentView import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.commons.ui.theme.SmallBorder import com.vitorpamplona.amethyst.commons.ui.theme.subtleBorder import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.ui.components.AutoNonlazyGrid -import com.vitorpamplona.amethyst.ui.components.ZoomableContentView -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent +import com.vitorpamplona.quartz.utils.parseBigDecimalOrNull import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList @@ -137,7 +138,7 @@ fun RenderClassifieds( val priceTag = remember(noteEvent) { val newAmount = - price.amount.toBigDecimalOrNull()?.let { showAmount(it) } + parseBigDecimalOrNull(price.amount)?.let { showAmount(it) } ?: price.amount if (price.frequency != null && price.currency != null) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/CommunityHeader.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/CommunityHeader.kt index 95c20d0123..1a72b7bfdc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/CommunityHeader.kt @@ -18,9 +18,8 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types -import android.content.Intent import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -48,7 +47,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow @@ -64,6 +62,7 @@ import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.about_us import com.vitorpamplona.amethyst.commons.resources.community_no_descriptor @@ -77,8 +76,23 @@ import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for import com.vitorpamplona.amethyst.commons.resources.profile_image import com.vitorpamplona.amethyst.commons.resources.quick_action_share import com.vitorpamplona.amethyst.commons.resources.quick_action_share_browser_link +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage +import com.vitorpamplona.amethyst.commons.ui.components.RichTextViewer import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer +import com.vitorpamplona.amethyst.commons.ui.components.rememberTextSharer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.NoteAuthorPicture +import com.vitorpamplona.amethyst.commons.ui.note.NoteUsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeader +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeaderBackground +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayUncitedHashtags +import com.vitorpamplona.amethyst.commons.ui.note.externalLinkForNote +import com.vitorpamplona.amethyst.commons.ui.note.platform.LikeReaction +import com.vitorpamplona.amethyst.commons.ui.note.platform.ZapReaction import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder @@ -94,22 +108,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.innerPostModifier import com.vitorpamplona.amethyst.commons.util.equalImmutableLists -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.components.RichTextViewer -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.LikeReaction -import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture -import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.ZapReaction -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeaderBackground -import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags -import com.vitorpamplona.amethyst.ui.note.externalLinkForNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent import com.vitorpamplona.quartz.nip72ModCommunities.definition.tags.ModeratorTag @@ -542,27 +541,11 @@ fun ShareCommunityButton( ) { val quickActionShareBrowserLinkStr = stringRes(Res.string.quick_action_share_browser_link) val quickActionShareStr = stringRes(Res.string.quick_action_share) - val actContext = LocalContext.current + val sharer = rememberTextSharer() FilledTonalIconButton( onClick = { - val sendIntent = - Intent().apply { - action = Intent.ACTION_SEND - type = "text/plain" - putExtra( - Intent.EXTRA_TEXT, - externalLinkForNote(note), - ) - putExtra( - Intent.EXTRA_TITLE, - quickActionShareBrowserLinkStr, - ) - } - - val shareIntent = - Intent.createChooser(sendIntent, quickActionShareStr) - actContext.startActivity(shareIntent) + sharer.share(externalLinkForNote(note), quickActionShareBrowserLinkStr, quickActionShareStr) }, ) { Icon( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ContactList.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ContactList.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ContactList.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ContactList.kt index 19754e5a98..bf6ca8f7d1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ContactList.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ContactList.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -40,12 +40,12 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.contact_list_containing_label import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.GalleryUnloaded import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.SpacedBy5dp import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.note.GalleryUnloaded -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CyberspaceBag.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/CyberspaceBag.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CyberspaceBag.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/CyberspaceBag.kt index 1490ae1cde..59c2e2911d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CyberspaceBag.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/CyberspaceBag.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -67,7 +67,7 @@ import com.vitorpamplona.amethyst.commons.ui.note.SnoObjectCard import com.vitorpamplona.amethyst.commons.ui.note.SnoObjectUnreadableCard import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.cyberspace.CyberspaceBagContents import com.vitorpamplona.quartz.cyberspace.CyberspaceBagEvent import com.vitorpamplona.quartz.cyberspace.CyberspaceBagItem diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Emoji.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Emoji.kt index d65958b79d..0cd86c39c5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Emoji.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -48,16 +48,16 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteAndMap +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.ui.components.AddButton import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled import com.vitorpamplona.amethyst.commons.ui.components.RemoveButton +import com.vitorpamplona.amethyst.commons.ui.components.ShowMoreButton +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.getGradient import com.vitorpamplona.amethyst.commons.ui.theme.Size35Modifier -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteAndMap -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.components.ShowMoreButton -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.getGradient -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.aTag.isTaggedAddressableNote import com.vitorpamplona.quartz.nip30CustomEmoji.EmojiUrlTag import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/EntityRating.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/EntityRating.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/EntityRating.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/EntityRating.kt index af8149cfad..b1c4be6212 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/EntityRating.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/EntityRating.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -58,10 +58,18 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for import com.vitorpamplona.amethyst.commons.resources.rating_stars_out_of_five +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp @@ -69,15 +77,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size18dp import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.publications.PublicationIndexEvent import com.vitorpamplona.quartz.experimental.ratings.EntityRatingEvent import com.vitorpamplona.quartz.experimental.ratings.RatingMark diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ExternalReaction.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ExternalReaction.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ExternalReaction.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ExternalReaction.kt index 397ccddb2a..fd74dd3b88 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ExternalReaction.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ExternalReaction.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth @@ -33,20 +33,20 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.ui.components.ClickableUrlOrBlossom import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.ActivityBadge import com.vitorpamplona.amethyst.commons.ui.note.ActivityCardFrame import com.vitorpamplona.amethyst.commons.ui.note.ActivityHeaderRow +import com.vitorpamplona.amethyst.commons.ui.note.DisplayBlankAuthor import com.vitorpamplona.amethyst.commons.ui.note.LikeTint import com.vitorpamplona.amethyst.commons.ui.note.LikedIcon +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.ui.components.ClickableUrl -import com.vitorpamplona.amethyst.ui.note.DisplayBlankAuthor -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip25Reactions.ExternalReactionEvent -import com.vitorpamplona.amethyst.ui.note.RenderReaction as RenderReactionEmoji +import com.vitorpamplona.amethyst.commons.ui.note.RenderReaction as RenderReactionEmoji /** * Renders a kind-17 reaction — NIP-25's form for reacting to something that is **not** a nostr @@ -96,7 +96,7 @@ fun RenderExternalReaction( if (target != null) { Column(Modifier.fillMaxWidth().padding(top = 6.dp)) { if (url != null) { - ClickableUrl(urlText = url, url = url) + ClickableUrlOrBlossom(urlText = url, url = url) } else { // An ISBN or a podcast GUID is an identifier, not a link; show it as text // rather than as something that looks tappable and does nothing. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FavoriteFollowSetToggle.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/FavoriteFollowSetToggle.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FavoriteFollowSetToggle.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/FavoriteFollowSetToggle.kt index 6979d181a4..7c7c4ece6b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FavoriteFollowSetToggle.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/FavoriteFollowSetToggle.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable @@ -34,7 +34,7 @@ import com.vitorpamplona.amethyst.commons.resources.remove_follow_set_from_favor import com.vitorpamplona.amethyst.commons.ui.components.ClickableBox import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.AddressBookmark /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileHeader.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/FileHeader.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileHeader.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/FileHeader.kt index a494d9b9b3..822bd79bda 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileHeader.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/FileHeader.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.runtime.Composable import androidx.compose.runtime.remember @@ -31,9 +31,9 @@ import com.vitorpamplona.amethyst.commons.richtext.MediaUrlPdf import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.commons.ui.components.FileAttachmentCard -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.components.ZoomableContentView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning +import com.vitorpamplona.amethyst.commons.ui.note.platform.ZoomableContentView +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip94FileMetadata.FileMetadataEvent @@ -72,7 +72,7 @@ fun FileMetadataDisplay( * video event the kind itself asserts nothing about how to render the payload. A null here means * the file belongs in [FileMetadataAttachmentCard] rather than being pushed into the video player. */ -internal fun FileMetadataEvent.toMediaContent( +fun FileMetadataEvent.toMediaContent( note: Note, url: String, mimeType: String?, @@ -128,7 +128,7 @@ internal fun FileMetadataEvent.toMediaContent( /** The link card a kind-1063 header falls back to when [toMediaContent] returns null. */ @Composable -internal fun FileMetadataAttachmentCard( +fun FileMetadataAttachmentCard( event: FileMetadataEvent, url: String, mimeType: String?, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileStorage.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/FileStorage.kt similarity index 89% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileStorage.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/FileStorage.kt index 5b8108f14f..10ecc08deb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileStorage.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/FileStorage.kt @@ -18,27 +18,26 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.layout.ContentScale -import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.richtext.BaseMediaContent import com.vitorpamplona.amethyst.commons.richtext.MediaLocalImage import com.vitorpamplona.amethyst.commons.richtext.MediaLocalVideo import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.components.ZoomableContentView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning +import com.vitorpamplona.amethyst.commons.ui.note.platform.ZoomableContentView +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.nip95.header.FileStorageHeaderEvent import com.vitorpamplona.quartz.nip31Alts.alt -import java.io.File @Composable fun FileStorageHeaderDisplay( @@ -74,7 +73,7 @@ private fun ObserverAndRenderNIP95( // Creates a new object when the event arrives to force an update of the image. val note = noteState.note val uri = header.toNostrUri() - val localDir = note.idHex.let { File(Amethyst.instance.nip95cache, it) } + val localDir = LocalCache.appHost.nip95Blobs?.path(note.idHex) val blurHash = eventHeader.blurhash() val thumbHash = eventHeader.thumbhash() val dimensions = eventHeader.dimensions() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Fundraiser.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Fundraiser.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Fundraiser.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Fundraiser.kt index 3a34469f92..3db490b29c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Fundraiser.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Fundraiser.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box @@ -37,7 +37,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalClipboard -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -48,19 +47,19 @@ import com.vitorpamplona.amethyst.commons.resources.copy_to_clipboard import com.vitorpamplona.amethyst.commons.resources.fundraiser_ends import com.vitorpamplona.amethyst.commons.resources.fundraiser_onchain_donation import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.CopyIcon +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeader +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeaderBackground +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayUncitedHashtags import com.vitorpamplona.amethyst.commons.ui.note.timeAheadNoDot import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size18Modifier import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeaderBackground -import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.agora.FundraiserEvent import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.launch @@ -129,7 +128,6 @@ fun RenderFundraiser( deadline?.let { if (it > TimeUtils.now()) { - val context = LocalContext.current Spacer(Modifier.height(6.dp)) Text( text = stringRes(Res.string.fundraiser_ends, timeAheadNoDot(it)), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Geocache.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Geocache.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Geocache.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Geocache.kt index 11b3217698..8b40aa0277 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Geocache.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Geocache.kt @@ -18,25 +18,25 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.model.location.LocationResult +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.geocache_nearby import com.vitorpamplona.amethyst.commons.service.georelay.GeoRelayDirectory import com.vitorpamplona.amethyst.commons.ui.note.FoundLogProof import com.vitorpamplona.amethyst.commons.ui.note.GeocacheCard import com.vitorpamplona.amethyst.commons.ui.note.GeocacheFoundLogCard +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.platform.LocationPreviewMap import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.location.LocationState -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.creators.location.LocationPreviewMap -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.geohash.toGeoHash import com.vitorpamplona.quartz.nipCCGeocaching.foundLog.GeocacheFoundLogEvent import com.vitorpamplona.quartz.nipCCGeocaching.listing.GeocacheListingEvent @@ -97,7 +97,7 @@ fun distanceToCache( noteEvent: GeocacheListingEvent, accountViewModel: AccountViewModel, ): String? { - val here = accountViewModel.account.geolocationFlow().value as? LocationState.LocationResult.Success ?: return null + val here = accountViewModel.account.geolocationFlow().value as? LocationResult.Success ?: return null val nearby = stringRes(Res.string.geocache_nearby) @@ -116,7 +116,7 @@ fun distanceToCache( /** * A distance formatted no finer than its source can support. * - * The reader's position comes from [LocationState.geohashStateFlow], which is a **5-character + * The reader's position comes from `LocationState.geohashStateFlow`, which is a **5-character * geohash** — a 4.89km × 4.89km cell — so the centroid this measures from can be ~3.5km from * where the reader is standing. Printing metres off that would be fiction: someone standing at * the cache would read "3 km", and a cache 2km away could read "120 m". Anything inside one diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Goal.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Goal.kt similarity index 85% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Goal.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Goal.kt index 7d6c699e66..d71da1b009 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Goal.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Goal.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -44,26 +44,27 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.model.ZapraiserStatus +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteZaps import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.goal_closed import com.vitorpamplona.amethyst.commons.resources.goal_progress import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeader +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeaderBackground import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Font14SP import com.vitorpamplona.amethyst.commons.ui.theme.fundraiserProgressColor import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteZaps -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.note.ZapraiserStatus -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeaderBackground -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip75ZapGoals.ZapGoalEvent +import com.vitorpamplona.quartz.utils.BigDecimal import com.vitorpamplona.quartz.utils.TimeUtils -import java.math.BigDecimal import kotlin.math.roundToInt +import com.vitorpamplona.amethyst.commons.model.zapraiserStatus as computeZapraiserStatus @Composable fun RenderGoal( @@ -149,23 +150,11 @@ fun GoalProgressBar( val zapsState by observeNoteZaps(note, accountViewModel) var zapraiserStatus by - remember { mutableStateOf(ZapraiserStatus(0F, showAmount(goalAmountSats.toBigDecimal()))) } + remember { mutableStateOf(ZapraiserStatus(0F, showAmount(BigDecimal(goalAmountSats)))) } LaunchedEffect(key1 = zapsState) { zapsState?.note?.let { - val newZapAmount = accountViewModel.account.zaps.calculateZappedAmount(note) - var percentage = newZapAmount.div(goalAmountSats.toBigDecimal()).toFloat() - if (percentage > 1) percentage = 1f - - val left = - if (percentage > 0.99) { - "0" - } else { - showAmount( - goalAmountSats.toBigDecimal() * BigDecimal(1.0 - percentage), - ) - } - zapraiserStatus = ZapraiserStatus(percentage, left) + zapraiserStatus = computeZapraiserStatus(accountViewModel.account.zaps.calculateZappedAmount(note), goalAmountSats) } } @@ -193,7 +182,7 @@ fun GoalProgressBar( stringRes( Res.string.goal_progress, totalPercentage, - showAmount(goalAmountSats.toBigDecimal()), + showAmount(BigDecimal(goalAmountSats)), ), fontSize = Font14SP, maxLines = 1, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Highlight.kt similarity index 85% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Highlight.kt index 5418504ac7..fef242fe65 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Highlight.kt @@ -18,9 +18,8 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types -import android.net.Uri import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi @@ -51,27 +50,27 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.highlights.HighlightQuote import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary +import com.vitorpamplona.amethyst.commons.ui.components.ClickableUrlOrBlossom +import com.vitorpamplona.amethyst.commons.ui.components.CreateClickableTextWithEmoji +import com.vitorpamplona.amethyst.commons.ui.components.RenderUserAsClickableText +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer +import com.vitorpamplona.amethyst.commons.ui.components.measureSpaceWidth +import com.vitorpamplona.amethyst.commons.ui.components.rememberTranslation import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.note.HighlightQuoteIndent import com.vitorpamplona.amethyst.commons.ui.note.HighlightQuoteSpacing import com.vitorpamplona.amethyst.commons.ui.note.HighlightedQuote +import com.vitorpamplona.amethyst.commons.ui.note.nip22Comments.DisplayExternalId import com.vitorpamplona.amethyst.commons.ui.richtext.CreateClickableTextWithEmoji +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.kindName import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.ui.components.ClickableUrl -import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji -import com.vitorpamplona.amethyst.ui.components.RenderUserAsClickableText -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.components.measureSpaceWidth -import com.vitorpamplona.amethyst.ui.components.rememberTranslation -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.nip22Comments.DisplayExternalId -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.kindName +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.firstTagValueFor import com.vitorpamplona.quartz.nip01Core.tags.events.ETag @@ -79,10 +78,12 @@ import com.vitorpamplona.quartz.nip01Core.tags.references.HttpUrlFormatter import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent import com.vitorpamplona.quartz.nip73ExternalIds.ExternalId import com.vitorpamplona.quartz.nip84Highlights.HighlightEvent +import com.vitorpamplona.quartz.nip84Highlights.parse.TextFragmentParser import com.vitorpamplona.quartz.utils.Log +import com.vitorpamplona.quartz.utils.Rfc3986 import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.withContext -import java.net.URL @Composable fun RenderHighlight( @@ -267,46 +268,6 @@ fun DisplayHighlight( } } -private const val FRAGMENT_EDGE_WORDS = 4 - -/** - * Builds a URL with a Text Fragment (`#:~:text=`) directive that scrolls the source page - * to the highlighted text. When a W3C `textquoteselector` supplies surrounding prefix/suffix - * text, a few words of each are added as `prefix-,` / `,-suffix` disambiguators so the browser - * lands on the correct occurrence even when the quote repeats on the page. - * - * See https://wicg.github.io/scroll-to-text-fragment/ - */ -private fun buildTextFragmentUrl( - baseUrl: String, - exact: String, - prefix: String?, - suffix: String?, -): String { - val separator = if (baseUrl.contains("#")) "&" else "#" - - val prefixPart = trimToFragmentEdge(prefix, keepStart = false)?.let { "${Uri.encode(it)}-," } ?: "" - val suffixPart = trimToFragmentEdge(suffix, keepStart = true)?.let { ",-${Uri.encode(it)}" } ?: "" - - return "$baseUrl$separator:~:text=$prefixPart${Uri.encode(exact)}$suffixPart" -} - -/** - * Keeps only the [FRAGMENT_EDGE_WORDS] words nearest the highlight (the last words when - * [keepStart] is false, for a prefix; the first words when true, for a suffix) and collapses - * whitespace so newlines from the selector don't break Text Fragment matching. - */ -private fun trimToFragmentEdge( - text: String?, - keepStart: Boolean, -): String? { - if (text == null) return null - val words = text.trim().split(Regex("\\s+")).filter { it.isNotEmpty() } - if (words.isEmpty()) return null - val slice = if (keepStart) words.take(FRAGMENT_EDGE_WORDS) else words.takeLast(FRAGMENT_EDGE_WORDS) - return slice.joinToString(" ") -} - @Composable private fun DisplayQuoteAuthor( highlightQuote: String, @@ -378,7 +339,7 @@ private fun DisplayQuoteAuthor( baseUrl != null && HighlightEvent.isUrlReference(baseUrl) -> { val url = remember(baseUrl, highlightQuote, textFragmentPrefix, textFragmentSuffix) { - buildTextFragmentUrl(HttpUrlFormatter.addSchemeIfNeeded(baseUrl), highlightQuote, textFragmentPrefix, textFragmentSuffix) + TextFragmentParser.buildUrl(HttpUrlFormatter.addSchemeIfNeeded(baseUrl), highlightQuote, textFragmentPrefix, textFragmentSuffix) } DisplayEntryForAUrl(url, userBase, accountViewModel, nav) @@ -502,17 +463,17 @@ fun DisplayEntryForAUrl( val validatedUrl = remember(url) { try { - URL(url) + Rfc3986.host(url) } catch (_: Exception) { Log.w("Note Compose") { "Invalid URI: $url" } null } } - validatedUrl?.host?.let { host -> + validatedUrl?.let { host -> if (userBase != null) { Text("-", maxLines = 1) } - ClickableUrl(urlText = host, url = url) + ClickableUrlOrBlossom(urlText = host, url = url) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/InteractiveStory.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/InteractiveStory.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/InteractiveStory.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/InteractiveStory.kt index f3e3d65512..93cdb28c50 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/InteractiveStory.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/InteractiveStory.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -40,16 +40,16 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.EmptyTagList import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.restart +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.interactiveStories.InteractiveStoryBaseEvent import com.vitorpamplona.quartz.experimental.interactiveStories.InteractiveStoryReadingStateEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Library.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Library.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Library.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Library.kt index 18d383e4b4..b529519195 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Library.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Library.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -56,6 +56,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.library_blossom_piece import com.vitorpamplona.amethyst.commons.resources.library_directory @@ -69,19 +70,18 @@ import com.vitorpamplona.amethyst.commons.richtext.MediaUrlPdf import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.commons.ui.components.FileAttachmentCard +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayUncitedHashtags +import com.vitorpamplona.amethyst.commons.ui.note.platform.ZoomableContentView import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier import com.vitorpamplona.amethyst.commons.util.countToHumanReadableBytes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.components.ZoomableContentView -import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.library.BlossomPieceIndexEvent import com.vitorpamplona.quartz.experimental.library.BookshelfDirectoryEvent import com.vitorpamplona.quartz.experimental.library.LearningResourceEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/LiveActivity.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/LiveActivity.kt index 599b5b6438..64d5846e32 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/LiveActivity.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box @@ -40,8 +40,9 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.text.capitalize import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -51,32 +52,32 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.LiveFlag import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.ScheduledFlag +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.live_stream_has_ended import com.vitorpamplona.amethyst.commons.resources.live_stream_is_offline import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for +import com.vitorpamplona.amethyst.commons.ui.components.CheckIfVideoIsOnline +import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeCheckIfVideoIsOnline import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.DisplayAuthorBanner +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeader +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeaderBackground +import com.vitorpamplona.amethyst.commons.ui.note.platform.VideoView import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.util.equalImmutableLists -import com.vitorpamplona.amethyst.service.playback.composable.VideoView -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.DisplayAuthorBanner -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeaderBackground -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CheckIfVideoIsOnline -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CrossfadeCheckIfVideoIsOnline -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.ParticipantTag @@ -85,6 +86,7 @@ import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext @@ -276,8 +278,6 @@ fun RenderLiveActivityEventInner( } } - val locale = LocalConfiguration.current.locales.get(0) - participantUsers.forEach { Row( verticalAlignment = Alignment.CenterVertically, @@ -293,9 +293,7 @@ fun RenderLiveActivityEventInner( it.first.role?.let { Text( text = - it.replaceFirstChar { - if (it.isLowerCase()) it.titlecase(locale) else it.toString() - }, + it.capitalize(Locale.current), color = MaterialTheme.colorScheme.placeholderText, maxLines = 1, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivityChatMessage.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/LiveActivityChatMessage.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivityChatMessage.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/LiveActivityChatMessage.kt index a1c4297b06..05261a7fc3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivityChatMessage.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/LiveActivityChatMessage.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding @@ -32,11 +32,11 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadLiveActivityChannel +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header.LiveActivitiesChannelHeader import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.note.LoadLiveActivityChannel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header.LiveActivitiesChannelHeader +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessageEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/LongForm.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/LongForm.kt index 53f70af9d0..8d5d5fff0f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LongForm.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/LongForm.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -51,20 +51,20 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.long_form_reading_minutes import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.NoteUsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.WatchAuthor +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeader +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeaderBackground import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgo import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Font10SP import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.note.BaseUserPicture -import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay -import com.vitorpamplona.amethyst.ui.note.WatchAuthor -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeaderBackground -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip23LongContent.LongFormContentEvent import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MedicalData.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/MedicalData.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MedicalData.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/MedicalData.kt index fc6298c657..ca3ef144df 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MedicalData.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/MedicalData.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -56,16 +56,15 @@ import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.util.DecimalPatternFormatter +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.medical.FhirResourceEvent import com.vitorpamplona.quartz.nip01Core.core.Event import kotlinx.collections.immutable.ImmutableMap import kotlinx.collections.immutable.toImmutableMap import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.withContext -import java.text.DecimalFormat -import java.text.NumberFormat -import java.util.Locale import kotlin.math.abs @Preview @@ -258,7 +257,7 @@ fun RenderEyeGlassesPrescription( visionPrescription.status?.let { Text( text = "Status: ${it.replaceFirstChar { - if (it.isLowerCase()) it.titlecase(Locale.ROOT) else it.toString() + if (it.isLowerCase()) it.titlecase() else it.toString() }}", modifier = Modifier.padding(4.dp).fillMaxWidth(), ) @@ -350,9 +349,9 @@ fun RenderEyeGlassesPrescriptionHeaderRow() { @Composable fun RenderEyeGlassesPrescriptionRow(data: LensSpecification) { - val numberFormat = DecimalFormat("##.00") - val pdFormat = DecimalFormat("##.0") - val integerFormat = DecimalFormat("###") + val numberFormat = DecimalPatternFormatter("##.00") + val pdFormat = DecimalPatternFormatter("##.0") + val integerFormat = DecimalPatternFormatter("###") Row( modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Min), @@ -362,7 +361,7 @@ fun RenderEyeGlassesPrescriptionRow(data: LensSpecification) { Text( text = data.eye?.replaceFirstChar { - if (it.isLowerCase()) it.titlecase(Locale.ROOT) else it.toString() + if (it.isLowerCase()) it.titlecase() else it.toString() } ?: "Unknown", modifier = Modifier.padding(4.dp).weight(1f), ) @@ -510,8 +509,8 @@ fun RenderEyeContactsPrescriptionHeaderRow() { @Composable fun RenderEyeContactsPrescriptionRow(data: LensSpecification) { - val numberFormat = DecimalFormat("##.00") - val integerFormat = DecimalFormat("###") + val numberFormat = DecimalPatternFormatter("##.00") + val integerFormat = DecimalPatternFormatter("###") Row( modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Min), @@ -521,7 +520,7 @@ fun RenderEyeContactsPrescriptionRow(data: LensSpecification) { Text( text = data.eye?.replaceFirstChar { - if (it.isLowerCase()) it.titlecase(Locale.ROOT) else it.toString() + if (it.isLowerCase()) it.titlecase() else it.toString() } ?: "Unknown", modifier = Modifier.padding(4.dp).weight(1f), ) @@ -626,7 +625,7 @@ fun RenderEyeContactsPrescriptionRow(data: LensSpecification) { fun formatOrBlank( amount: Double?, - numberFormat: NumberFormat, + numberFormat: DecimalPatternFormatter, ): String { if (amount == null) return "" if (abs(amount) < 0.01) return "" diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MeetingSpace.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/MeetingSpace.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MeetingSpace.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/MeetingSpace.kt index 163b3bbc5d..3e435e4a64 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MeetingSpace.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/MeetingSpace.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -29,6 +29,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -40,17 +41,20 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.text.capitalize import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.core.net.toUri import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.LiveFlag import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.ScheduledFlag +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.meeting_room_in_space import com.vitorpamplona.amethyst.commons.resources.meeting_room_in_space_unknown @@ -67,24 +71,30 @@ import com.vitorpamplona.amethyst.commons.resources.nest_presence_listening import com.vitorpamplona.amethyst.commons.resources.nest_presence_on_stage import com.vitorpamplona.amethyst.commons.resources.nest_presence_raised_hand import com.vitorpamplona.amethyst.commons.resources.nest_presence_speaking +import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeCheckIfVideoIsOnline import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.DateTimeStyle +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.formatDateTime +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.nests.room.lobby.JoinNestButton import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.SmallBorder import com.vitorpamplona.amethyst.commons.ui.theme.SpacedBy5dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.util.equalImmutableLists -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CrossfadeCheckIfVideoIsOnline +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingRoomEvent import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent +import com.vitorpamplona.quartz.nip53LiveActivities.presence.MeetingRoomPresenceEvent import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.ParticipantTag import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.StatusTag +import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.tags.StatusTag as MeetingSpaceStatusTag @@ -193,7 +203,7 @@ fun RenderMeetingSpaceEventInner( ListenToRecordingButton(url = it, accountViewModel = accountViewModel) } } else { - com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.lobby.JoinNestButton( + JoinNestButton( event = noteEvent, nav = nav, ) @@ -213,17 +223,10 @@ private fun ListenToRecordingButton( url: String, accountViewModel: AccountViewModel, ) { - val context = androidx.compose.ui.platform.LocalContext.current + val uriHandler = LocalUriHandler.current val noAppMessage = stringRes(Res.string.nest_no_app_to_open_link) - androidx.compose.material3.OutlinedButton(onClick = { - val launched = - runCatching { - context.startActivity( - android.content - .Intent(android.content.Intent.ACTION_VIEW, url.toUri()) - .addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK), - ) - }.isSuccess + OutlinedButton(onClick = { + val launched = runCatching { uriHandler.openUri(url) }.isSuccess if (!launched) { accountViewModel.toastManager.toast( Res.string.nest_chat_send_failed_title, @@ -332,13 +335,13 @@ fun RenderMeetingRoomEventInner( */ @Composable private fun ParentMeetingSpaceLink( - spaceAddress: com.vitorpamplona.quartz.nip01Core.core.Address, + spaceAddress: Address, accountViewModel: AccountViewModel, nav: INav, ) { if (spaceAddress.kind != MeetingSpaceEvent.KIND) return - com.vitorpamplona.amethyst.ui.note.LoadAddressableNote( + LoadAddressableNote( address = spaceAddress, ) { spaceNote -> spaceNote ?: return@LoadAddressableNote @@ -354,7 +357,7 @@ private fun ParentMeetingSpaceLink( .fillMaxWidth() .clickable { nav.nav { - com.vitorpamplona.amethyst.ui.navigation.routes.routeFor( + com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor( spaceNote, accountViewModel.account, ) @@ -390,7 +393,7 @@ fun RenderMeetingRoomPresence( accountViewModel: AccountViewModel, nav: INav, ) { - val event = baseNote.event as? com.vitorpamplona.quartz.nip53LiveActivities.presence.MeetingRoomPresenceEvent ?: return + val event = baseNote.event as? MeetingRoomPresenceEvent ?: return val handRaised = remember(event) { event.handRaised() == true } val publishing = remember(event) { event.publishing() == true } @@ -407,7 +410,7 @@ fun RenderMeetingRoomPresence( val user = remember(event.pubKey) { - com.vitorpamplona.amethyst.commons.model.cache.LocalCache + LocalCache .getOrCreateUser(event.pubKey) } @@ -458,8 +461,6 @@ private fun RenderParticipants( } } - val locale = LocalConfiguration.current.locales.get(0) - participantUsers.forEach { Row( verticalAlignment = Alignment.CenterVertically, @@ -475,9 +476,7 @@ private fun RenderParticipants( it.first.role?.let { Text( text = - it.replaceFirstChar { - if (it.isLowerCase()) it.titlecase(locale) else it.toString() - }, + it.capitalize(Locale.current), color = MaterialTheme.colorScheme.placeholderText, maxLines = 1, ) @@ -564,13 +563,11 @@ fun MeetingSpacePlannedFlag( .padding(horizontal = 5.dp) }, ) - val now = System.currentTimeMillis() / 1000L + val now = TimeUtils.now() if (startsUnixSec != null && startsUnixSec > now) { val pretty = remember(startsUnixSec) { - java.text.DateFormat - .getDateTimeInstance(java.text.DateFormat.MEDIUM, java.text.DateFormat.SHORT) - .format(java.util.Date(startsUnixSec * 1000L)) + formatDateTime(startsUnixSec * 1000L, DateTimeStyle.MEDIUM, DateTimeStyle.SHORT) } Text( text = stringRes(Res.string.meeting_space_planned_starts_at, pretty), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MusicPlaylist.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/MusicPlaylist.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MusicPlaylist.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/MusicPlaylist.kt index cb9ddb2e41..422665d439 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MusicPlaylist.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/MusicPlaylist.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -63,6 +63,7 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists import com.vitorpamplona.amethyst.commons.music.formatTrackDuration +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.music_playlist_collaborative import com.vitorpamplona.amethyst.commons.resources.music_playlist_edit_action @@ -72,8 +73,16 @@ import com.vitorpamplona.amethyst.commons.resources.music_playlist_private import com.vitorpamplona.amethyst.commons.resources.music_playlist_track_count import com.vitorpamplona.amethyst.commons.resources.music_playlist_unknown_track import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.WatchAuthor +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageBanner +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageBannerBackground import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp @@ -81,20 +90,12 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.note.BaseUserPicture -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.WatchAuthor -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageBanner -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageBannerBackground -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.experimental.music.playlist.MusicPlaylistEvent import com.vitorpamplona.quartz.experimental.music.track.MusicTrackEvent import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90ContentDiscoveryResponse.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/NIP90ContentDiscoveryResponse.kt similarity index 89% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90ContentDiscoveryResponse.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/NIP90ContentDiscoveryResponse.kt index 8e2aa280a6..d5a6cff051 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90ContentDiscoveryResponse.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/NIP90ContentDiscoveryResponse.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable @@ -29,11 +29,11 @@ import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.commons.model.EmptyTagList import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayUncitedHashtags +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags import com.vitorpamplona.quartz.nip90Dvms.contentDiscoveryResponse.DvmContentDiscoveryResponseEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90Status.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/NIP90Status.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90Status.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/NIP90Status.kt index 19c27a2c83..0661bca6c1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90Status.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/NIP90Status.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.material3.Text import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip90Dvms.status.DvmStatusEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Nip.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Nip.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Nip.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Nip.kt index d606a31bd8..6a552e8a42 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Nip.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Nip.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.nipsOnNostr.ui.NipCard import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.nipsOnNostr.NipTextEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Nutzap.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Nutzap.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Nutzap.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Nutzap.kt index 071875487c..53e1b2bcb0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Nutzap.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Nutzap.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.size import androidx.compose.material3.Icon @@ -36,16 +36,16 @@ import com.vitorpamplona.amethyst.commons.ui.note.ActivityAmountRow import com.vitorpamplona.amethyst.commons.ui.note.ActivityBadge import com.vitorpamplona.amethyst.commons.ui.note.ActivityCardFrame import com.vitorpamplona.amethyst.commons.ui.note.ActivityHeaderRow +import com.vitorpamplona.amethyst.commons.ui.note.CrossfadeToDisplayComment +import com.vitorpamplona.amethyst.commons.ui.note.DisplayBlankAuthor +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp import com.vitorpamplona.amethyst.commons.ui.theme.bitcoinColor import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.ui.note.CrossfadeToDisplayComment -import com.vitorpamplona.amethyst.ui.note.DisplayBlankAuthor -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip61Nutzaps.nutzap.NutzapEvent import com.vitorpamplona.quartz.nip61Nutzaps.nutzap.claimedSatsTotal -import java.math.BigDecimal +import com.vitorpamplona.quartz.utils.BigDecimal /** * Renders a NIP-61 nutzap (kind 9321) as an activity card, like lightning zaps. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/OnchainZapEvent.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/OnchainZapEvent.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/OnchainZapEvent.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/OnchainZapEvent.kt index 75f953ca66..39c14e65c7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/OnchainZapEvent.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/OnchainZapEvent.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.LinearEasing @@ -73,17 +73,18 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.theme.Size16Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp import com.vitorpamplona.amethyst.commons.ui.theme.bitcoinColor -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.util.PlatformNumberFormatter +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nipBCOnchainZaps.chain.BitcoinTx import com.vitorpamplona.quartz.nipBCOnchainZaps.zap.OnchainZapEvent import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import java.text.NumberFormat private const val MEMPOOL_TX_URL = "https://mempool.space/tx/" @@ -314,7 +315,7 @@ private fun AmountRow( ) { Row(verticalAlignment = Alignment.Bottom, horizontalArrangement = Arrangement.spacedBy(6.dp)) { Text( - text = NumberFormat.getNumberInstance().format(sats), + text = PlatformNumberFormatter().format(sats), style = MaterialTheme.typography.displaySmall, fontWeight = FontWeight.ExtraBold, color = orange, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PeopleList.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PeopleList.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PeopleList.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PeopleList.kt index e567b43ac5..c122c268a5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PeopleList.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PeopleList.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -50,12 +50,12 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.ui.components.ShowMoreButton import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserCompose +import com.vitorpamplona.amethyst.commons.ui.note.getGradient import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness -import com.vitorpamplona.amethyst.ui.components.ShowMoreButton -import com.vitorpamplona.amethyst.ui.note.UserCompose -import com.vitorpamplona.amethyst.ui.note.getGradient -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.people.taggedUserIds import com.vitorpamplona.quartz.nip51Lists.followSet.FollowSetEvent import kotlinx.collections.immutable.ImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PictureDisplay.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PictureDisplay.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PictureDisplay.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PictureDisplay.kt index 09d3df6f10..68df138a67 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PictureDisplay.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PictureDisplay.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -36,20 +36,20 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.style.TextOverflow import com.vitorpamplona.amethyst.commons.model.EmptyTagList +import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage +import com.vitorpamplona.amethyst.commons.ui.components.AutoNonlazyGrid +import com.vitorpamplona.amethyst.commons.ui.components.BlurhashBackdrop +import com.vitorpamplona.amethyst.commons.ui.components.BlurhashGridBackdrop +import com.vitorpamplona.amethyst.commons.ui.components.ContentWarningGate +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer +import com.vitorpamplona.amethyst.commons.ui.components.collectContentWarningReasons +import com.vitorpamplona.amethyst.commons.ui.components.mediaSizingModifier import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.platform.ZoomableContentView import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer -import com.vitorpamplona.amethyst.model.MediaAspectRatioCache -import com.vitorpamplona.amethyst.ui.components.AutoNonlazyGrid -import com.vitorpamplona.amethyst.ui.components.BlurhashBackdrop -import com.vitorpamplona.amethyst.ui.components.BlurhashGridBackdrop -import com.vitorpamplona.amethyst.ui.components.ContentWarningGate -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.components.ZoomableContentView -import com.vitorpamplona.amethyst.ui.components.collectContentWarningReasons -import com.vitorpamplona.amethyst.ui.components.mediaSizingModifier -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip36SensitiveContent.isSensitiveOrNSFW import com.vitorpamplona.quartz.nip68Picture.PictureEvent import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PinList.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PinList.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PinList.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PinList.kt index 81480e8a59..8099bcef40 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PinList.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PinList.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -46,12 +46,12 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.ui.components.ShowMoreButton import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.PinIcon +import com.vitorpamplona.amethyst.commons.ui.note.getGradient import com.vitorpamplona.amethyst.commons.ui.theme.Size15Modifier -import com.vitorpamplona.amethyst.ui.components.ShowMoreButton -import com.vitorpamplona.amethyst.ui.note.getGradient -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent import com.vitorpamplona.quartz.nip51Lists.PinListEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastBookmarkButton.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastBookmarkButton.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastBookmarkButton.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastBookmarkButton.kt index d282f524b7..da41a8e667 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastBookmarkButton.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastBookmarkButton.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -30,7 +30,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.ui.note.BookmarkToggleButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * A bookmark toggle for a podcast (show or episode). "Favoriting"/subscribing to a podcast reuses diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastChaptersSection.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastChaptersSection.kt similarity index 82% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastChaptersSection.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastChaptersSection.kt index 0c887900ee..f988bba998 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastChaptersSection.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastChaptersSection.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -42,21 +42,15 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import com.vitorpamplona.amethyst.commons.podcasts.fetchPreviewText import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.podcast_chapters import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.podcasts.PodcastChapter import com.vitorpamplona.quartz.podcasts.PodcastChapters -import com.vitorpamplona.quartz.utils.Log -import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.coroutines.executeAsync private sealed interface ChaptersUiState { data object Loading : ChaptersUiState @@ -79,8 +73,7 @@ fun PodcastChaptersSection( accountViewModel: AccountViewModel, ) { val state by produceState(ChaptersUiState.Loading, chaptersUrl) { - val client = accountViewModel.httpClientBuilder.okHttpClientForPreview(chaptersUrl) - val parsed = loadChapters(chaptersUrl, client) + val parsed = accountViewModel.httpClientBuilder.fetchPreviewText(chaptersUrl)?.let { PodcastChapters.parse(it) } value = if (parsed != null) ChaptersUiState.Loaded(parsed.chapters) else ChaptersUiState.Failed } @@ -133,30 +126,13 @@ fun PodcastChaptersSection( } } -private suspend fun loadChapters( - url: String, - client: OkHttpClient, -): PodcastChapters? = - withContext(Dispatchers.IO) { - try { - val request = Request.Builder().url(url).build() - client.newCall(request).executeAsync().use { response -> - if (response.isSuccessful) PodcastChapters.parse(response.body.string()) else null - } - } catch (e: Exception) { - if (e is CancellationException) throw e - Log.w("PodcastChapters", "Failed to load chapters from $url", e) - null - } - } - private fun formatTimestamp(seconds: Long): String { val hours = seconds / 3600 val minutes = (seconds % 3600) / 60 val secs = seconds % 60 return if (hours > 0) { - "%d:%02d:%02d".format(hours, minutes, secs) + "$hours:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}" } else { - "%d:%02d".format(minutes, secs) + "$minutes:${secs.toString().padStart(2, '0')}" } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastChaptersView.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastChaptersView.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastChaptersView.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastChaptersView.kt index a90350532f..40485706e5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastChaptersView.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastChaptersView.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -43,14 +43,14 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols -import com.vitorpamplona.amethyst.commons.podcasts.PodcastRemoteContent +import com.vitorpamplona.amethyst.commons.podcasts.fetchPreviewText import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.podcast_chapters_count import com.vitorpamplona.amethyst.commons.ui.note.PodcastSoundbites import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size18Modifier import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.podcasts.PodcastChapter import com.vitorpamplona.quartz.podcasts.PodcastChapters @@ -67,8 +67,7 @@ fun PodcastChaptersView( accountViewModel: AccountViewModel, ) { val chapters by produceState(initialValue = emptyList(), chaptersUrl) { - val client = accountViewModel.httpClientBuilder.okHttpClientForPreview(chaptersUrl) - val body = PodcastRemoteContent.fetchText(chaptersUrl, client) + val body = accountViewModel.httpClientBuilder.fetchPreviewText(chaptersUrl) value = body?.let { PodcastChapters.parse(it)?.chapters }?.filter { it.title?.isNotBlank() == true } ?: emptyList() } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastCoverCard.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastCoverCard.kt similarity index 89% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastCoverCard.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastCoverCard.kt index eefd09930d..5a825617f0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastCoverCard.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastCoverCard.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.aspectRatio @@ -33,11 +33,11 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeader +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeaderBackground import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeaderBackground -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel // Top-rounded square cover used by both PodcastEpisode and PodcastMetadata renderers. // Shape + modifier hoisted to constants so they aren't rebuilt on every recomposition. @@ -49,7 +49,7 @@ private val COVER_IMAGE_MODIFIER = .clip(COVER_IMAGE_SHAPE) @Composable -internal fun PodcastCoverCard( +fun PodcastCoverCard( image: String?, note: Note, accountViewModel: AccountViewModel, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastEpisode.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastEpisode.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastEpisode.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastEpisode.kt index 5ddea72590..4b35476fdb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastEpisode.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastEpisode.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -55,15 +55,16 @@ import com.vitorpamplona.amethyst.commons.resources.podcast_season import com.vitorpamplona.amethyst.commons.resources.podcast_season_episode import com.vitorpamplona.amethyst.commons.resources.podcast_transcript import com.vitorpamplona.amethyst.commons.resources.podcast_video +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.PodcastBadge import com.vitorpamplona.amethyst.commons.ui.note.PodcastLinkChip import com.vitorpamplona.amethyst.commons.ui.note.PodcastValueSplits +import com.vitorpamplona.amethyst.commons.ui.note.platform.PodcastEpisodeAudioPlayer import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.podcasts.PodcastEpisode // Bottom-rounded border on the audio player so it visually butts up against the cover's diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastMetadata.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastMetadata.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastMetadata.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastMetadata.kt index 883b09e006..7f79804596 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastMetadata.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastMetadata.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -53,6 +53,7 @@ import com.vitorpamplona.amethyst.commons.resources.podcast_completed import com.vitorpamplona.amethyst.commons.resources.podcast_explicit import com.vitorpamplona.amethyst.commons.resources.podcast_support_show import com.vitorpamplona.amethyst.commons.resources.podcast_view_episodes +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.PodcastBadge import com.vitorpamplona.amethyst.commons.ui.note.PodcastLinkChip @@ -61,8 +62,7 @@ import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nipXXPodcasting20.metadata.resolvePodcastShow @OptIn(ExperimentalLayoutApi::class) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastPeople.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastPeople.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastPeople.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastPeople.kt index 5e00ab1f3a..cb4527786e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastPeople.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastPeople.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -47,15 +47,15 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.podcast_hosts_and_guests import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.podcasts.PodcastPerson /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastTranscriptView.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastTranscriptView.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastTranscriptView.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastTranscriptView.kt index 44ad8f5398..0766c9f7f4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PodcastTranscriptView.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PodcastTranscriptView.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column @@ -40,11 +40,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols -import com.vitorpamplona.amethyst.commons.podcasts.PodcastRemoteContent +import com.vitorpamplona.amethyst.commons.podcasts.fetchPreviewText import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.podcast_transcript import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * The episode's transcript (from the off-event file referenced by the `transcript` tag), fetched and @@ -58,8 +58,7 @@ fun PodcastTranscriptView( accountViewModel: AccountViewModel, ) { val transcript by produceState(initialValue = null as String?, transcriptUrl) { - val client = accountViewModel.httpClientBuilder.okHttpClientForPreview(transcriptUrl) - val body = PodcastRemoteContent.fetchText(transcriptUrl, client) + val body = accountViewModel.httpClientBuilder.fetchPreviewText(transcriptUrl) value = body?.let { cleanTranscript(it) }?.takeIf { it.isNotBlank() } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Poll.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Poll.kt index a0c92badb1..162a6f3ef2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Poll.kt @@ -18,9 +18,8 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types -import android.annotation.SuppressLint import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.foundation.background @@ -82,8 +81,13 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.poll_results_vote_count_link import com.vitorpamplona.amethyst.commons.resources.poll_submit import com.vitorpamplona.amethyst.commons.resources.poll_view_results +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayUncitedHashtags import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.BigPadding @@ -96,14 +100,9 @@ import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.subtleBorder -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags -import com.vitorpamplona.amethyst.ui.note.showCount -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.util.showCount +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent import com.vitorpamplona.quartz.nip88Polls.poll.tags.PollType @@ -769,7 +768,7 @@ fun RenderPollManualLongPreview() { } } -@SuppressLint("StateFlowValueCalledInComposition") +@Suppress("StateFlowValueCalledInComposition") @Preview @Composable fun RenderPollGameResultsPreview() { @@ -845,7 +844,7 @@ fun RenderPollGameResultsPreview() { } } -@SuppressLint("StateFlowValueCalledInComposition") +@Suppress("StateFlowValueCalledInComposition") @Preview @Composable fun RenderPollColorResultsPreview() { @@ -954,7 +953,7 @@ fun RenderPollColorResultsPreview() { } } -@SuppressLint("StateFlowValueCalledInComposition") +@Suppress("StateFlowValueCalledInComposition") @Preview @Composable fun RenderPollMultiChoicePreview() { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PrivateMessage.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PrivateMessage.kt index 743ada7075..23022bbadf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PrivateMessage.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -40,18 +40,18 @@ import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.private_conversation_notification +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.LoadDecryptedContent +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayUncitedHashtags +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.privateDM.header.ChatroomHeader import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.LoadDecryptedContent -import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.header.ChatroomHeader +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags import com.vitorpamplona.quartz.nip04Dm.messages.EncryptedDmEvent import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ProfileCard.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ProfileCard.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ProfileCard.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ProfileCard.kt index c12f7659cb..809a5ad557 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ProfileCard.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ProfileCard.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background @@ -62,12 +62,22 @@ import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.account.observeAccountIsHiddenUser +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserAssertionsFollowerCount +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserIsFollowing import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.number_followers import com.vitorpamplona.amethyst.commons.resources.profile_card_bot import com.vitorpamplona.amethyst.commons.resources.profile_card_follows_you import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.ObserveDisplayNip05Status +import com.vitorpamplona.amethyst.commons.ui.note.ShowFollowingOrUnfollowingButton import com.vitorpamplona.amethyst.commons.ui.note.ShowUserButton +import com.vitorpamplona.amethyst.commons.ui.note.WatchAuthor +import com.vitorpamplona.amethyst.commons.ui.note.elements.BannerImage import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size16Modifier @@ -75,17 +85,7 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.bitcoinColor import com.vitorpamplona.amethyst.commons.ui.theme.innerPostModifier import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.observeAccountIsHiddenUser -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserAssertionsFollowerCount -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsFollowing -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.BaseUserPicture -import com.vitorpamplona.amethyst.ui.note.ObserveDisplayNip05Status -import com.vitorpamplona.amethyst.ui.note.ShowFollowingOrUnfollowingButton -import com.vitorpamplona.amethyst.ui.note.WatchAuthor -import com.vitorpamplona.amethyst.ui.note.elements.BannerImage -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.metadata.UserMetadata // A kind-0 in the feed is a person, not a JSON blob. The card mirrors the profile diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Ps1Save.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Ps1Save.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Ps1Save.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Ps1Save.kt index 9c3de10a93..49441bd124 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Ps1Save.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Ps1Save.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.Image import androidx.compose.foundation.layout.size @@ -31,9 +31,8 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.withFrameMillis import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.FilterQuality -import androidx.compose.ui.graphics.asImageBitmap -import androidx.core.graphics.createBitmap import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.service.image.argbPixelsToImageBitmap import com.vitorpamplona.amethyst.commons.ui.note.Ps1SaveCard import com.vitorpamplona.amethyst.commons.ui.theme.Size24dp import com.vitorpamplona.quartz.experimental.ps1saves.Ps1SaveEvent @@ -92,9 +91,7 @@ private fun Ps1SaveIconImage(icon: Ps1SaveIcon) { val frames = remember(icon) { icon.frames.map { pixels -> - createBitmap(Ps1SaveIcon.SIZE, Ps1SaveIcon.SIZE) - .apply { setPixels(pixels, 0, Ps1SaveIcon.SIZE, 0, 0, Ps1SaveIcon.SIZE, Ps1SaveIcon.SIZE) } - .asImageBitmap() + argbPixelsToImageBitmap(pixels, Ps1SaveIcon.SIZE, Ps1SaveIcon.SIZE) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicMessage.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PublicMessage.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicMessage.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PublicMessage.kt index 6450038e62..5ba5564f8b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicMessage.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PublicMessage.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow @@ -35,14 +35,14 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextOverflow import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.ui.components.RenderUserAsClickableText +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayUncitedHashtags import com.vitorpamplona.amethyst.commons.ui.theme.HalfHalfTopPadding import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.components.RenderUserAsClickableText -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags import com.vitorpamplona.quartz.nipA4PublicMessages.PublicMessageEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Publication.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Publication.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Publication.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Publication.kt index fdccdb6b39..4d09eb6b6f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Publication.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Publication.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -56,23 +56,23 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for import com.vitorpamplona.amethyst.commons.resources.publication_contents import com.vitorpamplona.amethyst.commons.resources.publication_more_sections import com.vitorpamplona.amethyst.commons.resources.publication_section_count import com.vitorpamplona.amethyst.commons.resources.publication_untitled_section +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.library.BlossomPieceIndexEvent import com.vitorpamplona.quartz.experimental.library.BookshelfDirectoryEvent import com.vitorpamplona.quartz.experimental.library.LearningResourceEvent @@ -105,7 +105,7 @@ private const val MAX_PREVIEW_SECTIONS = 12 * few that do not cannot cost 240 subscriptions in one frame. Past it the row count is shown, and * the previous/next pager walks the rest. */ -internal const val MAX_THREAD_SECTIONS = 60 +const val MAX_THREAD_SECTIONS = 60 /** * Renders a kind-30040 NKBIP-01 publication index: cover, title, author, and what the index knows diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicationSection.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PublicationSection.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicationSection.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PublicationSection.kt index 8eeaeba528..9264c848c2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicationSection.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/PublicationSection.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -48,20 +48,20 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.publication_untitled_section import com.vitorpamplona.amethyst.commons.richtext.CachedAsciiDocToMarkdown +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.richtext.LocalRichTextPlatform import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.components.markdown.RenderContentAsMarkdown -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.publications.PublicationContentEvent import com.vitorpamplona.quartz.experimental.publications.PublicationIndexEvent import com.vitorpamplona.quartz.experimental.publications.PublicationSectionRef @@ -129,7 +129,7 @@ fun RenderPublicationSection( if (markdown.isNotBlank()) { val tags = remember(noteEvent) { noteEvent.tags.toImmutableListOfLists() } - RenderContentAsMarkdown( + LocalRichTextPlatform.current.Markdown( content = markdown, tags = tags, canPreview = canPreview && !makeItShort, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Reaction.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Reaction.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Reaction.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Reaction.kt index a64200d07d..ec85bfb015 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Reaction.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Reaction.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable @@ -31,13 +31,13 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.ActivityBadge import com.vitorpamplona.amethyst.commons.ui.note.ActivityCardFrame import com.vitorpamplona.amethyst.commons.ui.note.ActivityHeaderRow +import com.vitorpamplona.amethyst.commons.ui.note.DisplayBlankAuthor import com.vitorpamplona.amethyst.commons.ui.note.LikeTint import com.vitorpamplona.amethyst.commons.ui.note.LikedIcon +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp -import com.vitorpamplona.amethyst.ui.note.DisplayBlankAuthor -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.note.RenderReaction as RenderReactionEmoji +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.note.RenderReaction as RenderReactionEmoji /** * Renders a kind 7 reaction as an activity card, like the zap kinds, tinted diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayDiscovery.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RelayDiscovery.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayDiscovery.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RelayDiscovery.kt index ef59365496..618e9a476b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayDiscovery.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RelayDiscovery.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.RelayDiscoveryCard -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip66RelayMonitor.discovery.RelayDiscoveryEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayGroupMessage.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RelayGroupMessage.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayGroupMessage.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RelayGroupMessage.kt index a090661335..3a3abfddaf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayGroupMessage.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RelayGroupMessage.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -48,15 +48,15 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.nip29RelayGroups.ui.RelayNameChip +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserName import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.buzz.workspace.buzzParticipants import com.vitorpamplona.quartz.buzz.workspace.isBuzzDm import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RelayList.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RelayList.kt index 3a5e7e4ed6..342cee5e73 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RelayList.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -47,6 +47,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip51Lists.relayLists.RelayListCard +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserRelayIntoList import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.blocked_relays_title import com.vitorpamplona.amethyst.commons.resources.broadcast_relays_title @@ -58,15 +59,14 @@ import com.vitorpamplona.amethyst.commons.resources.public_home_section import com.vitorpamplona.amethyst.commons.resources.public_notif_section import com.vitorpamplona.amethyst.commons.resources.search_relays_title import com.vitorpamplona.amethyst.commons.resources.trusted_relays_title +import com.vitorpamplona.amethyst.commons.ui.components.ShowMoreButton import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.AddRelayButton +import com.vitorpamplona.amethyst.commons.ui.note.RemoveRelayButton +import com.vitorpamplona.amethyst.commons.ui.note.getGradient import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserRelayIntoList -import com.vitorpamplona.amethyst.ui.components.ShowMoreButton -import com.vitorpamplona.amethyst.ui.note.AddRelayButton -import com.vitorpamplona.amethyst.ui.note.RemoveRelayButton -import com.vitorpamplona.amethyst.ui.note.getGradient -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.firstTagValueFor import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayMembers.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RelayMembers.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayMembers.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RelayMembers.kt index 22c1fc34c7..a861c170b2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayMembers.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RelayMembers.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.Note @@ -28,7 +28,7 @@ import com.vitorpamplona.amethyst.commons.nip43RelayMembers.ui.RelayLeaveRequest import com.vitorpamplona.amethyst.commons.nip43RelayMembers.ui.RelayMembershipListCard import com.vitorpamplona.amethyst.commons.nip43RelayMembers.ui.RelayRemoveMemberCard import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip43RelayMembers.addMember.RelayAddMemberEvent import com.vitorpamplona.quartz.nip43RelayMembers.list.RelayMembershipListEvent import com.vitorpamplona.quartz.nip43RelayMembers.removeMember.RelayRemoveMemberEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayReview.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RelayReview.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayReview.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RelayReview.kt index d9796011fa..6f1b95a335 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayReview.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RelayReview.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -46,15 +46,15 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.ratings.RatingMark import com.vitorpamplona.quartz.experimental.ratings.RelayReviewEvent import com.vitorpamplona.quartz.experimental.ratings.tags.CategoryRatingTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RememberCaptionTracks.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RememberCaptionTracks.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RememberCaptionTracks.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RememberCaptionTracks.kt index b122f7fa43..eba8a84516 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RememberCaptionTracks.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RememberCaptionTracks.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -29,8 +29,8 @@ import com.vitorpamplona.amethyst.commons.model.nip71Video.CaptionTrack import com.vitorpamplona.amethyst.commons.model.nip71Video.captionTracks import com.vitorpamplona.amethyst.commons.model.nip71Video.mergeCaptionTracks import com.vitorpamplona.amethyst.commons.model.nip71Video.toCaptionTrack -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip71Video.VideoEvent import com.vitorpamplona.quartz.nip71Video.textTrack.TextTrackEvent import kotlinx.collections.immutable.ImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderPostApproval.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RenderPostApproval.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderPostApproval.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RenderPostApproval.kt index 1936c22fb9..889c2809d1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderPostApproval.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RenderPostApproval.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth @@ -37,11 +37,11 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.community_approved_posts import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip72ModCommunities.approval.CommunityPostApprovalEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderVideoCollaboration.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RenderVideoCollaboration.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderVideoCollaboration.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RenderVideoCollaboration.kt index 6eccfe2176..062043e5ad 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderVideoCollaboration.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RenderVideoCollaboration.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -37,10 +37,10 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.video_collaboration_accepted_on import com.vitorpamplona.amethyst.commons.resources.video_collaboration_declined_on import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.videoCollaboration.VideoCollaborationEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderVideoCredits.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RenderVideoCredits.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderVideoCredits.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RenderVideoCredits.kt index 7dd1ebb208..9744b4fbd1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderVideoCredits.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RenderVideoCredits.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow @@ -46,11 +46,11 @@ import com.vitorpamplona.amethyst.commons.resources.video_credit_inspired_by import com.vitorpamplona.amethyst.commons.resources.video_credit_references import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextColor import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.HalfTopPadding import com.vitorpamplona.amethyst.commons.ui.theme.lessImportantLink -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.videoCollaboration.VideoCollaborationEvent import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderVideoCurationSet.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RenderVideoCurationSet.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderVideoCurationSet.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RenderVideoCurationSet.kt index d47478fa3f..45bba7b0c0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderVideoCurationSet.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RenderVideoCurationSet.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.clickable import androidx.compose.foundation.horizontalScroll @@ -48,15 +48,15 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.video_curation_set_private_items import com.vitorpamplona.amethyst.commons.resources.video_curation_set_video_count +import com.vitorpamplona.amethyst.commons.ui.components.DisplayBlurHash +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier -import com.vitorpamplona.amethyst.ui.components.DisplayBlurHash -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.AddressBookmark import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.BookmarkIdTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Report.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Report.kt index 63fa04bc7b..ff448c7078 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Report.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable @@ -30,11 +30,11 @@ import com.vitorpamplona.amethyst.commons.model.EmptyTagList import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.nip56Reports.ui.reportTypeLabel import com.vitorpamplona.amethyst.commons.nip56Reports.ui.reportTypeLabels +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip56Reports.ReportEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RoadEvent.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RoadEvent.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RoadEvent.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RoadEvent.kt index 975a11cc4c..e011c6dd88 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RoadEvent.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/RoadEvent.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.ui.note.RoadEventConfirmationCard import com.vitorpamplona.amethyst.commons.ui.note.RoadEventReportCard -import com.vitorpamplona.amethyst.ui.note.creators.location.LocationPreviewMap +import com.vitorpamplona.amethyst.commons.ui.note.platform.LocationPreviewMap import com.vitorpamplona.quartz.experimental.roadstr.confirmation.RoadEventConfirmationEvent import com.vitorpamplona.quartz.experimental.roadstr.report.RoadEventReportEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SnoAvatar.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/SnoAvatar.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SnoAvatar.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/SnoAvatar.kt index 9bfc6b2ac4..d4a064d107 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SnoAvatar.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/SnoAvatar.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -35,7 +35,7 @@ import com.vitorpamplona.amethyst.commons.sno.ui.SnoObjectViewer import com.vitorpamplona.amethyst.commons.ui.note.SnoAvatarCard import com.vitorpamplona.amethyst.commons.ui.note.SnoAvatarDefaultCard import com.vitorpamplona.amethyst.commons.ui.note.SnoAvatarUnpaidCard -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.cyberspace.deck0003Sno.SnoAvatarEvent import com.vitorpamplona.quartz.cyberspace.deck0003Sno.SnoPaletteRef import com.vitorpamplona.quartz.cyberspace.deck0003Sno.SnoPayload diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SnoObject.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/SnoObject.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SnoObject.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/SnoObject.kt index 638579782c..4667ffb40f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SnoObject.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/SnoObject.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -34,7 +34,7 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.sno.ui.SnoObjectViewer import com.vitorpamplona.amethyst.commons.ui.note.SnoObjectCard import com.vitorpamplona.amethyst.commons.ui.note.SnoObjectUnreadableCard -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.cyberspace.deck0003Sno.SnoObjectEvent import com.vitorpamplona.quartz.cyberspace.deck0003Sno.SnoPaletteRef import com.vitorpamplona.quartz.cyberspace.deck0003Sno.SnoResult diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SnoPalettes.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/SnoPalettes.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SnoPalettes.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/SnoPalettes.kt index 06ce9e82d9..c5d8f5da0c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SnoPalettes.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/SnoPalettes.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.runtime.Composable import androidx.compose.runtime.remember -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.cyberspace.deck0003Sno.SnoPalette import com.vitorpamplona.quartz.cyberspace.deck0003Sno.SnoPaletteEventReader import com.vitorpamplona.quartz.cyberspace.deck0003Sno.SnoPaletteRef diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SnoShard.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/SnoShard.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SnoShard.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/SnoShard.kt index c67fdd61e5..ff9cdff412 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SnoShard.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/SnoShard.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -37,7 +37,7 @@ import com.vitorpamplona.amethyst.commons.resources.sno_shard_ideaspace import com.vitorpamplona.amethyst.commons.sno.ui.SnoObjectViewer import com.vitorpamplona.amethyst.commons.ui.note.SnoObjectCard import com.vitorpamplona.amethyst.commons.ui.note.SnoObjectUnreadableCard -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.cyberspace.CyberspaceCoordinate import com.vitorpamplona.quartz.cyberspace.CyberspacePlane import com.vitorpamplona.quartz.cyberspace.deck0003Sno.SnoPaletteRef diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SoftwareApp.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/SoftwareApp.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SoftwareApp.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/SoftwareApp.kt index 2caa900e85..225abd6a9d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SoftwareApp.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/SoftwareApp.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -61,10 +61,12 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil3.compose.AsyncImage +import com.vitorpamplona.amethyst.commons.model.MediaAspectRatioCache import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.nip82_assets_count import com.vitorpamplona.amethyst.commons.resources.nip82_by_author @@ -75,6 +77,11 @@ import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.LinkIcon +import com.vitorpamplona.amethyst.commons.ui.note.NoteAuthorPicture +import com.vitorpamplona.amethyst.commons.ui.note.NoteUsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.elements.MoreOptionsButton +import com.vitorpamplona.amethyst.commons.ui.note.platform.ReactionsRow +import com.vitorpamplona.amethyst.commons.ui.note.platform.ZoomableContentView import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.QuoteBorder @@ -85,15 +92,9 @@ import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.subtleBorder +import com.vitorpamplona.amethyst.commons.util.DecimalPatternFormatter import com.vitorpamplona.amethyst.commons.util.prettyMime -import com.vitorpamplona.amethyst.model.MediaAspectRatioCache -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.components.ZoomableContentView -import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture -import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay -import com.vitorpamplona.amethyst.ui.note.ReactionsRow -import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.application.SoftwareApplicationEvent import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.asset.SoftwareAssetEvent import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.release.isNip82SoftwareRelease @@ -758,9 +759,9 @@ fun RenderSoftwareAsset( internal fun formatBytes(bytes: Long): String { if (bytes < 1024L) return "$bytes B" val kb = bytes / 1024.0 - if (kb < 1024) return "%.1f KB".format(kb) + if (kb < 1024) return "${DecimalPatternFormatter("0.0").format(kb)} KB" val mb = kb / 1024 - if (mb < 1024) return "%.1f MB".format(mb) + if (mb < 1024) return "${DecimalPatternFormatter("0.0").format(mb)} MB" val gb = mb / 1024 - return "%.2f GB".format(gb) + return "${DecimalPatternFormatter("0.00").format(gb)} GB" } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/StarterPack.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/StarterPack.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/StarterPack.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/StarterPack.kt index 88ca1ebd7e..5326d5498e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/StarterPack.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/StarterPack.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -45,27 +45,27 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEventAndMap import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.follow_list_item_label import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.GalleryUnloaded +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeader +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeaderBackground +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.discover.nip51FollowSets.FollowSetCard import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.FollowSetImageModifier import com.vitorpamplona.amethyst.commons.ui.theme.SpacedBy5dp import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.blackTagModifier -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEventAndMap -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.GalleryUnloaded -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeaderBackground -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip51FollowSets.FollowSetCard -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip51Lists.starterPack.StarterPackEvent import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Text.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Text.kt index 908ff3f919..9b4cd4de87 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Text.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -40,20 +40,21 @@ import com.vitorpamplona.amethyst.commons.model.navigation.routeFor 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.components.SensitivityWarning +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.LoadDecryptedContent +import com.vitorpamplona.amethyst.commons.ui.note.ReplyNoteComposition import com.vitorpamplona.amethyst.commons.ui.note.ReplyToLabel +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayUncitedHashtags +import com.vitorpamplona.amethyst.commons.ui.note.nip22Comments.DisplayCommentScope +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderAudioFromIMeta +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.threadview.datasources.PreloadThreadForReply import com.vitorpamplona.amethyst.commons.ui.theme.HalfVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.LoadDecryptedContent -import com.vitorpamplona.amethyst.ui.note.ReplyNoteComposition -import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags -import com.vitorpamplona.amethyst.ui.note.nip22Comments.DisplayCommentScope -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.datasources.PreloadThreadForReply +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags import com.vitorpamplona.quartz.nip01Core.tags.people.hasAnyTaggedUser import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/TextModification.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/TextModification.kt index 627d61916c..cf8d6a8330 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/TextModification.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -47,24 +47,24 @@ import com.vitorpamplona.amethyst.commons.model.EmptyTagList import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.accept_the_suggestion import com.vitorpamplona.amethyst.commons.resources.proposal_to_edit import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.NoteBody +import com.vitorpamplona.amethyst.commons.ui.note.observeEdits +import com.vitorpamplona.amethyst.commons.ui.note.platform.EditPostView import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier import com.vitorpamplona.amethyst.commons.ui.theme.innerPostModifier -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.actions.EditPostView -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.NoteBody -import com.vitorpamplona.amethyst.ui.note.observeEdits -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.edits.TextNoteModificationEvent import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Thread.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Thread.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Thread.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Thread.kt index f500aea25a..e54b83742c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Thread.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Thread.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -38,7 +38,7 @@ import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip7DThreads.ThreadEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Torrent.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Torrent.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Torrent.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Torrent.kt index b54f6661f7..76ccfb057e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Torrent.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Torrent.kt @@ -18,9 +18,8 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types -import android.content.Intent import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -41,36 +40,36 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.core.net.toUri import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.torrent_failure import com.vitorpamplona.amethyst.commons.resources.torrent_no_apps import com.vitorpamplona.amethyst.commons.resources.torrent_no_info +import com.vitorpamplona.amethyst.commons.ui.components.ShowMoreButton import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.DownloadForOfflineIcon +import com.vitorpamplona.amethyst.commons.ui.note.getGradient import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.Size30dp import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.util.countToHumanReadableBytes -import com.vitorpamplona.amethyst.ui.components.ShowMoreButton -import com.vitorpamplona.amethyst.ui.note.getGradient -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip35Torrents.TorrentEvent import com.vitorpamplona.quartz.nip35Torrents.tags.FileTag import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import kotlin.coroutines.cancellation.CancellationException @@ -218,16 +217,14 @@ fun DisplayFileList( modifier = Modifier.fillMaxWidth(), ) - val context = LocalContext.current + val uriHandler = LocalUriHandler.current IconButton( onClick = { try { val linkStr = link() if (linkStr != null) { - val intent = Intent(Intent.ACTION_VIEW, linkStr.toUri()) - intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK - context.startActivity(intent) + uriHandler.openUri(linkStr) } else { accountViewModel.toastManager.toast(Res.string.torrent_failure, Res.string.torrent_no_info) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TorrentComment.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/TorrentComment.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TorrentComment.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/TorrentComment.kt index c6814f0d7e..3a99bf7f4d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TorrentComment.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/TorrentComment.kt @@ -20,7 +20,7 @@ */ @file:Suppress("DEPRECATION") -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -47,24 +47,25 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.torrent_file import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier import com.vitorpamplona.amethyst.commons.util.countToHumanReadableBytes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip35Torrents.TorrentCommentEvent import com.vitorpamplona.quartz.nip35Torrents.TorrentEvent import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Video.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Video.kt index 45e0fe62b4..c36159377c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Video.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement.spacedBy @@ -50,18 +50,18 @@ import com.vitorpamplona.amethyst.commons.richtext.MediaContentKind import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo import com.vitorpamplona.amethyst.commons.richtext.RichTextParser +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeader +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeaderBackground +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayUncitedHashtags +import com.vitorpamplona.amethyst.commons.ui.note.platform.ZoomableContentView import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.components.ZoomableContentView -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeaderBackground -import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags import com.vitorpamplona.quartz.nip31Alts.alt diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Wiki.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Wiki.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Wiki.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Wiki.kt index 1412044f68..6ca6a50bc5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Wiki.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/Wiki.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.border import androidx.compose.foundation.layout.Column @@ -39,17 +39,17 @@ import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeader +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageHeaderBackground import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier import com.vitorpamplona.amethyst.commons.ui.theme.subtleBorder -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeaderBackground -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip54Wiki.WikiArticleEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/WikiCollaboration.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/WikiCollaboration.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/WikiCollaboration.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/WikiCollaboration.kt index 521e0e02db..8951ba4e74 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/WikiCollaboration.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/WikiCollaboration.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -45,15 +45,15 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip54Wiki.WikiArticleEvent import com.vitorpamplona.quartz.nip54Wiki.WikiMergeAcceptanceEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ZapEvent.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ZapEvent.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ZapEvent.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ZapEvent.kt index 26815bdee9..3d46b37ce2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ZapEvent.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ZapEvent.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -42,6 +42,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.model.ZapAmountCommentNotification import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav @@ -49,6 +50,10 @@ import com.vitorpamplona.amethyst.commons.ui.note.ActivityAmountRow import com.vitorpamplona.amethyst.commons.ui.note.ActivityBadge import com.vitorpamplona.amethyst.commons.ui.note.ActivityCardFrame import com.vitorpamplona.amethyst.commons.ui.note.ActivityHeaderRow +import com.vitorpamplona.amethyst.commons.ui.note.CrossfadeToDisplayComment +import com.vitorpamplona.amethyst.commons.ui.note.DisplayBlankAuthor +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.note.ZapIcon import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size24Modifier @@ -57,15 +62,11 @@ import com.vitorpamplona.amethyst.commons.ui.theme.SpacedBy5dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.bitcoinColor -import com.vitorpamplona.amethyst.ui.note.CrossfadeToDisplayComment -import com.vitorpamplona.amethyst.ui.note.DisplayBlankAuthor -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.ZapAmountCommentNotification -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ZapPoll.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ZapPoll.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ZapPoll.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ZapPoll.kt index d81d2501e8..8dc6f6c28b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/ZapPoll.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/ZapPoll.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types +package com.vitorpamplona.amethyst.commons.ui.note.types import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -37,15 +37,15 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.replyingDirectlyTo import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.ReplyNoteComposition +import com.vitorpamplona.amethyst.commons.ui.note.ZapPollNote +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayUncitedHashtags import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.note.ReplyNoteComposition -import com.vitorpamplona.amethyst.ui.note.ZapPollNote -import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags import com.vitorpamplona.quartz.nip01Core.tags.people.hasAnyTaggedUser diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/AddressLists.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/AddressLists.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/AddressLists.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/AddressLists.kt index 18cf50f963..2108e431d0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/AddressLists.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/AddressLists.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types.lists +package com.vitorpamplona.amethyst.commons.ui.note.types.lists import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -34,7 +34,7 @@ import com.vitorpamplona.amethyst.commons.resources.kind_git_repositories import com.vitorpamplona.amethyst.commons.resources.kind_simple_groups import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip51Lists.appCurationSet.AppCurationSetEvent import com.vitorpamplona.quartz.nip51Lists.favoriteAlgoFeedsList.FavoriteAlgoFeedsListEvent import com.vitorpamplona.quartz.nip51Lists.gitRepositoryList.GitRepositoryListEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/BookmarkLists.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/BookmarkLists.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/BookmarkLists.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/BookmarkLists.kt index 24ccbbe3c7..e6c921b6f6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/BookmarkLists.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/BookmarkLists.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types.lists +package com.vitorpamplona.amethyst.commons.ui.note.types.lists import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -33,7 +33,7 @@ import com.vitorpamplona.amethyst.commons.resources.kind_bookmark_list import com.vitorpamplona.amethyst.commons.resources.kind_bookmark_set import com.vitorpamplona.amethyst.commons.resources.kind_picture_curation_set import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip51Lists.articleCurationSet.ArticleCurationSetEvent import com.vitorpamplona.quartz.nip51Lists.bookmarkList.BookmarkListEvent import com.vitorpamplona.quartz.nip51Lists.bookmarkList.OldBookmarkListEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/GoodWikiRelayList.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/GoodWikiRelayList.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/GoodWikiRelayList.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/GoodWikiRelayList.kt index 3f5387c0ce..e4e47ed399 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/GoodWikiRelayList.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/GoodWikiRelayList.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types.lists +package com.vitorpamplona.amethyst.commons.ui.note.types.lists import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -30,7 +30,7 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.kind_good_wiki_relays import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import com.vitorpamplona.quartz.nip51Lists.goodWikiRelayList.GoodWikiRelayListEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/ListCard.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/ListCard.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/ListCard.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/ListCard.kt index d7332911fe..b33418dfaa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/ListCard.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/ListCard.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types.lists +package com.vitorpamplona.amethyst.commons.ui.note.types.lists import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -47,10 +47,10 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.nip51_list_has_private_members +import com.vitorpamplona.amethyst.commons.ui.components.ShowMoreButton +import com.vitorpamplona.amethyst.commons.ui.note.getGradient import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.components.ShowMoreButton -import com.vitorpamplona.amethyst.ui.note.getGradient -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.utils.Log diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/ListItemRows.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/ListItemRows.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/ListItemRows.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/ListItemRows.kt index bf722835da..7398ba7a2b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/ListItemRows.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/ListItemRows.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types.lists +package com.vitorpamplona.amethyst.commons.ui.note.types.lists import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -34,14 +34,14 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.note.UserCompose import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.note.UserCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.AddressBookmark diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/MuteList.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/MuteList.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/MuteList.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/MuteList.kt index 9d1b21782d..bd5ea3c5e9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/MuteList.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/MuteList.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types.lists +package com.vitorpamplona.amethyst.commons.ui.note.types.lists import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -29,11 +29,11 @@ import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.kind_mute_list +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip51Lists.muteList.MuteListEvent import com.vitorpamplona.quartz.nip51Lists.muteList.tags.EventTag import com.vitorpamplona.quartz.nip51Lists.muteList.tags.HashtagTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/TagLists.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/TagLists.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/TagLists.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/TagLists.kt index 993591f7cf..58b8866bad 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/TagLists.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/TagLists.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types.lists +package com.vitorpamplona.amethyst.commons.ui.note.types.lists import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -33,7 +33,7 @@ import com.vitorpamplona.amethyst.commons.resources.kind_hashtag_follows import com.vitorpamplona.amethyst.commons.resources.kind_interest_set import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.hashtags.HashtagTag import com.vitorpamplona.quartz.nip51Lists.geohashList.GeohashListEvent import com.vitorpamplona.quartz.nip51Lists.interestList.InterestListEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/UserLists.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/UserLists.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/UserLists.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/UserLists.kt index bba3069fc7..0c62a6c90c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/UserLists.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/types/lists/UserLists.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.note.types.lists +package com.vitorpamplona.amethyst.commons.ui.note.types.lists import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -35,7 +35,7 @@ import com.vitorpamplona.amethyst.commons.resources.kind_media_starter_pack import com.vitorpamplona.amethyst.commons.resources.kind_mute_set_for_kind import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip51Lists.gitAuthorList.GitAuthorListEvent import com.vitorpamplona.quartz.nip51Lists.goodWikiAuthorList.GoodWikiAuthorListEvent import com.vitorpamplona.quartz.nip51Lists.kindMuteSet.KindMuteSetEvent diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/platform/AppPlatform.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/platform/AppPlatform.kt new file mode 100644 index 0000000000..4fd7c0991c --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/platform/AppPlatform.kt @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.platform + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.Modifier +import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel + +/** + * The app shell's pieces that shared screens embed but only the front end can draw yet: the + * bottom navigation bar (its pinned favorites and groups read app stores) and the "around me" + * location label (it asks for the location permission). Installed at the composition root + * through [LocalAppPlatform]; each member draws nothing by default. + */ +@Stable +interface AppPlatform { + @Composable + fun AppBottomBar( + selectedRoute: Route?, + nav: INav, + accountViewModel: AccountViewModel, + onClick: (Route) -> Unit, + ) {} + + @Composable + fun AroundMeLocationLabel() {} + + /** A full-screen dialog to pick a place (map, search, "use my location"), as a geohash. */ + @Composable + fun GeohashLocationPickerDialog( + initialGeohash: String?, + onDismiss: () -> Unit, + onConfirm: (String) -> Unit, + ) {} + + /** The picker's body, for screens that host it in their own scaffold. */ + @Composable + fun GeohashLocationPickerContent( + initialGeohash: String?, + confirmLabel: String, + onConfirm: (String) -> Unit, + modifier: Modifier, + ) {} + + /** Draws nothing: previews, and front ends still wiring their pieces. */ + object None : AppPlatform +} + +/** The front end's [AppPlatform]. Static: it is set once at the root and never changes. */ +val LocalAppPlatform = staticCompositionLocalOf { AppPlatform.None } + +@Composable +fun AppBottomBar( + selectedRoute: Route?, + nav: INav, + accountViewModel: AccountViewModel, + onClick: (Route) -> Unit, +) = LocalAppPlatform.current.AppBottomBar(selectedRoute, nav, accountViewModel, onClick) + +@Composable +fun AroundMeLocationLabel() = LocalAppPlatform.current.AroundMeLocationLabel() + +@Composable +fun GeohashLocationPickerDialog( + initialGeohash: String?, + onDismiss: () -> Unit, + onConfirm: (String) -> Unit, +) = LocalAppPlatform.current.GeohashLocationPickerDialog(initialGeohash, onDismiss, onConfirm) + +@Composable +fun GeohashLocationPickerContent( + initialGeohash: String?, + confirmLabel: String, + onConfirm: (String) -> Unit, + modifier: Modifier = Modifier, +) = LocalAppPlatform.current.GeohashLocationPickerContent(initialGeohash, confirmLabel, onConfirm, modifier) diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/richtext/RichTextPlatform.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/richtext/RichTextPlatform.kt new file mode 100644 index 0000000000..ec824271de --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/richtext/RichTextPlatform.kt @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.richtext + +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.Stable +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.graphics.Color +import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists +import com.vitorpamplona.amethyst.commons.richtext.RichTextViewerState +import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel + +/** + * What a front end plugs into the shared rich-text viewer: the [RichTextSegmentRenderer] for its + * platform leaves (zoomable media, LaTeX, payments, link previews, Blossom links) and its markdown + * renderer. The shared viewer parses, lays out paragraphs and renders text, emoji, hashtags and + * mentions itself, and asks this for everything else. + * + * A front end installs its own through [LocalRichTextPlatform] at its composition root (Android + * does so in its theme). Without one, [Plain] renders every platform segment as text, which is + * what previews and a front end still wiring its leaves get. + */ +@Stable +interface RichTextPlatform { + /** The segment renderer for one viewer call; it may close over every argument. */ + fun segmentRenderer( + accountViewModel: AccountViewModel, + nav: INav, + backgroundColor: MutableState, + callbackUri: String?, + canPreview: Boolean, + ): RichTextSegmentRenderer + + /** Renders [content] that the parser recognised as markdown. */ + @Composable + fun Markdown( + content: String, + tags: ImmutableListOfLists, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + callbackUri: String?, + accountViewModel: AccountViewModel, + nav: INav, + ) + + /** + * Renders a decoded secret message (text hidden in an emoji's variation selectors) with the + * platform's leaves, the way the viewer renders a note body. + */ + @Composable + fun SecretMessage( + content: RichTextViewerState, + callbackUri: String?, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) + + /** Text for every platform segment, and markdown shown as its source. */ + object Plain : RichTextPlatform { + override fun segmentRenderer( + accountViewModel: AccountViewModel, + nav: INav, + backgroundColor: MutableState, + callbackUri: String?, + canPreview: Boolean, + ): RichTextSegmentRenderer = PlainTextSegmentRenderer + + @Composable + override fun Markdown( + content: String, + tags: ImmutableListOfLists, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + callbackUri: String?, + accountViewModel: AccountViewModel, + nav: INav, + ) = Text(content) + + @Composable + override fun SecretMessage( + content: RichTextViewerState, + callbackUri: String?, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) = Text(content.paragraphs.joinToString("\n") { paragraph -> paragraph.words.joinToString(" ") { it.segmentText } }) + } +} + +/** The front end's [RichTextPlatform]. Static: it is set once at the root and never changes. */ +val LocalRichTextPlatform = staticCompositionLocalOf { RichTextPlatform.Plain } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AndroidFeedViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/AndroidFeedViewModel.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AndroidFeedViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/AndroidFeedViewModel.kt index 461aaf220c..1839ed4ee0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AndroidFeedViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/AndroidFeedViewModel.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen +package com.vitorpamplona.amethyst.commons.ui.screen import com.vitorpamplona.amethyst.commons.feeds.FeedFilter import com.vitorpamplona.amethyst.commons.model.Note diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/FeedView.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/FeedView.kt index bcb73b461a..dda280bd8d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/FeedView.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen +package com.vitorpamplona.amethyst.commons.ui.screen import androidx.compose.animation.core.tween import androidx.compose.foundation.lazy.LazyListState @@ -33,17 +33,17 @@ import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled import com.vitorpamplona.amethyst.commons.ui.feeds.FeedEmpty import com.vitorpamplona.amethyst.commons.ui.feeds.FeedError +import com.vitorpamplona.amethyst.commons.ui.feeds.FeedLoaded import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed +import com.vitorpamplona.amethyst.commons.ui.feeds.PrefetchLoadedFeedMedia import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox import com.vitorpamplona.amethyst.commons.ui.feeds.StickToTopOnPrepend import com.vitorpamplona.amethyst.commons.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverLazyGridState import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverLazyListState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.FeedViewModel -import com.vitorpamplona.amethyst.ui.feeds.FeedLoaded -import com.vitorpamplona.amethyst.ui.feeds.PrefetchLoadedFeedMedia -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @Composable fun RefresheableFeedView( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/TopNavFeedQueryStates.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/TopNavFeedQueryStates.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/TopNavFeedQueryStates.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/TopNavFeedQueryStates.kt index 8c38940c35..0c8299fe13 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/TopNavFeedQueryStates.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/TopNavFeedQueryStates.kt @@ -18,13 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn +package com.vitorpamplona.amethyst.commons.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.viewmodels.AccountViewModel import kotlinx.coroutines.flow.StateFlow /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/ProfileAppRecommendationsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/apps/recommendations/ProfileAppRecommendationsScreen.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/ProfileAppRecommendationsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/apps/recommendations/ProfileAppRecommendationsScreen.kt index 98793bc953..1924676828 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/ProfileAppRecommendationsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/apps/recommendations/ProfileAppRecommendationsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.apps.recommendations +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.apps.recommendations import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -58,6 +58,8 @@ import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.cache.filterIntoSet import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_definition_handles import com.vitorpamplona.amethyst.commons.resources.app_definition_no_supported_kinds @@ -70,25 +72,24 @@ import com.vitorpamplona.amethyst.commons.resources.profile_app_recommendations_ import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.ui.components.RobohashAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon import com.vitorpamplona.amethyst.commons.ui.note.ClearTextIcon import com.vitorpamplona.amethyst.commons.ui.note.SearchIcon +import com.vitorpamplona.amethyst.commons.ui.note.types.ByAuthorChip +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.apps.recommendations.datasource.ProfileAppRecommendationsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.kindDisplayName import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.note.types.ByAuthorChip -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.apps.recommendations.datasource.ProfileAppRecommendationsFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.kindDisplayName +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.kinds.KindNames import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.flowOn @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsFilterAssemblerSubscription.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsFilterAssemblerSubscription.kt index 5a4c15633f..336f6b999d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/apps/recommendations/datasource/ProfileAppRecommendationsFilterAssemblerSubscription.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.apps.recommendations.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.apps.recommendations.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.apps.recommendations.ProfileAppRecommendationsQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun ProfileAppRecommendationsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/ProfileBadgesScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/badges/profile/ProfileBadgesScreen.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/ProfileBadgesScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/badges/profile/ProfileBadgesScreen.kt index ae2a6a0ff8..441f6f553f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/ProfileBadgesScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/badges/profile/ProfileBadgesScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.profile +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.badges.profile import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -53,6 +53,8 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil3.compose.AsyncImage import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.badge_untitled import com.vitorpamplona.amethyst.commons.resources.profile_badges_description @@ -60,19 +62,18 @@ import com.vitorpamplona.amethyst.commons.resources.profile_badges_empty import com.vitorpamplona.amethyst.commons.resources.profile_badges_title import com.vitorpamplona.amethyst.commons.ui.components.RobohashAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.badges.profile.datasource.ProfileBadgesFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.profile.datasource.ProfileBadgesFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip58Badges.accepted.AcceptedBadgeSetEvent import com.vitorpamplona.quartz.nip58Badges.award.BadgeAwardEvent import com.vitorpamplona.quartz.nip58Badges.definition.BadgeDefinitionEvent import com.vitorpamplona.quartz.nip58Badges.profile.ProfileBadgesEvent import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.launch @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/datasource/ProfileBadgesFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/badges/profile/datasource/ProfileBadgesFilterAssemblerSubscription.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/datasource/ProfileBadgesFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/badges/profile/datasource/ProfileBadgesFilterAssemblerSubscription.kt index 459462b1cd..bbaa52ff29 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/badges/profile/datasource/ProfileBadgesFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/badges/profile/datasource/ProfileBadgesFilterAssemblerSubscription.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.profile.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.badges.profile.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.badges.profile.ProfileBadgesQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun ProfileBadgesFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/default/BookmarkListScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/default/BookmarkListScreen.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/default/BookmarkListScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/default/BookmarkListScreen.kt index 54212de746..ac38c55e6e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/default/BookmarkListScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/default/BookmarkListScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.default import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Box @@ -43,7 +43,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.relayClient.event.EventFinderQueryState import com.vitorpamplona.amethyst.commons.resources.Res @@ -51,15 +50,16 @@ import com.vitorpamplona.amethyst.commons.resources.bookmarks_title import com.vitorpamplona.amethyst.commons.resources.private_bookmarks import com.vitorpamplona.amethyst.commons.resources.public_bookmarks import com.vitorpamplona.amethyst.commons.ui.components.DeletedItemsBanner +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.default.dal.BookmarkPrivateFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.default.dal.BookmarkPublicFeedViewModel import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.TabRowHeight -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default.dal.BookmarkPrivateFeedViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default.dal.BookmarkPublicFeedViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.coroutines.launch @Composable @@ -68,13 +68,13 @@ fun BookmarkListScreen( nav: INav, ) { val publicFeedViewModel: BookmarkPublicFeedViewModel = - viewModel( + rememberViewModel( key = "NostrBookmarkPublicFeedViewModel", factory = BookmarkPublicFeedViewModel.Factory(accountViewModel.account), ) val privateFeedViewModel: BookmarkPrivateFeedViewModel = - viewModel( + rememberViewModel( key = "NostrBookmarkPrivateFeedViewModel", factory = BookmarkPrivateFeedViewModel.Factory(accountViewModel.account), ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPrivateFeedFilter.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPrivateFeedFilter.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPrivateFeedFilter.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPrivateFeedFilter.kt index f8b64f5039..e8e2ca18be 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPrivateFeedFilter.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPrivateFeedFilter.kt @@ -18,11 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default.dal +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.default.dal import com.vitorpamplona.amethyst.commons.feeds.FeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.model.Account class BookmarkPrivateFeedFilter( val account: Account, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPrivateFeedViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPrivateFeedViewModel.kt similarity index 76% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPrivateFeedViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPrivateFeedViewModel.kt index fb1a0928e3..901296c7e9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPrivateFeedViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPrivateFeedViewModel.kt @@ -18,13 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default.dal +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.default.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import androidx.lifecycle.viewmodel.CreationExtras +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel +import kotlin.reflect.KClass @Stable class BookmarkPrivateFeedViewModel( @@ -34,6 +36,9 @@ class BookmarkPrivateFeedViewModel( val account: Account, ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class): T = BookmarkPrivateFeedViewModel(account) as T + override fun create( + modelClass: KClass, + extras: CreationExtras, + ): T = BookmarkPrivateFeedViewModel(account) as T } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPublicFeedFilter.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPublicFeedFilter.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPublicFeedFilter.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPublicFeedFilter.kt index e6d7cba209..213a80d8bb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPublicFeedFilter.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPublicFeedFilter.kt @@ -18,11 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default.dal +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.default.dal import com.vitorpamplona.amethyst.commons.feeds.FeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.model.Account class BookmarkPublicFeedFilter( val account: Account, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPublicFeedViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPublicFeedViewModel.kt similarity index 76% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPublicFeedViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPublicFeedViewModel.kt index 481843dc70..b3a895c5d3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPublicFeedViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/default/dal/BookmarkPublicFeedViewModel.kt @@ -18,13 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default.dal +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.default.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import androidx.lifecycle.viewmodel.CreationExtras +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel +import kotlin.reflect.KClass @Stable class BookmarkPublicFeedViewModel( @@ -34,6 +36,9 @@ class BookmarkPublicFeedViewModel( val account: Account, ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class): T = BookmarkPublicFeedViewModel(account) as T + override fun create( + modelClass: KClass, + extras: CreationExtras, + ): T = BookmarkPublicFeedViewModel(account) as T } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/ListOfBookmarkGroupsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/list/ListOfBookmarkGroupsScreen.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/ListOfBookmarkGroupsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/list/ListOfBookmarkGroupsScreen.kt index 727d168bf8..4c40778e1d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/list/ListOfBookmarkGroupsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/list/ListOfBookmarkGroupsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.list +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.list import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxHeight @@ -48,9 +48,9 @@ import com.vitorpamplona.amethyst.commons.resources.follow_set_create_btn_label import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.fabBottomBarPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/membershipManagement/ArticleBookmarkListManagementScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/membershipManagement/ArticleBookmarkListManagementScreen.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/membershipManagement/ArticleBookmarkListManagementScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/membershipManagement/ArticleBookmarkListManagementScreen.kt index c562d73658..d57e476dc9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/membershipManagement/ArticleBookmarkListManagementScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/membershipManagement/ArticleBookmarkListManagementScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.membershipManagement +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.membershipManagement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.consumeWindowInsets @@ -46,10 +46,10 @@ import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.lists.list.NewListButton import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list.NewListButton +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.AddressBookmark diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/membershipManagement/PostBookmarkListManagementScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/membershipManagement/PostBookmarkListManagementScreen.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/membershipManagement/PostBookmarkListManagementScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/membershipManagement/PostBookmarkListManagementScreen.kt index 49564f47a5..d56674b3d2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/membershipManagement/PostBookmarkListManagementScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/membershipManagement/PostBookmarkListManagementScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.membershipManagement +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.membershipManagement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.consumeWindowInsets @@ -42,14 +42,14 @@ import com.vitorpamplona.amethyst.commons.nip51Lists.ui.BookmarkGroupManagementI import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.bookmarks_title import com.vitorpamplona.amethyst.commons.resources.post_bookmark_management_title +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.lists.list.NewListButton import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list.NewListButton +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.EventBookmark @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/podcasts/BookmarkedPodcastsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/podcasts/BookmarkedPodcastsScreen.kt similarity index 83% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/podcasts/BookmarkedPodcastsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/podcasts/BookmarkedPodcastsScreen.kt index 2238aa50c7..14f240517f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/podcasts/BookmarkedPodcastsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/podcasts/BookmarkedPodcastsScreen.kt @@ -18,22 +18,22 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.podcasts +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.podcasts import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.podcast_bookmarks +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.podcasts.dal.BookmarkPodcastsFeedViewModel import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.podcasts.dal.BookmarkPodcastsFeedViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun BookmarkedPodcastsScreen( @@ -41,7 +41,7 @@ fun BookmarkedPodcastsScreen( nav: INav, ) { val podcastsFeedViewModel: BookmarkPodcastsFeedViewModel = - viewModel( + rememberViewModel( key = "NostrBookmarkPodcastsFeedViewModel", factory = BookmarkPodcastsFeedViewModel.Factory(accountViewModel.account), ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/podcasts/dal/BookmarkPodcastsFeedFilter.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/podcasts/dal/BookmarkPodcastsFeedFilter.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/podcasts/dal/BookmarkPodcastsFeedFilter.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/podcasts/dal/BookmarkPodcastsFeedFilter.kt index a24837c64b..d50c0f7284 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/podcasts/dal/BookmarkPodcastsFeedFilter.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/podcasts/dal/BookmarkPodcastsFeedFilter.kt @@ -18,11 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.podcasts.dal +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.podcasts.dal import com.vitorpamplona.amethyst.commons.feeds.FeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nipXXPodcasting20.metadata.isPodcastEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/podcasts/dal/BookmarkPodcastsFeedViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/podcasts/dal/BookmarkPodcastsFeedViewModel.kt similarity index 76% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/podcasts/dal/BookmarkPodcastsFeedViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/podcasts/dal/BookmarkPodcastsFeedViewModel.kt index 2c65ed9673..a5d627ca70 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/podcasts/dal/BookmarkPodcastsFeedViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/podcasts/dal/BookmarkPodcastsFeedViewModel.kt @@ -18,13 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.podcasts.dal +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.podcasts.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import androidx.lifecycle.viewmodel.CreationExtras +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel +import kotlin.reflect.KClass @Stable class BookmarkPodcastsFeedViewModel( @@ -34,6 +36,9 @@ class BookmarkPodcastsFeedViewModel( val account: Account, ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class): T = BookmarkPodcastsFeedViewModel(account) as T + override fun create( + modelClass: KClass, + extras: CreationExtras, + ): T = BookmarkPodcastsFeedViewModel(account) as T } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/repositories/BookmarkedRepositoriesScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/repositories/BookmarkedRepositoriesScreen.kt similarity index 87% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/repositories/BookmarkedRepositoriesScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/repositories/BookmarkedRepositoriesScreen.kt index e0ee7a1320..3ebe6c2a78 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/repositories/BookmarkedRepositoriesScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/repositories/BookmarkedRepositoriesScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.repositories +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.repositories import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect @@ -26,17 +26,17 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.relayClient.event.EventFinderQueryState import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.repository_bookmarks +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.repositories.dal.BookmarkRepositoriesFeedViewModel import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.repositories.dal.BookmarkRepositoriesFeedViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address @Composable @@ -45,7 +45,7 @@ fun BookmarkedRepositoriesScreen( nav: INav, ) { val repositoriesFeedViewModel: BookmarkRepositoriesFeedViewModel = - viewModel( + rememberViewModel( key = "NostrBookmarkRepositoriesFeedViewModel", factory = BookmarkRepositoriesFeedViewModel.Factory(accountViewModel.account), ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/repositories/dal/BookmarkRepositoriesFeedFilter.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/repositories/dal/BookmarkRepositoriesFeedFilter.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/repositories/dal/BookmarkRepositoriesFeedFilter.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/repositories/dal/BookmarkRepositoriesFeedFilter.kt index f59d590b20..6afc2dfef4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/repositories/dal/BookmarkRepositoriesFeedFilter.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/repositories/dal/BookmarkRepositoriesFeedFilter.kt @@ -18,11 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.repositories.dal +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.repositories.dal import com.vitorpamplona.amethyst.commons.feeds.FeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.model.Account /** * The user's bookmarked (starred) git repositories — the public NIP-51 kind 10018 diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/repositories/dal/BookmarkRepositoriesFeedViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/repositories/dal/BookmarkRepositoriesFeedViewModel.kt similarity index 75% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/repositories/dal/BookmarkRepositoriesFeedViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/repositories/dal/BookmarkRepositoriesFeedViewModel.kt index cbef857aec..03bfda3b95 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/repositories/dal/BookmarkRepositoriesFeedViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/bookmarkgroups/repositories/dal/BookmarkRepositoriesFeedViewModel.kt @@ -18,13 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.repositories.dal +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.bookmarkgroups.repositories.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import androidx.lifecycle.viewmodel.CreationExtras +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel +import kotlin.reflect.KClass @Stable class BookmarkRepositoriesFeedViewModel( @@ -34,6 +36,9 @@ class BookmarkRepositoriesFeedViewModel( val account: Account, ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class): T = BookmarkRepositoriesFeedViewModel(account) as T + override fun create( + modelClass: KClass, + extras: CreationExtras, + ): T = BookmarkRepositoriesFeedViewModel(account) as T } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentPersonaEditScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/buzz/AgentPersonaEditScreen.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentPersonaEditScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/buzz/AgentPersonaEditScreen.kt index d91bcf5103..cb87858fa0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentPersonaEditScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/buzz/AgentPersonaEditScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.buzz import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -37,7 +37,6 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.buzz.ui.DropdownOption import com.vitorpamplona.amethyst.commons.buzz.ui.EditableSuggestDropdown import com.vitorpamplona.amethyst.commons.resources.Res @@ -53,10 +52,11 @@ import com.vitorpamplona.amethyst.commons.resources.buzz_persona_runtime import com.vitorpamplona.amethyst.commons.resources.buzz_persona_slug import com.vitorpamplona.amethyst.commons.resources.buzz_persona_slug_help import com.vitorpamplona.amethyst.commons.resources.buzz_persona_system_prompt +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel // Well-known values for the persona's optional model / provider / runtime — suggestions only; any // string is still accepted (the fields are free-form both in NIP-AP and in Buzz's persona events). @@ -93,7 +93,7 @@ fun AgentPersonaEditScreen( nav: INav, ) { val pubkey = accountViewModel.account.userProfile().pubkeyHex - val viewModel: AgentPersonaEditViewModel = viewModel(key = "PersonaEdit-$pubkey-${slug ?: "new"}") + val viewModel: AgentPersonaEditViewModel = rememberViewModel(key = "PersonaEdit-$pubkey-${slug ?: "new"}") { AgentPersonaEditViewModel() } viewModel.bind(accountViewModel.account, slug) val state by viewModel.state.collectAsStateWithLifecycle() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentPersonaEditViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/buzz/AgentPersonaEditViewModel.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentPersonaEditViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/buzz/AgentPersonaEditViewModel.kt index e3e4ed39d3..b8aeca7b13 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/AgentPersonaEditViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/buzz/AgentPersonaEditViewModel.kt @@ -18,22 +18,24 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.buzz import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.buzz.BuzzRelayDialect import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.buzz.apPersonas.PersonaContent import com.vitorpamplona.quartz.buzz.apPersonas.PersonaEvent import com.vitorpamplona.quartz.nip01Core.core.Address import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import kotlin.concurrent.Volatile import kotlin.coroutines.cancellation.CancellationException /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzForumPostScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/buzz/BuzzForumPostScreen.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzForumPostScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/buzz/BuzzForumPostScreen.kt index de6e21895d..9357168de3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzForumPostScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/buzz/BuzzForumPostScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.buzz import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -50,10 +50,11 @@ import com.vitorpamplona.amethyst.commons.resources.buzz_forum_post_action import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.buzz.forum.ForumPostEvent import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.launch import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzNewDmScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/buzz/BuzzNewDmScreen.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzNewDmScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/buzz/BuzzNewDmScreen.kt index 3c3bf07f45..4179f78f02 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzNewDmScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/buzz/BuzzNewDmScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.buzz import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -58,12 +58,12 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserName import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.buzz_dm_add_hint import com.vitorpamplona.amethyst.commons.resources.buzz_dm_new @@ -72,12 +72,12 @@ import com.vitorpamplona.amethyst.commons.resources.buzz_dm_recipients import com.vitorpamplona.amethyst.commons.resources.buzz_dm_remove import com.vitorpamplona.amethyst.commons.resources.buzz_dm_start import com.vitorpamplona.amethyst.commons.resources.buzz_dm_workspace +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl @@ -94,7 +94,7 @@ fun BuzzNewDmScreen( accountViewModel: AccountViewModel, nav: INav, ) { - val viewModel: BuzzNewDmViewModel = viewModel(key = "BuzzNewDm-$relayUrl") + val viewModel: BuzzNewDmViewModel = rememberViewModel(key = "BuzzNewDm-$relayUrl") { BuzzNewDmViewModel() } viewModel.bind(accountViewModel.account, relayUrl) val relays by viewModel.relays.collectAsStateWithLifecycle() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzNewDmViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/buzz/BuzzNewDmViewModel.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzNewDmViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/buzz/BuzzNewDmViewModel.kt index 56dd1135d7..68b11b99fa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/buzz/BuzzNewDmViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/buzz/BuzzNewDmViewModel.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.buzz import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.buzz.dm.DmOpenEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.isValid @@ -32,6 +32,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip19Bech32.decodePublicKeyAsHexOrNull import com.vitorpamplona.quartz.nip29RelayGroups.GroupId import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow @@ -40,6 +41,7 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import kotlin.concurrent.Volatile import kotlin.coroutines.cancellation.CancellationException /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnInvitationsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/cordnGroup/CordnInvitationsScreen.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnInvitationsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/cordnGroup/CordnInvitationsScreen.kt index b145042c85..ff29f7a4bf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnInvitationsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/cordnGroup/CordnInvitationsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.cordnGroup +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.cordnGroup import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -52,6 +52,8 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.cordn.CordnInvitation +import com.vitorpamplona.amethyst.commons.model.cordn.CordnInvitations import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back @@ -74,14 +76,12 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_unreachabl import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_via import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.model.cordn.CordnInvitation -import com.vitorpamplona.amethyst.model.cordn.CordnInvitations -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex -import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.CoordinatorIdentityRow -import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.coordinatorDisplayName -import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings.cordn.CoordinatorIdentityRow +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings.cordn.coordinatorDisplayName +import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.coroutines.launch import org.jetbrains.compose.resources.pluralStringResource diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderBuzzSystemMessage.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/feed/types/RenderBuzzSystemMessage.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderBuzzSystemMessage.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/feed/types/RenderBuzzSystemMessage.kt index 47f30f5858..15407c8a23 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderBuzzSystemMessage.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/feed/types/RenderBuzzSystemMessage.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -30,6 +30,7 @@ import com.vitorpamplona.amethyst.commons.chats.ui.ChatSystemMessage import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserName import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.buzz_system_channel_archived import com.vitorpamplona.amethyst.commons.resources.buzz_system_channel_created @@ -56,12 +57,11 @@ import com.vitorpamplona.amethyst.commons.resources.duration_days import com.vitorpamplona.amethyst.commons.resources.duration_hours import com.vitorpamplona.amethyst.commons.resources.duration_minutes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size18dp -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.buzz.stream.SystemMessageEvent import com.vitorpamplona.quartz.buzz.stream.SystemMessagePayload import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChatClip.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/feed/types/RenderChatClip.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChatClip.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/feed/types/RenderChatClip.kt index 493524718c..f86db2c1f2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChatClip.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/feed/types/RenderChatClip.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -39,15 +39,15 @@ import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.StreamSystemCar import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.chat_clip_created_a_clip import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.CrossfadeToDisplayComment +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.platform.VideoView import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer -import com.vitorpamplona.amethyst.service.playback.composable.VideoView -import com.vitorpamplona.amethyst.ui.note.CrossfadeToDisplayComment -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip53LiveActivities.clip.LiveActivitiesClipEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderEncryptedFile.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/feed/types/RenderEncryptedFile.kt similarity index 89% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderEncryptedFile.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/feed/types/RenderEncryptedFile.kt index bfc0d136ee..fdfe6f54ea 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderEncryptedFile.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/feed/types/RenderEncryptedFile.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -28,7 +28,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.audio.WaveformData import com.vitorpamplona.amethyst.commons.model.EmptyTagList import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.resources.Res @@ -37,16 +37,16 @@ import com.vitorpamplona.amethyst.commons.richtext.BaseMediaContent import com.vitorpamplona.amethyst.commons.richtext.EncryptedMediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.EncryptedMediaUrlVideo import com.vitorpamplona.amethyst.commons.richtext.RichTextParser +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.platform.RenderAudioWithWaveform +import com.vitorpamplona.amethyst.commons.ui.note.platform.ZoomableContentView import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.playback.composable.WaveformData -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.components.ZoomableContentView -import com.vitorpamplona.amethyst.ui.note.types.RenderAudioWithWaveform -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip17Dm.files.ChatMessageEncryptedFileHeaderEvent import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.utils.ciphers.AESGCM +import com.vitorpamplona.quartz.utils.ciphers.AES_GCM_NAME import kotlinx.collections.immutable.persistentListOf @Composable @@ -63,8 +63,8 @@ fun RenderEncryptedFile( val nonce = noteEvent.nonce() val mimeType = noteEvent.mimeType() - if (algo == AESGCM.NAME && key != null && nonce != null) { - Amethyst.instance.keyCache.add(noteEvent.content, AESGCM(key, nonce), mimeType) + if (algo == AES_GCM_NAME && key != null && nonce != null) { + accountViewModel.account.encryptionKeyCache.add(noteEvent.content, AESGCM(key, nonce), mimeType) // Audio is neither an image nor a video, and the image-or-video split // below would hand it to the video player: a picture-less surface where diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/GeohashTeleportScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/geohashChat/GeohashTeleportScreen.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/GeohashTeleportScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/geohashChat/GeohashTeleportScreen.kt index 64a8c48852..ab1838ea20 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/geohashChat/GeohashTeleportScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/geohashChat/GeohashTeleportScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.geohashChat +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.geohashChat import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -32,9 +32,9 @@ import com.vitorpamplona.amethyst.commons.resources.geohash_teleport_action import com.vitorpamplona.amethyst.commons.resources.geohash_teleport_title import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton +import com.vitorpamplona.amethyst.commons.ui.platform.GeohashLocationPickerContent import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.note.creators.location.GeohashLocationPickerContent -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Teleport: pick a point on the map to join a remote geohash cell (at a chosen diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/ChatroomHeader.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/privateDM/header/ChatroomHeader.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/ChatroomHeader.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/privateDM/header/ChatroomHeader.kt index 12aa554715..8956f4e0a1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/ChatroomHeader.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/privateDM/header/ChatroomHeader.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.header +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.privateDM.header import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -32,13 +32,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.NonClickableUserPictures +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.theme.Size34dp import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.NonClickableUserPictures -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/RoomNameOnlyDisplay.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/privateDM/header/RoomNameOnlyDisplay.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/RoomNameOnlyDisplay.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/privateDM/header/RoomNameOnlyDisplay.kt index 363ba6a17e..bd270d8320 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/RoomNameOnlyDisplay.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/privateDM/header/RoomNameOnlyDisplay.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.header +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.privateDM.header import androidx.compose.foundation.layout.Row import androidx.compose.material3.Text @@ -30,12 +30,12 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey import kotlin.math.min diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordInviteScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/concord/ConcordInviteScreen.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordInviteScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/concord/ConcordInviteScreen.kt index fda5e42f95..a72355ef84 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordInviteScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/concord/ConcordInviteScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -58,10 +58,10 @@ import com.vitorpamplona.amethyst.commons.resources.concord_invite_preview_relay import com.vitorpamplona.amethyst.commons.resources.concord_invite_preview_unknown_name import com.vitorpamplona.amethyst.commons.resources.concord_redeeming_invite import com.vitorpamplona.amethyst.commons.resources.retry +import com.vitorpamplona.amethyst.commons.ui.components.ConcordInvitePreviewRow import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.components.ConcordInvitePreviewRow -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.concord.cord05Invites.ParsedInviteLink import org.jetbrains.compose.resources.StringResource @@ -97,7 +97,7 @@ private sealed interface RedeemState { * the user's own identity to those relays, and writes the community into the user's * private kind-13302 list. Doing that on arrival turned any link into a one-click * deanonymize-and-enroll primitive, so the screen now opens on a local-only preview - * and only calls [com.vitorpamplona.amethyst.model.Account.joinConcordViaInvite] from + * and only calls [com.vitorpamplona.amethyst.commons.model.Account.joinConcordViaInvite] from * the Join button. * * Everything shown before that tap comes from decoding the URL itself diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordMemberHarvest.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/concord/ConcordMemberHarvest.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordMemberHarvest.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/concord/ConcordMemberHarvest.kt index c68a503873..17da86b8b8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordMemberHarvest.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/concord/ConcordMemberHarvest.kt @@ -18,19 +18,20 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.concord.envelope.ConcordStreamEnvelope import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.fetchAllPagesFromPool import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.withContext /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordMembersScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/concord/ConcordMembersScreen.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordMembersScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/concord/ConcordMembersScreen.kt index d09ff1be8d..8df45dbba3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/ConcordMembersScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/concord/ConcordMembersScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -83,12 +83,12 @@ import com.vitorpamplona.amethyst.commons.resources.concord_role_banned import com.vitorpamplona.amethyst.commons.resources.concord_role_owner import com.vitorpamplona.amethyst.commons.resources.more_options import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource.ConcordChannelSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.concord.cord04Roles.ConcordPermissions import com.vitorpamplona.quartz.nip01Core.core.HexKey import kotlinx.coroutines.flow.MutableStateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelPreviewLoader.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelPreviewLoader.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelPreviewLoader.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelPreviewLoader.kt index 7c287c1241..19a525309c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelPreviewLoader.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelPreviewLoader.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.coroutines.delay /** @@ -33,7 +33,7 @@ import kotlinx.coroutines.delay * * Not a live subscription: it drains one `limit:1` REQ per channel once (the wraps ingest through the * normal cache path and the always-on plane subscription keeps them fresh afterward — see - * [com.vitorpamplona.amethyst.model.Account.warmConcordChannelPreviews]). It re-runs when a fold + * [com.vitorpamplona.amethyst.commons.model.Account.warmConcordChannelPreviews]). It re-runs when a fold * changes the channel set, debounced so the cold-boot burst of fold revisions coalesces into one warm. */ @Composable @@ -59,7 +59,7 @@ fun ConcordChannelPreviewLoader( * high in the logged-in tree from `ConcordChannelPreload`. This is why the Messages inbox shows a last * message for channels the user never opened — one drain covers all joined communities at once. * - * A single [com.vitorpamplona.amethyst.model.Account.warmConcordChannelPreviews] call groups every + * A single [com.vitorpamplona.amethyst.commons.model.Account.warmConcordChannelPreviews] call groups every * community's per-channel `limit:1` filters by relay, so there is one REQ per relay (not one live * subscription per community). Debounced on the fold revision so the cold-boot burst warms once. */ diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelSubscription.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelSubscription.kt index 9e25cb7c40..f9cfdfeb36 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/concord/datasource/ConcordChannelSubscription.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.concord.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.concord.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -26,10 +26,12 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.chats.publicChannels.concord.datasource.ConcordChannelFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.concord.datasource.ConcordChannelQueryState import com.vitorpamplona.amethyst.commons.model.navigation.BottomBarEntry import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.utils.TimeUtils @@ -120,7 +122,7 @@ fun ConcordChannelPreload(accountViewModel: AccountViewModel) { * ([ConcordChannelFilterAssembler]) carries brand-new editions in real time, but it advances a * `since` cursor and rides the relay's per-filter cap, so it can miss an edition below the high-water * mark or a cropped initial page — either of which folds a partial channel list / stale roster. - * [com.vitorpamplona.amethyst.model.Account.syncConcordControlPlanes] closes both by re-fetching the + * [com.vitorpamplona.amethyst.commons.model.Account.syncConcordControlPlanes] closes both by re-fetching the * whole plane with no `since`, paging past the cap. * * It fires only on the **events** that can create a gap — never on a wall-clock poll, because a @@ -185,7 +187,7 @@ private const val RECONNECT_RESWEEP_MIN_INTERVAL_MS = 60_000L /** * Fetch the private kind-13302 list of any Concord community pinned to the bottom bar whose list we * don't already have, from the relays saved on its tab (see - * [com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel.importConcordCommunities]). Runs + * [com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel.importConcordCommunities]). Runs * app-wide as part of [ConcordChannelPreload], so a pinned community loads without the user ever * opening the Concord hub (which has its own import). Keyed on the exact set of missing communities, * so the (slow, stock-relay) fetch runs when a new gap appears — a freshly pinned community we can't @@ -209,7 +211,9 @@ private fun bootstrapPinnedCommunities(accountViewModel: AccountViewModel) { is BottomBarEntry.ConcordChannel -> it.communityId else -> null } - }.filterTo(sortedSetOf()) { it !in known } + }.filter { it !in known } + .sorted() + .toSet() } LaunchedEffect(missingPinned) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/PublicChatChannelHeader.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/PublicChatChannelHeader.kt similarity index 86% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/PublicChatChannelHeader.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/PublicChatChannelHeader.kt index d501a77dff..e5c839cf71 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/PublicChatChannelHeader.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/PublicChatChannelHeader.kt @@ -18,19 +18,19 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat import androidx.compose.foundation.layout.padding import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadPublicChatChannel +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.PublicChatChannelHeader import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding import com.vitorpamplona.amethyst.commons.ui.theme.innerPostModifier -import com.vitorpamplona.amethyst.ui.note.LoadPublicChatChannel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.PublicChatChannelHeader +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/LongPublicChatChannelHeader.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/LongPublicChatChannelHeader.kt similarity index 87% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/LongPublicChatChannelHeader.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/LongPublicChatChannelHeader.kt index 9a7cd2b7f1..e03d597b79 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/LongPublicChatChannelHeader.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/LongPublicChatChannelHeader.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -45,33 +45,33 @@ import com.vitorpamplona.amethyst.commons.chats.ui.LeaveChannelButton import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.commons.nip28PublicChat.ui.EditChannelButton +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannel +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserIsFollowingChannel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.channel_image import com.vitorpamplona.amethyst.commons.resources.created_at import com.vitorpamplona.amethyst.commons.resources.groups_no_descriptor import com.vitorpamplona.amethyst.commons.resources.owner +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteAuthorPicture +import com.vitorpamplona.amethyst.commons.ui.note.NoteUsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.elements.MoreOptionsButton import com.vitorpamplona.amethyst.commons.ui.note.elements.NormalTimeAgo import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions.LinkChatButton +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions.MuteChatButton +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions.OpenChatButton +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions.ShareChatButton import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.largeProfilePictureModifier -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsFollowingChannel -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture -import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay -import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions.LinkChatButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions.MuteChatButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions.OpenChatButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions.ShareChatButton +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun LongPublicChatChannelHeader( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/PublicChatChannelHeader.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/PublicChatChannelHeader.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/PublicChatChannelHeader.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/PublicChatChannelHeader.kt index 49537a10c5..d365415c92 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/PublicChatChannelHeader.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/PublicChatChannelHeader.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -31,9 +31,9 @@ import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun PublicChatChannelHeader( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/ShortPublicChatChannelHeader.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/ShortPublicChatChannelHeader.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/ShortPublicChatChannelHeader.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/ShortPublicChatChannelHeader.kt index 3d25da077a..14cc928633 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/ShortPublicChatChannelHeader.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/ShortPublicChatChannelHeader.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -39,22 +39,22 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.chats.ui.JoinChannelButton import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannel +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserIsFollowingChannel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.profile_image +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.platform.LikeReaction +import com.vitorpamplona.amethyst.commons.ui.note.platform.ZapReaction import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.HeaderPictureModifier import com.vitorpamplona.amethyst.commons.ui.theme.RowColSpacing import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsFollowingChannel -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.note.LikeReaction -import com.vitorpamplona.amethyst.ui.note.ZapReaction -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun ShortPublicChatChannelHeader( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/LinkChatButton.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/LinkChatButton.kt similarity index 72% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/LinkChatButton.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/LinkChatButton.kt index 47fa72b18d..e66fcfdeea 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/LinkChatButton.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/LinkChatButton.kt @@ -18,28 +18,27 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions -import android.content.Intent import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material3.FilledTonalButton import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.unit.dp -import androidx.core.net.toUri import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.quick_action_copy_note_id import com.vitorpamplona.amethyst.commons.resources.quick_action_share_browser_link +import com.vitorpamplona.amethyst.commons.ui.components.rememberTextSharer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.ZeroPadding -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun LinkChatButton( @@ -49,7 +48,8 @@ fun LinkChatButton( ) { val quickActionShareBrowserLinkStr = stringRes(Res.string.quick_action_share_browser_link) val quickActionCopyNoteIdStr = stringRes(Res.string.quick_action_copy_note_id) - val context = LocalContext.current + val uriHandler = LocalUriHandler.current + val sharer = rememberTextSharer() FilledTonalButton( modifier = @@ -57,26 +57,9 @@ fun LinkChatButton( .padding(horizontal = 3.dp) .width(50.dp), onClick = { - val intent = Intent(Intent.ACTION_VIEW, channel.toNostrUri().toUri()) - intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + runCatching { uriHandler.openUri(channel.toNostrUri()) } - context.startActivity(intent) - - val sendIntent = - Intent().apply { - action = Intent.ACTION_SEND - type = "text/plain" - putExtra(Intent.EXTRA_TEXT, channel.toNostrUri()) - putExtra(Intent.EXTRA_TITLE, quickActionShareBrowserLinkStr) - } - - val shareIntent = - Intent.createChooser( - sendIntent, - quickActionCopyNoteIdStr, - ) - - context.startActivity(shareIntent) + sharer.share(channel.toNostrUri(), quickActionShareBrowserLinkStr, quickActionCopyNoteIdStr) }, contentPadding = ZeroPadding, ) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/MuteChatButton.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/MuteChatButton.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/MuteChatButton.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/MuteChatButton.kt index 47418b63c9..8aeb1ae0d2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/MuteChatButton.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/MuteChatButton.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.chats.ui.MuteChannelButton import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun MuteChatButton( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/OpenChatButton.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/OpenChatButton.kt similarity index 82% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/OpenChatButton.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/OpenChatButton.kt index a4d8814e45..2c951e4aac 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/OpenChatButton.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/OpenChatButton.kt @@ -18,17 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions -import android.content.Intent import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material3.FilledTonalButton import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.unit.dp -import androidx.core.net.toUri import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChannel @@ -38,7 +36,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.ZeroPadding -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun OpenChatButton( @@ -46,7 +44,7 @@ fun OpenChatButton( accountViewModel: AccountViewModel, nav: INav, ) { - val context = LocalContext.current + val uriHandler = LocalUriHandler.current FilledTonalButton( modifier = @@ -54,10 +52,7 @@ fun OpenChatButton( .padding(horizontal = 3.dp) .width(50.dp), onClick = { - val intent = Intent(Intent.ACTION_VIEW, channel.toNostrUri().toUri()) - intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK - - context.startActivity(intent) + runCatching { uriHandler.openUri(channel.toNostrUri()) } }, contentPadding = ZeroPadding, ) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/ShareChatButton.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/ShareChatButton.kt similarity index 77% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/ShareChatButton.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/ShareChatButton.kt index 8eff26b595..9d5c889754 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/ShareChatButton.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/actions/ShareChatButton.kt @@ -18,15 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions -import android.content.Intent import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material3.FilledTonalButton import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -34,12 +32,13 @@ import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChann import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.quick_action_share import com.vitorpamplona.amethyst.commons.resources.quick_action_share_browser_link +import com.vitorpamplona.amethyst.commons.ui.components.rememberTextSharer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.ZeroPadding import com.vitorpamplona.amethyst.commons.util.njumpLink -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun ShareChatButton( @@ -49,7 +48,7 @@ fun ShareChatButton( ) { val quickActionShareBrowserLinkStr = stringRes(Res.string.quick_action_share_browser_link) val quickActionShareStr = stringRes(Res.string.quick_action_share) - val context = LocalContext.current + val sharer = rememberTextSharer() FilledTonalButton( modifier = @@ -57,21 +56,7 @@ fun ShareChatButton( .padding(horizontal = 3.dp) .width(50.dp), onClick = { - val sendIntent = - Intent().apply { - action = Intent.ACTION_SEND - type = "text/plain" - putExtra(Intent.EXTRA_TEXT, njumpLink(channel.toNEvent())) - putExtra(Intent.EXTRA_TITLE, quickActionShareBrowserLinkStr) - } - - val shareIntent = - Intent.createChooser( - sendIntent, - quickActionShareStr, - ) - - context.startActivity(shareIntent) + sharer.share(njumpLink(channel.toNEvent()), quickActionShareBrowserLinkStr, quickActionShareStr) }, contentPadding = ZeroPadding, ) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/ShowVideoStreaming.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/ShowVideoStreaming.kt similarity index 87% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/ShowVideoStreaming.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/ShowVideoStreaming.kt index d5c87934d4..e064918d70 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/ShowVideoStreaming.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/ShowVideoStreaming.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row @@ -28,13 +28,13 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.layout.ContentScale import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannelInfo import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo +import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeCheckIfVideoIsOnline +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning +import com.vitorpamplona.amethyst.commons.ui.note.platform.ZoomableContentView import com.vitorpamplona.amethyst.commons.ui.theme.StreamingHeaderModifier -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannelInfo -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.components.ZoomableContentView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CrossfadeCheckIfVideoIsOnline +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun ShowVideoStreaming( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveActivitiesChannelHeader.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveActivitiesChannelHeader.kt similarity index 89% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveActivitiesChannelHeader.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveActivitiesChannelHeader.kt index 2745ea645a..bc1c44496f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveActivitiesChannelHeader.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveActivitiesChannelHeader.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -31,10 +31,10 @@ import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.ShowVideoStreaming import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.ShowVideoStreaming +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun LiveActivitiesChannelHeader( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LongLiveActivityChannelHeader.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LongLiveActivityChannelHeader.kt similarity index 87% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LongLiveActivityChannelHeader.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LongLiveActivityChannelHeader.kt index 99a26c721d..c0e824072d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LongLiveActivityChannelHeader.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LongLiveActivityChannelHeader.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -37,7 +37,8 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.text.capitalize +import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.User @@ -45,27 +46,27 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.created_at import com.vitorpamplona.amethyst.commons.resources.groups_no_descriptor import com.vitorpamplona.amethyst.commons.resources.owner +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.NoteAuthorPicture +import com.vitorpamplona.amethyst.commons.ui.note.NoteUsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.elements.DisplayUncitedHashtags +import com.vitorpamplona.amethyst.commons.ui.note.elements.MoreOptionsButton import com.vitorpamplona.amethyst.commons.ui.note.elements.NormalTimeAgo import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp import com.vitorpamplona.amethyst.commons.util.equalImmutableLists -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture -import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags -import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.ParticipantTag @@ -73,6 +74,7 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.launch @Composable @@ -149,8 +151,6 @@ fun LongLiveActivityChannelHeader( } } - val locale = LocalConfiguration.current.locales.get(0) - participantUsers.forEach { Row( lineModifier.clickable { nav.nav(routeFor(it.second)) }, @@ -159,9 +159,7 @@ fun LongLiveActivityChannelHeader( it.first.role?.let { it1 -> Text( text = - it1.replaceFirstChar { - if (it.isLowerCase()) it.titlecase(locale) else it.toString() - }, + it1.capitalize(Locale.current), maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier.width(55.dp), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/ShortLiveActivityChannelHeader.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/ShortLiveActivityChannelHeader.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/ShortLiveActivityChannelHeader.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/ShortLiveActivityChannelHeader.kt index 7279559775..c8298857b2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/ShortLiveActivityChannelHeader.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/ShortLiveActivityChannelHeader.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -41,17 +41,17 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.LiveFlag import com.vitorpamplona.amethyst.commons.nip53LiveActivities.ui.OfflineFlag +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannel +import com.vitorpamplona.amethyst.commons.ui.components.CheckIfVideoIsOnline import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.platform.LikeReaction +import com.vitorpamplona.amethyst.commons.ui.note.platform.ZapReaction import com.vitorpamplona.amethyst.commons.ui.theme.RowColSpacing import com.vitorpamplona.amethyst.commons.ui.theme.Size34dp import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.ui.note.LikeReaction -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.ZapReaction -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CheckIfVideoIsOnline +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/BuzzChannelMenuItems.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/BuzzChannelMenuItems.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/BuzzChannelMenuItems.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/BuzzChannelMenuItems.kt index 81836641f5..878be1c761 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/BuzzChannelMenuItems.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/BuzzChannelMenuItems.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -27,7 +27,7 @@ import com.vitorpamplona.amethyst.commons.buzz.ui.BuzzPinDropdownItem import com.vitorpamplona.amethyst.commons.model.buzz.BuzzChannelStars import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.nip29RelayGroups.ui.RelayGroupMessagesDropdownItem -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip29RelayGroups.GroupId /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/LoadRelayGroupChannel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/LoadRelayGroupChannel.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/LoadRelayGroupChannel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/LoadRelayGroupChannel.kt index 65baa02dab..e71f181d98 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/LoadRelayGroupChannel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/LoadRelayGroupChannel.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel -import com.vitorpamplona.amethyst.ui.note.produceStateIfNotNull +import com.vitorpamplona.amethyst.commons.ui.note.produceStateIfNotNull import com.vitorpamplona.quartz.nip29RelayGroups.GroupId @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupDiscoveryScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupDiscoveryScreen.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupDiscoveryScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupDiscoveryScreen.kt index f2c36607d5..0597fe1ab9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupDiscoveryScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupDiscoveryScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -53,14 +53,18 @@ 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.chats.publicChannels.relayGroup.dal.relayGroupDiscoveryChannelFor 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 import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.WarmNip11 +import com.vitorpamplona.amethyst.commons.model.nip11RelayInfo.loadRelayInfo import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.toGroupConstraints +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserName import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.relay_group_badge_invite_only import com.vitorpamplona.amethyst.commons.resources.relay_group_badge_live @@ -73,35 +77,31 @@ import com.vitorpamplona.amethyst.commons.resources.relay_group_relay_group_coun import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar +import com.vitorpamplona.amethyst.commons.ui.note.RenderRelayIcon +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.note.timeAgo +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupSubscription +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupsDiscoveryFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp import com.vitorpamplona.amethyst.commons.ui.theme.warningColor -import com.vitorpamplona.amethyst.model.nip11RelayInfo.WarmNip11 -import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.note.RenderRelayIcon -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.dal.relayGroupDiscoveryChannelFor -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupsDiscoveryFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer @@ -110,7 +110,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl /** * Discover NIP-29 groups across the relay set the top-bar filter resolves to. Built on the shared * feed stack exactly like the Git-repositories screen: a [FeedContentState] - * ([com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountFeedContentStates.relayGroupsDiscoveryFeed]) + * ([com.vitorpamplona.amethyst.commons.viewmodels.AccountFeedContentStates.relayGroupsDiscoveryFeed]) * fed by the per-type datasource, a [FeedFilterSpinner] persisting the selection to * `defaultRelayGroupsDiscoveryFollowList`, and a [RefresheableBox] + [RenderFeedContentState]. Rows * are the relay-signed 39000 metadata notes, rendered as joinable group cards. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMembersScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMembersScreen.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMembersScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMembersScreen.kt index d94934ee10..8fc523e52a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMembersScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupMembersScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -62,7 +62,6 @@ 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.Amethyst import com.vitorpamplona.amethyst.commons.buzz.ui.PresenceDot import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -72,6 +71,7 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupMembership +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.channel.observeChannel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.buzz_add_people_hint import com.vitorpamplona.amethyst.commons.resources.buzz_agent_working @@ -91,16 +91,16 @@ import com.vitorpamplona.amethyst.commons.resources.relay_group_role_moderator import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.ShowUserSuggestionList +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.LoadRelayGroupChannel +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightChat -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.buzz.aoObserver.ObserverFrameEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.subscribeAsFlow @@ -269,7 +269,7 @@ private fun AddMemberBar( var query by remember { mutableStateOf("") } val userSuggestions = remember(accountViewModel) { - UserSuggestionState(accountViewModel.account, Amethyst.instance.nip05Client) + UserSuggestionState(accountViewModel.account, accountViewModel.nip05ClientBuilder()) } LaunchedEffect(query) { userSuggestions.processCurrentWord(query) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupThreadsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupThreadsScreen.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupThreadsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupThreadsScreen.kt index d190ffe3eb..217646dec4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupThreadsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/RelayGroupThreadsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -56,6 +56,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupOpenThreadsHistorySubAssembler import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note @@ -63,6 +64,7 @@ import com.vitorpamplona.amethyst.commons.model.buzz.BuzzRelayDialect import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupMembership +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteReplyCount import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.buzz_channel_archive import com.vitorpamplona.amethyst.commons.resources.buzz_channel_unarchive @@ -76,15 +78,13 @@ import com.vitorpamplona.amethyst.commons.resources.relay_group_threads_loading_ import com.vitorpamplona.amethyst.commons.resources.relay_group_threads_title import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupOpenThreadsHistorySubscription +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupOpenThreadsSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteReplyCount -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupOpenThreadsHistorySubAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupOpenThreadsHistorySubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupOpenThreadsSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.buzz.forum.ForumPostEvent import com.vitorpamplona.quartz.buzz.workspace.BUZZ_CHANNEL_TYPE_FORUM import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupCardWarmupSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupCardWarmupSubscription.kt similarity index 81% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupCardWarmupSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupCardWarmupSubscription.kt index 0f8b589b6e..2da98833b3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupCardWarmupSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupCardWarmupSubscription.kt @@ -18,13 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RELAY_GROUP_WARMUP_LIMIT +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupCardWarmupQueryState import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Mount on a group card to warm its recent content ahead of a tap. [contentOnly] drops the diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupOpenThreadsSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupOpenThreadsSubscription.kt similarity index 86% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupOpenThreadsSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupOpenThreadsSubscription.kt index f94b833729..c22c96e5ac 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupOpenThreadsSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupOpenThreadsSubscription.kt @@ -18,15 +18,17 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupOpenThreadsHistoryFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupOpenThreadsHistoryQueryState import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel import com.vitorpamplona.amethyst.commons.relayClient.channel.relayGroup.RelayGroupOpenThreadsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.channel.relayGroup.RelayGroupOpenThreadsQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip29RelayGroups.GroupId /** Mount on a group's Threads screen to stream its kind-11 threads + 1111 comments (the recent live tail). */ diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoveryFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoveryFilterAssemblerSubscription.kt similarity index 83% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoveryFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoveryFilterAssemblerSubscription.kt index 395e732d5e..89da904bd2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoveryFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/chats/publicChannels/relayGroup/datasource/RelayGroupsDiscoveryFilterAssemblerSubscription.kt @@ -18,13 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupsDiscoveryFilterAssembler +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.datasource.RelayGroupsDiscoveryQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun RelayGroupsDiscoveryFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/CommunityScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/CommunityScreen.kt similarity index 89% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/CommunityScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/CommunityScreen.kt index f06d203aa1..7bc5cdf95b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/CommunityScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/CommunityScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.communities +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.communities import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -42,33 +42,33 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.relayClient.communities.CommunityFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.feed import com.vitorpamplona.amethyst.commons.resources.mod_queue +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverPagerState +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TitleIconModifier import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.nip22Comments.LocalCurrentExternalScope +import com.vitorpamplona.amethyst.commons.ui.note.types.LongCommunityHeader +import com.vitorpamplona.amethyst.commons.ui.note.types.ShortCommunityActionOptions +import com.vitorpamplona.amethyst.commons.ui.note.types.ShortCommunityHeaderNoActions +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.communities.dal.CommunityFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.communities.dal.CommunityModerationFeedViewModel import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp import com.vitorpamplona.amethyst.commons.ui.theme.TabRowHeight import com.vitorpamplona.amethyst.commons.ui.theme.isLight -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.nip22Comments.LocalCurrentExternalScope -import com.vitorpamplona.amethyst.ui.note.types.LongCommunityHeader -import com.vitorpamplona.amethyst.ui.note.types.ShortCommunityActionOptions -import com.vitorpamplona.amethyst.ui.note.types.ShortCommunityHeaderNoActions -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.dal.CommunityFeedViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.dal.CommunityModerationFeedViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import kotlinx.coroutines.launch @@ -96,7 +96,7 @@ fun PrepareViewModelsCommunityScreen( nav: INav, ) { val followsFeedViewModel: CommunityFeedViewModel = - viewModel( + rememberViewModel( key = note.idHex + "CommunityFeedViewModel", factory = CommunityFeedViewModel.Factory( @@ -106,7 +106,7 @@ fun PrepareViewModelsCommunityScreen( ) val modFeedViewModel: CommunityModerationFeedViewModel = - viewModel( + rememberViewModel( key = note.idHex + "CommunityModerationFeedViewModel", factory = CommunityModerationFeedViewModel.Factory( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/NewCommunityNoteButton.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/NewCommunityNoteButton.kt similarity index 87% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/NewCommunityNoteButton.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/NewCommunityNoteButton.kt index 5caf54d578..ef17c05e29 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/NewCommunityNoteButton.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/NewCommunityNoteButton.kt @@ -18,25 +18,25 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.communities +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.communities import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.ic_compose import com.vitorpamplona.amethyst.commons.resources.new_community_note +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun NewCommunityNoteButton( @@ -68,7 +68,7 @@ fun NewCommunityNoteButton( containerColor = MaterialTheme.colorScheme.primary, ) { Icon( - painter = painterRes(R.drawable.ic_compose, 2), + painter = painterRes(Res.drawable.ic_compose, 2), contentDescription = stringRes(id = Res.string.new_community_note), modifier = Size26Modifier, tint = MaterialTheme.colorScheme.onPrimary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/dal/CommunityFeedFilter.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/dal/CommunityFeedFilter.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/dal/CommunityFeedFilter.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/dal/CommunityFeedFilter.kt index 9970d5352d..ea76b8d4c4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/dal/CommunityFeedFilter.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/dal/CommunityFeedFilter.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.dal +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.communities.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip72Communities.latestCommunityRules import com.vitorpamplona.amethyst.commons.model.nip72Communities.violatesCommunityRules -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip22Comments.CommentEvent import com.vitorpamplona.quartz.nip72ModCommunities.approval.CommunityPostApprovalEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/dal/CommunityFeedViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/dal/CommunityFeedViewModel.kt similarity index 78% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/dal/CommunityFeedViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/dal/CommunityFeedViewModel.kt index b8dab3c93d..b6ea382119 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/dal/CommunityFeedViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/dal/CommunityFeedViewModel.kt @@ -18,13 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.dal +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.communities.dal import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewmodel.CreationExtras +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel +import kotlin.reflect.KClass class CommunityFeedViewModel( val note: AddressableNote, @@ -41,6 +43,9 @@ class CommunityFeedViewModel( val account: Account, ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class): T = CommunityFeedViewModel(note, account) as T + override fun create( + modelClass: KClass, + extras: CreationExtras, + ): T = CommunityFeedViewModel(note, account) as T } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/dal/CommunityModerationFeedFilter.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/dal/CommunityModerationFeedFilter.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/dal/CommunityModerationFeedFilter.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/dal/CommunityModerationFeedFilter.kt index 044eb8f25a..52b797d104 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/dal/CommunityModerationFeedFilter.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/dal/CommunityModerationFeedFilter.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.dal +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.communities.dal import com.vitorpamplona.amethyst.commons.feeds.AdditiveFeedFilter +import com.vitorpamplona.amethyst.commons.feeds.sortedByDefaultFeedOrder +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip72Communities.latestCommunityRules import com.vitorpamplona.amethyst.commons.model.nip72Communities.violatesCommunityRules -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.dal.sortedByDefaultFeedOrder import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent import com.vitorpamplona.quartz.nip18Reposts.RepostEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/dal/CommunityModerationFeedViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/dal/CommunityModerationFeedViewModel.kt similarity index 78% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/dal/CommunityModerationFeedViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/dal/CommunityModerationFeedViewModel.kt index 773286c0d6..dd5e8b2469 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/dal/CommunityModerationFeedViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/communities/dal/CommunityModerationFeedViewModel.kt @@ -18,13 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.dal +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.communities.dal import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewmodel.CreationExtras +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel +import kotlin.reflect.KClass class CommunityModerationFeedViewModel( val note: AddressableNote, @@ -41,6 +43,9 @@ class CommunityModerationFeedViewModel( val account: Account, ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class): T = CommunityModerationFeedViewModel(note, account) as T + override fun create( + modelClass: KClass, + extras: CreationExtras, + ): T = CommunityModerationFeedViewModel(note, account) as T } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/contactList/ContactListUsersScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/contactList/ContactListUsersScreen.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/contactList/ContactListUsersScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/contactList/ContactListUsersScreen.kt index 56ae45f75f..c842b4691b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/contactList/ContactListUsersScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/contactList/ContactListUsersScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.contactList +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.contactList import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize @@ -34,18 +34,18 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEventAndMap import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.contact_list_screen_title import com.vitorpamplona.amethyst.commons.resources.contact_list_screen_title_with_count import com.vitorpamplona.amethyst.commons.resources.fetching_follow_list +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.UserCompose import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEventAndMap -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.note.UserCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip51FollowSets/FollowSetCard.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/discover/nip51FollowSets/FollowSetCard.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip51FollowSets/FollowSetCard.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/discover/nip51FollowSets/FollowSetCard.kt index 3e249d4a59..a802051143 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip51FollowSets/FollowSetCard.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/discover/nip51FollowSets/FollowSetCard.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip51FollowSets +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.discover.nip51FollowSets import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -39,10 +39,19 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteAndMap import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.GalleryUnloaded +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageBanner +import com.vitorpamplona.amethyst.commons.ui.note.elements.DefaultImageBannerBackground +import com.vitorpamplona.amethyst.commons.ui.note.platform.LikeReaction +import com.vitorpamplona.amethyst.commons.ui.note.platform.ZapReaction import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.FollowSetImageModifier @@ -51,17 +60,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.StdPadding import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteAndMap -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.note.GalleryUnloaded -import com.vitorpamplona.amethyst.ui.note.LikeReaction -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.ZapReaction -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageBanner -import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageBannerBackground -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip51Lists.starterPack.StarterPackEvent import kotlinx.collections.immutable.ImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/drafts/DraftListScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/drafts/DraftListScreen.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/drafts/DraftListScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/drafts/DraftListScreen.kt index 87ecad05b7..341cb6fd29 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/drafts/DraftListScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/drafts/DraftListScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.drafts +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.drafts import androidx.compose.animation.animateContentSize import androidx.compose.foundation.layout.Row @@ -53,22 +53,22 @@ import com.vitorpamplona.amethyst.commons.resources.no import com.vitorpamplona.amethyst.commons.resources.yes import com.vitorpamplona.amethyst.commons.ui.components.SwipeToDeleteWithConfirmation import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys.DRAFTS import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.SaveableFeedState import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.maxWidthWithBackground -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.SaveableFeedState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun DraftListScreen( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmHeartbeatObservation.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/dvms/DvmHeartbeatObservation.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmHeartbeatObservation.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/dvms/DvmHeartbeatObservation.kt index 5f9ae8e46e..573a64af3a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmHeartbeatObservation.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/dvms/DvmHeartbeatObservation.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.dvms import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row @@ -42,11 +42,11 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip90DVMs.DvmHeartbeatRegistry +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteAndMap import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.dvm_offline_banner import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteAndMap -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip90Dvms.dvmHeartbeat.DvmHeartbeatEvent import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/browse/BrowseEmojiSetsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/browse/BrowseEmojiSetsScreen.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/browse/BrowseEmojiSetsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/browse/BrowseEmojiSetsScreen.kt index ddcb0b073f..2918f9175b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/browse/BrowseEmojiSetsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/browse/BrowseEmojiSetsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.browse +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.browse import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Arrangement @@ -50,12 +50,12 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.StickToTopOnPrepend import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverLazyGridState +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.browse.datasource.BrowseEmojiSetsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.browse.datasource.BrowseEmojiSetsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent import com.vitorpamplona.quartz.nip30CustomEmoji.taggedEmojis diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/browse/BrowseEmojiSetsTopBar.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/browse/BrowseEmojiSetsTopBar.kt similarity index 86% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/browse/BrowseEmojiSetsTopBar.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/browse/BrowseEmojiSetsTopBar.kt index c5cf5c4fec..05370b32eb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/browse/BrowseEmojiSetsTopBar.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/browse/BrowseEmojiSetsTopBar.kt @@ -18,22 +18,22 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.browse +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.browse import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/browse/datasource/BrowseEmojiSetsFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/browse/datasource/BrowseEmojiSetsFilterAssemblerSubscription.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/browse/datasource/BrowseEmojiSetsFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/browse/datasource/BrowseEmojiSetsFilterAssemblerSubscription.kt index 1ed6bba621..0eb2fd0f0e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/browse/datasource/BrowseEmojiSetsFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/browse/datasource/BrowseEmojiSetsFilterAssemblerSubscription.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.browse.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.browse.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.emojipacks.BrowseEmojiSetsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun BrowseEmojiSetsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/list/ListOfEmojiPacksScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/list/ListOfEmojiPacksScreen.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/list/ListOfEmojiPacksScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/list/ListOfEmojiPacksScreen.kt index e385a772aa..b0acd8b104 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/list/ListOfEmojiPacksScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/list/ListOfEmojiPacksScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.list +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.list import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -58,6 +58,7 @@ import com.vitorpamplona.amethyst.commons.model.NoteState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.OwnedEmojiPack import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.EmojiPackCard +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteAndMap import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.add_to_emoji_list import com.vitorpamplona.amethyst.commons.resources.edit_emoji_pack @@ -77,15 +78,14 @@ import com.vitorpamplona.amethyst.commons.ui.components.M3ActionSection import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.fabBottomBarPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.note.VerticalDotsIcon +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.Size40Modifier import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteAndMap -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.tags.aTag.isTaggedAddressableNote import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/membershipManagement/EmojiPackSelectionScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/membershipManagement/EmojiPackSelectionScreen.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/membershipManagement/EmojiPackSelectionScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/membershipManagement/EmojiPackSelectionScreen.kt index e3774aa912..c987c06252 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/membershipManagement/EmojiPackSelectionScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/membershipManagement/EmojiPackSelectionScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.membershipManagement +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.membershipManagement import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -46,6 +46,7 @@ import androidx.compose.ui.text.style.TextOverflow import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.AddressableNote +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteAndMap import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.add_to_emoji_list import com.vitorpamplona.amethyst.commons.resources.emoji_pack_is_in_list @@ -56,12 +57,11 @@ import com.vitorpamplona.amethyst.commons.resources.remove_from_emoji_list import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size40Modifier import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteAndMap -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.tags.aTag.isTaggedAddressableNote import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/membershipManagement/MyEmojiListScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/membershipManagement/MyEmojiListScreen.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/membershipManagement/MyEmojiListScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/membershipManagement/MyEmojiListScreen.kt index b23457dc69..4318bfd5d7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/membershipManagement/MyEmojiListScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/emojipacks/membershipManagement/MyEmojiListScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.membershipManagement +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.emojipacks.membershipManagement import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -53,17 +53,17 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.EmojiPackCard +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEventAndMap import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.my_emoji_list_empty import com.vitorpamplona.amethyst.commons.resources.my_emoji_list_title import com.vitorpamplona.amethyst.commons.resources.remove_from_emoji_list import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEventAndMap -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent import com.vitorpamplona.quartz.nip30CustomEmoji.selection.EmojiListEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocacheFinds.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/geocaches/GeocacheFinds.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocacheFinds.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/geocaches/GeocacheFinds.kt index 6c90d45d6d..a02094e772 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/GeocacheFinds.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/geocaches/GeocacheFinds.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.geocaches import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.nipCCGeocaching.ui.rememberFoundCacheIds -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** The addresses the signed-in user has already logged a find on, from their Finds feed. */ @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/datasource/GeocachesFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/geocaches/datasource/GeocachesFilterAssemblerSubscription.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/datasource/GeocachesFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/geocaches/datasource/GeocachesFilterAssemblerSubscription.kt index a291a69dbe..78533356f4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/datasource/GeocachesFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/geocaches/datasource/GeocachesFilterAssemblerSubscription.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.geocaches.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.geocaches.GeocachesFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * The one geocaching subscription. Every surface that shows a cache — the hub's five tabs, the diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/hunt/GeocacheHuntScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/geocaches/hunt/GeocacheHuntScreen.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/hunt/GeocacheHuntScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/geocaches/hunt/GeocacheHuntScreen.kt index f1aa5a1344..bbcbdb7803 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/hunt/GeocacheHuntScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/geocaches/hunt/GeocacheHuntScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.hunt +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.geocaches.hunt import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -56,6 +56,8 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.GeocacheTab import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back import com.vitorpamplona.amethyst.commons.resources.geocache_hunt_progress @@ -63,19 +65,17 @@ import com.vitorpamplona.amethyst.commons.resources.geocache_hunt_start import com.vitorpamplona.amethyst.commons.resources.geocache_loading import com.vitorpamplona.amethyst.commons.resources.geocache_unnamed import com.vitorpamplona.amethyst.commons.resources.route_geocache_hunt_detail +import com.vitorpamplona.amethyst.commons.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.GeocacheSpecLine +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.note.geocacheEmoji import com.vitorpamplona.amethyst.commons.ui.note.rememberGeocachePalette +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.geocaches.datasource.GeocachesFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.geocaches.rememberMyFoundCacheIds import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.datasource.GeocachesFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.rememberMyFoundCacheIds +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nipCCGeocaching.curation.GeocacheCurationListEvent import com.vitorpamplona.quartz.nipCCGeocaching.listing.GeocacheListingEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/hunt/NewGeocacheHuntScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/geocaches/hunt/NewGeocacheHuntScreen.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/hunt/NewGeocacheHuntScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/geocaches/hunt/NewGeocacheHuntScreen.kt index 3b2f7f7ba5..cc25994f67 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/hunt/NewGeocacheHuntScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/geocaches/hunt/NewGeocacheHuntScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.hunt +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.geocaches.hunt import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -46,9 +46,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back import com.vitorpamplona.amethyst.commons.resources.geocache_hunt_banner @@ -63,12 +63,12 @@ import com.vitorpamplona.amethyst.commons.resources.geocache_new_publish import com.vitorpamplona.amethyst.commons.resources.geocache_unnamed import com.vitorpamplona.amethyst.commons.resources.route_edit_geocache_hunt import com.vitorpamplona.amethyst.commons.resources.route_new_geocache_hunt +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nipCCGeocaching.listing.GeocacheListingEvent import kotlinx.coroutines.launch @@ -94,7 +94,7 @@ fun NewGeocacheHuntScreen( editPubKeyHex: String? = null, editDTag: String? = null, ) { - val model: NewGeocacheHuntViewModel = viewModel() + val model: NewGeocacheHuntViewModel = rememberViewModel { NewGeocacheHuntViewModel() } val scope = rememberCoroutineScope() remember(editKind, editPubKeyHex, editDTag, seedCache) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/hunt/NewGeocacheHuntViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/geocaches/hunt/NewGeocacheHuntViewModel.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/hunt/NewGeocacheHuntViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/geocaches/hunt/NewGeocacheHuntViewModel.kt index 6d125fd6d8..1372286400 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geocaches/hunt/NewGeocacheHuntViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/geocaches/hunt/NewGeocacheHuntViewModel.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.hunt +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.geocaches.hunt import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nipCCGeocaching.curation.GeocacheCurationListEvent import com.vitorpamplona.quartz.nipCCGeocaching.curation.tags.ListTheme diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepositories/GitRepositoriesScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/gitRepositories/GitRepositoriesScreen.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepositories/GitRepositoriesScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/gitRepositories/GitRepositoriesScreen.kt index dcc52c03ba..7f9608924f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepositories/GitRepositoriesScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/gitRepositories/GitRepositoriesScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepositories +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.gitRepositories import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Column @@ -53,24 +53,24 @@ import com.vitorpamplona.amethyst.commons.resources.git_repositories_search_no_r import com.vitorpamplona.amethyst.commons.resources.git_repositories_search_placeholder import com.vitorpamplona.amethyst.commons.search.GitRepositorySearchMatcher import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.ClearTextIcon +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.note.SearchIcon +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.gitRepositories.datasource.GitRepositoriesFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepositories.datasource.GitRepositoriesFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepositories/GitRepositoriesTopBar.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/gitRepositories/GitRepositoriesTopBar.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepositories/GitRepositoriesTopBar.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/gitRepositories/GitRepositoriesTopBar.kt index 9ae61dcf9e..61e336c582 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepositories/GitRepositoriesTopBar.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/gitRepositories/GitRepositoriesTopBar.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepositories +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.gitRepositories import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -31,6 +31,8 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter @@ -40,17 +42,15 @@ import com.vitorpamplona.amethyst.commons.resources.git_repositories_search_open import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ShorterTopAppBar +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarNavigationIcon +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.searchRouteFor import com.vitorpamplona.amethyst.commons.ui.note.SearchIcon import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size22Modifier import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarNavigationIcon -import com.vitorpamplona.amethyst.ui.navigation.topbars.searchRouteFor -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent /** diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepositories/datasource/GitRepositoriesFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/gitRepositories/datasource/GitRepositoriesFilterAssemblerSubscription.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepositories/datasource/GitRepositoriesFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/gitRepositories/datasource/GitRepositoriesFilterAssemblerSubscription.kt index b646c0d5f5..df3a45587a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepositories/datasource/GitRepositoriesFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/gitRepositories/datasource/GitRepositoriesFilterAssemblerSubscription.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepositories.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.gitRepositories.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.gitRepositories.GitRepositoriesFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun GitRepositoriesFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/HighlightsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/highlights/HighlightsScreen.kt similarity index 87% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/HighlightsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/highlights/HighlightsScreen.kt index 52b246a02e..f48564f62d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/HighlightsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/highlights/HighlightsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.highlights +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.highlights import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -27,15 +27,15 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.highlights.datasource.HighlightsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.highlights.datasource.HighlightsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun HighlightsScreen( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/HighlightsTopBar.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/highlights/HighlightsTopBar.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/HighlightsTopBar.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/highlights/HighlightsTopBar.kt index d91793977f..ed3cda1f73 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/HighlightsTopBar.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/highlights/HighlightsTopBar.kt @@ -18,24 +18,24 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.highlights +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.highlights import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip84Highlights.HighlightEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/NewHighlightButton.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/highlights/NewHighlightButton.kt similarity index 89% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/NewHighlightButton.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/highlights/NewHighlightButton.kt index c42de023fe..7d2749d92b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/NewHighlightButton.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/highlights/NewHighlightButton.kt @@ -18,22 +18,22 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.highlights +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.highlights import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.ic_compose import com.vitorpamplona.amethyst.commons.resources.new_highlight_title import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier -import com.vitorpamplona.amethyst.ui.painterRes @Composable fun NewHighlightButton(nav: INav) { @@ -46,7 +46,7 @@ fun NewHighlightButton(nav: INav) { containerColor = MaterialTheme.colorScheme.primary, ) { Icon( - painter = painterRes(R.drawable.ic_compose, 4), + painter = painterRes(Res.drawable.ic_compose, 4), contentDescription = stringRes(Res.string.new_highlight_title), modifier = Size26Modifier, tint = MaterialTheme.colorScheme.onPrimary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/datasource/HighlightsFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/highlights/datasource/HighlightsFilterAssemblerSubscription.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/datasource/HighlightsFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/highlights/datasource/HighlightsFilterAssemblerSubscription.kt index ceab18159e..9b128077e8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/highlights/datasource/HighlightsFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/highlights/datasource/HighlightsFilterAssemblerSubscription.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.highlights.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.highlights.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.highlights.HighlightsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun HighlightsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/interestSets/display/InterestSetScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/interestSets/display/InterestSetScreen.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/interestSets/display/InterestSetScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/interestSets/display/InterestSetScreen.kt index a73e52934e..6b44235214 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/interestSets/display/InterestSetScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/interestSets/display/InterestSetScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.interestSets.display +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.interestSets.display import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -60,7 +60,7 @@ import com.vitorpamplona.amethyst.commons.resources.quick_action_delete import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun InterestSetScreen( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/interestSets/list/ListOfInterestSetsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/interestSets/list/ListOfInterestSetsScreen.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/interestSets/list/ListOfInterestSetsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/interestSets/list/ListOfInterestSetsScreen.kt index e0269d1c9c..be9c843090 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/interestSets/list/ListOfInterestSetsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/interestSets/list/ListOfInterestSetsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.interestSets.list +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.interestSets.list import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -55,11 +55,11 @@ import com.vitorpamplona.amethyst.commons.resources.interest_sets_title import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.fabBottomBarPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.coroutines.launch @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/interestSets/list/metadata/InterestSetMetadataScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/interestSets/list/metadata/InterestSetMetadataScreen.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/interestSets/list/metadata/InterestSetMetadataScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/interestSets/list/metadata/InterestSetMetadataScreen.kt index 1a509dffbe..569710bcfa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/interestSets/list/metadata/InterestSetMetadataScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/interestSets/list/metadata/InterestSetMetadataScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.interestSets.list.metadata +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.interestSets.list.metadata import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize @@ -38,7 +38,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.style.TextDirection import androidx.compose.ui.unit.dp -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.interest_set_creation_screen_title import com.vitorpamplona.amethyst.commons.resources.interest_set_name_label @@ -46,13 +45,14 @@ import com.vitorpamplona.amethyst.commons.resources.interest_set_name_placeholde import com.vitorpamplona.amethyst.commons.resources.interest_set_rename import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_be_able_to_sign_events import com.vitorpamplona.amethyst.commons.resources.read_only_user +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.CreatingTopBar import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.SavingTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions @Composable @@ -61,7 +61,7 @@ fun InterestSetMetadataScreen( accountViewModel: AccountViewModel, nav: INav, ) { - val viewModel: InterestSetMetadataViewModel = viewModel() + val viewModel: InterestSetMetadataViewModel = rememberViewModel { InterestSetMetadataViewModel() } viewModel.init(accountViewModel) if (identifier != null) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/interestSets/list/metadata/InterestSetMetadataViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/interestSets/list/metadata/InterestSetMetadataViewModel.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/interestSets/list/metadata/InterestSetMetadataViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/interestSets/list/metadata/InterestSetMetadataViewModel.kt index e3458289e7..90d0802e21 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/interestSets/list/metadata/InterestSetMetadataViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/interestSets/list/metadata/InterestSetMetadataViewModel.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.interestSets.list.metadata +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.interestSets.list.metadata import androidx.compose.runtime.Stable import androidx.compose.runtime.derivedStateOf @@ -27,9 +27,9 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.ViewModel +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.nip51Lists.interestSets.InterestSet -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Stable class InterestSetMetadataViewModel : ViewModel() { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/FollowPackViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/list/FollowPackViewModel.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/FollowPackViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/list/FollowPackViewModel.kt index a2bdd2eb2d..6d98405b81 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/FollowPackViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/list/FollowPackViewModel.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.lists.list import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import com.vitorpamplona.amethyst.commons.model.nip51Lists.followSets.PeopleList -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Stable class FollowPackViewModel : ViewModel() { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/ListOfPeopleListFeedView.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/list/ListOfPeopleListFeedView.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/ListOfPeopleListFeedView.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/list/ListOfPeopleListFeedView.kt index e05a5cc192..290455bbba 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/ListOfPeopleListFeedView.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/list/ListOfPeopleListFeedView.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.lists.list import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/ListOfPeopleListsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/list/ListOfPeopleListsScreen.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/ListOfPeopleListsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/list/ListOfPeopleListsScreen.kt index 048618b974..10fb42d4af 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/ListOfPeopleListsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/list/ListOfPeopleListsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.lists.list import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -32,19 +32,19 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.follow_set_create_btn_label import com.vitorpamplona.amethyst.commons.resources.my_lists +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.SpacedBy5dp -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.coroutines.launch @Composable @@ -52,10 +52,10 @@ fun ListOfPeopleListsScreen( accountViewModel: AccountViewModel, nav: INav, ) { - val list: PeopleListViewModel = viewModel() + val list: PeopleListViewModel = rememberViewModel { PeopleListViewModel() } list.init(accountViewModel) - val pack: FollowPackViewModel = viewModel() + val pack: FollowPackViewModel = rememberViewModel { FollowPackViewModel() } pack.init(accountViewModel) ListOfPeopleListsScreen(list, pack, accountViewModel, nav) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/PeopleListViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/list/PeopleListViewModel.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/PeopleListViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/list/PeopleListViewModel.kt index 808b175ada..10ba0e6075 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/PeopleListViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/list/PeopleListViewModel.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.lists.list import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import com.vitorpamplona.amethyst.commons.model.nip51Lists.followSets.PeopleList -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Stable class PeopleListViewModel : ViewModel() { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/memberEdit/FollowListAndPackAndUserScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/memberEdit/FollowListAndPackAndUserScreen.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/memberEdit/FollowListAndPackAndUserScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/memberEdit/FollowListAndPackAndUserScreen.kt index ea3b3be635..d71d1dfc85 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/memberEdit/FollowListAndPackAndUserScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/memberEdit/FollowListAndPackAndUserScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.memberEdit +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.lists.memberEdit import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.consumeWindowInsets @@ -36,14 +36,14 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserName import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.follow_set_man_dialog_title2 import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey @OptIn(ExperimentalMaterial3Api::class) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/memberEdit/FollowListAndPackAndUserView.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/memberEdit/FollowListAndPackAndUserView.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/memberEdit/FollowListAndPackAndUserView.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/memberEdit/FollowListAndPackAndUserView.kt index 4dbd832a96..d9c24b44af 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/memberEdit/FollowListAndPackAndUserView.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/lists/memberEdit/FollowListAndPackAndUserView.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.memberEdit +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.lists.memberEdit import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -40,6 +40,7 @@ import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.nip51Lists.ui.FollowPackAndUserItem import com.vitorpamplona.amethyst.commons.nip51Lists.ui.PeopleListAndUserItem +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserName import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.discover_follows import com.vitorpamplona.amethyst.commons.resources.discover_follows_explainer @@ -47,15 +48,14 @@ import com.vitorpamplona.amethyst.commons.resources.feed_is_empty import com.vitorpamplona.amethyst.commons.resources.follow_sets import com.vitorpamplona.amethyst.commons.resources.follow_sets_explainer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.lists.list.NewListButton import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.MaxWidthWithHorzPadding import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.SpacedBy5dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list.NewListButton +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun FollowListAndPackAndUserView( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicPlaylistsFeedLoaded.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicPlaylistsFeedLoaded.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicPlaylistsFeedLoaded.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicPlaylistsFeedLoaded.kt index f4fd7423ed..8fcfb43052 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicPlaylistsFeedLoaded.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicPlaylistsFeedLoaded.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.music +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.music import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height @@ -34,10 +34,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun MusicPlaylistsFeedLoaded( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicPlaylistsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicPlaylistsScreen.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicPlaylistsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicPlaylistsScreen.kt index ebe632548e..b170db8466 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicPlaylistsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicPlaylistsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.music +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.music import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -29,19 +29,19 @@ import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.music.ui.NewMusicPlaylistFab import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.music.datasource.MusicPlaylistsFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.datasource.MusicPlaylistsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel @Composable fun MusicPlaylistsScreen( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicPlaylistsTopBar.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicPlaylistsTopBar.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicPlaylistsTopBar.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicPlaylistsTopBar.kt index d15697b6fe..c986934688 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicPlaylistsTopBar.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicPlaylistsTopBar.kt @@ -18,13 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.music +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.music import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter @@ -32,14 +34,12 @@ import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.experimental.music.playlist.MusicPlaylistEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicTracksFeedLoaded.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicTracksFeedLoaded.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicTracksFeedLoaded.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicTracksFeedLoaded.kt index b9078364ff..e0db3bb057 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicTracksFeedLoaded.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicTracksFeedLoaded.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.music +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.music import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height @@ -34,10 +34,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun MusicTracksFeedLoaded( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicTracksScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicTracksScreen.kt similarity index 89% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicTracksScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicTracksScreen.kt index d992351abd..b9d4987472 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicTracksScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicTracksScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.music +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.music import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -29,19 +29,19 @@ import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.music.ui.NewMusicTrackButton import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.music.datasource.MusicTracksFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.datasource.MusicTracksFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel @Composable fun MusicTracksScreen( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicTracksTopBar.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicTracksTopBar.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicTracksTopBar.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicTracksTopBar.kt index 4b1cdd57d7..f4b3802e92 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/MusicTracksTopBar.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/MusicTracksTopBar.kt @@ -18,13 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.music +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.music import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter @@ -32,14 +34,12 @@ import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.experimental.music.track.MusicTrackEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/datasource/MusicPlaylistsFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/datasource/MusicPlaylistsFilterAssemblerSubscription.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/datasource/MusicPlaylistsFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/datasource/MusicPlaylistsFilterAssemblerSubscription.kt index e105b5b9ed..758a4c574e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/datasource/MusicPlaylistsFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/datasource/MusicPlaylistsFilterAssemblerSubscription.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.music.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.music.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.music.MusicPlaylistsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun MusicPlaylistsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/datasource/MusicTracksFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/datasource/MusicTracksFilterAssemblerSubscription.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/datasource/MusicTracksFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/datasource/MusicTracksFilterAssemblerSubscription.kt index c3046afa90..890fc9d09f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/music/datasource/MusicTracksFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/music/datasource/MusicTracksFilterAssemblerSubscription.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.music.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.music.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.music.MusicTracksFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun MusicTracksFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lobby/NestJoinCard.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/nests/room/lobby/NestJoinCard.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lobby/NestJoinCard.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/nests/room/lobby/NestJoinCard.kt index b3e36b6ded..f70fa61bc5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lobby/NestJoinCard.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/nests/room/lobby/NestJoinCard.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.lobby +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.nests.room.lobby import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -52,17 +52,17 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.nest_join import com.vitorpamplona.amethyst.commons.resources.nest_lobby_host_label import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.ClickableUserPicture +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.types.MeetingSpaceClosedFlag +import com.vitorpamplona.amethyst.commons.ui.note.types.MeetingSpaceOpenFlag +import com.vitorpamplona.amethyst.commons.ui.note.types.MeetingSpacePlannedFlag +import com.vitorpamplona.amethyst.commons.ui.note.types.MeetingSpacePrivateFlag import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.types.MeetingSpaceClosedFlag -import com.vitorpamplona.amethyst.ui.note.types.MeetingSpaceOpenFlag -import com.vitorpamplona.amethyst.ui.note.types.MeetingSpacePlannedFlag -import com.vitorpamplona.amethyst.ui.note.types.MeetingSpacePrivateFlag -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.tags.StatusTag import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.ROLE diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/newUser/ImportFollowListPickFollowsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/newUser/ImportFollowListPickFollowsScreen.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/newUser/ImportFollowListPickFollowsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/newUser/ImportFollowListPickFollowsScreen.kt index 4ab3f4ce13..61a91e6f46 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/newUser/ImportFollowListPickFollowsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/newUser/ImportFollowListPickFollowsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.newUser +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.newUser import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -57,6 +57,7 @@ import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEventAndMap import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.accounts_found import com.vitorpamplona.amethyst.commons.resources.fetching_follow_list @@ -69,10 +70,9 @@ import com.vitorpamplona.amethyst.commons.resources.skip_for_now import com.vitorpamplona.amethyst.commons.resources.start_with_a_great_feed_by_following_the_same_people_as_someone_you_trust import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserLine import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEventAndMap -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserLine -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent import kotlinx.collections.immutable.ImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/newUser/ImportFollowListSelectUserScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/newUser/ImportFollowListSelectUserScreen.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/newUser/ImportFollowListSelectUserScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/newUser/ImportFollowListSelectUserScreen.kt index acb24257cf..bccd850274 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/newUser/ImportFollowListSelectUserScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/newUser/ImportFollowListSelectUserScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.newUser +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.newUser import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -55,12 +55,14 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewModelScope -import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.lifecycle.viewmodel.CreationExtras import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.searchCommand.UserSearchDataSourceSubscription import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.import_follow_list import com.vitorpamplona.amethyst.commons.resources.import_follows_tips @@ -70,21 +72,22 @@ import com.vitorpamplona.amethyst.commons.resources.skip_for_now import com.vitorpamplona.amethyst.commons.resources.start_with_a_great_feed_by_following_the_same_people_as_someone_you_trust import com.vitorpamplona.amethyst.commons.resources.supports_npub_nip_05_hex_and_namecoin_bit_d_id import com.vitorpamplona.amethyst.commons.resources.tip +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserLine +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserSuggestionState import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.relayClient.searchCommand.UserSearchDataSourceSubscription -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserLine -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserSuggestionState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip05DnsIdentifiers.INip05Client import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import kotlin.reflect.KClass @Stable class ImportFollowListSelectUserViewModel( @@ -112,7 +115,10 @@ class ImportFollowListSelectUserViewModel( val nip05Client: INip05Client, ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class): T = ImportFollowListSelectUserViewModel(account, nip05Client) as T + override fun create( + modelClass: KClass, + extras: CreationExtras, + ): T = ImportFollowListSelectUserViewModel(account, nip05Client) as T } } @@ -122,7 +128,7 @@ fun ImportFollowListSelectUserScreen( nav: INav, ) { val viewModel: ImportFollowListSelectUserViewModel = - viewModel( + rememberViewModel( factory = ImportFollowListSelectUserViewModel.Factory(accountViewModel.account, accountViewModel.nip05ClientBuilder()), ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nsites/NsitesScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/nsites/NsitesScreen.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nsites/NsitesScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/nsites/NsitesScreen.kt index 5ef15b0073..e5555b7bec 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nsites/NsitesScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/nsites/NsitesScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.nsites +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.nsites import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize @@ -36,16 +36,16 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.nsite_none_found import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.nsites.datasource.NsitesFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.nsites.datasource.NsitesFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip5aStaticWebsites.NamedSiteEvent import com.vitorpamplona.quartz.nip5aStaticWebsites.RootSiteEvent @@ -70,7 +70,7 @@ fun NsitesScreen( NsitesFilterAssemblerSubscription(accountViewModel) val nsites by remember { - Amethyst.instance.cache.observeNotes( + LocalCache.observeNotes( Filter(kinds = listOf(RootSiteEvent.KIND, NamedSiteEvent.KIND)), ) }.collectAsStateWithLifecycle(emptyList()) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nsites/NsitesTopBar.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/nsites/NsitesTopBar.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nsites/NsitesTopBar.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/nsites/NsitesTopBar.kt index a5d08d72bd..0338bb20e4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nsites/NsitesTopBar.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/nsites/NsitesTopBar.kt @@ -18,21 +18,21 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.nsites +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.nsites import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip5aStaticWebsites.NamedSiteEvent import com.vitorpamplona.quartz.nip5aStaticWebsites.RootSiteEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nsites/datasource/NsitesFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/nsites/datasource/NsitesFilterAssemblerSubscription.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nsites/datasource/NsitesFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/nsites/datasource/NsitesFilterAssemblerSubscription.kt index 571252a2b9..205baad74c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nsites/datasource/NsitesFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/nsites/datasource/NsitesFilterAssemblerSubscription.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.nsites.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.nsites.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun NsitesFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pinnednotes/PinnedNotesScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/pinnednotes/PinnedNotesScreen.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pinnednotes/PinnedNotesScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/pinnednotes/PinnedNotesScreen.kt index 1483f69cb0..19a713563e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pinnednotes/PinnedNotesScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/pinnednotes/PinnedNotesScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.pinnednotes +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.pinnednotes import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize @@ -33,19 +33,19 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.relayClient.event.EventFinderQueryState import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.pinned_notes import com.vitorpamplona.amethyst.commons.ui.components.DeletedItemsBanner +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.screen.RefresheableFeedView +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.pinnednotes.dal.PinnedNotesFeedViewModel import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.pinnednotes.dal.PinnedNotesFeedViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun PinnedNotesScreen( @@ -53,7 +53,7 @@ fun PinnedNotesScreen( nav: INav, ) { val pinnedNotesFeedViewModel: PinnedNotesFeedViewModel = - viewModel( + rememberViewModel( key = "NostrPinnedNotesFeedViewModel", factory = PinnedNotesFeedViewModel.Factory(accountViewModel.account), ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pinnednotes/dal/PinnedNotesFeedFilter.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/pinnednotes/dal/PinnedNotesFeedFilter.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pinnednotes/dal/PinnedNotesFeedFilter.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/pinnednotes/dal/PinnedNotesFeedFilter.kt index c4efaaad3f..2b3c3fb9ab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pinnednotes/dal/PinnedNotesFeedFilter.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/pinnednotes/dal/PinnedNotesFeedFilter.kt @@ -18,11 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.pinnednotes.dal +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.pinnednotes.dal import com.vitorpamplona.amethyst.commons.feeds.FeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.model.Account class PinnedNotesFeedFilter( val account: Account, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pinnednotes/dal/PinnedNotesFeedViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/pinnednotes/dal/PinnedNotesFeedViewModel.kt similarity index 76% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pinnednotes/dal/PinnedNotesFeedViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/pinnednotes/dal/PinnedNotesFeedViewModel.kt index ec26d217c0..82f660b292 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pinnednotes/dal/PinnedNotesFeedViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/pinnednotes/dal/PinnedNotesFeedViewModel.kt @@ -18,13 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.pinnednotes.dal +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.pinnednotes.dal import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.AndroidFeedViewModel +import androidx.lifecycle.viewmodel.CreationExtras +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.ui.screen.AndroidFeedViewModel +import kotlin.reflect.KClass @Stable class PinnedNotesFeedViewModel( @@ -34,6 +36,9 @@ class PinnedNotesFeedViewModel( val account: Account, ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class): T = PinnedNotesFeedViewModel(account) as T + override fun create( + modelClass: KClass, + extras: CreationExtras, + ): T = PinnedNotesFeedViewModel(account) as T } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastEpisodesFeedLoaded.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastEpisodesFeedLoaded.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastEpisodesFeedLoaded.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastEpisodesFeedLoaded.kt index 88f79f36d9..0ec036cc2b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastEpisodesFeedLoaded.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastEpisodesFeedLoaded.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height @@ -34,10 +34,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.NoteCompose import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel // One shared body for both Episodes (kind 54) and Shows (kind 10154) — NoteCompose's // renderer dispatch picks the right card per item, the list scaffolding is identical. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastEpisodesScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastEpisodesScreen.kt similarity index 89% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastEpisodesScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastEpisodesScreen.kt index f7218bb1dc..c024524a5d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastEpisodesScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastEpisodesScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -28,18 +28,18 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts.datasource.PodcastEpisodesFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.datasource.PodcastEpisodesFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel @Composable fun PodcastEpisodesScreen( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastEpisodesTopBar.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastEpisodesTopBar.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastEpisodesTopBar.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastEpisodesTopBar.kt index 54c0c11514..9915a16ef6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastEpisodesTopBar.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastEpisodesTopBar.kt @@ -18,13 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter @@ -32,14 +34,12 @@ import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nipXXPodcasting20.episode.Podcasting20EpisodeEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastTrailerListItem.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastTrailerListItem.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastTrailerListItem.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastTrailerListItem.kt index 0cfe5c96db..b1840bbd8c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastTrailerListItem.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastTrailerListItem.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -33,7 +33,6 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -42,13 +41,13 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.podcast_trailer import com.vitorpamplona.amethyst.commons.resources.podcast_trailer_season import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.platform.PodcastEpisodeAudioPlayer import com.vitorpamplona.amethyst.commons.ui.note.rememberTimeAgoLabels import com.vitorpamplona.amethyst.commons.ui.note.timeAgoWith import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.ui.note.types.PodcastEpisodeAudioPlayer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nipXXPodcasting20.trailer.Podcasting20TrailerEvent import com.vitorpamplona.quartz.podcasts.PodcastAudio @@ -56,7 +55,7 @@ private val PLAYER_SHAPE = Modifier.clip(RoundedCornerShape(12.dp)) /** * A Podcasting-2.0 trailer (kind 30055) as a compact row, used on a podcast's show page and as - * the inline renderer in [com.vitorpamplona.amethyst.ui.note.NoteCompose]. A "Trailer" badge (with + * the inline renderer in [com.vitorpamplona.amethyst.commons.ui.note.NoteCompose]. A "Trailer" badge (with * the season, when present) distinguishes it from episode rows; the media plays through the same * player as episodes via the spec-neutral [PodcastAudio]. */ @@ -75,7 +74,6 @@ fun PodcastTrailerListItem( noteEvent.url()?.let { PodcastAudio(it, noteEvent.mimeType()) } } - val context = LocalContext.current val timeLabels = rememberTimeAgoLabels() val dateStr = remember(noteEvent, timeLabels) { timeAgoWith(noteEvent.createdAt, timeLabels, prefix = "") } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastsFeedLoaded.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastsFeedLoaded.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastsFeedLoaded.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastsFeedLoaded.kt index 323dbe2417..c5ff1b538a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastsFeedLoaded.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastsFeedLoaded.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts import androidx.compose.foundation.lazy.LazyListState import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel // Episodes (kind 54) and Shows (kind 10154) feeds render identically — each note flows // through NoteCompose's renderer dispatch. Keeping one shared composable means a divider diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastsScreen.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastsScreen.kt index 42173a892e..d91bed4462 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.FloatingActionButton @@ -35,20 +35,20 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.podcast_your_podcast import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts.datasource.PodcastsFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.datasource.PodcastsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel @Composable fun PodcastsScreen( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastsTopBar.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastsTopBar.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastsTopBar.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastsTopBar.kt index e9d03166c6..534c0deeb5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/PodcastsTopBar.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/PodcastsTopBar.kt @@ -18,13 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter @@ -32,14 +34,12 @@ import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.quartz.nipF4Podcasts.metadata.PodcastMetadataEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/PodcastAuthoringScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/authoring/PodcastAuthoringScreen.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/PodcastAuthoringScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/authoring/PodcastAuthoringScreen.kt index 2ebdb8f83d..03da229ab3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/authoring/PodcastAuthoringScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/authoring/PodcastAuthoringScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.authoring +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts.authoring import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -73,10 +73,10 @@ import com.vitorpamplona.amethyst.commons.resources.podcast_your_podcast import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts.datasource.MyPodcastFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.datasource.MyPodcastFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip78AppData.AppSpecificDataEvent import com.vitorpamplona.quartz.nipXXPodcasting20.episode.Podcasting20EpisodeEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/datasource/MyPodcastFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/datasource/MyPodcastFilterAssemblerSubscription.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/datasource/MyPodcastFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/datasource/MyPodcastFilterAssemblerSubscription.kt index da78487bf7..a875f61572 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/datasource/MyPodcastFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/datasource/MyPodcastFilterAssemblerSubscription.kt @@ -18,13 +18,13 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.podcasts.MyPodcastQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * While the authoring hub is on screen, keeps a REQ open for the logged-in creator's own diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/datasource/PodcastEpisodesFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/datasource/PodcastEpisodesFilterAssemblerSubscription.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/datasource/PodcastEpisodesFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/datasource/PodcastEpisodesFilterAssemblerSubscription.kt index 0655abd66b..b8a65e1656 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/datasource/PodcastEpisodesFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/datasource/PodcastEpisodesFilterAssemblerSubscription.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.podcasts.PodcastEpisodesFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun PodcastEpisodesFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/datasource/PodcastsFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/datasource/PodcastsFilterAssemblerSubscription.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/datasource/PodcastsFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/datasource/PodcastsFilterAssemblerSubscription.kt index 077cbeb95f..c6f355bac1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/podcasts/datasource/PodcastsFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/podcasts/datasource/PodcastsFilterAssemblerSubscription.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.podcasts.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.podcasts.PodcastsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun PodcastsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/NewPollButton.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/NewPollButton.kt similarity index 89% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/NewPollButton.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/NewPollButton.kt index 254f5410e4..540542adae 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/NewPollButton.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/NewPollButton.kt @@ -18,22 +18,22 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.polls +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.polls import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.ic_compose import com.vitorpamplona.amethyst.commons.resources.new_poll import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.painterRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier -import com.vitorpamplona.amethyst.ui.painterRes @Composable fun NewPollButton(nav: INav) { @@ -44,7 +44,7 @@ fun NewPollButton(nav: INav) { containerColor = MaterialTheme.colorScheme.primary, ) { Icon( - painter = painterRes(R.drawable.ic_compose, 4), + painter = painterRes(Res.drawable.ic_compose, 4), contentDescription = stringRes(id = Res.string.new_poll), modifier = Size26Modifier, tint = MaterialTheme.colorScheme.onPrimary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/PollsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/PollsScreen.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/PollsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/PollsScreen.kt index 92e442ca85..f5158fc122 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/PollsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/PollsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.polls +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.polls import androidx.compose.foundation.layout.Column import androidx.compose.foundation.pager.HorizontalPager @@ -42,19 +42,19 @@ import com.vitorpamplona.amethyst.commons.resources.closed_polls import com.vitorpamplona.amethyst.commons.resources.open_polls import com.vitorpamplona.amethyst.commons.ui.feeds.PagerStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverPagerState +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.polls.datasource.PollsFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.TabRowHeight -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.polls.datasource.PollsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/PollsTopBar.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/PollsTopBar.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/PollsTopBar.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/PollsTopBar.kt index 43f335f370..55842944c9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/PollsTopBar.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/PollsTopBar.kt @@ -18,24 +18,24 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.polls +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.polls import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.zapPolls.ZapPollEvent import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/datasource/PollsFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/datasource/PollsFilterAssemblerSubscription.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/datasource/PollsFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/datasource/PollsFilterAssemblerSubscription.kt index a41910bf76..6d882660de 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/datasource/PollsFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/datasource/PollsFilterAssemblerSubscription.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.polls.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.polls.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.polls.PollsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun PollsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/results/PollResultsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/results/PollResultsScreen.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/results/PollResultsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/results/PollResultsScreen.kt index 1ccf04c10c..6ef7e41775 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/results/PollResultsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/results/PollResultsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.polls.results +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.polls.results import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.RepeatMode @@ -69,9 +69,9 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.relayClient.polls.results.RelayPollResponseLoader import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.poll_multiple_choice @@ -93,13 +93,22 @@ import com.vitorpamplona.amethyst.commons.resources.poll_results_selections import com.vitorpamplona.amethyst.commons.resources.poll_results_title import com.vitorpamplona.amethyst.commons.resources.poll_results_your_pick import com.vitorpamplona.amethyst.commons.resources.poll_single_choice +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.note.UsernameDisplay +import com.vitorpamplona.amethyst.commons.ui.note.creators.userSuggestions.UserLine +import com.vitorpamplona.amethyst.commons.ui.note.elements.MoreOptionsButton import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgo import com.vitorpamplona.amethyst.commons.ui.note.elements.TimeAgoStyle import com.vitorpamplona.amethyst.commons.ui.note.timeAgoNoDot import com.vitorpamplona.amethyst.commons.ui.note.timeAheadNoDot +import com.vitorpamplona.amethyst.commons.ui.note.types.UserGallery import com.vitorpamplona.amethyst.commons.ui.pluralStringRes +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.polls.results.datasources.PollResponsesFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.Size25dp @@ -109,20 +118,11 @@ import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.subtleBorder import com.vitorpamplona.amethyst.commons.ui.theme.warningColor +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.nip88Polls.PollOptionResult import com.vitorpamplona.amethyst.commons.viewmodels.nip88Polls.PollResultsUiState import com.vitorpamplona.amethyst.commons.viewmodels.nip88Polls.PollResultsViewModel import com.vitorpamplona.amethyst.commons.viewmodels.nip88Polls.PollVoterRow -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.components.LoadNote -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.note.UsernameDisplay -import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserLine -import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton -import com.vitorpamplona.amethyst.ui.note.types.UserGallery -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.polls.results.datasources.PollResponsesFilterAssemblerSubscription import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent import com.vitorpamplona.quartz.nip88Polls.poll.tags.PollType import com.vitorpamplona.quartz.utils.TimeUtils @@ -180,7 +180,7 @@ private fun PollResults( (note.event as? PollEvent)?.let { accountViewModel.markPollResultsViewed(it.id, it.endsAt()) } } - // Remembered: viewModel() only consults the factory once, but building it inline allocated a + // Remembered: the view model store only consults the factory once, but building it inline allocated a // loader, two lambdas and a mapped Flow on every recomposition. val factory = remember(note, account) { @@ -194,7 +194,7 @@ private fun PollResults( ) } - val viewModel: PollResultsViewModel = viewModel(key = "PollResults-${note.idHex}", factory = factory) + val viewModel: PollResultsViewModel = rememberViewModel(key = "PollResults-${note.idHex}", factory = factory) val state by viewModel.uiState.collectAsStateWithLifecycle() val selected by viewModel.selectedOption.collectAsStateWithLifecycle() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/results/datasources/PollResponsesFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/results/datasources/PollResponsesFilterAssemblerSubscription.kt similarity index 91% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/results/datasources/PollResponsesFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/results/datasources/PollResponsesFilterAssemblerSubscription.kt index cb747f4855..901011c556 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/results/datasources/PollResponsesFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/polls/results/datasources/PollResponsesFilterAssemblerSubscription.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.polls.results.datasources +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.polls.results.datasources import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.relayClient.polls.results.PollResponsesFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.polls.results.PollResponsesQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey /** Subscribes to a poll's votes for as long as its results screen is composed. */ diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/apps/WatchApp.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/profile/header/apps/WatchApp.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/apps/WatchApp.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/profile/header/apps/WatchApp.kt index 86ace006e9..13cd00211d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/apps/WatchApp.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/profile/header/apps/WatchApp.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.header.apps +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.profile.header.apps import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Row @@ -43,14 +43,15 @@ import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.app_definition_untitled import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.withContext /** diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/relays/KindChip.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/relays/KindChip.kt new file mode 100644 index 0000000000..63e921574a --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/relays/KindChip.kt @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays + +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.unit.dp +import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.ui.theme.bitcoinColor +import com.vitorpamplona.amethyst.commons.ui.theme.redColorOnSecondSurface +import com.vitorpamplona.quartz.kinds.KindNames +import com.vitorpamplona.quartz.nip09Deletions.DeletionRequestEvent +import com.vitorpamplona.quartz.nip51Lists.muteList.MuteListEvent +import com.vitorpamplona.quartz.nip56Reports.ReportEvent +import com.vitorpamplona.quartz.nip59Giftwrap.wraps.EphemeralGiftWrapEvent +import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent +import com.vitorpamplona.quartz.nip62RequestToVanish.RequestToVanishEvent + +private val posts = setOf(0, 1, 6, 7, 16, 30023) +private val settings = setOf(3, 10002, 10000, 10001, 10003, 10004, 30000) +private val dms = setOf(4, GiftWrapEvent.KIND, EphemeralGiftWrapEvent.KIND, 10050) +private val zaps = setOf(9734, 9735, 9041, 17375, 23194, 23195) +private val reports = setOf(ReportEvent.KIND, MuteListEvent.KIND, DeletionRequestEvent.KIND, RequestToVanishEvent.KIND) + +@Composable +fun KindChip(kind: Int) { + val nameResId = kindDisplayName(kind) + val name = if (nameResId != null) stringRes(nameResId) else (KindNames.nameFor(kind) ?: "k$kind") + val (bg, fg) = + when (kind) { + in posts -> { + MaterialTheme.colorScheme.primaryContainer to MaterialTheme.colorScheme.onPrimaryContainer + } + + // + in settings -> { + MaterialTheme.colorScheme.secondaryContainer to MaterialTheme.colorScheme.onSecondaryContainer + } + + // dms + in dms -> { + MaterialTheme.colorScheme.tertiaryContainer to MaterialTheme.colorScheme.onTertiaryContainer + } + + // zaps + in zaps -> { + MaterialTheme.colorScheme.background to MaterialTheme.colorScheme.bitcoinColor + } + + in reports -> { + MaterialTheme.colorScheme.secondaryContainer to MaterialTheme.colorScheme.redColorOnSecondSurface + } + + else -> { + MaterialTheme.colorScheme.surfaceVariant to MaterialTheme.colorScheme.onSurfaceVariant + } + } + Surface( + shape = RoundedCornerShape(50), + color = bg, + ) { + Text( + text = name, + modifier = Modifier.padding(horizontal = 8.dp, vertical = 3.dp), + style = MaterialTheme.typography.labelSmall.copy(fontFamily = FontFamily.Monospace), + color = fg, + ) + } +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/KindDisplayName.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/relays/KindDisplayName.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/KindDisplayName.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/relays/KindDisplayName.kt index 1b80cdec86..22692e2c39 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/KindDisplayName.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/relays/KindDisplayName.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.resources.Res diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/eventsync/EventSyncScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/relays/eventsync/EventSyncScreen.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/eventsync/EventSyncScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/relays/eventsync/EventSyncScreen.kt index 18b9e8c273..7d1e11d14e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/eventsync/EventSyncScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/relays/eventsync/EventSyncScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.eventsync +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.eventsync import androidx.compose.foundation.background import androidx.compose.foundation.gestures.detectDragGestures @@ -59,13 +59,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.pointerInput -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.relays.eventsync.EventSync import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.event_sync_activity_log import com.vitorpamplona.amethyst.commons.resources.event_sync_activity_log_finished @@ -106,13 +106,15 @@ import com.vitorpamplona.amethyst.commons.resources.event_sync_what_happens_titl import com.vitorpamplona.amethyst.commons.resources.event_sync_wifi_warning import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.DateTimeStyle +import com.vitorpamplona.amethyst.commons.ui.note.formatDateTime import com.vitorpamplona.amethyst.commons.ui.note.timeAgoNoDotNoDay import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow -import com.vitorpamplona.amethyst.ui.note.formatMediumDate -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl +import com.vitorpamplona.quartz.utils.TimeUtils @Composable fun EventSyncScreen( @@ -680,7 +682,6 @@ private fun ActivityLogRow(info: EventSync.LiveSyncActivity.SourceRelayInfo) { modifier = Modifier.weight(0.6f), ) if (hasEvents) { - val context = LocalContext.current val untilPage by info.pageUntil.collectAsStateWithLifecycle() val eventsAccepted by info.eventsAccepted.collectAsStateWithLifecycle() untilPage?.let { @@ -750,7 +751,7 @@ private fun DateRangeFilterCard( onSinceChanged: (Long?) -> Unit = {}, onUntilChanged: (Long?) -> Unit = {}, ) { - val now = remember { System.currentTimeMillis() / 1000 } + val now = remember { TimeUtils.now() } // Slider range: 0f = EPOCH_2020, 1f = now val range = (now - EPOCH_2023).toFloat() @@ -785,8 +786,6 @@ private fun DateRangeFilterCard( LaunchedEffect(effectiveSince) { onSinceChanged(effectiveSince) } LaunchedEffect(effectiveUntil) { onUntilChanged(effectiveUntil) } - val context = LocalContext.current - Card( modifier = Modifier.fillMaxWidth(), @@ -812,7 +811,7 @@ private fun DateRangeFilterCard( if (effectiveSince == null) { stringRes(Res.string.event_sync_date_filter_all_time) } else { - stringRes(Res.string.event_sync_date_filter_since) + " " + formatMediumDate(sinceEpoch, context) + stringRes(Res.string.event_sync_date_filter_since) + " " + formatDateTime(sinceEpoch * 1000, DateTimeStyle.MEDIUM, DateTimeStyle.NONE) }, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.primary, @@ -822,7 +821,7 @@ private fun DateRangeFilterCard( if (effectiveUntil == null) { stringRes(Res.string.event_sync_date_filter_now) } else { - stringRes(Res.string.event_sync_date_filter_until) + " " + formatMediumDate(untilEpoch, context) + stringRes(Res.string.event_sync_date_filter_until) + " " + formatDateTime(untilEpoch * 1000, DateTimeStyle.MEDIUM, DateTimeStyle.NONE) }, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.primary, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip43/RelayMembersScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/relays/nip43/RelayMembersScreen.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip43/RelayMembersScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/relays/nip43/RelayMembersScreen.kt index 4ed732db3a..c42f5f6072 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip43/RelayMembersScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/relays/nip43/RelayMembersScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.nip43 +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.nip43 import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -59,9 +59,9 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.nip43RelayMembers.ui.RelayRoleChips import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.relay_members_count @@ -77,10 +77,10 @@ import com.vitorpamplona.amethyst.commons.resources.relay_members_title import com.vitorpamplona.amethyst.commons.resources.relay_members_unverifiable import com.vitorpamplona.amethyst.commons.resources.relay_members_you_are_member import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserCompose import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.note.UserCompose -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.fetchAsFlow import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter @@ -94,6 +94,7 @@ import com.vitorpamplona.quartz.nip43RelayMembers.list.tags.RelayMember import com.vitorpamplona.quartz.nip43RelayMembers.roles.RelayRole import com.vitorpamplona.quartz.nip43RelayMembers.roles.RelayRoleEvent import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.lastOrNull import kotlinx.coroutines.launch @@ -124,7 +125,7 @@ fun RelayMembersScreen( LaunchedEffect(normalizedRelayUrl) { launch(Dispatchers.IO) { var relaySelf: HexKey? = null - Amethyst.instance.nip11Cache.loadRelayInfo( + LocalCache.appHost.nip11Cache.loadRelayInfo( relay = normalizedRelayUrl, onInfo = { relaySelf = it.self }, onError = { _, _, _ -> }, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/vanish/VanishEventsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/relays/vanish/VanishEventsScreen.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/vanish/VanishEventsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/relays/vanish/VanishEventsScreen.kt index 023e23db3e..fcbb4dc047 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/vanish/VanishEventsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/relays/vanish/VanishEventsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.vanish +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.relays.vanish import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -47,7 +47,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -71,10 +70,11 @@ import com.vitorpamplona.amethyst.commons.resources.vanish_test_button import com.vitorpamplona.amethyst.commons.resources.vanish_test_error import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton +import com.vitorpamplona.amethyst.commons.ui.note.DateTimeStyle +import com.vitorpamplona.amethyst.commons.ui.note.formatDateTime import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness -import com.vitorpamplona.amethyst.ui.note.formatMediumDateTime -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import kotlinx.coroutines.launch @@ -181,7 +181,6 @@ private fun VanishEventCard( containerColor = MaterialTheme.colorScheme.surfaceContainerLow, ), ) { - val context = LocalContext.current Column(modifier = Modifier.padding(16.dp)) { Row( modifier = Modifier.fillMaxWidth(), @@ -194,7 +193,7 @@ private fun VanishEventCard( color = MaterialTheme.colorScheme.onSurfaceVariant, ) Text( - text = formatMediumDateTime(item.event.createdAt, context), + text = formatDateTime(item.event.createdAt * 1000, DateTimeStyle.MEDIUM, DateTimeStyle.SHORT), style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.SemiBold, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/report/ReportNoteDialog.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/report/ReportNoteDialog.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/report/ReportNoteDialog.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/report/ReportNoteDialog.kt index 23017a308e..0cf02b922d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/report/ReportNoteDialog.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/report/ReportNoteDialog.kt @@ -18,12 +18,12 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.report +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.report import androidx.compose.runtime.Composable import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.nip56Reports.ui.ReportDialog -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun ReportNoteDialog( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/CallSettingsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/settings/CallSettingsScreen.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/CallSettingsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/settings/CallSettingsScreen.kt index 9863ed7803..08f33a4b4f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/CallSettingsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/settings/CallSettingsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -54,6 +54,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.CallTurnServer +import com.vitorpamplona.amethyst.commons.model.CallVideoResolution import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.call_settings import com.vitorpamplona.amethyst.commons.resources.call_settings_add_turn @@ -74,9 +76,7 @@ import com.vitorpamplona.amethyst.commons.resources.cancel import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.model.CallTurnServer -import com.vitorpamplona.amethyst.model.CallVideoResolution -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun CallSettingsScreen( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/MessagesSettingsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/settings/MessagesSettingsScreen.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/MessagesSettingsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/settings/MessagesSettingsScreen.kt index 14cf5b3aeb..591032f724 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/MessagesSettingsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/settings/MessagesSettingsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings import androidx.compose.animation.animateColorAsState import androidx.compose.foundation.background @@ -94,8 +94,8 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import org.jetbrains.compose.resources.StringResource @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ReactionsSettingsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/settings/ReactionsSettingsScreen.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ReactionsSettingsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/settings/ReactionsSettingsScreen.kt index ddb7244a83..ce482d0b2f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ReactionsSettingsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/settings/ReactionsSettingsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.ScrollState @@ -60,6 +60,8 @@ import androidx.compose.ui.zIndex import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols +import com.vitorpamplona.amethyst.commons.model.ReactionRowAction +import com.vitorpamplona.amethyst.commons.model.ReactionRowItem import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.reactions_settings import com.vitorpamplona.amethyst.commons.resources.reactions_settings_boost @@ -84,10 +86,8 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackBu import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow -import com.vitorpamplona.amethyst.model.ReactionRowAction -import com.vitorpamplona.amethyst.model.ReactionRowItem -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel @Composable @Preview(device = "spec:width=2100px,height=2340px,dpi=440") diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CoordinatorIdentity.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/settings/cordn/CoordinatorIdentity.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CoordinatorIdentity.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/settings/cordn/CoordinatorIdentity.kt index 2de55c63fa..345f3fb938 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CoordinatorIdentity.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/settings/cordn/CoordinatorIdentity.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.settings.cordn import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row @@ -31,11 +31,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.chats.feed.types.observeUserNameByHex +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.contextvm.cep06Announcements.CvmServerAnnouncementEvent import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/SoftwareAppsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/softwareapps/SoftwareAppsScreen.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/SoftwareAppsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/softwareapps/SoftwareAppsScreen.kt index 353f9db2c4..8355be0318 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/SoftwareAppsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/softwareapps/SoftwareAppsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.softwareapps +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.softwareapps import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height @@ -36,18 +36,18 @@ import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.types.RenderSoftwareApplication +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.softwareapps.datasource.SoftwareAppsFilterAssemblerSubscription import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.note.types.RenderSoftwareApplication -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.softwareapps.datasource.SoftwareAppsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.application.SoftwareApplicationEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/SoftwareAppsTopBar.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/softwareapps/SoftwareAppsTopBar.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/SoftwareAppsTopBar.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/softwareapps/SoftwareAppsTopBar.kt index 4490428b0d..90d6052ce8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/SoftwareAppsTopBar.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/softwareapps/SoftwareAppsTopBar.kt @@ -18,24 +18,24 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.softwareapps +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.softwareapps import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.application.SoftwareApplicationEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/datasource/SoftwareAppsFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/softwareapps/datasource/SoftwareAppsFilterAssemblerSubscription.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/datasource/SoftwareAppsFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/softwareapps/datasource/SoftwareAppsFilterAssemblerSubscription.kt index 367116517e..1dcd1f7bde 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/softwareapps/datasource/SoftwareAppsFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/softwareapps/datasource/SoftwareAppsFilterAssemblerSubscription.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.softwareapps.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.softwareapps.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember @@ -26,7 +26,7 @@ import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.commons.relayClient.softwareapps.SoftwareAppsFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.softwareapps.SoftwareAppsQueryState import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun SoftwareAppsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/datasources/ThreadFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/threadview/datasources/ThreadFilterAssemblerSubscription.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/datasources/ThreadFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/threadview/datasources/ThreadFilterAssemblerSubscription.kt index ad12f21afc..62ac674bbf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/datasources/ThreadFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/threadview/datasources/ThreadFilterAssemblerSubscription.kt @@ -18,16 +18,16 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.datasources +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.threadview.datasources import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription import com.vitorpamplona.amethyst.commons.relayClient.thread.ThreadFilterAssembler import com.vitorpamplona.amethyst.commons.relayClient.thread.ThreadQueryState -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.HexKey @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/AddWalletScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/AddWalletScreen.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/AddWalletScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/AddWalletScreen.kt index b61e5d6251..2746dcbe91 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/AddWalletScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/AddWalletScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -61,7 +61,7 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_add_nwc_description import com.vitorpamplona.amethyst.commons.resources.wallet_add_nwc_title import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Wallet-type chooser. Each card routes to a dedicated setup screen for the diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuMintRecommendationsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/CashuMintRecommendationsScreen.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuMintRecommendationsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/CashuMintRecommendationsScreen.kt index a51face0dc..0f16edb281 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuMintRecommendationsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/CashuMintRecommendationsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -60,7 +60,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.hashtags.Cashu import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons import com.vitorpamplona.amethyst.commons.icons.symbols.Icon @@ -75,11 +74,12 @@ import com.vitorpamplona.amethyst.commons.resources.cashu_settings_delete_confir import com.vitorpamplona.amethyst.commons.resources.cashu_settings_delete_recommendation import com.vitorpamplona.amethyst.commons.resources.cashu_settings_my_recommendations import com.vitorpamplona.amethyst.commons.resources.cashu_settings_no_recommendations +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip87Ecash.recommendation.MintRecommendationEvent import androidx.compose.material3.Icon as Material3Icon @@ -96,7 +96,7 @@ fun CashuMintRecommendationsScreen( accountViewModel: AccountViewModel, nav: INav, ) { - val viewModel: CashuWalletViewModel = viewModel() + val viewModel: CashuWalletViewModel = rememberViewModel { CashuWalletViewModel() } viewModel.init(accountViewModel) val recommendations by viewModel.ownRecommendations.collectAsState() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuMintsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/CashuMintsScreen.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuMintsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/CashuMintsScreen.kt index a6d8910bbc..46d03d08e9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuMintsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/CashuMintsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -63,7 +63,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.cache.LocalCache @@ -84,10 +83,11 @@ import com.vitorpamplona.amethyst.commons.resources.cashu_wallet_autosaves import com.vitorpamplona.amethyst.commons.resources.cashu_wallet_saving import com.vitorpamplona.amethyst.commons.resources.wallet_add_cashu_title import com.vitorpamplona.amethyst.commons.resources.wallet_edit_cashu_title +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Manages the mints a Cashu wallet uses (and creates the wallet on the first @@ -101,7 +101,7 @@ fun CashuMintsScreen( accountViewModel: AccountViewModel, nav: INav, ) { - val viewModel: CashuWalletViewModel = viewModel() + val viewModel: CashuWalletViewModel = rememberViewModel { CashuWalletViewModel() } // Synchronous init so state-flow getters don't hit a null `account` on // the first composition pass. init() is idempotent — just sets refs. viewModel.init(accountViewModel) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuWalletSettingsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/CashuWalletSettingsScreen.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuWalletSettingsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/CashuWalletSettingsScreen.kt index 746f6bd39f..d3bf031786 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuWalletSettingsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/CashuWalletSettingsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -58,7 +58,6 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -96,11 +95,12 @@ import com.vitorpamplona.amethyst.commons.resources.cashu_settings_stop_nutzaps_ import com.vitorpamplona.amethyst.commons.resources.cashu_settings_stop_nutzaps_subtitle import com.vitorpamplona.amethyst.commons.resources.cashu_settings_title import com.vitorpamplona.amethyst.commons.resources.danger_zone +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Settings hub for the Cashu wallet. Lives behind the gear icon on the @@ -118,7 +118,7 @@ fun CashuWalletSettingsScreen( accountViewModel: AccountViewModel, nav: INav, ) { - val viewModel: CashuWalletViewModel = viewModel() + val viewModel: CashuWalletViewModel = rememberViewModel { CashuWalletViewModel() } viewModel.init(accountViewModel) val walletEvent by viewModel.walletEvent.collectAsState() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuWalletViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/CashuWalletViewModel.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuWalletViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/CashuWalletViewModel.kt index 3a389c0e16..d03a656cc8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuWalletViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/CashuWalletViewModel.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -28,9 +28,9 @@ import com.vitorpamplona.amethyst.commons.cashu.ops.TokenEntry import com.vitorpamplona.amethyst.commons.cashu.ops.describeMintError import com.vitorpamplona.amethyst.commons.cashu.ops.describeRedeemError import com.vitorpamplona.amethyst.commons.cashu.ops.requireP2pkRedeemable -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.nip60Cashu.CashuWalletState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.model.nip60Cashu.CashuWalletState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.lightning.LnInvoiceUtil import com.vitorpamplona.quartz.nip60Cashu.mintApi.MeltQuoteBolt11ResponseDto import com.vitorpamplona.quartz.nip60Cashu.mintApi.MintHttpException @@ -39,6 +39,7 @@ import com.vitorpamplona.quartz.nip60Cashu.token.CashuTokenB64Parser import com.vitorpamplona.quartz.nip87Ecash.recommendation.MintRecommendationEvent import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.startsWith +import com.vitorpamplona.quartz.utils.toLongValue import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -679,7 +680,7 @@ class CashuWalletViewModel : ViewModel() { // is the only reliable way to drive completeMintFromLightning // on resume. val amountSats = - runCatching { LnInvoiceUtil.getAmountInSats(status.request).toLong() } + runCatching { LnInvoiceUtil.getAmountInSats(status.request).toLongValue() } .getOrElse { 0L } val paid = status.isSettled() if (paid && amountSats > 0) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/MintDirectoryRow.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/MintDirectoryRow.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/MintDirectoryRow.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/MintDirectoryRow.kt index e8aabd3ae6..c69eea37c2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/MintDirectoryRow.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/MintDirectoryRow.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -46,11 +46,11 @@ import com.vitorpamplona.amethyst.commons.resources.cashu_mint_plus_others import com.vitorpamplona.amethyst.commons.resources.cashu_mint_recommended_by import com.vitorpamplona.amethyst.commons.resources.cashu_mint_recommended_by_others import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel /** * Shared mint directory row. Used by the wallet's add-cashu-mint diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/ReloadMintScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/ReloadMintScreen.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/ReloadMintScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/ReloadMintScreen.kt index d6a85fe7e3..d2366bfb45 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/ReloadMintScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/ReloadMintScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.layout.Arrangement @@ -65,7 +65,6 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.hashtags.Cashu import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons import com.vitorpamplona.amethyst.commons.icons.symbols.Icon @@ -94,35 +93,43 @@ import com.vitorpamplona.amethyst.commons.resources.reload_mint_summary_funded import com.vitorpamplona.amethyst.commons.resources.reload_mint_title import com.vitorpamplona.amethyst.commons.resources.reload_mint_topup_label import com.vitorpamplona.amethyst.commons.resources.sats +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.UserPicture import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.util.showAmount -import com.vitorpamplona.amethyst.ui.note.UserPicture -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.wallet.ReloadMintRequest +import com.vitorpamplona.amethyst.commons.wallet.ReloadMintViewModel +import com.vitorpamplona.amethyst.commons.wallet.ReloadSource +import com.vitorpamplona.amethyst.commons.wallet.ReloadStatus +import com.vitorpamplona.quartz.utils.BigDecimal import kotlinx.coroutines.launch -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid import androidx.compose.material3.Icon as Material3Icon /** * Stash the pending nutzap and open the Reload Mint screen. Called from the zap * picker when the user taps an underfunded (NEEDS_RELOAD) cashu logo. */ +@OptIn(ExperimentalUuidApi::class) fun navigateToReloadMint( accountViewModel: AccountViewModel, nav: INav, baseNote: Note, amountSats: Long, ) { - val uid = UUID.randomUUID().toString() + val uid = Uuid.random().toString() accountViewModel.tempReloadRequestCache.put(uid, ReloadMintRequest(baseNote, amountSats)) nav.nav(Route.ReloadMint(uid)) } internal fun shortMint(url: String): String = url.removePrefix("https://").removePrefix("http://").removeSuffix("/") -internal fun sats(value: Long): String = showAmount(value.toBigDecimal().setScale(1)) +fun sats(value: Long): String = showAmount(BigDecimal(value)) @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -139,7 +146,7 @@ fun ReloadMintScreen( return } - val viewModel: ReloadMintViewModel = viewModel() + val viewModel: ReloadMintViewModel = rememberViewModel { ReloadMintViewModel() } LaunchedEffect(requestId) { viewModel.init(accountViewModel, request) } val ui by viewModel.uiState.collectAsStateWithLifecycle() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/TopUpMintScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/TopUpMintScreen.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/TopUpMintScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/TopUpMintScreen.kt index 768250c714..5b0415255b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/TopUpMintScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/TopUpMintScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -61,7 +61,6 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.hashtags.Cashu import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons import com.vitorpamplona.amethyst.commons.icons.symbols.Icon @@ -77,11 +76,13 @@ import com.vitorpamplona.amethyst.commons.resources.sats import com.vitorpamplona.amethyst.commons.resources.topup_mint_amount_label import com.vitorpamplona.amethyst.commons.resources.topup_mint_confirm import com.vitorpamplona.amethyst.commons.resources.topup_mint_title +import com.vitorpamplona.amethyst.commons.ui.components.rememberViewModel import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.wallet.ReloadSource import kotlinx.coroutines.launch import androidx.compose.material3.Icon as Material3Icon @@ -92,7 +93,7 @@ fun TopUpMintScreen( accountViewModel: AccountViewModel, nav: INav, ) { - val viewModel: TopUpMintViewModel = viewModel() + val viewModel: TopUpMintViewModel = rememberViewModel { TopUpMintViewModel() } LaunchedEffect(mintUrl) { viewModel.init(accountViewModel, mintUrl) } val ui by viewModel.uiState.collectAsStateWithLifecycle() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/TopUpMintViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/TopUpMintViewModel.kt similarity index 96% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/TopUpMintViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/TopUpMintViewModel.kt index f6dc022003..70f6fd8f3a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/TopUpMintViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/wallet/TopUpMintViewModel.kt @@ -18,14 +18,17 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.commons.cashu.ops.describeMintError -import com.vitorpamplona.amethyst.model.nip60Cashu.CashuWalletState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.model.nip60Cashu.CashuWalletState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.amethyst.commons.wallet.ReloadMintViewModel +import com.vitorpamplona.amethyst.commons.wallet.ReloadSource +import com.vitorpamplona.amethyst.commons.wallet.ReloadStatus import com.vitorpamplona.quartz.nip47WalletConnect.Nip47WalletConnect import com.vitorpamplona.quartz.nip47WalletConnect.rpc.PayInvoiceMethod import kotlinx.collections.immutable.ImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/ExerciseTemplateDisplay.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/ExerciseTemplateDisplay.kt similarity index 95% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/ExerciseTemplateDisplay.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/ExerciseTemplateDisplay.kt index 55260e91dd..f3deb4e60c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/ExerciseTemplateDisplay.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/ExerciseTemplateDisplay.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box @@ -46,11 +46,11 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.fitness.workout.ExerciseTemplateEvent import com.vitorpamplona.quartz.experimental.fitness.workout.slugToTitle diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/NewWorkoutButton.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/NewWorkoutButton.kt similarity index 94% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/NewWorkoutButton.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/NewWorkoutButton.kt index 18b459e412..5025459b52 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/NewWorkoutButton.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/NewWorkoutButton.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.FloatingActionButton @@ -30,6 +30,7 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.new_workout import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts.symbol import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/WorkoutDisplay.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/WorkoutDisplay.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/WorkoutDisplay.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/WorkoutDisplay.kt index ad005c6a8c..816cb00287 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/WorkoutDisplay.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/WorkoutDisplay.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -50,6 +50,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.exercise_amrap import com.vitorpamplona.amethyst.commons.resources.exercise_circuit @@ -81,14 +82,14 @@ import com.vitorpamplona.amethyst.commons.resources.workout_speed import com.vitorpamplona.amethyst.commons.resources.workout_steps import com.vitorpamplona.amethyst.commons.resources.workout_volume import com.vitorpamplona.amethyst.commons.resources.workout_weight +import com.vitorpamplona.amethyst.commons.ui.components.SensitivityWarning +import com.vitorpamplona.amethyst.commons.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.components.SensitivityWarning -import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.amethyst.commons.util.phonePrefersMiles +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.fitness.workout.ExerciseGroup import com.vitorpamplona.quartz.experimental.fitness.workout.ExerciseTemplateEvent import com.vitorpamplona.quartz.experimental.fitness.workout.WorkoutRecordEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/WorkoutsScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/WorkoutsScreen.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/WorkoutsScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/WorkoutsScreen.kt index 6f5480f8da..0338de39bf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/WorkoutsScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/WorkoutsScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -27,16 +27,16 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.RenderFeedContentState +import com.vitorpamplona.amethyst.commons.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState -import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold -import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.datasource.WorkoutsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts.datasource.WorkoutsFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun WorkoutsScreen( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/WorkoutsTopBar.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/WorkoutsTopBar.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/WorkoutsTopBar.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/WorkoutsTopBar.kt index 56d9263941..032bfaa5db 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/WorkoutsTopBar.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/WorkoutsTopBar.kt @@ -18,24 +18,24 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedDefinition +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.select_list_to_filter import com.vitorpamplona.amethyst.commons.search.SearchSeed import com.vitorpamplona.amethyst.commons.search.asSearchQuery import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.FeedFilterSpinner +import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.UserDrawerSearchTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.ui.navigation.topbars.FeedFilterSpinner -import com.vitorpamplona.amethyst.ui.navigation.topbars.UserDrawerSearchTopBar -import com.vitorpamplona.amethyst.ui.screen.FeedDefinition -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.experimental.fitness.workout.WorkoutRecordEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/datasource/WorkoutsFilterAssemblerSubscription.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/datasource/WorkoutsFilterAssemblerSubscription.kt similarity index 90% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/datasource/WorkoutsFilterAssemblerSubscription.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/datasource/WorkoutsFilterAssemblerSubscription.kt index faa5417f61..c2dfa4f2af 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/datasource/WorkoutsFilterAssemblerSubscription.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/datasource/WorkoutsFilterAssemblerSubscription.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.datasource +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts.datasource import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.LifecycleAwareKeyDataSourceSubscription import com.vitorpamplona.amethyst.commons.relayClient.workouts.WorkoutsFilterAssembler -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.topNavFeedQueryState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel @Composable fun WorkoutsFilterAssemblerSubscription(accountViewModel: AccountViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/health/HealthConnectRationaleScreen.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/health/HealthConnectRationaleScreen.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/health/HealthConnectRationaleScreen.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/health/HealthConnectRationaleScreen.kt index e2118ebff4..3d3a932ff8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/health/HealthConnectRationaleScreen.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/screen/loggedIn/workouts/health/HealthConnectRationaleScreen.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.health +package com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.workouts.health import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountFeedContentStates.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountFeedContentStates.kt similarity index 82% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountFeedContentStates.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountFeedContentStates.kt index a62a265f18..3242eeb674 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountFeedContentStates.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountFeedContentStates.kt @@ -18,73 +18,72 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn +package com.vitorpamplona.amethyst.commons.viewmodels -import android.content.ComponentCallbacks2 -import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.articles.dal.ArticlesFeedFilter +import com.vitorpamplona.amethyst.commons.badges.dal.BadgesFeedFilter +import com.vitorpamplona.amethyst.commons.calendars.dal.CalendarAppointmentsFeedFilter +import com.vitorpamplona.amethyst.commons.calendars.dal.CalendarCollectionsFeedFilter +import com.vitorpamplona.amethyst.commons.chats.publicChannels.relayGroup.dal.RelayGroupDiscoveryFeedFilter +import com.vitorpamplona.amethyst.commons.chats.rooms.dal.ChatroomListKnownFeedFilter +import com.vitorpamplona.amethyst.commons.chats.rooms.dal.ChatroomListNewFeedFilter +import com.vitorpamplona.amethyst.commons.communities.list.dal.CommunitiesFeedFilter +import com.vitorpamplona.amethyst.commons.discover.nip23LongForm.DiscoverLongFormFeedFilter +import com.vitorpamplona.amethyst.commons.discover.nip28Chats.DiscoverChatFeedFilter +import com.vitorpamplona.amethyst.commons.discover.nip51FollowSets.DiscoverFollowSetsFeedFilter +import com.vitorpamplona.amethyst.commons.discover.nip53LiveActivities.DiscoverLiveFeedFilter +import com.vitorpamplona.amethyst.commons.discover.nip72Communities.DiscoverCommunityFeedFilter +import com.vitorpamplona.amethyst.commons.discover.nip90DVMs.DiscoverNIP89FeedFilter +import com.vitorpamplona.amethyst.commons.discover.nip99Classifieds.DiscoverMarketplaceFeedFilter +import com.vitorpamplona.amethyst.commons.drafts.dal.DraftEventsFeedFilter +import com.vitorpamplona.amethyst.commons.emojipacks.browse.dal.BrowseEmojiSetsFeedFilter import com.vitorpamplona.amethyst.commons.feeds.ChannelFeedContentState import com.vitorpamplona.amethyst.commons.feeds.FeedContentState +import com.vitorpamplona.amethyst.commons.feeds.TopNavFilterState +import com.vitorpamplona.amethyst.commons.followPacks.list.dal.FollowPacksFeedFilter +import com.vitorpamplona.amethyst.commons.geocaches.dal.GeocacheFindsFeedFilter +import com.vitorpamplona.amethyst.commons.geocaches.dal.GeocacheHuntsFeedFilter +import com.vitorpamplona.amethyst.commons.geocaches.dal.GeocacheMineFeedFilter +import com.vitorpamplona.amethyst.commons.geocaches.dal.GeocachesFeedFilter +import com.vitorpamplona.amethyst.commons.gitRepositories.dal.GitRepositoriesFeedFilter +import com.vitorpamplona.amethyst.commons.highlights.dal.HighlightsFeedFilter +import com.vitorpamplona.amethyst.commons.home.dal.HomeConversationsFeedFilter +import com.vitorpamplona.amethyst.commons.home.dal.HomeEverythingFeedFilter +import com.vitorpamplona.amethyst.commons.home.dal.HomeLiveFilter +import com.vitorpamplona.amethyst.commons.home.dal.HomeNewThreadFeedFilter +import com.vitorpamplona.amethyst.commons.livestreams.dal.LiveStreamsFeedFilter +import com.vitorpamplona.amethyst.commons.longs.dal.LongsFeedFilter +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.articles.dal.ArticlesFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.dal.BadgesFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.dal.CalendarAppointmentsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.calendars.dal.CalendarCollectionsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.dal.RelayGroupDiscoveryFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.dal.ChatroomListKnownFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.dal.ChatroomListNewFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.communities.list.dal.CommunitiesFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip23LongForm.DiscoverLongFormFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip28Chats.DiscoverChatFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip51FollowSets.DiscoverFollowSetsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip53LiveActivities.DiscoverLiveFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip72Communities.DiscoverCommunityFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip90DVMs.DiscoverNIP89FeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip99Classifieds.DiscoverMarketplaceFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.drafts.dal.DraftEventsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.emojipacks.browse.dal.BrowseEmojiSetsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.followPacks.list.dal.FollowPacksFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.dal.GeocacheFindsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.dal.GeocacheHuntsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.dal.GeocacheMineFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.dal.GeocachesFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepositories.dal.GitRepositoriesFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.highlights.dal.HighlightsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.dal.HomeConversationsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.dal.HomeEverythingFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.dal.HomeLiveFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.dal.HomeNewThreadFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.livestreams.dal.LiveStreamsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.longs.dal.LongsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.dal.MusicPlaylistsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.music.dal.MusicTracksFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.dal.NestsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.CardFeedContentState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.NotificationSummaryState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.OpenPollsState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.dal.NotificationFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.pictures.dal.PictureFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.dal.PodcastEpisodesFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.podcasts.dal.PodcastsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.polls.dal.ClosedPollsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.polls.dal.OpenPollsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.polls.dal.PollsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.products.dal.ProductsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.publicChats.dal.PublicChatsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.shorts.dal.ShortsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.softwareapps.dal.SoftwareAppsFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.dal.VideoFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.webBookmarks.dal.WebBookmarkFeedFilter -import com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.dal.WorkoutFeedFilter +import com.vitorpamplona.amethyst.commons.music.dal.MusicPlaylistsFeedFilter +import com.vitorpamplona.amethyst.commons.music.dal.MusicTracksFeedFilter +import com.vitorpamplona.amethyst.commons.nests.dal.NestsFeedFilter +import com.vitorpamplona.amethyst.commons.notifications.CardFeedContentState +import com.vitorpamplona.amethyst.commons.notifications.NotificationSummaryState +import com.vitorpamplona.amethyst.commons.notifications.OpenPollsState +import com.vitorpamplona.amethyst.commons.notifications.dal.NotificationFeedFilter +import com.vitorpamplona.amethyst.commons.pictures.dal.PictureFeedFilter +import com.vitorpamplona.amethyst.commons.podcasts.dal.PodcastEpisodesFeedFilter +import com.vitorpamplona.amethyst.commons.podcasts.dal.PodcastsFeedFilter +import com.vitorpamplona.amethyst.commons.polls.dal.ClosedPollsFeedFilter +import com.vitorpamplona.amethyst.commons.polls.dal.OpenPollsFeedFilter +import com.vitorpamplona.amethyst.commons.polls.dal.PollsFeedFilter +import com.vitorpamplona.amethyst.commons.products.dal.ProductsFeedFilter +import com.vitorpamplona.amethyst.commons.publicChats.dal.PublicChatsFeedFilter +import com.vitorpamplona.amethyst.commons.shorts.dal.ShortsFeedFilter +import com.vitorpamplona.amethyst.commons.softwareapps.dal.SoftwareAppsFeedFilter +import com.vitorpamplona.amethyst.commons.video.dal.VideoFeedFilter +import com.vitorpamplona.amethyst.commons.webBookmarks.dal.WebBookmarkFeedFilter +import com.vitorpamplona.amethyst.commons.workouts.dal.WorkoutFeedFilter import com.vitorpamplona.quartz.nip90Dvms.dvmHeartbeat.DvmHeartbeatEvent import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.IO import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.sample import kotlinx.coroutines.isActive @@ -93,6 +92,7 @@ import kotlinx.coroutines.launch class AccountFeedContentStates( val account: Account, val scope: CoroutineScope, + memoryPressure: Flow, ) { val homeLive = ChannelFeedContentState(HomeLiveFilter(account), scope) val homeNewThreads = FeedContentState(HomeNewThreadFeedFilter(account), scope, LocalCache) @@ -161,15 +161,10 @@ class AccountFeedContentStates( val webBookmarks = FeedContentState(WebBookmarkFeedFilter(account), scope, LocalCache) init { - // Under real memory pressure (process on the system LRU list — the strongest trim - // level the OS still delivers since API 34), trim every feed down to release the - // strong Note references that would otherwise keep pruned cache objects alive. + // Under real memory pressure, trim every feed down to release the strong Note + // references that would otherwise keep pruned cache objects alive. scope.launch(Dispatchers.IO) { - Amethyst.instance.trimLevelEvents.collect { level -> - if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) { - trimFeedsToSize(200) - } - } + memoryPressure.collect { trimFeedsToSize(200) } } // Marmot group list changes (new group, group marked known, group @@ -378,7 +373,7 @@ class AccountFeedContentStates( } fun updateFeedsWith(newNotes: Set) { - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() homeLive.updateFeedWith(newNotes) homeNewThreads.updateFeedWith(newNotes) @@ -452,7 +447,7 @@ class AccountFeedContentStates( } fun deleteNotes(newNotes: Set) { - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() homeLive.deleteFromFeed(newNotes) homeNewThreads.deleteFromFeed(newNotes) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountViewModel.kt similarity index 88% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountViewModel.kt index f92eae835c..54f5d4a7aa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountViewModel.kt @@ -18,36 +18,35 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn +package com.vitorpamplona.amethyst.commons.viewmodels -import android.annotation.SuppressLint -import android.app.NotificationManager -import android.content.Context -import android.net.Uri -import android.os.Handler -import android.os.Looper -import android.util.LruCache -import android.widget.Toast -import androidx.compose.runtime.Composable +import androidx.collection.LruCache import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable import androidx.compose.runtime.rememberCoroutineScope -import androidx.core.content.ContextCompat import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import com.vitorpamplona.amethyst.AccountInfo -import com.vitorpamplona.amethyst.Amethyst -import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.commons.audio.VisualizerStyle import com.vitorpamplona.amethyst.commons.cashu.ops.describeMintError +import com.vitorpamplona.amethyst.commons.chats.rooms.markRoomNoteAsRead +import com.vitorpamplona.amethyst.commons.chats.rooms.rowHasUnread +import com.vitorpamplona.amethyst.commons.feeds.CardFeedState import com.vitorpamplona.amethyst.commons.feeds.FeedState +import com.vitorpamplona.amethyst.commons.marmot.GroupMemberInfo +import com.vitorpamplona.amethyst.commons.marmot.MarmotGroupIconChange +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.AddressableNote +import com.vitorpamplona.amethyst.commons.model.CombinedZap import com.vitorpamplona.amethyst.commons.model.Dao +import com.vitorpamplona.amethyst.commons.model.LatestKeyPackageOwner import com.vitorpamplona.amethyst.commons.model.LiveHiddenUsers +import com.vitorpamplona.amethyst.commons.model.NOTIFICATION_LAST_READ_KEY import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.commons.model.UiSettingsFlow +import com.vitorpamplona.amethyst.commons.model.ReactionRowItem import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.model.VideoPlayerButtonItem +import com.vitorpamplona.amethyst.commons.model.ZapAmountCommentNotification +import com.vitorpamplona.amethyst.commons.model.ZapraiserStatus import com.vitorpamplona.amethyst.commons.model.backups.ReplaceableBackupConflict import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.composer.NewMessageTagger @@ -62,8 +61,11 @@ import com.vitorpamplona.amethyst.commons.model.nip56Reports.UserReportWarningSt import com.vitorpamplona.amethyst.commons.model.nip56Reports.dmReportWarningFor import com.vitorpamplona.amethyst.commons.model.observables.CreatedAtComparator import com.vitorpamplona.amethyst.commons.model.privateChatLastReadRoute +import com.vitorpamplona.amethyst.commons.model.zapraiserStatus +import com.vitorpamplona.amethyst.commons.nests.room.activity.NestBridge import com.vitorpamplona.amethyst.commons.relayClient.BlockedRelayFilteringClient -import com.vitorpamplona.amethyst.commons.relayClient.nip47WalletConnect.NWCPaymentFilterAssembler +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.RelaySubscriptionsCoordinator +import com.vitorpamplona.amethyst.commons.relays.eventsync.EventSync import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.bolt12_offers import com.vitorpamplona.amethyst.commons.resources.bolt12_payment_failed @@ -76,7 +78,6 @@ import com.vitorpamplona.amethyst.commons.resources.concord_members_roles_failed import com.vitorpamplona.amethyst.commons.resources.concord_members_roles_title import com.vitorpamplona.amethyst.commons.resources.draft_note import com.vitorpamplona.amethyst.commons.resources.error_dialog_zap_error -import com.vitorpamplona.amethyst.commons.resources.failed_to_save_the_video import com.vitorpamplona.amethyst.commons.resources.it_s_not_possible_to_quote_to_a_draft_note import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_be_able_to_boost_posts import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_be_able_to_sign_events @@ -96,53 +97,28 @@ import com.vitorpamplona.amethyst.commons.resources.signer_not_found_exception_d import com.vitorpamplona.amethyst.commons.resources.unauthorized_exception import com.vitorpamplona.amethyst.commons.resources.unauthorized_exception_description import com.vitorpamplona.amethyst.commons.resources.user_x_does_not_have_a_lightning_address_setup_to_receive_sats -import com.vitorpamplona.amethyst.commons.resources.video_saved_to_the_gallery -import com.vitorpamplona.amethyst.commons.service.OnlineChecker +import com.vitorpamplona.amethyst.commons.service.ClinkDebitPayer +import com.vitorpamplona.amethyst.commons.service.V4VPaymentHandler +import com.vitorpamplona.amethyst.commons.service.ZapPaymentHandler import com.vitorpamplona.amethyst.commons.service.broadcast.BroadcastTracker -import com.vitorpamplona.amethyst.commons.service.http.EmptyRoleBasedHttpClientBuilder +import com.vitorpamplona.amethyst.commons.service.call.CallSessionBridge +import com.vitorpamplona.amethyst.commons.service.cashu.melt.MeltProcessor import com.vitorpamplona.amethyst.commons.service.http.IRoleBasedHttpClientBuilder +import com.vitorpamplona.amethyst.commons.service.lnurl.LightningInvoiceResolver import com.vitorpamplona.amethyst.commons.service.pow.PoWCategory +import com.vitorpamplona.amethyst.commons.service.pow.powKindLabelRes import com.vitorpamplona.amethyst.commons.state.UiSettingsState import com.vitorpamplona.amethyst.commons.tor.TorSettingsFlow -import com.vitorpamplona.amethyst.commons.tor.TorType -import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewState import com.vitorpamplona.amethyst.commons.ui.components.toasts.ToastManager import com.vitorpamplona.amethyst.commons.ui.loadStringRes -import com.vitorpamplona.amethyst.commons.ui.notifications.CardFeedState import com.vitorpamplona.amethyst.commons.ui.state.GenericBaseCache import com.vitorpamplona.amethyst.commons.ui.state.GenericBaseCacheAsync import com.vitorpamplona.amethyst.commons.util.DebouncedPublisher +import com.vitorpamplona.amethyst.commons.util.logTime import com.vitorpamplona.amethyst.commons.util.showAmount import com.vitorpamplona.amethyst.commons.util.showAmountInteger -import com.vitorpamplona.amethyst.logTime -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.AccountSettings -import com.vitorpamplona.amethyst.model.LatestKeyPackageOwner -import com.vitorpamplona.amethyst.model.UrlCachedPreviewer -import com.vitorpamplona.amethyst.model.privacyOptions.RoleBasedHttpClientBuilder -import com.vitorpamplona.amethyst.service.ClinkDebitPayer -import com.vitorpamplona.amethyst.service.V4VPaymentHandler -import com.vitorpamplona.amethyst.service.ZapPaymentHandler -import com.vitorpamplona.amethyst.service.cashu.melt.MeltProcessor -import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.service.lnurl.LightningAddressResolver -import com.vitorpamplona.amethyst.service.location.LocationState -import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.dismissNotificationForEvent -import com.vitorpamplona.amethyst.service.pow.powKindLabelRes -import com.vitorpamplona.amethyst.service.relayClient.reqCommand.RelaySubscriptionsCoordinator -import com.vitorpamplona.amethyst.ui.actions.MediaSaverToDisk -import com.vitorpamplona.amethyst.ui.note.ZapAmountCommentNotification -import com.vitorpamplona.amethyst.ui.note.ZapraiserStatus -import com.vitorpamplona.amethyst.ui.note.payViaIntent -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.send.MarmotGroupIconChange -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.send.MarmotGroupIconUpload -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.send.MarmotGroupIconUploader -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.markRoomNoteAsRead -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.rowHasUnread -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.CombinedZap -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.NOTIFICATION_LAST_READ_KEY -import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.eventsync.EventSync -import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.ReloadMintRequest +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModelHost +import com.vitorpamplona.amethyst.commons.wallet.ReloadMintRequest import com.vitorpamplona.quartz.experimental.clink.debits.DebitResponse import com.vitorpamplona.quartz.experimental.clink.pointers.NDebit import com.vitorpamplona.quartz.experimental.interactiveStories.InteractiveStoryBaseEvent @@ -154,36 +130,26 @@ import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray -import com.vitorpamplona.quartz.nip01Core.core.toHexKey -import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle -import com.vitorpamplona.quartz.nip01Core.relay.client.EmptyNostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient -import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.RelayOfflineTracker -import com.vitorpamplona.quartz.nip01Core.relay.client.auth.EmptyIAuthStatus import com.vitorpamplona.quartz.nip01Core.relay.client.auth.RelayAuthenticator import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.CachingEventDecoder import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate import com.vitorpamplona.quartz.nip01Core.tags.people.PubKeyReferenceTag import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent -import com.vitorpamplona.quartz.nip03Timestamp.EmptyOtsResolverBuilder import com.vitorpamplona.quartz.nip04Dm.messages.EncryptedDmEvent -import com.vitorpamplona.quartz.nip05DnsIdentifiers.EmptyNip05Client import com.vitorpamplona.quartz.nip05DnsIdentifiers.INip05Client -import com.vitorpamplona.quartz.nip05DnsIdentifiers.Nip05Client import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey import com.vitorpamplona.quartz.nip17Dm.base.NIP17Group import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent import com.vitorpamplona.quartz.nip18Reposts.RepostEvent import com.vitorpamplona.quartz.nip19Bech32.Nip19Parser -import com.vitorpamplona.quartz.nip19Bech32.bech32.bechToBytes import com.vitorpamplona.quartz.nip19Bech32.entities.NAddress import com.vitorpamplona.quartz.nip19Bech32.entities.NEmbed import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent @@ -209,20 +175,23 @@ import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent import com.vitorpamplona.quartz.nip57Zaps.ZapRequestEvent import com.vitorpamplona.quartz.nip57Zaps.validate.LnurlForm import com.vitorpamplona.quartz.nip57Zaps.zapraiser.zapraiserAmount +import com.vitorpamplona.quartz.nip59Giftwrap.rumors.RumorAssembler import com.vitorpamplona.quartz.nip59Giftwrap.seals.SealEvent import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent import com.vitorpamplona.quartz.nip60Cashu.token.CashuToken import com.vitorpamplona.quartz.nip90Dvms.contentDiscoveryResponse.DvmContentDiscoveryResponseEvent +import com.vitorpamplona.quartz.nip92IMeta.IMetaTag import com.vitorpamplona.quartz.nip92IMeta.imeta import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag import com.vitorpamplona.quartz.podcasts.PodcastBoostagram import com.vitorpamplona.quartz.podcasts.PodcastEpisode import com.vitorpamplona.quartz.podcasts.PodcastShow import com.vitorpamplona.quartz.podcasts.PodcastValue -import com.vitorpamplona.quartz.utils.Hex +import com.vitorpamplona.quartz.utils.BigDecimal import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.mapNotNullAsync +import com.vitorpamplona.quartz.utils.plus import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.persistentSetOf @@ -232,6 +201,7 @@ import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.IO import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow @@ -264,31 +234,28 @@ class AccountViewModel( val dataSources: RelaySubscriptionsCoordinator, val httpClientBuilder: IRoleBasedHttpClientBuilder, val nip05ClientBuilder: () -> INip05Client, + val host: AccountViewModelHost, ) : ViewModel(), Dao { var firstRoute: Route? = null val toastManager = ToastManager() val broadcastTracker = BroadcastTracker() - val feedStates = AccountFeedContentStates(account, viewModelScope) + val feedStates = AccountFeedContentStates(account, viewModelScope, host.memoryPressure) /** * `true` when the local Blossom cache is enabled and the probe sees it up. Only drives the * "detected" chip in settings: the routing itself happens in LocalBlossomCacheRedirectInterceptor. */ val localBlossomCacheDetected: StateFlow = - try { - combine( - account.settings.useLocalBlossomCache, - Amethyst.instance.localBlossomCacheProbe.available, - ) { toggle, probeUp -> toggle && probeUp }.stateIn( - viewModelScope, - SharingStarted.Eagerly, - false, - ) - } catch (e: UninitializedPropertyAccessException) { - MutableStateFlow(false) - } + combine( + account.settings.useLocalBlossomCache, + host.localBlossomCacheAvailable, + ) { toggle, probeUp -> toggle && probeUp }.stateIn( + viewModelScope, + SharingStarted.Eagerly, + false, + ) /** * The account's call state machine. Owned by [Account], not by this ViewModel: a call must @@ -299,13 +266,13 @@ class AccountViewModel( init { // Populate CallSessionBridge so CallActivity and background // receivers can reach callManager + account + accountViewModel. - com.vitorpamplona.amethyst.service.call.CallSessionBridge + CallSessionBridge .set(callManager, account, this) // A mined post that fails to sign or broadcast would otherwise die // silently — the composer already returned when it was enqueued. viewModelScope.launch { - Amethyst.instance.powPublishQueue.failures.collect { failure -> + host.powPublishFailures.collect { failure -> val kindLabel = loadStringRes(powKindLabelRes(failure.kind)) if (failure.willRetryOnRestart) { toastManager.toast(Res.string.pow_settings_title, Res.string.pow_publish_failed_retry, kindLabel) @@ -322,7 +289,7 @@ class AccountViewModel( * never tried, ordered busiest-first so the most fruitful are queried first. */ fun crawlRelayDb(): List { - val stats = Amethyst.instance.relayStats.snapshot() + val stats = host.relayStats.snapshot() val relays = account.cache.relayHints.relayDB @@ -358,7 +325,7 @@ class AccountViewModel( // account's NIP-51 kind:10006 blocked relays either. val newClient = BlockedRelayFilteringClient( - NostrClient(Amethyst.instance.websocketBuilder, customScope, CachingEventDecoder()), + NostrClient(host.websocketBuilder, customScope, CachingEventDecoder()), blockedRelays = { account.blockedRelayList.flow.value }, ) @@ -727,7 +694,7 @@ class AccountViewModel( accountChoices: LiveHiddenUsers, followUsers: Set, ): NoteComposeReportState { - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() val isFromLoggedIn = note.author?.pubkeyHex == userProfile().pubkeyHex val isFromLoggedInFollow = note.author?.let { followUsers.contains(it.pubkeyHex) } ?: true @@ -867,10 +834,10 @@ class AccountViewModel( return if (zappedNote.zapPayments.isNotEmpty()) { withContext(Dispatchers.IO) { val nwc = account.zaps.calculateZappedAmount(zappedNote) - showAmount(nwc + java.math.BigDecimal(ownPendingOnchain)) + showAmount(nwc + BigDecimal(ownPendingOnchain)) } } else { - showAmount(zappedNote.zapsAmount + java.math.BigDecimal(ownPendingOnchain)) + showAmount(zappedNote.zapsAmount + BigDecimal(ownPendingOnchain)) } } @@ -878,39 +845,10 @@ class AccountViewModel( val zapraiserAmount = zappedNote.event?.zapraiserAmount() ?: 0 return if (zappedNote.zapPayments.isNotEmpty()) { withContext(Dispatchers.IO) { - val newZapAmount = account.zaps.calculateZappedAmount(zappedNote) - var percentage = newZapAmount.div(zapraiserAmount.toBigDecimal()).toFloat() - - if (percentage > 1) { - percentage = 1f - } - - val newZapraiserProgress = percentage - val newZapraiserLeft = - if (percentage > 0.99) { - "0" - } else { - showAmount((zapraiserAmount * (1 - percentage)).toBigDecimal()) - } - - ZapraiserStatus(newZapraiserProgress, newZapraiserLeft) + zapraiserStatus(account.zaps.calculateZappedAmount(zappedNote), zapraiserAmount) } } else { - var percentage = zappedNote.zapsAmount.div(zapraiserAmount.toBigDecimal()).toFloat() - - if (percentage > 1) { - percentage = 1f - } - - val newZapraiserProgress = percentage - val newZapraiserLeft = - if (percentage > 0.99) { - "0" - } else { - showAmount((zapraiserAmount * (1 - percentage)).toBigDecimal()) - } - - ZapraiserStatus(newZapraiserProgress, newZapraiserLeft) + zapraiserStatus(zappedNote.zapsAmount, zapraiserAmount) } } @@ -1153,7 +1091,6 @@ class AccountViewModel( amountInMillisats: Long, pollOption: Int?, message: String, - context: Context, showErrorIfNoLnAddress: Boolean = true, onError: (String, String, User?) -> Unit, onProgress: (percent: Float) -> Unit, @@ -1174,7 +1111,6 @@ class AccountViewModel( podcastName = (note.event as? PodcastShow)?.showTitle(), episodeName = (note.event as? PodcastEpisode)?.episodeTitle(), zappedNote = note, - context = context, streaming = false, onProgress = onProgress, ) @@ -1193,14 +1129,13 @@ class AccountViewModel( requestedType } - ZapPaymentHandler(account).zap( + ZapPaymentHandler(account, host.moneyOpRelays).zap( note = note, amountMilliSats = amountInMillisats, pollOption = pollOption, message = message, - context = context, showErrorIfNoLnAddress = showErrorIfNoLnAddress, - okHttpClient = httpClientBuilder::okHttpClientForMoney, + lnurl = host.lnurlTransport, onError = onError, onProgress = onProgress, onPayViaIntent = onPayViaIntent, @@ -1253,7 +1188,6 @@ class AccountViewModel( podcastName: String?, episodeName: String?, zappedNote: Note?, - context: Context, streaming: Boolean = false, onProgress: (Float) -> Unit = {}, ) = launchSigner { @@ -1263,7 +1197,6 @@ class AccountViewModel( podcastName = podcastName, episodeName = episodeName, zappedNote = zappedNote, - context = context, streaming = streaming, onProgress = onProgress, ) @@ -1283,7 +1216,6 @@ class AccountViewModel( podcastName: String?, episodeName: String?, zappedNote: Note?, - context: Context, streaming: Boolean, onProgress: (Float) -> Unit, ) { @@ -1302,15 +1234,14 @@ class AccountViewModel( val noWalletFoundStr = loadStringRes(Res.string.no_wallet_found) val zapErrorTitle = loadStringRes(Res.string.error_dialog_zap_error) - V4VPaymentHandler(account).pay( + V4VPaymentHandler(account, host.moneyOpRelays).pay( value = value, totalMilliSats = totalMilliSats, boostagram = boostagram, zappedNote = zappedNote, - context = context, asZap = !streaming, zapType = ZapReceiptEvent.ZapType.PUBLIC, - okHttpClient = httpClientBuilder::okHttpClientForMoney, + lnurl = host.lnurlTransport, onError = { title, message -> if (!streaming) toastManager.toast(title, message) }, @@ -1318,9 +1249,7 @@ class AccountViewModel( onPayInvoicesViaIntent = { invoices -> if (!streaming) { invoices.forEach { invoice -> - payViaIntent(invoice, context, noWalletFoundStr, onPaid = {}, onError = { - toastManager.toast(zapErrorTitle, it) - }) + if (!host.openLightningWallet(invoice)) toastManager.toast(zapErrorTitle, noWalletFoundStr) } } }, @@ -1360,7 +1289,7 @@ class AccountViewModel( ) return@launchSigner } - val zappedEvent = baseNote.toEventHint() + val zappedEvent = baseNote.toEventHint() if (zappedEvent == null) { onError( loadStringRes(Res.string.nutzap_failed_title), @@ -2044,7 +1973,7 @@ class AccountViewModel( fun reactionRowItemsFlow() = account.settings.syncedSettings.reactions.reactionRowItems - fun changeReactionRowItems(items: List) = + fun changeReactionRowItems(items: List) = launchSigner { account.changeReactionRowItems(items) } @@ -2057,7 +1986,7 @@ class AccountViewModel( viewModelScope.launch { account.changeCaptionsEnabled(enabled) } } - fun changeVideoPlayerButtonItems(items: List) = + fun changeVideoPlayerButtonItems(items: List) = launchSigner { account.changeVideoPlayerButtonItems(items) } @@ -2121,7 +2050,7 @@ class AccountViewModel( /** * Publish any pending picker edits now. Called when a picker screen leaves the composition or the * app stops, so an edit is never left sitting only in memory: synced settings have no local copy - * of their own — [com.vitorpamplona.amethyst.model.AccountSettings.backupAppSpecificData], written + * of their own — [com.vitorpamplona.amethyst.commons.model.AccountSettings.backupAppSpecificData], written * when the published event comes back through the collector, *is* the local copy. */ fun flushPickerPublish() = pickerPublisher.flush() @@ -2212,15 +2141,6 @@ class AccountViewModel( account.deleteStatus(LocalCache.getOrCreateAddressableNote(address)) } - fun urlPreview( - url: String, - onResult: suspend (UrlPreviewState) -> Unit, - ) { - viewModelScope.launch(Dispatchers.IO) { - UrlCachedPreviewer.previewInfo(url, httpClientBuilder::okHttpClientForPreview, onResult) - } - } - fun loadReactionTo(note: Note?): String? { if (note == null) return null @@ -2318,11 +2238,6 @@ class AccountViewModel( .mapNotNull { hex -> checkGetOrCreateUser(hex) } .sortedByDescending { account.isKnown(it) } - suspend fun checkVideoIsOnline(videoUrl: String): Boolean = - withContext(Dispatchers.IO) { - OnlineChecker.isOnline(videoUrl, httpClientBuilder::okHttpClientForVideo) - } - fun loadAndMarkAsRead( routeForLastRead: String, createdAt: Long?, @@ -2346,11 +2261,7 @@ class AccountViewModel( return onIsNew } - private fun dismissTrayNotificationFor(eventId: HexKey) { - ContextCompat - .getSystemService(Amethyst.instance.appContext, NotificationManager::class.java) - ?.dismissNotificationForEvent(eventId) - } + private fun dismissTrayNotificationFor(eventId: HexKey) = host.dismissNotificationFor(eventId) fun markAllChatNotesAsRead(notes: List) { viewModelScope.launch(Dispatchers.IO) { @@ -2373,26 +2284,6 @@ class AccountViewModel( } } - class Factory( - val account: Account, - val settings: UiSettingsState, - val torSettings: TorSettingsFlow, - val dataSources: RelaySubscriptionsCoordinator, - val okHttpClient: RoleBasedHttpClientBuilder, - val nip05ClientBuilder: () -> Nip05Client, - ) : ViewModelProvider.Factory { - @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class): T = - AccountViewModel( - account, - settings, - torSettings, - dataSources, - okHttpClient, - nip05ClientBuilder, - ) as T - } - init { Log.d("AccountViewModel", "Init") viewModelScope.launch(Dispatchers.IO) { @@ -2518,7 +2409,7 @@ class AccountViewModel( suspend fun sendMarmotGroupMediaMessage( nostrGroupId: String, url: String, - imeta: com.vitorpamplona.quartz.nip92IMeta.IMetaTag, + imeta: IMetaTag, ) { val template = eventTemplate( @@ -2532,8 +2423,8 @@ class AccountViewModel( // is authenticated by the MLS sender's LeafNode + the pubkey↔ // credential-identity equality check on the receive side. val innerEvent = - com.vitorpamplona.quartz.nip59Giftwrap.rumors.RumorAssembler - .assembleRumor( + RumorAssembler + .assembleRumor( account.signer.pubKey, template, ) @@ -2662,7 +2553,7 @@ class AccountViewModel( account.marmot.resetMarmotState() } - fun marmotGroupMembers(nostrGroupId: String): List = account.marmotManager?.memberPubkeys(nostrGroupId) ?: emptyList() + fun marmotGroupMembers(nostrGroupId: String): List = account.marmotManager?.memberPubkeys(nostrGroupId) ?: emptyList() suspend fun addMarmotGroupMember( nostrGroupId: String, @@ -2693,19 +2584,6 @@ class AccountViewModel( account.marmot.revokeMarmotGroupAdmin(nostrGroupId, targetPubKey, relays) } - /** - * Encrypt + upload a picked image as a group avatar (canonical - * `marmot-group-image-v1` scheme). The returned handle is later passed to - * [updateMarmotGroupMetadata] as [MarmotGroupIconChange.Set] to commit it into - * the group's metadata. Uploading is separated from the metadata commit so the - * (slow) Blossom upload can show its own progress before the commit is signed. - */ - suspend fun uploadMarmotGroupIcon( - uri: Uri, - mimeType: String?, - context: Context, - ): MarmotGroupIconUpload = MarmotGroupIconUploader(account).upload(uri, mimeType, account.settings.defaultFileServer, context) - suspend fun updateMarmotGroupMetadata( nostrGroupId: String, name: String, @@ -2752,9 +2630,9 @@ class AccountViewModel( // reference is dropped; the call itself is account-scoped and keeps running. // Real logout / account switch tears the call down via CallSessionBridge.clear(), // called from AccountSessionManager alongside NestBridge.clear(). - com.vitorpamplona.amethyst.service.call.CallSessionBridge + CallSessionBridge .clearViewModel() - com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.activity.NestBridge + NestBridge .clear() feedStates.destroy() } @@ -2806,7 +2684,6 @@ class AccountViewModel( fun meltCashu( token: CashuToken, - context: Context, onDone: (String, String) -> Unit, ) { val lud16 = @@ -2824,8 +2701,8 @@ class AccountViewModel( MeltProcessor().melt( token, lud16, - httpClientBuilder::okHttpClientForMoney, - context, + account.cashuMintTransport, + host.lnurlTransport, // Mints the user deliberately added are exempt from the // private-address block (self-hosted LAN mints are legit). knownWalletMints = @@ -2840,7 +2717,7 @@ class AccountViewModel( meltResult.fees.toString(), ), ) - } catch (e: LightningAddressResolver.LightningAddressError) { + } catch (e: LightningInvoiceResolver.LightningAddressError) { onDone(e.title, e.msg) } catch (e: Exception) { if (e is kotlin.coroutines.cancellation.CancellationException) throw e @@ -3021,7 +2898,7 @@ class AccountViewModel( bolt11: String, onResult: (DebitResponse?) -> Unit, ) = launchSigner { - val response = ClinkDebitPayer.payInvoice(account, pointer, bolt11) + val response = ClinkDebitPayer.payInvoice(account, host.moneyOpRelays, pointer, bolt11) withContext(Dispatchers.Main) { onResult(response) } } @@ -3051,7 +2928,6 @@ class AccountViewModel( onNewInvoice: (String) -> Unit, onError: (String, String) -> Unit, onProgress: (percent: Float) -> Unit, - context: Context, zapType: ZapReceiptEvent.ZapType? = null, ) { viewModelScope.launch(Dispatchers.IO) { @@ -3073,21 +2949,19 @@ class AccountViewModel( } val invoice = - LightningAddressResolver().lnAddressInvoice( + LightningInvoiceResolver(host.lnurlTransport).lnAddressInvoice( lnAddress = lnAddress, milliSats = milliSats, message = message, nostrRequest = zapRequest, - okHttpClient = httpClientBuilder::okHttpClientForMoney, onProgress = onProgress, - context = context, ) // Delivered on Main: every composer's onNewInvoice writes the invoice into // its message TextFieldState, which is UI-thread confined (see the KDoc on // commons' `onUiThread`). This whole block runs on Dispatchers.IO. withContext(Dispatchers.Main) { onNewInvoice(invoice) } - } catch (e: LightningAddressResolver.LightningAddressError) { + } catch (e: LightningInvoiceResolver.LightningAddressError) { onError(e.title, e.msg) } catch (e: Exception) { if (e is CancellationException) throw e @@ -3096,61 +2970,12 @@ class AccountViewModel( } } - fun saveMediaToGallery( - videoUri: String?, - mimeType: String?, - localContext: Context, - ) { - viewModelScope.launch { - // onSuccess is a plain callback, so the text is resolved here first. - val savedText = loadStringRes(Res.string.video_saved_to_the_gallery) - MediaSaverToDisk.saveDownloadingIfNeeded( - videoUri = videoUri, - okHttpClient = httpClientBuilder::okHttpClientForVideo, - mimeType = mimeType, - localContext = localContext, - resolveBlossom = { - Amethyst.instance.blossomResolver - .findServers(it) - ?.serverUrl - }, - onSuccess = { - Handler(Looper.getMainLooper()).post { - Toast - .makeText(localContext.applicationContext, savedText, Toast.LENGTH_SHORT) - .show() - } - }, - onError = { - toastManager.toast(Res.string.failed_to_save_the_video, null, it) - }, - ) - } - } - - fun convertAccounts(loggedInAccounts: List?): Set = - loggedInAccounts - ?.mapNotNull { - try { - it.npub.bechToBytes().toHexKey() - } catch (e: Exception) { - if (e is CancellationException) throw e - null - } - }?.toSet() ?: emptySet() - val trustedAccounts: StateFlow> = - LocalPreferences - .accountsFlow() - .map { loggedInAccounts -> - convertAccounts(loggedInAccounts) - }.onStart { - emit(convertAccounts(LocalPreferences.allSavedAccounts())) - }.stateIn( - viewModelScope, - SharingStarted.WhileSubscribed(5000), - emptySet(), - ) + host.savedAccounts.stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(5000), + emptySet(), + ) val draftNoteCache = CachedDraftNotes(this) @@ -3233,117 +3058,3 @@ class AccountViewModel( val baseNote: Note?, val nip19: Nip19Parser.ParseReturn, ) - -var mockedCache: AccountViewModel? = null - -@SuppressLint("ViewModelConstructorInComposable") -@Composable -fun mockAccountViewModel(): AccountViewModel { - mockedCache?.let { return it } - - val scope = rememberCoroutineScope() - - val uiState = - UiSettingsState( - uiSettingsFlow = UiSettingsFlow(), - isMobileOrMeteredConnection = MutableStateFlow(false), - scope = scope, - ) - - val keyPair = - KeyPair( - privKey = Hex.decode("0f761f8a5a481e26f06605a1d9b3e9eba7a107d351f43c43a57469b788274499"), - pubKey = Hex.decode("989c3734c46abac7ce3ce229971581a5a6ee39cdd6aa7261a55823fa7f8c4799"), - forceReplacePubkey = false, - ) - - val client = EmptyNostrClient() - val authenticator = EmptyIAuthStatus - - val nwcFilters = NWCPaymentFilterAssembler(client) - val failureTracker = RelayOfflineTracker(client) - - val account = - Account( - settings = AccountSettings(keyPair), - signer = NostrSignerInternal(keyPair), - geolocationFlow = { MutableStateFlow(LocationState.LocationResult.Loading) }, - nwcFilterAssembler = { nwcFilters }, - cashuMintDirectoryFilterAssembler = { - com.vitorpamplona.amethyst.commons.relayClient.assemblers - .CashuMintDirectoryFilterAssembler(client) - }, - okHttpClientForMoney = { okhttp3.OkHttpClient() }, - otsResolverBuilder = { EmptyOtsResolverBuilder.build() }, - cache = LocalCache, - client = client, - scope = scope, - ) - - return AccountViewModel( - account = account, - settings = uiState, - torSettings = TorSettingsFlow(torType = MutableStateFlow(TorType.OFF)), - httpClientBuilder = EmptyRoleBasedHttpClientBuilder(), - dataSources = RelaySubscriptionsCoordinator(LocalCache, client, authenticator, failureTracker, scope), - nip05ClientBuilder = { EmptyNip05Client() }, - ).also { - mockedCache = it - } -} - -var vitorCache: AccountViewModel? = null - -@SuppressLint("ViewModelConstructorInComposable") -@Composable -fun mockVitorAccountViewModel(): AccountViewModel { - mockedCache?.let { return it } - - val scope = rememberCoroutineScope() - - val uiState = - UiSettingsState( - uiSettingsFlow = UiSettingsFlow(), - isMobileOrMeteredConnection = MutableStateFlow(false), - scope = scope, - ) - - val keyPair = - KeyPair( - pubKey = Hex.decode("460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c"), - ) - - val client = EmptyNostrClient() - val authenticator = EmptyIAuthStatus - - val nwcFilters = NWCPaymentFilterAssembler(client) - val failureTracker = RelayOfflineTracker(client) - - val account = - Account( - settings = AccountSettings(keyPair), - signer = NostrSignerInternal(keyPair), - geolocationFlow = { MutableStateFlow(LocationState.LocationResult.Loading) }, - nwcFilterAssembler = { nwcFilters }, - cashuMintDirectoryFilterAssembler = { - com.vitorpamplona.amethyst.commons.relayClient.assemblers - .CashuMintDirectoryFilterAssembler(client) - }, - okHttpClientForMoney = { okhttp3.OkHttpClient() }, - otsResolverBuilder = { EmptyOtsResolverBuilder.build() }, - cache = LocalCache, - client = EmptyNostrClient(), - scope = scope, - ) - - return AccountViewModel( - account = account, - settings = uiState, - torSettings = TorSettingsFlow(torType = MutableStateFlow(TorType.OFF)), - httpClientBuilder = EmptyRoleBasedHttpClientBuilder(), - dataSources = RelaySubscriptionsCoordinator(LocalCache, client, authenticator, failureTracker, scope), - nip05ClientBuilder = { EmptyNip05Client() }, - ).also { - vitorCache = it - } -} diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountViewModelPreviews.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountViewModelPreviews.kt new file mode 100644 index 0000000000..8c3b9082f0 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountViewModelPreviews.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.viewmodels + +import androidx.compose.runtime.Composable + +/** + * A logged-in [AccountViewModel] over an offline client and the shared cache, for `@Preview`s. + * Built once and reused. Available where previews render (Android and Desktop); iOS has none. + */ +@Composable +expect fun mockAccountViewModel(): AccountViewModel + +/** [mockAccountViewModel] as a read-only (public key only) account. */ +@Composable +expect fun mockVitorAccountViewModel(): AccountViewModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/ReloadMintViewModel.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/wallet/ReloadMintViewModel.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/ReloadMintViewModel.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/wallet/ReloadMintViewModel.kt index 8a30b81dc5..8042055bc2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/ReloadMintViewModel.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/wallet/ReloadMintViewModel.kt @@ -18,15 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet +package com.vitorpamplona.amethyst.commons.wallet import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.commons.cashu.ops.describeMintError import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.model.nip60Cashu.CashuWalletState -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.commons.model.nip60Cashu.CashuWalletState +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip47WalletConnect.Nip47WalletConnect import com.vitorpamplona.quartz.nip47WalletConnect.rpc.PayInvoiceMethod diff --git a/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/AnimatedImageAutoPlay.ios.kt b/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/AnimatedImageAutoPlay.ios.kt new file mode 100644 index 0000000000..678a8c1413 --- /dev/null +++ b/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/AnimatedImageAutoPlay.ios.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.runtime.Composable +import coil3.Image + +@Composable +internal actual fun AnimatedImageAutoPlay( + image: Image?, + autoPlay: Boolean, +) { + // Nothing drives animated-image playback on iOS yet, so autoPlay has no effect here. +} diff --git a/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RememberViewModel.ios.kt b/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RememberViewModel.ios.kt new file mode 100644 index 0000000000..089cdea849 --- /dev/null +++ b/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RememberViewModel.ios.kt @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.remember +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.ViewModelStore +import androidx.lifecycle.viewmodel.CreationExtras +import kotlin.reflect.KClass + +/** + * No navigation back stack owns view models here yet, so each call gets its own store, scoped to + * the composition, and clears it on the way out: that is what runs `onCleared()` and cancels the + * view model's `viewModelScope`, which a bare `remember` never would. + */ +@Composable +actual fun rememberViewModel( + modelClass: KClass, + key: String?, + factory: ViewModelProvider.Factory, +): VM { + val store = remember(modelClass, key) { ViewModelStore() } + DisposableEffect(store) { onDispose { store.clear() } } + return remember(store) { ViewModelProvider.create(store, factory).get(modelClass) } +} + +@Composable +actual fun rememberViewModel( + modelClass: KClass, + key: String?, + factory: () -> VM, +): VM = + rememberViewModel( + modelClass, + key, + object : ViewModelProvider.Factory { + @Suppress("UNCHECKED_CAST") + override fun create( + modelClass: KClass, + extras: CreationExtras, + ): T = factory() as T + }, + ) diff --git a/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ShortNotice.ios.kt b/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ShortNotice.ios.kt new file mode 100644 index 0000000000..a991b09cfb --- /dev/null +++ b/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ShortNotice.ios.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.runtime.Composable +import com.vitorpamplona.quartz.utils.Log + +private val loggedNotice = ShortNotice { message -> Log.d("ShortNotice") { message } } + +@Composable +actual fun rememberShortNotice(): ShortNotice = loggedNotice diff --git a/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TextSharer.ios.kt b/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TextSharer.ios.kt new file mode 100644 index 0000000000..7796eb2308 --- /dev/null +++ b/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TextSharer.ios.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.runtime.Composable +import platform.UIKit.UIPasteboard + +private val clipboardSharer = TextSharer { text, _, _ -> UIPasteboard.generalPasteboard.string = text } + +@Composable +actual fun rememberTextSharer(): TextSharer = clipboardSharer diff --git a/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/DateTimeStyle.ios.kt b/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/DateTimeStyle.ios.kt new file mode 100644 index 0000000000..88e39056a7 --- /dev/null +++ b/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/ui/note/DateTimeStyle.ios.kt @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.note + +import platform.Foundation.NSDate +import platform.Foundation.NSDateFormatter +import platform.Foundation.NSDateFormatterLongStyle +import platform.Foundation.NSDateFormatterMediumStyle +import platform.Foundation.NSDateFormatterNoStyle +import platform.Foundation.NSDateFormatterShortStyle +import platform.Foundation.NSDateFormatterStyle +import platform.Foundation.dateWithTimeIntervalSince1970 + +private fun DateTimeStyle.nsStyle(): NSDateFormatterStyle = + when (this) { + DateTimeStyle.NONE -> NSDateFormatterNoStyle + DateTimeStyle.SHORT -> NSDateFormatterShortStyle + DateTimeStyle.MEDIUM -> NSDateFormatterMediumStyle + DateTimeStyle.LONG -> NSDateFormatterLongStyle + } + +actual fun formatDateTime( + epochMillis: Long, + date: DateTimeStyle, + time: DateTimeStyle, +): String { + if (date == DateTimeStyle.NONE && time == DateTimeStyle.NONE) return "" + val formatter = + NSDateFormatter().apply { + dateStyle = date.nsStyle() + timeStyle = time.nsStyle() + } + return formatter.stringFromDate(NSDate.dateWithTimeIntervalSince1970(epochMillis / 1000.0)) +} diff --git a/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountViewModelPreviews.ios.kt b/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountViewModelPreviews.ios.kt new file mode 100644 index 0000000000..e1ddc9efe5 --- /dev/null +++ b/commonsUI/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountViewModelPreviews.ios.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.viewmodels + +import androidx.compose.runtime.Composable + +@Composable +actual fun mockAccountViewModel(): AccountViewModel = error("Previews render on Android and Desktop only") + +@Composable +actual fun mockVitorAccountViewModel(): AccountViewModel = error("Previews render on Android and Desktop only") diff --git a/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RememberViewModel.jvmAndroid.kt b/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RememberViewModel.jvmAndroid.kt new file mode 100644 index 0000000000..7faaa0e1ee --- /dev/null +++ b/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RememberViewModel.jvmAndroid.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.runtime.Composable +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewmodel.CreationExtras +import androidx.lifecycle.viewmodel.compose.viewModel +import kotlin.reflect.KClass + +@Composable +actual fun rememberViewModel( + modelClass: KClass, + key: String?, + factory: ViewModelProvider.Factory, +): VM = viewModel(modelClass = modelClass, key = key, factory = factory) + +@Composable +actual fun rememberViewModel( + modelClass: KClass, + key: String?, + factory: () -> VM, +): VM = + viewModel( + modelClass = modelClass, + key = key, + factory = + object : ViewModelProvider.Factory { + @Suppress("UNCHECKED_CAST") + override fun create( + modelClass: KClass, + extras: CreationExtras, + ): T = factory() as T + }, + ) diff --git a/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/ui/note/DateTimeStyle.jvmAndroid.kt b/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/ui/note/DateTimeStyle.jvmAndroid.kt new file mode 100644 index 0000000000..d5ce157428 --- /dev/null +++ b/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/ui/note/DateTimeStyle.jvmAndroid.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.note + +import java.text.DateFormat +import java.util.Date + +private fun DateTimeStyle.javaStyle(): Int = + when (this) { + DateTimeStyle.SHORT -> DateFormat.SHORT + DateTimeStyle.MEDIUM -> DateFormat.MEDIUM + DateTimeStyle.LONG, DateTimeStyle.NONE -> DateFormat.LONG + } + +/** A fresh `DateFormat` per call: they are not thread-safe, and the locale may have changed. */ +actual fun formatDateTime( + epochMillis: Long, + date: DateTimeStyle, + time: DateTimeStyle, +): String { + val formatter = + when { + date == DateTimeStyle.NONE && time == DateTimeStyle.NONE -> return "" + date == DateTimeStyle.NONE -> DateFormat.getTimeInstance(time.javaStyle()) + time == DateTimeStyle.NONE -> DateFormat.getDateInstance(date.javaStyle()) + else -> DateFormat.getDateTimeInstance(date.javaStyle(), time.javaStyle()) + } + return formatter.format(Date(epochMillis)) +} diff --git a/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountViewModelPreviews.jvmAndroid.kt b/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountViewModelPreviews.jvmAndroid.kt new file mode 100644 index 0000000000..4c9a3d0b40 --- /dev/null +++ b/commonsUI/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/viewmodels/AccountViewModelPreviews.jvmAndroid.kt @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.viewmodels + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope +import com.vitorpamplona.amethyst.commons.model.Account +import com.vitorpamplona.amethyst.commons.model.AccountSettings +import com.vitorpamplona.amethyst.commons.model.InMemoryGeohashIdentityStore +import com.vitorpamplona.amethyst.commons.model.UiSettingsFlow +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.location.LocationResult +import com.vitorpamplona.amethyst.commons.model.marmot.MarmotGroupNotifier +import com.vitorpamplona.amethyst.commons.model.nip46Signer.Nip46ConsentPrompter +import com.vitorpamplona.amethyst.commons.relayClient.assemblers.CashuMintDirectoryFilterAssembler +import com.vitorpamplona.amethyst.commons.relayClient.nip47WalletConnect.NWCPaymentFilterAssembler +import com.vitorpamplona.amethyst.commons.relayClient.reqCommand.RelaySubscriptionsCoordinator +import com.vitorpamplona.amethyst.commons.service.http.EmptyRoleBasedHttpClientBuilder +import com.vitorpamplona.amethyst.commons.service.http.EncryptionKeyCache +import com.vitorpamplona.amethyst.commons.service.lnurl.LnurlHttpTransport +import com.vitorpamplona.amethyst.commons.service.pow.PoWJobFailure +import com.vitorpamplona.amethyst.commons.state.UiSettingsState +import com.vitorpamplona.amethyst.commons.tor.MoneyOpRelayRouting +import com.vitorpamplona.amethyst.commons.tor.TorSettingsFlow +import com.vitorpamplona.amethyst.commons.tor.TorType +import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair +import com.vitorpamplona.quartz.nip01Core.relay.client.EmptyNostrClient +import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.RelayOfflineTracker +import com.vitorpamplona.quartz.nip01Core.relay.client.auth.EmptyIAuthStatus +import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStats +import com.vitorpamplona.quartz.nip01Core.relay.sockets.okhttp.BasicOkHttpWebSocket +import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal +import com.vitorpamplona.quartz.nip03Timestamp.EmptyOtsResolverBuilder +import com.vitorpamplona.quartz.nip05DnsIdentifiers.EmptyNip05Client +import com.vitorpamplona.quartz.nip60Cashu.mintApi.OkHttpMintTransport +import com.vitorpamplona.quartz.utils.Hex +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.flowOf +import okhttp3.OkHttpClient + +private var mockedCache: AccountViewModel? = null + +@Suppress("ViewModelConstructorInComposable") +@Composable +actual fun mockAccountViewModel(): AccountViewModel { + mockedCache?.let { return it } + + val scope = rememberCoroutineScope() + + val uiState = + UiSettingsState( + uiSettingsFlow = UiSettingsFlow(), + isMobileOrMeteredConnection = MutableStateFlow(false), + scope = scope, + ) + + val keyPair = + KeyPair( + privKey = Hex.decode("0f761f8a5a481e26f06605a1d9b3e9eba7a107d351f43c43a57469b788274499"), + pubKey = Hex.decode("989c3734c46abac7ce3ce229971581a5a6ee39cdd6aa7261a55823fa7f8c4799"), + forceReplacePubkey = false, + ) + + val client = EmptyNostrClient() + val authenticator = EmptyIAuthStatus + + val nwcFilters = NWCPaymentFilterAssembler(client) + val failureTracker = RelayOfflineTracker(client) + + val account = + Account( + settings = AccountSettings(keyPair), + signer = NostrSignerInternal(keyPair), + geolocationFlow = { MutableStateFlow(LocationResult.Loading) }, + nwcFilterAssembler = { nwcFilters }, + cashuMintDirectoryFilterAssembler = { CashuMintDirectoryFilterAssembler(client) }, + cashuMintTransport = OkHttpMintTransport { OkHttpClient() }, + otsResolverBuilder = { EmptyOtsResolverBuilder.build() }, + cache = LocalCache, + client = client, + scope = scope, + appVersion = "preview", + encryptionKeyCache = EncryptionKeyCache(), + saveSettings = {}, + marmotNotifier = { MarmotGroupNotifier.None }, + nip46Consent = Nip46ConsentPrompter.Unanswered, + geohashIdentityStore = InMemoryGeohashIdentityStore(), + marmotStreamTransportFactory = { error("Previews do not stream") }, + ) + + return AccountViewModel( + account = account, + settings = uiState, + torSettings = TorSettingsFlow(torType = MutableStateFlow(TorType.OFF)), + httpClientBuilder = EmptyRoleBasedHttpClientBuilder(), + dataSources = RelaySubscriptionsCoordinator(LocalCache, client, authenticator, failureTracker, scope), + nip05ClientBuilder = { EmptyNip05Client() }, + host = PreviewAccountViewModelHost, + ).also { + mockedCache = it + } +} + +private var vitorCache: AccountViewModel? = null + +@Suppress("ViewModelConstructorInComposable") +@Composable +actual fun mockVitorAccountViewModel(): AccountViewModel { + mockedCache?.let { return it } + + val scope = rememberCoroutineScope() + + val uiState = + UiSettingsState( + uiSettingsFlow = UiSettingsFlow(), + isMobileOrMeteredConnection = MutableStateFlow(false), + scope = scope, + ) + + val keyPair = + KeyPair( + pubKey = Hex.decode("460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c"), + ) + + val client = EmptyNostrClient() + val authenticator = EmptyIAuthStatus + + val nwcFilters = NWCPaymentFilterAssembler(client) + val failureTracker = RelayOfflineTracker(client) + + val account = + Account( + settings = AccountSettings(keyPair), + signer = NostrSignerInternal(keyPair), + geolocationFlow = { MutableStateFlow(LocationResult.Loading) }, + nwcFilterAssembler = { nwcFilters }, + cashuMintDirectoryFilterAssembler = { CashuMintDirectoryFilterAssembler(client) }, + cashuMintTransport = OkHttpMintTransport { OkHttpClient() }, + otsResolverBuilder = { EmptyOtsResolverBuilder.build() }, + cache = LocalCache, + client = EmptyNostrClient(), + scope = scope, + appVersion = "preview", + encryptionKeyCache = EncryptionKeyCache(), + saveSettings = {}, + marmotNotifier = { MarmotGroupNotifier.None }, + nip46Consent = Nip46ConsentPrompter.Unanswered, + geohashIdentityStore = InMemoryGeohashIdentityStore(), + marmotStreamTransportFactory = { error("Previews do not stream") }, + ) + + return AccountViewModel( + account = account, + settings = uiState, + torSettings = TorSettingsFlow(torType = MutableStateFlow(TorType.OFF)), + httpClientBuilder = EmptyRoleBasedHttpClientBuilder(), + dataSources = RelaySubscriptionsCoordinator(LocalCache, client, authenticator, failureTracker, scope), + nip05ClientBuilder = { EmptyNip05Client() }, + host = PreviewAccountViewModelHost, + ).also { + vitorCache = it + } +} + +/** Nothing to probe, dismiss or pay from inside a preview. */ +private object PreviewAccountViewModelHost : AccountViewModelHost { + override val memoryPressure: Flow = emptyFlow() + override val localBlossomCacheAvailable: Flow = flowOf(false) + override val powPublishFailures: Flow = emptyFlow() + override val relayStats = RelayStats(EmptyNostrClient()) + override val websocketBuilder = BasicOkHttpWebSocket.Builder { OkHttpClient() } + override val lnurlTransport = LnurlHttpTransport { throw IllegalStateException("Previews do not reach the network") } + override val moneyOpRelays = MoneyOpRelayRouting.None + override val savedAccounts: Flow> = flowOf(emptySet()) + + override fun dismissNotificationFor(eventId: HexKey) = Unit + + override fun openLightningWallet(invoice: String) = false +} diff --git a/commonsUI/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ShortNotice.jvm.kt b/commonsUI/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ShortNotice.jvm.kt new file mode 100644 index 0000000000..a991b09cfb --- /dev/null +++ b/commonsUI/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ShortNotice.jvm.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.runtime.Composable +import com.vitorpamplona.quartz.utils.Log + +private val loggedNotice = ShortNotice { message -> Log.d("ShortNotice") { message } } + +@Composable +actual fun rememberShortNotice(): ShortNotice = loggedNotice diff --git a/commonsUI/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TextSharer.jvm.kt b/commonsUI/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TextSharer.jvm.kt new file mode 100644 index 0000000000..f18e140df6 --- /dev/null +++ b/commonsUI/src/jvmMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/TextSharer.jvm.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.runtime.Composable +import java.awt.Toolkit +import java.awt.datatransfer.StringSelection + +private val clipboardSharer = TextSharer { text, _, _ -> Toolkit.getDefaultToolkit().systemClipboard.setContents(StringSelection(text), null) } + +@Composable +actual fun rememberTextSharer(): TextSharer = clipboardSharer diff --git a/commonsUI/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/LightningInvoiceResolverTest.kt b/commonsUI/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/LightningInvoiceResolverTest.kt new file mode 100644 index 0000000000..dd9dbc73ae --- /dev/null +++ b/commonsUI/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/service/lnurl/LightningInvoiceResolverTest.kt @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.service.lnurl + +import com.vitorpamplona.amethyst.commons.service.lnurl.LightningInvoiceResolver +import com.vitorpamplona.amethyst.commons.service.lnurl.LnurlHttpResponse +import com.vitorpamplona.amethyst.commons.service.lnurl.LnurlHttpTransport +import com.vitorpamplona.amethyst.commons.service.lnurl.roundHalfUpToSats +import com.vitorpamplona.quartz.nip57Zaps.ZapRequestEvent +import kotlinx.coroutines.runBlocking +import kotlin.test.Test +import kotlin.test.assertEquals + +/** + * [LightningInvoiceResolver] over a scripted transport. The replies use the loose typing real + * LNURL servers send (a boolean as text, a number for a flag), which the resolver was written to + * read through Jackson's lenient readers. + */ +class LightningInvoiceResolverTest { + // A 1 mBTC (100,000 sat) BOLT-11. + private val invoice100kSats = "lnbc1m1pjt9u0qsp553q90pj5mafzv20w45eqavned9tgwhl4q99n9s5ppcw24nzw3zeqpp5002kd3ktym67du86kj665fgaev7ka8ys7j5yz5fg686lr5e2gfkshp5dkk27nnuax05az3pk2r6ytxtvwn5j4xzsq9ajprhc7crjkmgvr3qxqyjw5qcqpjrzjqtzxvfsuxe4l92pf97tt4rcgpy2xalkmlwexh899wqxf83l8nwv4xzh0gvqq89qqqqqqqqlgqqqqq0gqvs9qxpqysgqx5mz04wd7kqu5zhhel9enr036hjrp4gga0nz084p2asjl36a0zmrk6mhqa249zsgqref2rlvhffm73u7rxgr47gden6rugup4ksvpzsqvds4pz" + + private class ScriptedTransport( + private val replies: Map, + ) : LnurlHttpTransport { + val requested = mutableListOf() + + override suspend fun get(url: String): LnurlHttpResponse { + requested += url + val key = replies.keys.first { url.startsWith(it) } + return LnurlHttpResponse(200, "OK", replies.getValue(key)) + } + } + + private fun resolverFor( + lnurlp: String, + invoiceReply: String = """{"pr":"$invoice100kSats","routes":[]}""", + ): Pair { + val transport = + ScriptedTransport( + mapOf( + "https://example.com/.well-known/lnurlp/alice" to lnurlp, + "https://example.com/callback" to invoiceReply, + ), + ) + return LightningInvoiceResolver(transport) to transport + } + + @Test + fun resolvesAnInvoiceAndEncodesTheComment() = + runBlocking { + val (resolver, transport) = resolverFor("""{"callback":"https://example.com/callback","allowsNostr":true,"nostrPubkey":"ab"}""") + var progress = 0f + + val pr = resolver.lnAddressInvoice("alice@example.com", 100_000_000L, "gm & ☕", onProgress = { progress = it }) + + assertEquals(invoice100kSats, pr) + assertEquals(0.7f, progress) + assertEquals("https://example.com/callback?amount=100000000&comment=gm+%26+%E2%98%95", transport.requested[1]) + } + + @Test + fun readsLooselyTypedFlagsLikeJackson() = + runBlocking { + val zapRequest = ZapRequestEvent("00".repeat(32), "11".repeat(32), 1L, emptyArray(), "", "22".repeat(64)) + // The text "true" and a non-zero number count as true, as Jackson's asBoolean() read them. + listOf("\"true\"" to true, "true" to true, "1" to true, "0" to false, "false" to false, "\"yes\"" to false).forEach { (flag, allows) -> + val (resolver, transport) = resolverFor("""{"callback":"https://example.com/callback","allowsNostr":$flag}""") + var sent: ZapRequestEvent? = null + + resolver.lnAddressInvoice("alice@example.com", 100_000_000L, "", zapRequest, onProgress = {}, onZapRequestSent = { sent = it }) + + assertEquals(allows, sent != null, "allowsNostr=$flag") + assertEquals(allows, transport.requested[1].contains("&nostr="), "allowsNostr=$flag") + } + } + + @Test + fun appendsParametersToACallbackThatAlreadyHasAQuery() = + runBlocking { + val (resolver, transport) = resolverFor("""{"callback":"https://example.com/callback?id=7"}""") + + resolver.lnAddressInvoice("alice@example.com", 100_000_000L, "hi", onProgress = {}) + + assertEquals("https://example.com/callback?id=7&amount=100000000&comment=hi", transport.requested[1]) + } + + @Test + fun roundsHalfASatUp() { + assertEquals(0L, roundHalfUpToSats(499)) + assertEquals(1L, roundHalfUpToSats(500)) + assertEquals(100_000L, roundHalfUpToSats(100_000_000)) + assertEquals(-1L, roundHalfUpToSats(-500)) + } +} diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/RouteForPointerTest.kt b/commonsUI/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/ui/navigation/routes/RouteForPointerTest.kt similarity index 90% rename from amethyst/src/test/java/com/vitorpamplona/amethyst/ui/RouteForPointerTest.kt rename to commonsUI/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/ui/navigation/routes/RouteForPointerTest.kt index 19964c6862..3ffc9f08e5 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/RouteForPointerTest.kt +++ b/commonsUI/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/ui/navigation/routes/RouteForPointerTest.kt @@ -18,14 +18,14 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui +package com.vitorpamplona.amethyst.commons.ui.navigation.routes +import com.vitorpamplona.amethyst.commons.model.Account import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.navigation.routes.THREAD_VIEW_KINDS -import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.ui.navigation.routes.routeForPointer +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.THREAD_VIEW_KINDS +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeForPointer import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent @@ -39,9 +39,9 @@ import com.vitorpamplona.quartz.nip71Video.AddressableNormalVideoEvent import com.vitorpamplona.quartz.nip71Video.AddressableShortVideoEvent import com.vitorpamplona.quartz.utils.EventFactory import io.mockk.mockk -import org.junit.Assert.assertEquals -import org.junit.Assert.assertNull -import org.junit.Test +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNull /** * A notification tap on a cold process finds nothing in LocalCache, so the only thing left @@ -97,11 +97,11 @@ class RouteForPointerTest { EventFactory.create(id, "b".repeat(64), 1, kind, emptyArray(), "", "c".repeat(128)) assertEquals( - "kind $kind (${event::class.simpleName}) disagrees with routeFor", routeFor(event, account), routeForPointer(kind, id), + "kind $kind (${event::class.simpleName}) disagrees with routeFor", ) - assertEquals("kind $kind must resolve to the thread view", Route.Note(id), routeForPointer(kind, id)) + assertEquals(Route.Note(id), routeForPointer(kind, id), "kind $kind must resolve to the thread view") } } diff --git a/commonsUI/src/skikoMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/ArgbImageBitmap.skiko.kt b/commonsUI/src/skikoMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/ArgbImageBitmap.skiko.kt new file mode 100644 index 0000000000..ad049ea672 --- /dev/null +++ b/commonsUI/src/skikoMain/kotlin/com/vitorpamplona/amethyst/commons/service/image/ArgbImageBitmap.skiko.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.service.image + +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.asComposeImageBitmap +import org.jetbrains.skia.Bitmap +import org.jetbrains.skia.ColorAlphaType +import org.jetbrains.skia.ImageInfo + +/** Skia's N32 is BGRA in memory on every Skiko target, so each ARGB int is written low byte first. */ +actual fun argbPixelsToImageBitmap( + pixels: IntArray, + width: Int, + height: Int, +): ImageBitmap { + val bytes = ByteArray(pixels.size * 4) + for (i in pixels.indices) { + val argb = pixels[i] + val offset = i * 4 + bytes[offset] = (argb and 0xFF).toByte() + bytes[offset + 1] = ((argb shr 8) and 0xFF).toByte() + bytes[offset + 2] = ((argb shr 16) and 0xFF).toByte() + bytes[offset + 3] = ((argb shr 24) and 0xFF).toByte() + } + val bitmap = Bitmap() + bitmap.allocPixels(ImageInfo.makeN32(width, height, ColorAlphaType.UNPREMUL)) + bitmap.installPixels(bytes) + bitmap.setImmutable() + return bitmap.asComposeImageBitmap() +} diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/cache/DesktopLocalCache.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/cache/DesktopLocalCache.kt index 40736a1fa6..fb83c375e4 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/cache/DesktopLocalCache.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/cache/DesktopLocalCache.kt @@ -386,7 +386,7 @@ class DesktopLocalCache : ICacheProvider { /** * Consumes a kind 10063 (NIP-B7) Blossom media server list event. Stores * the newest per-author copy in [addressableNotes] so state holders like - * [com.vitorpamplona.amethyst.commons.model.nipB7Blossom.BlossomServerListState] + * [com.vitorpamplona.amethyst.desktop.model.BlossomServerListState] * observe it via their flows. This is the same event the Amethyst mobile * app uses for the media server list. Emits nothing to the event stream — * the UI doesn't render kind 10063s directly. diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/BlossomServerListState.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/BlossomServerListState.kt new file mode 100644 index 0000000000..c40bb61949 --- /dev/null +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/BlossomServerListState.kt @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.desktop.model + +import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.model.NoteState +import com.vitorpamplona.amethyst.commons.model.cache.ICacheProvider +import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner +import com.vitorpamplona.quartz.nipB7Blossom.BlossomServersEvent +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn + +/** + * Shared, platform-agnostic state holder for the user's Blossom media server + * list (NIP-B7 / kind 10063 [BlossomServersEvent]). + * + * This is the same event kind the Amethyst mobile app reads through its own + * `BlossomServerListState`: it loads the addressable event from the injected + * [ICacheProvider] and exposes the declared server URLs as a [StateFlow]. Both + * the Android and Desktop front ends can consume this so a server list + * configured on one client shows up on the other. + */ +class BlossomServerListState( + val signer: NostrSigner, + val cache: ICacheProvider, + val scope: CoroutineScope, +) { + // Creates a long-term reference for this note so that the GC doesn't collect the note itself + val blossomListNote = cache.getOrCreateAddressableNote(getBlossomServersAddress()) + + fun getBlossomServersAddress() = BlossomServersEvent.createAddress(signer.pubKey) + + fun getBlossomServersListFlow(): StateFlow = blossomListNote.flow().metadata.stateFlow + + fun getBlossomServersList(): BlossomServersEvent? = blossomListNote.event as? BlossomServersEvent + + fun normalizeServers(note: Note): List = (note.event as? BlossomServersEvent)?.servers() ?: emptyList() + + val flow: StateFlow> = + getBlossomServersListFlow() + .map { normalizeServers(it.note) } + .onStart { emit(normalizeServers(blossomListNote)) } + .flowOn(Dispatchers.IO) + .stateIn( + scope, + SharingStarted.Eagerly, + emptyList(), + ) + + suspend fun saveBlossomServersList(servers: List): BlossomServersEvent { + val serverList = getBlossomServersList() + + return if (serverList != null && serverList.tags.isNotEmpty()) { + BlossomServersEvent.updateRelayList( + earlierVersion = serverList, + servers = servers, + signer = signer, + ) + } else { + BlossomServersEvent.createFromScratch( + relays = servers, + signer = signer, + ) + } + } +} diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/BlossomServers.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/BlossomServers.kt index d3a319be66..9e0892f1a4 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/BlossomServers.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/BlossomServers.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.desktop.model /** * Fallback media server used when the account has published no kind-10063 * Blossom server list yet. The list itself is read reactively from the account's - * [com.vitorpamplona.amethyst.commons.model.nipB7Blossom.BlossomServerListState] + * [com.vitorpamplona.amethyst.desktop.model.BlossomServerListState] * (`iAccount.blossomServerList.flow`); this is only the empty-list default. */ const val DEFAULT_BLOSSOM_SERVER = "https://blossom.primal.net" diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/DesktopIAccount.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/DesktopIAccount.kt index b1c29e32ee..ae60470f1d 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/DesktopIAccount.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/DesktopIAccount.kt @@ -29,9 +29,6 @@ import com.vitorpamplona.amethyst.commons.model.nip02FollowList.Kind3FollowListR import com.vitorpamplona.amethyst.commons.model.nip02FollowList.Kind3FollowListState import com.vitorpamplona.amethyst.commons.model.nip51Lists.BookmarkListState import com.vitorpamplona.amethyst.commons.model.nip51Lists.OldBookmarkListState -import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListRepository -import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState -import com.vitorpamplona.amethyst.commons.model.nipB7Blossom.BlossomServerListState import com.vitorpamplona.amethyst.commons.model.privateChats.ChatroomList import com.vitorpamplona.amethyst.commons.moderation.PreferencesSensitiveContentSettings import com.vitorpamplona.amethyst.commons.relayClient.nip17Dm.DmInboxRelayResolver diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/DesktopRelayCategories.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/DesktopRelayCategories.kt index 586c7b1922..c4f86b7ad9 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/DesktopRelayCategories.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/DesktopRelayCategories.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.desktop.model import com.vitorpamplona.amethyst.commons.defaults.DefaultSearchRelayList -import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState import com.vitorpamplona.amethyst.commons.relays.index.PreferencesIndexRelays import com.vitorpamplona.amethyst.desktop.network.DefaultRelays import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/DesktopRelayListMutator.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/DesktopRelayListMutator.kt index 07dfb77539..56b70999a8 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/DesktopRelayListMutator.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/DesktopRelayListMutator.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.desktop.model -import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState import com.vitorpamplona.amethyst.commons.relays.health.RelayListKind import com.vitorpamplona.amethyst.commons.relays.health.RelayListMutator import com.vitorpamplona.amethyst.commons.relays.health.RelayRemovalResult diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip65RelayList/Nip65RelayListRepository.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/Nip65RelayListRepository.kt similarity index 96% rename from commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip65RelayList/Nip65RelayListRepository.kt rename to desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/Nip65RelayListRepository.kt index 6b58890747..3b27f79c79 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/nip65RelayList/Nip65RelayListRepository.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/Nip65RelayListRepository.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.commons.model.nip65RelayList +package com.vitorpamplona.amethyst.desktop.model import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip65RelayList/Nip65RelayListState.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/Nip65RelayListState.kt similarity index 79% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip65RelayList/Nip65RelayListState.kt rename to desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/Nip65RelayListState.kt index 581906ef10..a4a53693dc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip65RelayList/Nip65RelayListState.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/model/Nip65RelayListState.kt @@ -18,14 +18,11 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.model.nip65RelayList +package com.vitorpamplona.amethyst.desktop.model -import com.vitorpamplona.amethyst.commons.defaults.Constants -import com.vitorpamplona.amethyst.commons.defaults.relayListOrDefaultsWhenUnknown import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.NoteState -import com.vitorpamplona.amethyst.commons.model.cache.LocalCache -import com.vitorpamplona.amethyst.model.AccountSettings +import com.vitorpamplona.amethyst.commons.model.cache.ICacheProvider import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent @@ -34,6 +31,7 @@ import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn @@ -44,11 +42,11 @@ import kotlinx.coroutines.launch class Nip65RelayListState( val signer: NostrSigner, - val cache: LocalCache, + val cache: ICacheProvider, val scope: CoroutineScope, - val settings: AccountSettings, + val settings: Nip65RelayListRepository, ) { - // Creates a long-term reference for this note so that the GC doesn't collect the note it self + // Creates a long-term reference for this note so that the GC doesn't collect the note itself val nip65ListNote = cache.getOrCreateAddressableNote(getNIP65RelayListAddress()) fun getNIP65RelayListAddress() = AdvertisedRelayListEvent.createAddress(signer.pubKey) @@ -59,39 +57,18 @@ class Nip65RelayListState( fun nip65Event(note: Note) = note.event as? AdvertisedRelayListEvent ?: settings.backupNIP65RelayList - fun normalizeNIP65WriteRelayListWithBackup(note: Note): Set = relayListOrDefaultsWhenUnknown(nip65Event(note), Constants.eventFinderRelays) { it.writeRelaysNorm()?.toSet() } + fun normalizeNIP65WriteRelayListWithBackup(note: Note): Set = nip65Event(note)?.writeRelaysNorm()?.toSet() ?: settings.defaultOutboxRelays - fun normalizeNIP65ReadRelayListWithBackup(note: Note): Set = relayListOrDefaultsWhenUnknown(nip65Event(note), Constants.bootstrapInbox) { it.readRelaysNorm()?.toSet() } + fun normalizeNIP65ReadRelayListWithBackup(note: Note): Set = nip65Event(note)?.readRelaysNorm()?.toSet() ?: settings.defaultInboxRelays fun normalizeNIP65WriteRelayListNoDefaults(note: Note): Set = nip65Event(note)?.writeRelaysNorm()?.toSet() ?: emptySet() fun normalizeNIP65ReadRelayListNoDefaults(note: Note): Set = nip65Event(note)?.readRelaysNorm()?.toSet() ?: emptySet() - fun normalizeNIP65AllRelayListWithBackup(note: Note): Set = nip65Event(note)?.relays()?.map { it.relayUrl }?.toSet() ?: Constants.eventFinderRelays + fun normalizeNIP65AllRelayListWithBackup(note: Note): Set = nip65Event(note)?.relays()?.map { it.relayUrl }?.toSet() ?: settings.defaultOutboxRelays fun normalizeNIP65AllRelayListWithBackupNoDefaults(note: Note): Set = nip65Event(note)?.relays()?.map { it.relayUrl }?.toSet() ?: emptySet() - /** - * The app defaults currently standing in for a user we have no kind:10002 for — empty as soon - * as one exists, including an empty one. - * - * Uses the same `nip65Event(note) == null` predicate the substitution itself uses, so the two - * cannot drift: whatever is listed here is exactly what the app is guessing on the user's - * behalf. See [relayListOrDefaultsWhenUnknown]. - */ - fun assumedDefaults(note: Note): Set = if (nip65Event(note) == null) Constants.bootstrapInbox + Constants.eventFinderRelays else emptySet() - - val assumedDefaultsFlow = - getNIP65RelayListFlow() - .map { assumedDefaults(it.note) } - .onStart { emit(assumedDefaults(nip65ListNote)) } - .flowOn(Dispatchers.IO) - .stateIn( - scope, - SharingStarted.Eagerly, - assumedDefaults(nip65ListNote), - ) - val outboxFlow = getNIP65RelayListFlow() .map { normalizeNIP65WriteRelayListWithBackup(it.note) } diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/relay/Nip65RelayEditor.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/relay/Nip65RelayEditor.kt index 1f3e2798d6..08428cddd3 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/relay/Nip65RelayEditor.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/relay/Nip65RelayEditor.kt @@ -55,7 +55,7 @@ import androidx.compose.ui.input.key.type import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols -import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState +import com.vitorpamplona.amethyst.desktop.model.Nip65RelayListState import com.vitorpamplona.amethyst.desktop.network.DefaultRelays import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/relay/RelayConfigTab.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/relay/RelayConfigTab.kt index 7865f991be..744237d35b 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/relay/RelayConfigTab.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/relay/RelayConfigTab.kt @@ -45,8 +45,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols -import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState import com.vitorpamplona.amethyst.desktop.model.DesktopAccountRelays +import com.vitorpamplona.amethyst.desktop.model.Nip65RelayListState import com.vitorpamplona.amethyst.desktop.network.DesktopRelayConnectionManager import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/relay/RelayDashboardScreen.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/relay/RelayDashboardScreen.kt index f2d6163f49..d46996abe4 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/relay/RelayDashboardScreen.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/relay/RelayDashboardScreen.kt @@ -39,8 +39,8 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState import com.vitorpamplona.amethyst.desktop.model.DesktopAccountRelays +import com.vitorpamplona.amethyst.desktop.model.Nip65RelayListState import com.vitorpamplona.amethyst.desktop.network.DesktopRelayConnectionManager import com.vitorpamplona.amethyst.desktop.network.Nip11Fetcher import com.vitorpamplona.quartz.nip01Core.core.Event diff --git a/desktopApp/src/jvmTest/kotlin/com/vitorpamplona/amethyst/desktop/cache/DesktopBlossomServerListTest.kt b/desktopApp/src/jvmTest/kotlin/com/vitorpamplona/amethyst/desktop/cache/DesktopBlossomServerListTest.kt index 5816e4e085..e526531018 100644 --- a/desktopApp/src/jvmTest/kotlin/com/vitorpamplona/amethyst/desktop/cache/DesktopBlossomServerListTest.kt +++ b/desktopApp/src/jvmTest/kotlin/com/vitorpamplona/amethyst/desktop/cache/DesktopBlossomServerListTest.kt @@ -20,7 +20,7 @@ */ package com.vitorpamplona.amethyst.desktop.cache -import com.vitorpamplona.amethyst.commons.model.nipB7Blossom.BlossomServerListState +import com.vitorpamplona.amethyst.desktop.model.BlossomServerListState import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4c1961e706..13297f858e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -178,6 +178,7 @@ charlietap-cachemap = { module = "io.github.charlietap:cachemap", version.ref = coil-compose = { group = "io.coil-kt.coil3", name = "coil-compose", version.ref = "coil" } coil-gif = { group = "io.coil-kt.coil3", name = "coil-gif", version.ref = "coil" } coil-svg = { group = "io.coil-kt.coil3", name = "coil-svg", version.ref = "coil" } +coil-network-core = { group = "io.coil-kt.coil3", name = "coil-network-core", version.ref = "coil" } coil-okhttp = { group = "io.coil-kt.coil3", name = "coil-network-okhttp", version.ref = "coil" } coil-video = { group = "io.coil-kt.coil3", name = "coil-video", version.ref = "coil" } commons-imaging = { group = "org.apache.commons", name = "commons-imaging", version.ref = "commonsImaging" } diff --git a/quartz/src/appleMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.apple.kt b/quartz/src/appleMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.apple.kt index 4bf7fc3821..750b607d1c 100644 --- a/quartz/src/appleMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.apple.kt +++ b/quartz/src/appleMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.apple.kt @@ -21,3 +21,5 @@ package com.vitorpamplona.quartz.utils actual fun BigDecimal.toLongValue(): Long = toLong() + +actual fun BigDecimal.toDoubleValue(): Double = toDouble() diff --git a/quartz/src/appleMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.apple.kt b/quartz/src/appleMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.apple.kt index 9536b80e57..a564dd3cbb 100644 --- a/quartz/src/appleMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.apple.kt +++ b/quartz/src/appleMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.apple.kt @@ -39,7 +39,7 @@ actual class AESGCM actual constructor( private fun cipher() = keyDecoder.cipher() - actual override fun name(): String = "aes-gcm" + actual override fun name(): String = AES_GCM_NAME @OptIn(DelicateCryptographyApi::class) actual override fun encrypt(bytesToEncrypt: ByteArray): ByteArray = diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip57Zaps/validate/LnurlEndpointCache.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/validate/LnurlEndpointCache.kt similarity index 95% rename from quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip57Zaps/validate/LnurlEndpointCache.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/validate/LnurlEndpointCache.kt index c7fe418607..2fcb8d229f 100644 --- a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip57Zaps/validate/LnurlEndpointCache.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/validate/LnurlEndpointCache.kt @@ -21,8 +21,8 @@ package com.vitorpamplona.quartz.nip57Zaps.validate import com.vitorpamplona.quartz.utils.cache.ConcurrentLruCache +import com.vitorpamplona.quartz.utils.concurrent.ConcurrentMap import kotlinx.coroutines.CompletableDeferred -import java.util.concurrent.ConcurrentHashMap /** * Process-wide cache of LNURL-pay endpoint metadata, keyed by the canonical @@ -32,7 +32,7 @@ import java.util.concurrent.ConcurrentHashMap * recipient's LNURL provider's `nostrPubkey` to validate the signer (NIP-57 * Appendix F). Without a cache, we'd re-fetch the same lnurlp endpoint for * every zap from every popular author. Outbound zaps populate the cache as a - * side effect when [com.vitorpamplona.amethyst.service.lnurl.LightningAddressResolver] + * side effect when Amethyst's `LightningInvoiceResolver` * fetches the recipient's metadata. * * Keys are URLs (not lud16 forms) so callers can convert lud16 / bech32 LNURL @@ -50,7 +50,7 @@ object LnurlEndpointCache { // what counts as "the same address", which is why they live together: a // flight map that keyed URLs differently would silently stop deduplicating // the moment this object's canonicalisation changed, and nothing would fail. - private val inFlight = ConcurrentHashMap>() + private val inFlight = ConcurrentMap>() fun get(url: String): LnurlEndpointInfo? = cache.get(LnurlForm.normalizeUrl(url)) diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/CashuMintOperations.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/CashuMintOperations.kt similarity index 99% rename from quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/CashuMintOperations.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/CashuMintOperations.kt index 024413a720..ca15286ab7 100644 --- a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/CashuMintOperations.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/CashuMintOperations.kt @@ -687,10 +687,13 @@ class CashuMintOperations( val ys = ArrayList(proofs.size) proofs.forEach { proof -> val y = Bdhke.hashToCurveCompressed(proof.secret.encodeToByteArray()).toHexKey() - // putIfAbsent: two proofs can legitimately carry the same secret + // First one wins: two proofs can legitimately carry the same secret // (a duplicated kind:7375 the dedup pass hasn't retired yet), and // they map to the same state anyway. - if (secretByY.putIfAbsent(y, proof.secret) == null) ys.add(y) + if (y !in secretByY) { + secretByY[y] = proof.secret + ys.add(y) + } } val out = HashMap(secretByY.size) diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/CashuMintUrlValidator.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/CashuMintUrlValidator.kt similarity index 100% rename from quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/CashuMintUrlValidator.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/CashuMintUrlValidator.kt diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/MintHttpClient.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/MintHttpClient.kt similarity index 80% rename from quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/MintHttpClient.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/MintHttpClient.kt index c6cdd37c4e..9b754c2277 100644 --- a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/MintHttpClient.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/MintHttpClient.kt @@ -20,14 +20,13 @@ */ package com.vitorpamplona.quartz.nip60Cashu.mintApi +import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.withContext +import kotlinx.serialization.KSerializer import kotlinx.serialization.json.Json -import okhttp3.MediaType.Companion.toMediaType -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.RequestBody.Companion.toRequestBody -import okhttp3.coroutines.executeAsync +import kotlin.concurrent.Volatile /** * Thrown when the mint returns a non-2xx response or an HTTP error. @@ -53,7 +52,7 @@ class MintProtocolException( ) : RuntimeException(message) /** - * OkHttp-backed Cashu v1 mint client implementing NUT-00..06 endpoints. + * Cashu v1 mint client implementing NUT-00..06 endpoints, over a [MintHttpTransport]. * * Each instance is bound to a single mint URL (e.g. `https://mint.example.com`). * Trailing slashes are stripped on construction. @@ -70,7 +69,7 @@ class MintProtocolException( class MintHttpClient( mintUrl: String, userConfigured: Boolean = false, - private val okHttpClient: (String) -> OkHttpClient, + private val transport: MintHttpTransport, ) { private val baseUrl: String = CashuMintUrlValidator.validatedBaseUrl(mintUrl, userConfigured) @@ -92,13 +91,13 @@ class MintHttpClient( suspend fun info(force: Boolean = false): MintInfoDto { if (!force) { cachedInfo?.let { (info, at) -> - if (System.currentTimeMillis() - at < INFO_CACHE_TTL_MS) { + if (TimeUtils.nowMillis() - at < INFO_CACHE_TTL_MS) { return info } } } val fresh = get("/v1/info") - cachedInfo = fresh to System.currentTimeMillis() + cachedInfo = fresh to TimeUtils.nowMillis() return fresh } @@ -128,41 +127,20 @@ class MintHttpClient( private suspend inline fun get(path: String): R = withContext(Dispatchers.IO) { - val url = baseUrl + path - val client = okHttpClient(url) - val req = - Request - .Builder() - .url(url) - .get() - .build() - client.newCall(req).executeAsync().use { resp -> - val body = resp.body.string() - if (!resp.isSuccessful) throw decodeError(resp.code, body) - json.decodeFromString(body) - } + val resp = transport.get(baseUrl + path) + if (!resp.isSuccessful) throw decodeError(resp.status, resp.body) + json.decodeFromString(resp.body) } private suspend inline fun post( path: String, body: T, - serializer: kotlinx.serialization.KSerializer, + serializer: KSerializer, ): R = withContext(Dispatchers.IO) { - val url = baseUrl + path - val client = okHttpClient(url) - val bodyJson = json.encodeToString(serializer, body) - val req = - Request - .Builder() - .url(url) - .post(bodyJson.toRequestBody(jsonMediaType)) - .build() - client.newCall(req).executeAsync().use { resp -> - val text = resp.body.string() - if (!resp.isSuccessful) throw decodeError(resp.code, text) - json.decodeFromString(text) - } + val resp = transport.postJson(baseUrl + path, json.encodeToString(serializer, body)) + if (!resp.isSuccessful) throw decodeError(resp.status, resp.body) + json.decodeFromString(resp.body) } private fun decodeError( @@ -187,8 +165,6 @@ class MintHttpClient( explicitNulls = false } - private val jsonMediaType = "application/json; charset=utf-8".toMediaType() - /** * Mint info TTL. /v1/info typically changes on the order of * weeks (mint name, supported NUTs, motd updates). 30 minutes diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/MintHttpTransport.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/MintHttpTransport.kt new file mode 100644 index 0000000000..b4580029e3 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/MintHttpTransport.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip60Cashu.mintApi + +/** + * The HTTP a [MintHttpClient] needs: a GET, and a POST of a JSON body, each returning the status and + * the body as text. Each platform supplies one (OkHttp on Android and the JVM). Implementations + * pick the per-URL client themselves (Tor, proxies), run off the main thread, and throw on a + * transport failure; an HTTP error status is a [MintHttpResponse], not an exception. + */ +interface MintHttpTransport { + suspend fun get(url: String): MintHttpResponse + + suspend fun postJson( + url: String, + json: String, + ): MintHttpResponse +} + +/** One mint response. */ +class MintHttpResponse( + val status: Int, + val body: String, +) { + val isSuccessful: Boolean get() = status in 200..299 +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/parse/TextFragmentParser.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/parse/TextFragmentParser.kt index 63c6e76096..76fb7e9520 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/parse/TextFragmentParser.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/parse/TextFragmentParser.kt @@ -113,6 +113,63 @@ object TextFragmentParser { return if (beforeDirective.isEmpty()) base else "$base#$beforeDirective" } + /** + * Builds [baseUrl] with a `text=` directive that scrolls the page to [exact]. A few words of + * [prefix] and [suffix] (the ones nearest the quote) are added as `prefix-,` / `,-suffix` + * disambiguators, so the browser lands on the right occurrence when the quote repeats. + * [parse] reads back what this writes. + */ + fun buildUrl( + baseUrl: String, + exact: String, + prefix: String? = null, + suffix: String? = null, + ): String { + val separator = if (baseUrl.contains("#")) "&" else "#" + val prefixPart = trimToEdge(prefix, keepStart = false)?.let { "${percentEncode(it)}-," } ?: "" + val suffixPart = trimToEdge(suffix, keepStart = true)?.let { ",-${percentEncode(it)}" } ?: "" + return "$baseUrl$separator$DIRECTIVE_DELIMITER$TEXT_PARAM$prefixPart${percentEncode(exact)}$suffixPart" + } + + /** Words of a prefix/suffix kept next to the quote: enough to disambiguate, short enough to match. */ + private const val EDGE_WORDS = 4 + private const val UNRESERVED = "_!.~'()*" + private val HEX_DIGITS = "0123456789ABCDEF".toCharArray() + private val WHITESPACE = Regex("\\s+") + + /** + * Keeps the [EDGE_WORDS] words nearest the quote (the last ones of a prefix, the first ones of + * a suffix) and collapses whitespace, so newlines in a selector don't break the match. + */ + private fun trimToEdge( + text: String?, + keepStart: Boolean, + ): String? { + if (text == null) return null + val words = text.trim().split(WHITESPACE).filter { it.isNotEmpty() } + if (words.isEmpty()) return null + return (if (keepStart) words.take(EDGE_WORDS) else words.takeLast(EDGE_WORDS)).joinToString(" ") + } + + /** + * Percent-encodes as UTF-8, leaving only ASCII letters, digits and `_!.~'()*`: spaces become + * `%20` (not `+`, which [percentDecode] keeps literal), and `&`, `,` and `-` never appear raw, + * as the Text Fragments spec requires, so a quote that starts with `-` cannot be read back as + * a suffix. + */ + private fun percentEncode(text: String): String { + val out = StringBuilder(text.length) + for (byte in text.encodeToByteArray()) { + val c = (byte.toInt() and 0xFF).toChar() + if (c < '\u0080' && (c.isLetterOrDigit() || c in UNRESERVED)) { + out.append(c) + } else { + out.append('%').append(HEX_DIGITS[(byte.toInt() shr 4) and 0xF]).append(HEX_DIGITS[byte.toInt() and 0xF]) + } + } + return out.toString() + } + private fun decode(value: String?): String? { if (value.isNullOrEmpty()) return null return percentDecode(value).takeIf { it.isNotEmpty() } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.kt index be65f1dac7..02c409d91d 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.kt @@ -35,3 +35,15 @@ operator fun BigDecimal.minus(other: BigDecimal): BigDecimal = subtract(other) * the platform compilations and breaks `compileCommonMainKotlinMetadata`. */ expect fun BigDecimal.toLongValue(): Long + +/** The nearest Double, as Number.toDouble() gives on every platform. An expect for [toLongValue]'s reason. */ +expect fun BigDecimal.toDoubleValue(): Double + +private val PLAIN_DECIMAL = Regex("[+-]?(\\d+\\.?\\d*|\\.\\d+)") + +/** + * Parses a plain decimal ("12", "-0.5", ".5") into a [BigDecimal], or null for anything else, + * exponents included. The platform constructors disagree on bad input (the JVM throws, the others + * do not), so the check happens here, before any of them sees the text. + */ +fun parseBigDecimalOrNull(text: String): BigDecimal? = if (PLAIN_DECIMAL.matches(text)) BigDecimal(text) else null diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/ConcurrentLruCache.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/ConcurrentLruCache.kt similarity index 88% rename from quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/ConcurrentLruCache.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/ConcurrentLruCache.kt index eff79f0f92..bfd077eb67 100644 --- a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/ConcurrentLruCache.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/ConcurrentLruCache.kt @@ -20,7 +20,9 @@ */ package com.vitorpamplona.quartz.utils.cache -import java.util.concurrent.ConcurrentHashMap +import com.vitorpamplona.quartz.utils.concurrent.ConcurrentMap +import com.vitorpamplona.quartz.utils.concurrent.PlatformLock +import com.vitorpamplona.quartz.utils.concurrent.withLock /** * A bounded, thread-safe cache with a **lock-free [get]**. @@ -54,12 +56,12 @@ class ConcurrentLruCache( require(maxSize > 0) { "maxSize must be > 0, was $maxSize" } } - private val map = ConcurrentHashMap() + private val map = ConcurrentMap() // Guards writes + eviction so the map and the recency order stay consistent. // Reads never touch it. Writes are the cold path here, so serializing them // is fine; the point is a lock-free [get]. - private val writeLock = Any() + private val writeLock = PlatformLock() private val order = ArrayDeque() fun get(key: K): V? = map[key] @@ -68,9 +70,11 @@ class ConcurrentLruCache( key: K, value: V, ) { - synchronized(writeLock) { + writeLock.withLock { // Re-inserting an existing key makes it the youngest again. - val existed = map.put(key, value) != null + // Check-then-set is safe: every write holds writeLock. + val existed = map[key] != null + map[key] = value if (existed) order.remove(key) order.addLast(key) while (order.size > maxSize) { @@ -81,7 +85,7 @@ class ConcurrentLruCache( } fun clear() { - synchronized(writeLock) { + writeLock.withLock { order.clear() map.clear() } @@ -93,7 +97,7 @@ class ConcurrentLruCache( * the cache; values above the current size are a no-op. */ fun trimToSize(maxItems: Int) { - synchronized(writeLock) { + writeLock.withLock { while (order.size > maxItems) { val oldest = order.removeFirstOrNull() ?: break map.remove(oldest) @@ -101,5 +105,5 @@ class ConcurrentLruCache( } } - fun size(): Int = map.size + fun size(): Int = map.size() } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.kt index 831100a909..d34cf57906 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.kt @@ -22,6 +22,9 @@ package com.vitorpamplona.quartz.utils.ciphers import com.vitorpamplona.quartz.utils.RandomInstance +/** The name AES-GCM ciphers report, and that NIP-17 file messages carry as their `encryption-algorithm`. */ +const val AES_GCM_NAME = "aes-gcm" + expect class AESGCM( keyBytes: ByteArray = RandomInstance.bytes(32), nonce: ByteArray = RandomInstance.bytes(16), diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/concurrent/ConcurrentMap.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/concurrent/ConcurrentMap.kt index 98419bca89..bd5a8b2a83 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/concurrent/ConcurrentMap.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/concurrent/ConcurrentMap.kt @@ -93,4 +93,13 @@ expect class ConcurrentMap() { /** A point-in-time copy of the entries — safe to iterate without holding a lock. */ fun snapshot(): Map + + /** + * A read-only view to iterate or look up in right away, without copying: the live, + * weakly consistent map on JVM/Android (iteration never throws while others write, and may + * or may not see those writes), the current immutable copy-on-write state on native. Don't + * hold it expecting later writes to show up; use [snapshot] when a caller needs a stable + * copy it can keep. + */ + fun asMap(): Map } diff --git a/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip84Highlights/parse/TextFragmentParserTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip84Highlights/parse/TextFragmentParserTest.kt index 7b5c5d8d49..bb54ef3ad3 100644 --- a/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip84Highlights/parse/TextFragmentParserTest.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip84Highlights/parse/TextFragmentParserTest.kt @@ -115,4 +115,43 @@ class TextFragmentParserTest { TextFragmentParser.stripTextFragment("https://example.com/post#section"), ) } + + @Test + fun buildUrlRoundTripsThroughParse() { + val url = + TextFragmentParser.buildUrl( + baseUrl = "https://example.com/post", + exact = "-5 degrees, & falling: 100%+ sure — ok", + prefix = "the forecast said", + suffix = "by the weekend", + ) + val fragment = TextFragmentParser.parse(url) + assertEquals("-5 degrees, & falling: 100%+ sure — ok", fragment?.start) + assertEquals("the forecast said", fragment?.prefix) + assertEquals("by the weekend", fragment?.suffix) + assertNull(fragment?.end) + } + + @Test + fun buildUrlKeepsTheWordsNearestTheQuote() { + val url = + TextFragmentParser.buildUrl( + baseUrl = "https://example.com/post#intro", + exact = "quote", + prefix = "one two three four five six", + suffix = "alpha beta\ngamma delta epsilon", + ) + assertEquals("https://example.com/post#intro&:~:text=three%20four%20five%20six-,quote,-alpha%20beta%20gamma%20delta", url) + val fragment = TextFragmentParser.parse(url) + assertEquals("three four five six", fragment?.prefix) + assertEquals("alpha beta gamma delta", fragment?.suffix) + } + + @Test + fun buildUrlEncodesSpacesAsPercent20AndHyphens() { + assertEquals( + "https://example.com#:~:text=a%20b%2Dc%2C", + TextFragmentParser.buildUrl("https://example.com", "a b-c,"), + ) + } } diff --git a/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/utils/concurrent/ConcurrentCollectionsTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/utils/concurrent/ConcurrentCollectionsTest.kt index 5f78d107f1..ee73973ef8 100644 --- a/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/utils/concurrent/ConcurrentCollectionsTest.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/utils/concurrent/ConcurrentCollectionsTest.kt @@ -118,6 +118,20 @@ class ConcurrentCollectionsTest { assertEquals(3, m.size()) } + @Test + fun mapAsMapSeesEarlierWritesAndSurvivesLaterOnes() { + val map = ConcurrentMap() + map["a"] = 1 + map["b"] = 2 + val view = map.asMap() + assertEquals(mapOf("a" to 1, "b" to 2), view.toMap()) + // Writing while iterating must not throw on any target. One fixed key, so a view that + // does see the new entry (JVM may) still ends. + for (key in view.keys) map["written-during-iteration"] = 0 + assertEquals(0, map["written-during-iteration"]) + assertEquals(1, map["a"]) + } + @Test fun setAddContainsSize() { val s = ConcurrentSet() diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/OkHttpMintTransport.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/OkHttpMintTransport.kt new file mode 100644 index 0000000000..dd2a32db67 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip60Cashu/mintApi/OkHttpMintTransport.kt @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip60Cashu.mintApi + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import okhttp3.coroutines.executeAsync + +/** [MintHttpTransport] over OkHttp. [okHttpClient] picks the client for each URL (Tor, proxies). */ +class OkHttpMintTransport( + private val okHttpClient: (String) -> OkHttpClient, +) : MintHttpTransport { + override suspend fun get(url: String): MintHttpResponse = + execute( + url, + Request + .Builder() + .url(url) + .get() + .build(), + ) + + override suspend fun postJson( + url: String, + json: String, + ): MintHttpResponse = + execute( + url, + Request + .Builder() + .url(url) + .post(json.toRequestBody(jsonMediaType)) + .build(), + ) + + private suspend fun execute( + url: String, + request: Request, + ): MintHttpResponse = + withContext(Dispatchers.IO) { + okHttpClient(url).newCall(request).executeAsync().use { resp -> + MintHttpResponse(resp.code, resp.body.string()) + } + } + + companion object { + private val jsonMediaType = "application/json; charset=utf-8".toMediaType() + } +} + +/** A [MintHttpClient] over OkHttp, for callers that hold an OkHttp client factory. */ +fun MintHttpClient( + mintUrl: String, + userConfigured: Boolean = false, + okHttpClient: (String) -> OkHttpClient, +): MintHttpClient = MintHttpClient(mintUrl, userConfigured, OkHttpMintTransport(okHttpClient)) diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.jvmAndroid.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.jvmAndroid.kt index 4bf7fc3821..750b607d1c 100644 --- a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.jvmAndroid.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.jvmAndroid.kt @@ -21,3 +21,5 @@ package com.vitorpamplona.quartz.utils actual fun BigDecimal.toLongValue(): Long = toLong() + +actual fun BigDecimal.toDoubleValue(): Double = toDouble() diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.jvmAndroid.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.jvmAndroid.kt index a48ee39c67..0d00a9ddc0 100644 --- a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.jvmAndroid.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.jvmAndroid.kt @@ -86,6 +86,6 @@ actual class AESGCM actual constructor( } companion object { - const val NAME = "aes-gcm" + const val NAME = AES_GCM_NAME } } diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/concurrent/ConcurrentMap.jvmAndroid.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/concurrent/ConcurrentMap.jvmAndroid.kt index 0ed037d770..3f4f19aba4 100644 --- a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/concurrent/ConcurrentMap.jvmAndroid.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/concurrent/ConcurrentMap.jvmAndroid.kt @@ -66,4 +66,6 @@ actual class ConcurrentMap { actual fun size(): Int = map.size actual fun snapshot(): Map = HashMap(map) + + actual fun asMap(): Map = map } diff --git a/quartz/src/linuxMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.linux.kt b/quartz/src/linuxMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.linux.kt index 4bf7fc3821..750b607d1c 100644 --- a/quartz/src/linuxMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.linux.kt +++ b/quartz/src/linuxMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.linux.kt @@ -21,3 +21,5 @@ package com.vitorpamplona.quartz.utils actual fun BigDecimal.toLongValue(): Long = toLong() + +actual fun BigDecimal.toDoubleValue(): Double = toDouble() diff --git a/quartz/src/linuxMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.linux.kt b/quartz/src/linuxMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.linux.kt index 9536b80e57..a564dd3cbb 100644 --- a/quartz/src/linuxMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.linux.kt +++ b/quartz/src/linuxMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.linux.kt @@ -39,7 +39,7 @@ actual class AESGCM actual constructor( private fun cipher() = keyDecoder.cipher() - actual override fun name(): String = "aes-gcm" + actual override fun name(): String = AES_GCM_NAME @OptIn(DelicateCryptographyApi::class) actual override fun encrypt(bytesToEncrypt: ByteArray): ByteArray = diff --git a/quartz/src/nativeMain/kotlin/com/vitorpamplona/quartz/utils/concurrent/ConcurrentMap.native.kt b/quartz/src/nativeMain/kotlin/com/vitorpamplona/quartz/utils/concurrent/ConcurrentMap.native.kt index 8a32a1e7ef..949e66ecce 100644 --- a/quartz/src/nativeMain/kotlin/com/vitorpamplona/quartz/utils/concurrent/ConcurrentMap.native.kt +++ b/quartz/src/nativeMain/kotlin/com/vitorpamplona/quartz/utils/concurrent/ConcurrentMap.native.kt @@ -119,4 +119,7 @@ actual class ConcurrentMap { actual fun size(): Int = ref.load().size actual fun snapshot(): Map = HashMap(ref.load()) + + // The published map is never mutated after the CAS that installed it, so it is its own view. + actual fun asMap(): Map = ref.load() }