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/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/components/LoadUrlPreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt index 5087df059e..0a7a5dde29 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 @@ -36,6 +36,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.HalfVertPadding 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( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/PrefetchFeedMedia.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/PrefetchFeedMedia.kt index c13a8124a8..9c15403b81 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/PrefetchFeedMedia.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/PrefetchFeedMedia.kt @@ -46,6 +46,7 @@ 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.ui.screen.loggedIn.urlPreview import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip14Subject.subject 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..4a2f2a5d99 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 @@ -54,6 +54,7 @@ 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( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index e2e1556819..1b221b13e0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -25,12 +25,12 @@ import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable import androidx.compose.runtime.rememberCoroutineScope import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.commons.audio.VisualizerStyle import com.vitorpamplona.amethyst.commons.cashu.ops.describeMintError import com.vitorpamplona.amethyst.commons.feeds.CardFeedState import com.vitorpamplona.amethyst.commons.feeds.FeedState +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 @@ -88,13 +88,12 @@ 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.service.OnlineChecker import com.vitorpamplona.amethyst.commons.service.broadcast.BroadcastTracker import com.vitorpamplona.amethyst.commons.service.http.IRoleBasedHttpClientBuilder 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.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.state.GenericBaseCache @@ -104,16 +103,12 @@ 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.commons.viewmodels.AccountViewModelHost -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.lnurl.LightningAddressResolver -import com.vitorpamplona.amethyst.service.pow.powKindLabelRes import com.vitorpamplona.amethyst.service.relayClient.reqCommand.RelaySubscriptionsCoordinator -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.send.MarmotGroupIconChange 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.relays.eventsync.EventSync @@ -143,7 +138,6 @@ import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent import com.vitorpamplona.quartz.nip04Dm.messages.EncryptedDmEvent 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 @@ -2156,15 +2150,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 @@ -2262,11 +2247,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?, @@ -2313,28 +2293,6 @@ class AccountViewModel( } } - class Factory( - val account: Account, - val settings: UiSettingsState, - val torSettings: TorSettingsFlow, - val dataSources: RelaySubscriptionsCoordinator, - val okHttpClient: RoleBasedHttpClientBuilder, - val nip05ClientBuilder: () -> Nip05Client, - val host: AccountViewModelHost, - ) : ViewModelProvider.Factory { - @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class): T = - AccountViewModel( - account, - settings, - torSettings, - dataSources, - okHttpClient, - nip05ClientBuilder, - host, - ) as T - } - init { Log.d("AccountViewModel", "Init") viewModelScope.launch(Dispatchers.IO) { 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 index 23adfeef51..6ecb4c1ca1 100644 --- 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 @@ -27,17 +27,36 @@ 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.OnlineChecker +import com.vitorpamplona.amethyst.commons.ui.components.UrlPreviewState import com.vitorpamplona.amethyst.commons.ui.loadStringRes +import com.vitorpamplona.amethyst.model.UrlCachedPreviewer import com.vitorpamplona.amethyst.ui.actions.MediaSaverToDisk -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.send.MarmotGroupIconUpload import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.marmotGroup.send.MarmotGroupIconUploader +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext -// Account actions that read a content Uri or write to the device's media store, which only the -// Android app can do. They stay out of AccountViewModel so the view model does not need Android. +// 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 = + withContext(Dispatchers.IO) { + OnlineChecker.isOnline(videoUrl, httpClientBuilder::okHttpClientForVideo) + } /** * Encrypt + upload a picked image as a group avatar (canonical `marmot-group-image-v1` scheme). 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 2a86a63861..8a0f420378 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 @@ -69,19 +69,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 }, - host = AndroidAccountViewModelHost(Amethyst.instance), - ), - ) + 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/chats/marmotGroup/CreateGroupScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/CreateGroupScreen.kt index 7d3e052d6b..53a9196dc8 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 @@ -65,7 +66,6 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.CreatingTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes 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.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 ca0762da2a..1803143ba2 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 @@ -63,7 +64,6 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.ActionTopBar import com.vitorpamplona.amethyst.commons.ui.stringRes 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 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..a2ae6227b8 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 @@ -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/send/MarmotGroupIconUploader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/send/MarmotGroupIconUploader.kt index 53cbec4dc8..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,6 +22,7 @@ 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 @@ -31,53 +32,11 @@ 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/home/HomeScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeScreen.kt index d9ca991f9e..d950ef18e7 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 @@ -105,6 +105,7 @@ 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.backups.BackupConflictCards +import com.vitorpamplona.amethyst.ui.screen.loggedIn.checkVideoIsOnline import com.vitorpamplona.amethyst.ui.screen.loggedIn.geohash.NewGeoPostButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.NewHashtagPostButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.HomeFilterAssemblerSubscription 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..883edb4087 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 @@ -34,6 +34,7 @@ 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.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/webBookmarks/WebBookmarksScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/webBookmarks/WebBookmarksScreen.kt index d39857b4df..0e12a6c254 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 @@ -107,6 +107,7 @@ 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 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/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 + }