mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 11:18:24 +00:00
refactor: cut more shared-screen blockers (step 6 wave 5 seams)
- PlatformBackHandler (commonsUI): AndroidX BackHandler on Android, Compose Multiplatform's
ui-backhandler on desktop and iOS. The app's 21 BackHandler users switch to it.
commonsUI adds androidx.activity:activity-compose (androidMain) and
org.jetbrains.compose.ui:ui-backhandler (skikoMain); both Apache-2.0, both already shipped.
- rememberLongNotice joins rememberShortNotice, so Toast.LENGTH_LONG messages keep their
duration; four screens drop their Toasts for the shared notices.
- The wallet screens use formatGrouped instead of NumberFormat and the shared Clipboard
getText/setText extensions instead of ClipboardManager.
- formatMonthDayTime (commonsUI) builds "May 28 14:32" from DateSkeletonFormatter("MMMd") and the
system-clock time-of-day formatter; the two transaction lists use it.
- UsageKeys uses quartz's ConcurrentMap. LocalCacheHost gains a UsageCounter (no-op by default,
the Android host feeds its resource-usage ledger), so reconnectPoolAfterJoin no longer reaches
for Amethyst.instance.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7FuNBSKiyVecARSoE4B9P
This commit is contained in:
@@ -24,6 +24,7 @@ import com.vitorpamplona.amethyst.commons.model.cache.FileSystemNip95BlobStore
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCacheHost
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.Nip95BlobStore
|
||||
import com.vitorpamplona.amethyst.commons.service.UsageCounter
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStats
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
@@ -54,6 +55,8 @@ class AmethystLocalCacheHost(
|
||||
|
||||
override val relayStats: RelayStats get() = modules.relayStats
|
||||
|
||||
override val usageCounter: UsageCounter = UsageCounter { key, amount -> modules.resourceUsage.add(key, amount) }
|
||||
|
||||
override fun relaySelfPubKey(relay: NormalizedRelayUrl): HexKey? = modules.nip11Cache.getFromCache(relay).self
|
||||
|
||||
override fun relayInfo(relay: NormalizedRelayUrl): Nip11RelayInformation = modules.nip11Cache.getFromCache(relay)
|
||||
|
||||
+4
-4
@@ -30,7 +30,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.MachineReadabl
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.MachineReadablePrefix.RESTRICTED
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.MachineReadablePrefix.UNSUPPORTED
|
||||
import com.vitorpamplona.quartz.nip66RelayMonitor.reachability.RelayObserver
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import com.vitorpamplona.quartz.utils.concurrent.ConcurrentMap
|
||||
|
||||
/**
|
||||
* Counter-key grammar for the resource-usage ledger. Keys are flat strings so
|
||||
@@ -489,8 +489,8 @@ object UsageKeys {
|
||||
private const val UP = "up"
|
||||
private const val DOWN = "down"
|
||||
|
||||
private val VERB_UP_KEYS = ConcurrentHashMap<String, Array<String>>()
|
||||
private val VERB_DOWN_KEYS = ConcurrentHashMap<String, Array<String>>()
|
||||
private val VERB_UP_KEYS = ConcurrentMap<String, Array<String>>()
|
||||
private val VERB_DOWN_KEYS = ConcurrentMap<String, Array<String>>()
|
||||
|
||||
/**
|
||||
* `relay.purpose.home_feed.sent` / `.bytes` — REQ frames and REQ bytes by the
|
||||
@@ -562,7 +562,7 @@ object UsageKeys {
|
||||
|
||||
private val PURPOSE_SUFFIXES = arrayOf("sent", "bytes", "down", "downn", "dupbytes")
|
||||
|
||||
private val PURPOSE_KEYS = ConcurrentHashMap<String, Array<String>>()
|
||||
private val PURPOSE_KEYS = ConcurrentMap<String, Array<String>>()
|
||||
|
||||
/** The five `relay.purpose.<purpose>.*` keys, indexed by the `P_` constants above. */
|
||||
private fun purposeKeys(purpose: String): Array<String> = PURPOSE_KEYS.getOrPut(purpose) { Array(PURPOSE_SUFFIXES.size) { "relay.purpose.$purpose.${PURPOSE_SUFFIXES[it]}" } }
|
||||
|
||||
+3
-6
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.actions.mediaServers
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@@ -53,7 +52,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.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
@@ -83,6 +81,7 @@ import com.vitorpamplona.amethyst.commons.resources.blossom_import_sources_secti
|
||||
import com.vitorpamplona.amethyst.commons.resources.blossom_import_start_button
|
||||
import com.vitorpamplona.amethyst.commons.resources.blossom_import_title
|
||||
import com.vitorpamplona.amethyst.commons.resources.delete_media_server
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.rememberLongNotice
|
||||
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
|
||||
@@ -123,7 +122,7 @@ fun BlossomImportScreen(
|
||||
// kind-10063 list arrives from a relay just after the screen opens (common on cold start).
|
||||
val targetServers by accountViewModel.account.blossomServers.flow
|
||||
.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
val longNotice = rememberLongNotice()
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
@@ -254,9 +253,7 @@ fun BlossomImportScreen(
|
||||
when (vm.importSelected()) {
|
||||
is ImportStart.Started -> nav.popBack()
|
||||
ImportStart.Busy ->
|
||||
Toast
|
||||
.makeText(context, blossomImportBusyStr, Toast.LENGTH_LONG)
|
||||
.show()
|
||||
longNotice.show(blossomImportBusyStr)
|
||||
ImportStart.Empty -> {}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.call
|
||||
|
||||
import android.app.Activity
|
||||
import android.media.projection.MediaProjectionManager
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.background
|
||||
@@ -71,6 +70,7 @@ import com.vitorpamplona.amethyst.commons.resources.call_incoming
|
||||
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.components.PlatformBackHandler
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.call.session.CallSession
|
||||
@@ -98,7 +98,7 @@ fun CallScreen(
|
||||
val emptyStringFlow = remember { kotlinx.coroutines.flow.MutableStateFlow<String?>(null) }
|
||||
val errorMessage by (callSession?.errorMessage ?: emptyStringFlow).collectAsState()
|
||||
|
||||
BackHandler(enabled = callState !is CallState.Idle && callState !is CallState.Ended) {
|
||||
PlatformBackHandler(enabled = callState !is CallState.Idle && callState !is CallState.Ended) {
|
||||
scope.launch { callManager.hangup() }
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.note.nip22Comments
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -79,6 +78,7 @@ import com.vitorpamplona.amethyst.commons.resources.post_anonymously
|
||||
import com.vitorpamplona.amethyst.commons.resources.what_s_on_your_mind
|
||||
import com.vitorpamplona.amethyst.commons.resources.zapraiser
|
||||
import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDialog
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
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
|
||||
@@ -227,7 +227,7 @@ fun GenericCommentPostScreen(
|
||||
|
||||
StrippingFailureDialog(postViewModel.strippingFailureConfirmation)
|
||||
|
||||
BackHandler {
|
||||
PlatformBackHandler {
|
||||
accountViewModel.launchSigner {
|
||||
postViewModel.sendDraftSync()
|
||||
onUiThread { postViewModel.cancel() }
|
||||
|
||||
+2
-2
@@ -21,7 +21,6 @@
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
@@ -48,6 +47,7 @@ import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.navigation.NavDestination.Companion.hasRoute
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.LocalScreenLayout
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.NavigationStyle
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness
|
||||
@@ -182,7 +182,7 @@ private fun ModalDrawerShell(
|
||||
gesturesEnabled = drawerGesturesEnabled,
|
||||
drawerContent = {
|
||||
DrawerContent(nav, openSheet, accountViewModel)
|
||||
BackHandler(enabled = nav.drawerState.isOpen, nav::closeDrawer)
|
||||
PlatformBackHandler(enabled = nav.drawerState.isOpen, nav::closeDrawer)
|
||||
},
|
||||
content = {
|
||||
if (showRail) {
|
||||
|
||||
+2
-2
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.award
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -56,6 +55,7 @@ import com.vitorpamplona.amethyst.commons.resources.award_badge_remove_recipient
|
||||
import com.vitorpamplona.amethyst.commons.resources.award_badge_search_label
|
||||
import com.vitorpamplona.amethyst.commons.resources.award_badge_search_placeholder
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.Nip05OrPubkeyLine
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
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
|
||||
@@ -93,7 +93,7 @@ fun AwardBadgeScreen(
|
||||
onDispose { userSuggestions.reset() }
|
||||
}
|
||||
|
||||
BackHandler {
|
||||
PlatformBackHandler {
|
||||
nav.popBack()
|
||||
}
|
||||
|
||||
|
||||
+3
-9
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.old
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -44,7 +43,6 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
@@ -58,6 +56,7 @@ 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.components.rememberShortNotice
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold
|
||||
import com.vitorpamplona.amethyst.commons.ui.loadStringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded
|
||||
@@ -114,7 +113,7 @@ private fun RenderOldBookmarkScreen(
|
||||
) {
|
||||
val pagerState = rememberPagerState { 2 }
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
val shortNotice = rememberShortNotice()
|
||||
|
||||
val cache = accountViewModel.account.cache
|
||||
val deletedEventIds = remember(bookmarkState) { mutableSetOf<String>() }
|
||||
@@ -177,12 +176,7 @@ private fun RenderOldBookmarkScreen(
|
||||
accountViewModel.launchSigner {
|
||||
accountViewModel.account.migrateOldBookmarksToNew()
|
||||
coroutineScope.launch {
|
||||
Toast
|
||||
.makeText(
|
||||
context,
|
||||
loadStringRes(Res.string.migrate_bookmarks_success),
|
||||
Toast.LENGTH_SHORT,
|
||||
).show()
|
||||
shortNotice.show(loadStringRes(Res.string.migrate_bookmarks_success))
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+3
-3
@@ -24,7 +24,6 @@ import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.annotation.RequiresApi
|
||||
@@ -74,6 +73,7 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
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.components.PlatformBackHandler
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
@@ -299,9 +299,9 @@ private fun EmbeddedWebAppTab(
|
||||
}
|
||||
|
||||
val isFullscreen by controller.isFullscreen
|
||||
BackHandler(enabled = canGoBack && !isFullscreen) { controller.back() }
|
||||
PlatformBackHandler(enabled = canGoBack && !isFullscreen) { controller.back() }
|
||||
// A fullscreen video inside the tab: back leaves fullscreen first, as in Chrome.
|
||||
BackHandler(enabled = isFullscreen) { controller.exitFullscreen() }
|
||||
PlatformBackHandler(enabled = isFullscreen) { controller.exitFullscreen() }
|
||||
|
||||
EmbeddedPageUi(controller, chrome.ui, showPageInfo, onPageInfoDismiss = { showPageInfo = false })
|
||||
|
||||
|
||||
+2
-2
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@@ -63,6 +62,7 @@ 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.PlatformBackHandler
|
||||
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
|
||||
@@ -222,7 +222,7 @@ private fun CanvasEditor(
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
// Back cancels the edit and returns to the rendered canvas rather than leaving the screen.
|
||||
BackHandler(enabled = !saving, onBack = onClose)
|
||||
PlatformBackHandler(enabled = !saving, onBack = onClose)
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
|
||||
+2
-5
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.buzz
|
||||
|
||||
import com.vitorpamplona.amethyst.Amethyst
|
||||
import com.vitorpamplona.amethyst.commons.model.cache.LocalCache
|
||||
import com.vitorpamplona.amethyst.service.resourceusage.UsageKeys
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
|
||||
|
||||
@@ -45,9 +45,6 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
|
||||
* subscription — so `relay.trigger.buzz` undercounts joins, not re-challenges.
|
||||
*/
|
||||
internal fun reconnectPoolAfterJoin(client: INostrClient) {
|
||||
// Guarded like every other ledger write that reaches the application singleton
|
||||
// (MediaPlayTimeTracker, the workers): a diagnostics counter must never break a
|
||||
// user-visible join, and `Amethyst.instance` is lateinit.
|
||||
runCatching { Amethyst.instance.resourceUsage.add(UsageKeys.relayTrigger(UsageKeys.TRIGGER_BUZZ), 1) }
|
||||
LocalCache.appHost.usageCounter.add(UsageKeys.relayTrigger(UsageKeys.TRIGGER_BUZZ), 1)
|
||||
client.reconnect(onlyIfChanged = false, ignoreRetryDelays = true)
|
||||
}
|
||||
|
||||
+2
-2
@@ -21,7 +21,6 @@
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -88,6 +87,7 @@ import com.vitorpamplona.amethyst.commons.richtext.EncryptedMediaUrlVideo
|
||||
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.PlatformBackHandler
|
||||
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
|
||||
@@ -181,7 +181,7 @@ fun NewGroupDMScreen(
|
||||
|
||||
WatchAndLoadMyEmojiList(accountViewModel)
|
||||
|
||||
BackHandler {
|
||||
PlatformBackHandler {
|
||||
accountViewModel.launchSigner {
|
||||
postViewModel.sendDraftSync()
|
||||
onUiThread { postViewModel.cancel() }
|
||||
|
||||
+2
-2
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -63,6 +62,7 @@ import com.vitorpamplona.amethyst.commons.resources.retry_without_encryption
|
||||
import com.vitorpamplona.amethyst.commons.resources.this_message_will_disappear_in
|
||||
import com.vitorpamplona.amethyst.commons.resources.upload_without_encryption_warning
|
||||
import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDialog
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
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
|
||||
@@ -118,7 +118,7 @@ fun PrivateMessageEditFieldRow(
|
||||
onSendNewMessage: () -> Unit,
|
||||
nav: INav,
|
||||
) {
|
||||
BackHandler {
|
||||
PlatformBackHandler {
|
||||
if (channelScreenModel.message.text.isNotBlank()) {
|
||||
accountViewModel.launchSigner {
|
||||
channelScreenModel.sendDraftSync()
|
||||
|
||||
+2
-2
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.send
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@@ -54,6 +53,7 @@ import com.vitorpamplona.amethyst.commons.resources.buzz_editing_banner
|
||||
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.components.PlatformBackHandler
|
||||
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
|
||||
@@ -82,7 +82,7 @@ fun EditFieldRow(
|
||||
onSendNewMessage: suspend () -> Unit,
|
||||
nav: INav,
|
||||
) {
|
||||
BackHandler {
|
||||
PlatformBackHandler {
|
||||
accountViewModel.launchSigner {
|
||||
channelScreenModel.sendDraftSync()
|
||||
onUiThread { channelScreenModel.cancel() }
|
||||
|
||||
+2
-2
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip23LongForm
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
@@ -103,6 +102,7 @@ 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.components.PlatformBackHandler
|
||||
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
|
||||
@@ -169,7 +169,7 @@ fun LongFormPostScreen(
|
||||
|
||||
StrippingFailureDialog(postViewModel.strippingFailureConfirmation)
|
||||
|
||||
BackHandler {
|
||||
PlatformBackHandler {
|
||||
accountViewModel.launchSigner {
|
||||
postViewModel.sendDraftSync()
|
||||
onUiThread { postViewModel.cancel() }
|
||||
|
||||
+2
-2
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip99Classifieds
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -53,6 +52,7 @@ import com.vitorpamplona.amethyst.commons.resources.lightning_invoice
|
||||
import com.vitorpamplona.amethyst.commons.resources.new_product
|
||||
import com.vitorpamplona.amethyst.commons.resources.zapraiser
|
||||
import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDialog
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
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
|
||||
@@ -148,7 +148,7 @@ fun NewProductScreen(
|
||||
|
||||
StrippingFailureDialog(postViewModel.strippingFailureConfirmation)
|
||||
|
||||
BackHandler {
|
||||
PlatformBackHandler {
|
||||
accountViewModel.launchSigner {
|
||||
postViewModel.sendDraftSync()
|
||||
onUiThread { postViewModel.cancel() }
|
||||
|
||||
+3
-3
@@ -29,7 +29,6 @@ import android.graphics.BitmapFactory
|
||||
import android.os.Build
|
||||
import android.os.SystemClock
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.Canvas
|
||||
@@ -90,6 +89,7 @@ import com.vitorpamplona.amethyst.commons.browser.ui.pill.BrowserPillEvent
|
||||
import com.vitorpamplona.amethyst.commons.browser.ui.pill.ConsoleLine
|
||||
import com.vitorpamplona.amethyst.commons.browser.ui.pill.ConsoleSheet
|
||||
import com.vitorpamplona.amethyst.commons.browser.ui.pill.FindInPagePill
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
import com.vitorpamplona.amethyst.napplethost.BrowserWebTools
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
@@ -306,7 +306,7 @@ fun EmbeddedTabLayer(barFavoriteIds: List<String>) {
|
||||
}
|
||||
|
||||
if (pillExpanded) {
|
||||
BackHandler { pillExpanded = false }
|
||||
PlatformBackHandler { pillExpanded = false }
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
@@ -361,7 +361,7 @@ fun EmbeddedTabLayer(barFavoriteIds: List<String>) {
|
||||
|
||||
// Find in page: opened from the pill's Find tile.
|
||||
if (findShowing && findBridge != null) {
|
||||
BackHandler { closeFind() }
|
||||
PlatformBackHandler { closeFind() }
|
||||
val result by findBridge.findResult
|
||||
FindInPagePill(
|
||||
query = findQuery,
|
||||
|
||||
+2
-2
@@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.favorites
|
||||
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@@ -73,6 +72,7 @@ import com.vitorpamplona.amethyst.commons.resources.favorite_apps
|
||||
import com.vitorpamplona.amethyst.commons.resources.favorite_notice_paid
|
||||
import com.vitorpamplona.amethyst.commons.resources.favorite_notice_published
|
||||
import com.vitorpamplona.amethyst.commons.resources.favorite_notice_uploaded
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
import com.vitorpamplona.amethyst.commons.ui.loadStringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar
|
||||
@@ -262,7 +262,7 @@ private fun EmbeddedNostrAppTab(
|
||||
onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
|
||||
}
|
||||
|
||||
BackHandler(enabled = canGoBack) { controller.back() }
|
||||
PlatformBackHandler(enabled = canGoBack) { controller.back() }
|
||||
|
||||
if (showAccess) {
|
||||
Dialog(onDismissRequest = { showAccess = false }, properties = DialogProperties(usePlatformDefaultWidth = false)) {
|
||||
|
||||
+3
-3
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.code
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
@@ -73,6 +72,7 @@ import com.vitorpamplona.amethyst.commons.resources.git_repo_no_clone_url
|
||||
import com.vitorpamplona.amethyst.commons.resources.git_repo_no_search_results
|
||||
import com.vitorpamplona.amethyst.commons.resources.git_repo_root
|
||||
import com.vitorpamplona.amethyst.commons.resources.git_repo_search_files
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.LocalDisappearingBarState
|
||||
import com.vitorpamplona.amethyst.commons.ui.layouts.LocalDisappearingScaffoldPadding
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
@@ -141,7 +141,7 @@ private fun CodeBrowser(
|
||||
|
||||
if (openPath != null) {
|
||||
val entry = remember(openFilePath) { snapshot.entryAt(openPath) }
|
||||
BackHandler { openFilePath = null }
|
||||
PlatformBackHandler { openFilePath = null }
|
||||
Column(Modifier.fillMaxSize().padding(scaffoldPaddingTop)) {
|
||||
FileHeader(name = openPath.lastOrNull() ?: "", onBack = { openFilePath = null })
|
||||
HorizontalDivider(thickness = 0.5.dp)
|
||||
@@ -164,7 +164,7 @@ private fun CodeBrowser(
|
||||
var query by rememberSaveable(snapshot.headCommit) { mutableStateOf("") }
|
||||
val searching = query.isNotBlank()
|
||||
|
||||
BackHandler(enabled = searching || path.isNotEmpty()) {
|
||||
PlatformBackHandler(enabled = searching || path.isNotEmpty()) {
|
||||
if (searching) query = "" else pathString = path.dropLast(1).joinToString("/")
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -21,7 +21,6 @@
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.code
|
||||
|
||||
import android.text.format.DateUtils
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@@ -66,6 +65,7 @@ import com.vitorpamplona.amethyst.commons.resources.git_repo_code_loading
|
||||
import com.vitorpamplona.amethyst.commons.resources.git_repo_commits
|
||||
import com.vitorpamplona.amethyst.commons.resources.git_repo_file_load_error
|
||||
import com.vitorpamplona.amethyst.commons.resources.git_repo_no_commits
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.GitDiffView
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
@@ -103,7 +103,7 @@ fun GitCommitLog(
|
||||
|
||||
if (openCommit != null) {
|
||||
val commit = remember(openCommit, commits) { commits?.firstOrNull { it.oid == openCommit } }
|
||||
BackHandler { openCommit = null }
|
||||
PlatformBackHandler { openCommit = null }
|
||||
Column(Modifier.fillMaxSize()) {
|
||||
LogHeader(title = commit?.shortOid ?: "", onBack = { openCommit = null })
|
||||
HorizontalDivider(thickness = 0.5.dp)
|
||||
@@ -116,7 +116,7 @@ fun GitCommitLog(
|
||||
return
|
||||
}
|
||||
|
||||
BackHandler { onBack() }
|
||||
PlatformBackHandler { onBack() }
|
||||
Column(Modifier.fillMaxSize()) {
|
||||
LogHeader(title = stringRes(Res.string.git_repo_commits), onBack = onBack)
|
||||
HorizontalDivider(thickness = 0.5.dp)
|
||||
|
||||
+2
-2
@@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.home
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.clickable
|
||||
@@ -110,6 +109,7 @@ import com.vitorpamplona.amethyst.commons.resources.schedule_post_always_on_prom
|
||||
import com.vitorpamplona.amethyst.commons.resources.what_s_on_your_mind
|
||||
import com.vitorpamplona.amethyst.commons.resources.zapraiser
|
||||
import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDialog
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
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
|
||||
@@ -275,7 +275,7 @@ internal fun NewPostScreenInner(
|
||||
|
||||
StrippingFailureDialog(postViewModel.strippingFailureConfirmation)
|
||||
|
||||
BackHandler {
|
||||
PlatformBackHandler {
|
||||
accountViewModel.launchSigner {
|
||||
postViewModel.sendDraftSync()
|
||||
onUiThread { postViewModel.cancel() }
|
||||
|
||||
+2
-2
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.home
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
@@ -40,6 +39,7 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
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
|
||||
@@ -71,7 +71,7 @@ fun VoiceReplyScreen(
|
||||
viewModel.load(replyToNoteId, recordingFilePath, mimeType, duration, amplitudesJson)
|
||||
}
|
||||
|
||||
BackHandler {
|
||||
PlatformBackHandler {
|
||||
viewModel.cancel()
|
||||
nav.popBack()
|
||||
}
|
||||
|
||||
+2
-2
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.home.nip75Goals
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -59,6 +58,7 @@ import com.vitorpamplona.amethyst.commons.resources.goal_summary_placeholder
|
||||
import com.vitorpamplona.amethyst.commons.resources.goal_website_label
|
||||
import com.vitorpamplona.amethyst.commons.resources.goal_website_placeholder
|
||||
import com.vitorpamplona.amethyst.commons.resources.new_goal
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
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
|
||||
@@ -93,7 +93,7 @@ fun NewGoalScreen(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
BackHandler {
|
||||
PlatformBackHandler {
|
||||
goalViewModel.cancel()
|
||||
nav.popBack()
|
||||
}
|
||||
|
||||
+2
-2
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.nests.room.activity
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.activity.compose.LocalActivity
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -52,6 +51,7 @@ 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.components.PlatformBackHandler
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
@@ -362,7 +362,7 @@ private fun NestActivityBody(
|
||||
// Failed) or PIP isn't supported, we let back fall through to the
|
||||
// default Activity.finish() so the user can cancel out cleanly.
|
||||
val canMinimize = isPipSupported && !isInPipMode && ui.connection is ConnectionUiState.Connected
|
||||
BackHandler(enabled = canMinimize) { onMinimize() }
|
||||
PlatformBackHandler(enabled = canMinimize) { onMinimize() }
|
||||
|
||||
if (isInPipMode) {
|
||||
NestPipScreen(
|
||||
|
||||
+2
-2
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.publicMessages
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -61,6 +60,7 @@ import com.vitorpamplona.amethyst.commons.resources.messages_new_message_to_capt
|
||||
import com.vitorpamplona.amethyst.commons.resources.public_message
|
||||
import com.vitorpamplona.amethyst.commons.resources.zapraiser
|
||||
import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDialog
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
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
|
||||
@@ -142,7 +142,7 @@ fun NewPublicMessageScreen(
|
||||
|
||||
StrippingFailureDialog(postViewModel.strippingFailureConfirmation)
|
||||
|
||||
BackHandler {
|
||||
PlatformBackHandler {
|
||||
accountViewModel.launchSigner {
|
||||
postViewModel.sendDraftSync()
|
||||
onUiThread { postViewModel.cancel() }
|
||||
|
||||
+6
-5
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -46,7 +45,6 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
@@ -62,6 +60,8 @@ import com.vitorpamplona.amethyst.commons.resources.reset_marmot_confirm_title
|
||||
import com.vitorpamplona.amethyst.commons.resources.reset_marmot_failure
|
||||
import com.vitorpamplona.amethyst.commons.resources.reset_marmot_success
|
||||
import com.vitorpamplona.amethyst.commons.resources.settings_search_no_results
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.rememberLongNotice
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.rememberShortNotice
|
||||
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
|
||||
@@ -98,7 +98,8 @@ fun AllSettingsScreen(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val shortNotice = rememberShortNotice()
|
||||
val longNotice = rememberLongNotice()
|
||||
val uriHandler = LocalUriHandler.current
|
||||
val scope = rememberCoroutineScope()
|
||||
var showResetMarmotDialog by remember { mutableStateOf(false) }
|
||||
@@ -186,13 +187,13 @@ fun AllSettingsScreen(
|
||||
try {
|
||||
accountViewModel.resetMarmotState()
|
||||
launch(Dispatchers.Main) {
|
||||
Toast.makeText(context, successMessage, Toast.LENGTH_SHORT).show()
|
||||
shortNotice.show(successMessage)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
val failureMessage =
|
||||
loadStringRes(Res.string.reset_marmot_failure, e.message ?: "")
|
||||
launch(Dispatchers.Main) {
|
||||
Toast.makeText(context, failureMessage, Toast.LENGTH_LONG).show()
|
||||
longNotice.show(failureMessage)
|
||||
}
|
||||
} finally {
|
||||
isResettingMarmot = false
|
||||
|
||||
+2
-2
@@ -80,9 +80,9 @@ 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.commons.util.formatGrouped
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import java.text.NumberFormat
|
||||
|
||||
/**
|
||||
* "Bitcoin" card on the wallet screen, shown above the lightning NWC wallet
|
||||
@@ -277,7 +277,7 @@ private fun BalanceBlock(
|
||||
OnchainBalanceStatus.READY -> {
|
||||
val formatted =
|
||||
remember(sats) {
|
||||
NumberFormat.getIntegerInstance().format(sats ?: 0L)
|
||||
formatGrouped(sats ?: 0L)
|
||||
}
|
||||
Text(
|
||||
text = formatted,
|
||||
|
||||
+7
-8
@@ -51,7 +51,6 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.platform.UriHandler
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
@@ -81,13 +80,14 @@ 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.formatMonthDayTime
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.rememberTimeOfDayFormatter
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.TransactionFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.bitcoinColor
|
||||
import com.vitorpamplona.amethyst.commons.util.formatGrouped
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.note.formatMonthDayTime
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet.datasource.OnchainZapsFilterAssemblerSubscription
|
||||
import java.text.NumberFormat
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@@ -309,15 +309,14 @@ private fun OnchainTransactionItem(
|
||||
val amountSats = view.tx.netValueSats.absoluteValue
|
||||
val formattedAmount =
|
||||
remember(view.tx.netValueSats) {
|
||||
val fmt = NumberFormat.getIntegerInstance()
|
||||
(if (isIncoming) "+" else "-") + fmt.format(amountSats)
|
||||
(if (isIncoming) "+" else "-") + formatGrouped(amountSats)
|
||||
}
|
||||
|
||||
val context = LocalContext.current
|
||||
val timeOfDay = rememberTimeOfDayFormatter()
|
||||
val dateText =
|
||||
remember(view.tx.blockTime, view.tx.confirmations, context) {
|
||||
remember(view.tx.blockTime, view.tx.confirmations, timeOfDay) {
|
||||
val ts = view.tx.blockTime
|
||||
if (ts != null) formatMonthDayTime(ts, context) else ""
|
||||
if (ts != null) formatMonthDayTime(ts, timeOfDay) else ""
|
||||
}
|
||||
|
||||
val counterpartyPubkeyHex = view.counterpartyPubkeyHex()
|
||||
|
||||
+2
-3
@@ -65,8 +65,8 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_transactions
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.WalletViewModel
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.util.formatGrouped
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import java.text.NumberFormat
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@@ -122,8 +122,7 @@ fun WalletDetailScreen(
|
||||
} else {
|
||||
val formattedBalance =
|
||||
remember(balance) {
|
||||
val fmt = NumberFormat.getIntegerInstance()
|
||||
fmt.format(balance ?: 0L)
|
||||
formatGrouped(balance ?: 0L)
|
||||
}
|
||||
Text(
|
||||
text = formattedBalance,
|
||||
|
||||
+9
-10
@@ -20,9 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -52,10 +49,11 @@ import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalClipboard
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
@@ -73,13 +71,15 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_creating_invoice
|
||||
import com.vitorpamplona.amethyst.commons.resources.wallet_description
|
||||
import com.vitorpamplona.amethyst.commons.resources.wallet_receive
|
||||
import com.vitorpamplona.amethyst.commons.resources.wallet_sats
|
||||
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.qrcode.QrCodeDrawer
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.ReceiveState
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.WalletViewModel
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.util.formatGrouped
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import java.text.NumberFormat
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@@ -102,7 +102,8 @@ fun WalletReceiveScreen(
|
||||
val receiveState by walletViewModel.receiveState.collectAsState()
|
||||
var amountText by remember { mutableStateOf("") }
|
||||
var descriptionText by remember { mutableStateOf("") }
|
||||
val context = LocalContext.current
|
||||
val clipboard = LocalClipboard.current
|
||||
val clipboardScope = rememberCoroutineScope()
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
@@ -194,8 +195,7 @@ fun WalletReceiveScreen(
|
||||
|
||||
val formattedAmount =
|
||||
remember(state.amount) {
|
||||
val fmt = NumberFormat.getIntegerInstance()
|
||||
fmt.format(state.amount)
|
||||
formatGrouped(state.amount)
|
||||
}
|
||||
|
||||
Text(
|
||||
@@ -233,8 +233,7 @@ fun WalletReceiveScreen(
|
||||
) {
|
||||
OutlinedButton(
|
||||
onClick = {
|
||||
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText("invoice", state.invoice))
|
||||
clipboardScope.launch { clipboard.setText(state.invoice) }
|
||||
},
|
||||
modifier =
|
||||
Modifier
|
||||
|
||||
+6
-8
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
@@ -67,7 +66,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.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -103,6 +101,7 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_rename_title
|
||||
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.components.rememberLongNotice
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.platform.AppBottomBar
|
||||
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
|
||||
@@ -110,10 +109,10 @@ import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.CashuWalletV
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.WalletInfo
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.WalletViewModel
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.util.formatGrouped
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.quartz.experimental.clink.debits.DebitFrequency
|
||||
import kotlinx.coroutines.launch
|
||||
import java.text.NumberFormat
|
||||
import androidx.compose.material3.Icon as Material3Icon
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@@ -248,7 +247,7 @@ private fun MultiWalletHomeContent(
|
||||
cashuMintCount: Int,
|
||||
) {
|
||||
val walletInfoList by walletViewModel.walletInfoList.collectAsState()
|
||||
val context = LocalContext.current
|
||||
val longNotice = rememberLongNotice()
|
||||
val budgetApprovedMsg = stringRes(Res.string.clink_budget_approved)
|
||||
val debitNoResponseMsg = stringRes(Res.string.clink_debit_no_response)
|
||||
|
||||
@@ -298,7 +297,7 @@ private fun MultiWalletHomeContent(
|
||||
!error.isNullOrBlank() -> error
|
||||
else -> debitNoResponseMsg
|
||||
}
|
||||
Toast.makeText(context, msg, Toast.LENGTH_LONG).show()
|
||||
longNotice.show(msg)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -460,8 +459,7 @@ private fun WalletCard(
|
||||
Column(horizontalAlignment = Alignment.End) {
|
||||
val formattedBalance =
|
||||
remember(walletInfo.balanceSats) {
|
||||
val fmt = NumberFormat.getIntegerInstance()
|
||||
fmt.format(walletInfo.balanceSats ?: 0L)
|
||||
formatGrouped(walletInfo.balanceSats ?: 0L)
|
||||
}
|
||||
Text(
|
||||
text = formattedBalance,
|
||||
@@ -574,7 +572,7 @@ private fun CashuWalletRow(
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
val formattedBalance =
|
||||
remember(balanceSats) { NumberFormat.getIntegerInstance().format(balanceSats) }
|
||||
remember(balanceSats) { formatGrouped(balanceSats) }
|
||||
Card(
|
||||
modifier =
|
||||
Modifier
|
||||
|
||||
+7
-9
@@ -20,8 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.wallet
|
||||
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -47,10 +45,11 @@ import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalClipboard
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
@@ -63,11 +62,13 @@ import com.vitorpamplona.amethyst.commons.resources.wallet_pay
|
||||
import com.vitorpamplona.amethyst.commons.resources.wallet_payment_sending
|
||||
import com.vitorpamplona.amethyst.commons.resources.wallet_payment_success
|
||||
import com.vitorpamplona.amethyst.commons.resources.wallet_send
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.util.getText
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.SendState
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.WalletViewModel
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@@ -89,7 +90,8 @@ fun WalletSendScreen(
|
||||
|
||||
val sendState by walletViewModel.sendState.collectAsState()
|
||||
var invoiceText by remember { mutableStateOf("") }
|
||||
val context = LocalContext.current
|
||||
val clipboard = LocalClipboard.current
|
||||
val clipboardScope = rememberCoroutineScope()
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
@@ -128,11 +130,7 @@ fun WalletSendScreen(
|
||||
maxLines = 5,
|
||||
trailingIcon = {
|
||||
IconButton(onClick = {
|
||||
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = clipboard.primaryClip
|
||||
if (clip != null && clip.itemCount > 0) {
|
||||
invoiceText = clip.getItemAt(0).text?.toString() ?: ""
|
||||
}
|
||||
clipboardScope.launch { invoiceText = clipboard.getText() ?: "" }
|
||||
}) {
|
||||
Icon(
|
||||
symbol = MaterialSymbols.ContentPaste,
|
||||
|
||||
+7
-8
@@ -51,7 +51,6 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
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
|
||||
@@ -78,14 +77,15 @@ 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.formatMonthDayTime
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.rememberTimeOfDayFormatter
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.TransactionFilter
|
||||
import com.vitorpamplona.amethyst.commons.ui.screen.loggedIn.wallet.WalletViewModel
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.util.formatGrouped
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.note.formatMonthDayTime
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.rpc.NwcTransaction
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.rpc.NwcTransactionType
|
||||
import java.text.NumberFormat
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@@ -278,14 +278,13 @@ private fun TransactionItem(
|
||||
val amountSats = (tx.amount ?: 0L) / 1000L
|
||||
val formattedAmount =
|
||||
remember(amountSats) {
|
||||
val fmt = NumberFormat.getIntegerInstance()
|
||||
(if (isIncoming) "+" else "-") + fmt.format(amountSats)
|
||||
(if (isIncoming) "+" else "-") + formatGrouped(amountSats)
|
||||
}
|
||||
|
||||
val context = LocalContext.current
|
||||
val timeOfDay = rememberTimeOfDayFormatter()
|
||||
val dateText =
|
||||
remember(tx.created_at, context) {
|
||||
tx.created_at?.let { formatMonthDayTime(it, context) } ?: ""
|
||||
remember(tx.created_at, timeOfDay) {
|
||||
tx.created_at?.let { formatMonthDayTime(it, timeOfDay) } ?: ""
|
||||
}
|
||||
|
||||
val directionLabel =
|
||||
|
||||
+2
-2
@@ -101,8 +101,8 @@ 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.commons.util.formatGrouped
|
||||
import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
|
||||
import java.text.NumberFormat
|
||||
|
||||
/**
|
||||
* Find-or-create wizard for the Cashu wallet. Reached from the wallet screen's
|
||||
@@ -227,7 +227,7 @@ fun CashuWalletWizardScreen(
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatSats(sats: Long): String = NumberFormat.getInstance().format(sats)
|
||||
private fun formatSats(sats: Long): String = formatGrouped(sats)
|
||||
|
||||
/**
|
||||
* Animate a sats figure counting up from zero the first time it's shown, then
|
||||
|
||||
+2
-2
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -70,6 +69,7 @@ import com.vitorpamplona.amethyst.commons.resources.workout_minutes
|
||||
import com.vitorpamplona.amethyst.commons.resources.workout_notes
|
||||
import com.vitorpamplona.amethyst.commons.resources.workout_seconds
|
||||
import com.vitorpamplona.amethyst.commons.resources.workout_title
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.PlatformBackHandler
|
||||
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
|
||||
@@ -91,7 +91,7 @@ fun NewWorkoutScreen(
|
||||
postViewModel.init(accountViewModel)
|
||||
postViewModel.prefill(prefill)
|
||||
|
||||
BackHandler {
|
||||
PlatformBackHandler {
|
||||
postViewModel.cancel()
|
||||
nav.popBack()
|
||||
}
|
||||
|
||||
Vendored
+4
@@ -22,6 +22,7 @@ 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.amethyst.commons.service.UsageCounter
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStats
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
@@ -81,6 +82,9 @@ interface LocalCacheHost {
|
||||
*/
|
||||
fun relaySelfPubKey(relay: NormalizedRelayUrl): HexKey? = null
|
||||
|
||||
/** The resource-usage ledger's counters; counts nothing by default. */
|
||||
val usageCounter: UsageCounter get() = UsageCounter.None
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
+34
@@ -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
|
||||
|
||||
/** Adds to a diagnostics counter in the app's resource-usage ledger. Never throws. */
|
||||
fun interface UsageCounter {
|
||||
fun add(
|
||||
key: String,
|
||||
amount: Long,
|
||||
)
|
||||
|
||||
companion object {
|
||||
/** Counts nothing: hosts without a ledger. */
|
||||
val None = UsageCounter { _, _ -> }
|
||||
}
|
||||
}
|
||||
@@ -212,6 +212,8 @@ kotlin {
|
||||
implementation(libs.androidx.ui.tooling.preview)
|
||||
// WindowInsetsControllerCompat, for DisappearingScaffold's immersive status bar.
|
||||
implementation(libs.androidx.core.ktx)
|
||||
// BackHandler, behind the shared PlatformBackHandler. Apache-2.0, already in the app.
|
||||
implementation(libs.androidx.activity.compose)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,6 +231,11 @@ kotlin {
|
||||
val skikoMain =
|
||||
create("skikoMain") {
|
||||
dependsOn(commonMain.get())
|
||||
dependencies {
|
||||
// BackHandler for desktop (Esc) and iOS (swipe), behind PlatformBackHandler.
|
||||
// JetBrains Compose, Apache-2.0; Android uses AndroidX's instead.
|
||||
implementation(libs.jetbrains.compose.ui.backhandler)
|
||||
}
|
||||
}
|
||||
getByName("jvmMain").dependsOn(skikoMain)
|
||||
iosMain.dependsOn(skikoMain)
|
||||
|
||||
+30
@@ -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.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
@Composable
|
||||
actual fun PlatformBackHandler(
|
||||
enabled: Boolean,
|
||||
onBack: () -> Unit,
|
||||
) = BackHandler(enabled, onBack)
|
||||
+6
@@ -30,3 +30,9 @@ actual fun rememberShortNotice(): ShortNotice {
|
||||
val context = LocalContext.current
|
||||
return remember(context) { ShortNotice { message -> Toast.makeText(context, message, Toast.LENGTH_SHORT).show() } }
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun rememberLongNotice(): ShortNotice {
|
||||
val context = LocalContext.current
|
||||
return remember(context) { ShortNotice { message -> Toast.makeText(context, message, Toast.LENGTH_LONG).show() } }
|
||||
}
|
||||
|
||||
+33
@@ -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.ui.components
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
/**
|
||||
* Intercepts the system back gesture/button while [enabled]: AndroidX's `BackHandler` on
|
||||
* Android, Compose Multiplatform's on desktop (Esc) and iOS (swipe back).
|
||||
*/
|
||||
@Composable
|
||||
expect fun PlatformBackHandler(
|
||||
enabled: Boolean = true,
|
||||
onBack: () -> Unit,
|
||||
)
|
||||
+4
@@ -33,3 +33,7 @@ fun interface ShortNotice {
|
||||
*/
|
||||
@Composable
|
||||
expect fun rememberShortNotice(): ShortNotice
|
||||
|
||||
/** Like [rememberShortNotice], shown longer: for errors the reader needs time to take in. */
|
||||
@Composable
|
||||
expect fun rememberLongNotice(): ShortNotice
|
||||
|
||||
+35
@@ -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
|
||||
|
||||
private val monthDay = DateSkeletonFormatter("MMMd")
|
||||
|
||||
/**
|
||||
* Locale-ordered month and day followed by [timeOfDay] ("May 28 14:32" / "28 May 2:32 PM"). Pass
|
||||
* [rememberTimeOfDayFormatter] so the clock follows the system 12/24-hour setting.
|
||||
*/
|
||||
fun formatMonthDayTime(
|
||||
epochSeconds: Long,
|
||||
timeOfDay: (epochMillis: Long) -> String,
|
||||
): String {
|
||||
val millis = epochSeconds * 1000L
|
||||
return "${monthDay.format(millis)} ${timeOfDay(millis)}"
|
||||
}
|
||||
+3
@@ -27,3 +27,6 @@ private val loggedNotice = ShortNotice { message -> Log.d("ShortNotice") { messa
|
||||
|
||||
@Composable
|
||||
actual fun rememberShortNotice(): ShortNotice = loggedNotice
|
||||
|
||||
@Composable
|
||||
actual fun rememberLongNotice(): ShortNotice = loggedNotice
|
||||
|
||||
+3
@@ -27,3 +27,6 @@ private val loggedNotice = ShortNotice { message -> Log.d("ShortNotice") { messa
|
||||
|
||||
@Composable
|
||||
actual fun rememberShortNotice(): ShortNotice = loggedNotice
|
||||
|
||||
@Composable
|
||||
actual fun rememberLongNotice(): ShortNotice = loggedNotice
|
||||
|
||||
+32
@@ -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 androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.backhandler.BackHandler
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
actual fun PlatformBackHandler(
|
||||
enabled: Boolean,
|
||||
onBack: () -> Unit,
|
||||
) = BackHandler(enabled, onBack)
|
||||
@@ -197,6 +197,7 @@ jetbrains-compose-runtime = { module = "org.jetbrains.compose.runtime:runtime",
|
||||
jetbrains-compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "jetbrainsCompose" }
|
||||
jetbrains-compose-ui-tooling = { module = "org.jetbrains.compose.ui:ui-tooling", version.ref = "jetbrainsCompose" }
|
||||
jetbrains-compose-ui-tooling-preview = { module = "org.jetbrains.compose.ui:ui-tooling-preview", version.ref = "jetbrainsCompose" }
|
||||
jetbrains-compose-ui-backhandler = { module = "org.jetbrains.compose.ui:ui-backhandler", version.ref = "jetbrainsCompose" }
|
||||
jetbrains-compose-ui-test-junit4 = { module = "org.jetbrains.compose.ui:ui-test-junit4", version.ref = "jetbrainsCompose" }
|
||||
google-mlkit-genai-proofreading = { group = "com.google.mlkit", name = "genai-proofreading", version.ref = "genaiProofreading" }
|
||||
google-mlkit-genai-prompt = { group = "com.google.mlkit", name = "genai-prompt", version.ref = "genaiPrompt" }
|
||||
|
||||
Reference in New Issue
Block a user