From 7c94af2fb26535be498e472d26178df3b4d8df9b Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Thu, 9 Mar 2023 20:56:56 +0000 Subject: [PATCH 01/20] Use MasterKey.Builder instead of deprecated MasterKeys --- .../com/vitorpamplona/amethyst/EncryptedStorage.kt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/EncryptedStorage.kt b/app/src/main/java/com/vitorpamplona/amethyst/EncryptedStorage.kt index 9ab8a8684..fcc7d2b2e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/EncryptedStorage.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/EncryptedStorage.kt @@ -2,18 +2,20 @@ package com.vitorpamplona.amethyst import android.content.Context import androidx.security.crypto.EncryptedSharedPreferences -import androidx.security.crypto.MasterKeys +import androidx.security.crypto.MasterKey class EncryptedStorage { + private val preferencesName = "secret_keeper" fun preferences(context: Context): EncryptedSharedPreferences { - val secretKey: String = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC) - val preferencesName = "secret_keeper" + val masterKey: MasterKey = MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS) + .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) + .build() return EncryptedSharedPreferences.create( - preferencesName, - secretKey, context, + preferencesName, + masterKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM ) as EncryptedSharedPreferences From e7f814e2055afc0b65546abf2195756efe3ca953 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Thu, 9 Mar 2023 20:57:53 +0000 Subject: [PATCH 02/20] Change EncryptedStorage from class to object --- .../java/com/vitorpamplona/amethyst/EncryptedStorage.kt | 6 +++--- .../java/com/vitorpamplona/amethyst/LocalPreferences.kt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/EncryptedStorage.kt b/app/src/main/java/com/vitorpamplona/amethyst/EncryptedStorage.kt index fcc7d2b2e..d43669d7c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/EncryptedStorage.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/EncryptedStorage.kt @@ -4,8 +4,8 @@ import android.content.Context import androidx.security.crypto.EncryptedSharedPreferences import androidx.security.crypto.MasterKey -class EncryptedStorage { - private val preferencesName = "secret_keeper" +object EncryptedStorage { + private const val PREFERENCES_NAME = "secret_keeper" fun preferences(context: Context): EncryptedSharedPreferences { val masterKey: MasterKey = MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS) @@ -14,7 +14,7 @@ class EncryptedStorage { return EncryptedSharedPreferences.create( context, - preferencesName, + PREFERENCES_NAME, masterKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index abec38a63..83e0f331a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -29,7 +29,7 @@ class LocalPreferences(context: Context) { val LAST_READ: (String) -> String = { route -> "last_read_route_$route" } } - private val encryptedPreferences = EncryptedStorage().preferences(context) + private val encryptedPreferences = EncryptedStorage.preferences(context) private val gson = GsonBuilder().create() fun clearEncryptedStorage() { From 2704421fb384cef1eca054f779324ec9bc869c82 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 9 Mar 2023 18:55:57 -0500 Subject: [PATCH 03/20] Showing private message notifications in the notification tab --- .../amethyst/ui/note/MessageSetCompose.kt | 121 ++++++++++++++++++ .../amethyst/ui/note/NoteCompose.kt | 32 ++++- .../amethyst/ui/screen/CardFeedState.kt | 8 ++ .../amethyst/ui/screen/CardFeedView.kt | 7 + .../amethyst/ui/screen/CardFeedViewModel.kt | 5 +- app/src/main/res/values/strings.xml | 2 +- 6 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt new file mode 100644 index 000000000..5d7e07ab7 --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt @@ -0,0 +1,121 @@ +package com.vitorpamplona.amethyst.ui.note + +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background +import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.compositeOver +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import com.vitorpamplona.amethyst.NotificationCache +import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent +import com.vitorpamplona.amethyst.ui.screen.MessageSetCard +import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun MessageSetCompose(messageSetCard: MessageSetCard, isInnerNote: Boolean = false, routeForLastRead: String, accountViewModel: AccountViewModel, navController: NavController) { + val noteState by messageSetCard.note.live().metadata.observeAsState() + val note = noteState?.note + + val accountState by accountViewModel.accountLiveData.observeAsState() + val account = accountState?.account ?: return + + val context = LocalContext.current.applicationContext + + val noteEvent = note?.event + var popupExpanded by remember { mutableStateOf(false) } + + if (note == null) { + BlankNote(Modifier, isInnerNote) + } else { + var isNew by remember { mutableStateOf(false) } + + LaunchedEffect(key1 = messageSetCard) { + isNew = messageSetCard.createdAt() > NotificationCache.load(routeForLastRead, context) + + NotificationCache.markAsRead(routeForLastRead, messageSetCard.createdAt(), context) + } + + var backgroundColor = if (isNew) { + MaterialTheme.colors.primary.copy(0.12f).compositeOver(MaterialTheme.colors.background) + } else { + MaterialTheme.colors.background + } + + Column( + modifier = Modifier.background(backgroundColor).combinedClickable( + onClick = { + if (noteEvent !is ChannelMessageEvent) { + navController.navigate("Note/${note.idHex}") { + launchSingleTop = true + } + } else { + note.channel()?.let { + navController.navigate("Channel/${it.idHex}") + } + } + }, + onLongClick = { popupExpanded = true } + ) + ) { + Row( + modifier = Modifier + .padding( + start = if (!isInnerNote) 12.dp else 0.dp, + end = if (!isInnerNote) 12.dp else 0.dp, + top = 10.dp + ) + ) { + // Draws the like picture outside the boosted card. + if (!isInnerNote) { + Box( + modifier = Modifier + .width(55.dp) + .padding(top = 5.dp) + ) { + Icon( + painter = painterResource(R.drawable.ic_dm), + null, + modifier = Modifier.size(16.dp).align(Alignment.TopEnd), + tint = MaterialTheme.colors.primary + ) + } + } + + Column(modifier = Modifier.padding(start = if (!isInnerNote) 10.dp else 0.dp)) { + NoteCompose( + baseNote = note, + routeForLastRead = null, + isBoostedNote = true, + addMarginTop = false, + parentBackgroundColor = backgroundColor, + accountViewModel = accountViewModel, + navController = navController + ) + + NoteDropDownMenu(note, popupExpanded, { popupExpanded = false }, accountViewModel) + } + } + } + } +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index a41b277a2..44a958db5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -39,6 +39,7 @@ import com.google.accompanist.flowlayout.FlowRow import com.vitorpamplona.amethyst.NotificationCache import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.RoboHashCache +import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.model.BadgeAwardEvent @@ -70,6 +71,7 @@ fun NoteCompose( isQuotedNote: Boolean = false, unPackReply: Boolean = true, makeItShort: Boolean = false, + addMarginTop: Boolean = true, parentBackgroundColor: Color? = null, accountViewModel: AccountViewModel, navController: NavController @@ -167,7 +169,7 @@ fun NoteCompose( .padding( start = if (!isBoostedNote) 12.dp else 0.dp, end = if (!isBoostedNote) 12.dp else 0.dp, - top = 10.dp + top = if (addMarginTop) 10.dp else 0.dp ) ) { if (!isBoostedNote && !isQuotedNote) { @@ -403,6 +405,34 @@ fun NoteCompose( ReactionsRow(note, accountViewModel) + Divider( + modifier = Modifier.padding(top = 10.dp), + thickness = 0.25.dp + ) + } else if (noteEvent is PrivateDmEvent && + noteEvent.recipientPubKey() != account.userProfile().pubkeyHex && + note.author != account.userProfile() + ) { + val recepient = noteEvent.recipientPubKey()?.let { LocalCache.checkGetOrCreateUser(it) } + + TranslateableRichTextViewer( + stringResource( + id = R.string.private_conversation_notification, + "@${note.author?.pubkeyNpub()}", + "@${recepient?.pubkeyNpub()}" + ), + canPreview = !makeItShort, + Modifier.fillMaxWidth(), + noteEvent.tags(), + backgroundColor, + accountViewModel, + navController + ) + + if (!makeItShort) { + ReactionsRow(note, accountViewModel) + } + Divider( modifier = Modifier.padding(top = 10.dp), thickness = 0.25.dp diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedState.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedState.kt index 950430cc1..bdacb2639 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedState.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedState.kt @@ -63,6 +63,14 @@ class BoostSetCard(val note: Note, val boostEvents: List) : Card() { override fun id() = note.idHex + "B" + createdAt } +class MessageSetCard(val note: Note) : Card() { + override fun createdAt(): Long { + return note.createdAt() ?: 0 + } + + override fun id() = note.idHex +} + sealed class CardFeedState { object Loading : CardFeedState() class Loaded(val feed: MutableState>) : CardFeedState() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt index 7bd61ec1d..df4fa0ebf 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedView.kt @@ -21,6 +21,7 @@ import com.google.accompanist.swiperefresh.rememberSwipeRefreshState import com.vitorpamplona.amethyst.ui.note.BadgeCompose import com.vitorpamplona.amethyst.ui.note.BoostSetCompose import com.vitorpamplona.amethyst.ui.note.LikeSetCompose +import com.vitorpamplona.amethyst.ui.note.MessageSetCompose import com.vitorpamplona.amethyst.ui.note.MultiSetCompose import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.note.ZapSetCompose @@ -134,6 +135,12 @@ private fun FeedLoaded( navController = navController, routeForLastRead = routeForLastRead ) + is MessageSetCard -> MessageSetCompose( + messageSetCard = item, + routeForLastRead = routeForLastRead, + accountViewModel = accountViewModel, + navController = navController + ) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt index b7f9b1770..3060f307a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/CardFeedViewModel.kt @@ -9,6 +9,7 @@ import com.vitorpamplona.amethyst.service.model.BadgeAwardEvent import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent import com.vitorpamplona.amethyst.service.model.ChannelMetadataEvent import com.vitorpamplona.amethyst.service.model.LnZapEvent +import com.vitorpamplona.amethyst.service.model.PrivateDmEvent import com.vitorpamplona.amethyst.service.model.ReactionEvent import com.vitorpamplona.amethyst.service.model.RepostEvent import com.vitorpamplona.amethyst.ui.dal.FeedFilter @@ -111,7 +112,9 @@ open class CardFeedViewModel(val dataSource: FeedFilter) : ViewModel() { } val textNoteCards = notes.filter { it.event !is ReactionEvent && it.event !is RepostEvent && it.event !is LnZapEvent }.map { - if (it.event is BadgeAwardEvent) { + if (it.event is PrivateDmEvent) { + MessageSetCard(it) + } else if (it.event is BadgeAwardEvent) { BadgeCard(it) } else { NoteCard(it) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f3c2a9d95..f6d729ed9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -219,6 +219,6 @@ https://<server>/<user>/<proof post> https://twitter.com/<user>/status/<proof post> - + "<Unable to decrypt private message>\n\nYou were cited in a private/encrypted conversation between %1$s and %2$s." From 0c8ddc5067917acef1ae0caa4147a5dc06688f44 Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Fri, 10 Mar 2023 06:06:59 -0300 Subject: [PATCH 04/20] add missing portuguese translations --- .../amethyst/ui/note/NoteQuickActionMenu.kt | 4 +- app/src/main/res/values-pt-rBR/strings.xml | 37 +++++++++++++++++++ app/src/main/res/values/strings.xml | 10 ++--- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt index d03997ab6..1b0aaf245 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt @@ -220,12 +220,12 @@ fun NoteQuickActionMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Uni onDismiss() } ) { - Text("Don't show again") + Text(stringResource(R.string.quick_action_dont_show_again_button)) } Button( onClick = { accountViewModel.delete(note); onDismiss() } ) { - Text("Delete") + Text(stringResource(R.string.quick_action_delete_button)) } } } diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 1333bb192..019bdbca8 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -170,4 +170,41 @@ Denunciar discurso de ódio Denunciar nudez / pornografia outros + Marcar todos conhecidos como lidos + Marcar todas novas solicitações como lidas + Marcar todas como lidas + Erro + + ## Backup de chaves e dicas de segurança + \n\nSua conta é protegida por uma chave secreta. A chave é uma string aleatória longa começando com **nsec1**. Qualquer pessoa que tenha acesso à sua chave secreta pode publicar conteúdo usando sua identidade. + \n\n- **Não** coloque sua chave secreta em qualquer site ou software em que não confie. + \n- Os desenvolvedores do Amethyst **nunca** pedirão sua chave secreta. + \n- **Faça** um backup seguro de sua chave secreta para recuperação de conta. Recomendamos o uso de um gerenciador de senhas. + + Chave secreta (nsec) copiada + Copiar minha chave secreta + Autenticação falhou + Criado por %1$s + Imagem da medalha para %1$s + Você recebeu uma nova medalha + Medalha concedida para + Texto copiado + Copiado @npub do autor + Copiado ID da nota (@note1) + Selecionar texto + Selecionar + Compartilhar link do navegador + Compartilhar + ID do Autor + ID da Nota + Copiar texto + Excluir + Remover seguidor + Seguir + Pedir para excluir + Amethyst solicitará que sua nota seja excluída dos relays aos quais você está conectado no momento. Não há garantia de que sua nota será excluída permanentemente desses relays ou de outros relays onde possa estar armazenada. + Copia de segurança das chaves + <Não foi possível descriptografar a mensagem privada>\\n\\nVocê foi citado em uma conversa privada/criptografada entre %1$s and %2$s. + Excluir + Não mostar novamente diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f6d729ed9..baff7e1ad 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -178,13 +178,7 @@ Mark all New as read Mark all as read Backup Keys - - ## Key Backup and Safety Tips - \n\nYour account is secured by a secret key. The key is long random string starting with **nsec1**. Anyone who has access to your secret key can publish content using your identity. - \n\n- Do **not** put your secret key in any website or software you do not trust. - \n- Amethyst developers will **never** ask you for your secret key. - \n- **Do** keep a secure backup of your secret key for account recovery. We recommend using a password manager. - + " ## Key Backup and Safety Tips Your account is secured by a secret key. The key is long random string starting with **nsec1**. Anyone who has access to your secret key can publish content using your identity. - Do **not** put your secret key in any website or software you do not trust. - Amethyst developers will **never** ask you for your secret key. - **Do** keep a secure backup of your secret key for account recovery. We recommend using a password manager. " Secret key (nsec) copied to clipboard Copy my secret key Authentication failed @@ -220,5 +214,7 @@ https://twitter.com/<user>/status/<proof post> "<Unable to decrypt private message>\n\nYou were cited in a private/encrypted conversation between %1$s and %2$s." + Delete + Don\'t show again From 8530cf5afe4dc7a8c2bdbe6e48b1a3112afece36 Mon Sep 17 00:00:00 2001 From: Bardesss <30936735+Bardesss@users.noreply.github.com> Date: Fri, 10 Mar 2023 10:09:20 +0000 Subject: [PATCH 05/20] strings.xml Dutch translation --- app/src/main/res/values-nl | 211 +++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 app/src/main/res/values-nl diff --git a/app/src/main/res/values-nl b/app/src/main/res/values-nl new file mode 100644 index 000000000..d61578c79 --- /dev/null +++ b/app/src/main/res/values-nl @@ -0,0 +1,211 @@ + + Amethyst + Amethyst debug + Richt naar de QR-Code + QR tonen + Profielafbeelding + Scan QR + Laat evengoed zien + Bericht was gemarkeerd als ongepast door + Bericht niet gevonden + Kanaalafbeelding + Verwezen event niet gevonden + Kon het bericht niet ontcijferen + Groepafbeelding + Expliciete inhoud + Spam + Imitatie + Illegaal gedrag + Onbekend + Relay icoon + Onbekende auteur + Kopieer tekst + Kopieer auteur ID + Kopieer note ID + Verzenden + + Meld spam / scam + Meld imitatie + Rapporteer expliciete inhoud + Rapporteer illegaal gedrag + Login met een privésleutel om te reageren + Login met een privésleutel om berichten te boosten + Login met een privésleutel om berichten te liken + Geen Zap bedrag. Houdt ingedrukt om te veranderen + Login met een privésleutel om Zaps te versturen + Zaps + Bekijk telling + Boost + boosted + Quote + Nieuw bedrag in sats + Toevoegen + "reageren op " + " en " + "in kanaal " + Profielbanner + " Volgend" + " Volgers" + Profiel + Beveiligingsfilters + Uitloggen + Meer + Lightning invoice + Betalen + Lightning Tips + Notitie aan ontvanger + Hartelijk bedankt! + Bedrag in sats + Verstuur sats + "Nooit vertalen van " + "Foutieve parsing preview voor %1$s : %2$s" + "Voorbeeld kaartafbeelding voor %1$s" + Nieuw kanaal + Kanaalnaam + Mijn geweldige groep + Afbeelding URL + Omschrijving + "Over ons.. " + Waar denk je aan? + Verzenden + Opslaan + Maken + Annuleren + Het uploaden van de afbeelding is mislukt + Relay addres + Berichten + Errors + Beginfeed + Privéberichten + Publieke chats + Globale feed + Zoeken + AVoeg een relay toe + Naam + Mijn naam + Gebruikersnaam + Mijn gebruikersnaam + Over mij + Avatar URL + Banner URL + Website URL + LN Address + LN URL (verouderd) + Afbeelding opgeslagen in de galerij + De afbeelding is niet opgeslagen + Afbeelding uploaden + Uploaden… + De gebruiker heeft geen Lightning Adress ingesteld om sats te ontvangen + "hier reageren.. " + Kopieert de Notitie ID naar klembord om te delen + Kopieer kanaal ID (Notitie) naar klembord + Past de kanaal-metadata aan + Lid worden + Bekend + Nieuw verzoek + Geblokeerde gebruikers + Nieuwe draadjes + Gesprekken + Notities + Reacties + "Volgend" + "Rapporten" + Meer opties + " Relays" + Website + Lightning Address + Kopieert het NSec ID (uw wachtwoord) naar het klembord voor back-up. + Privésleutel kopiëren naar het klembord + Kopieert de publieke sleutel naar het klembord om te delen + Kopieer publieke sleutel (NPub) naar het klembord + Stuur een privébericht + Bewerkt de metagegevens van de gebruiker + Volgen + Deblokkeren + Kopieer gebruikers ID + Deblokkeer gebruiker + "npub, hex, gebruikersnaam " + Wissen + App logo + nsec / npub / hex privésleutel + Toon wachtwoord + Verberg wachtwoord + Ongeldige sleutel + "Ik accepteer de " + gebruiksvoorwaarden + Accepteren van de voorwaarden is vereist + Sleutel is vereist + Inloggen + Genereer een nieuwe sleutel + Feed laden + "Foutmelding bij het laden reacties: " + Opnieuw proberen + Feed is leeg. + Verversen + gemaakt + met beschrijving van + en afbeelding + heeft chatnaam veranderd naar + omschrijving naar + en afbeelding naar + Verlaten + Ontvolgen + Kanaal gemaakt + "Kanaalinformatie veranderd naar" + Publieke chat + berichten ontvangen + Verwijderen + sats + Auto + vertaald van + naar + Laten zien in + eerste + Altijd vertalen naar + NIP-05 + LNURL... + nooit + nu + h + m + d + Naaktheid + Godslastering / haatdragende taal + Haatdragende taal rapporteren + Naaktheid / porno rapporteren + anderen + Alle bekende als gelezen markeren + Alle nieuwe als gelezen markeren + Alles als gelezen markeren + Backup sleutels + + ## Sleutel back-up en veiligheidstips + \n\nUw account is beveiligd met een privésleutel. De sleutel is een lange, willekeurige reeks die begint met **nsec1**. Iedereen die toegang heeft tot uw privésleutel kan inhoud publiceren met uw identiteit. + \n\n- Voer uw privésleutel **nooit** in een website of software die u niet vertrouwt. + \n- Amethyst ontwikkelaars zullen u **nooit** om uw privésleutel vragen. + \n- **Bewaar** een veilige back-up van uw privésleutel voor accountherstel. Wij raden u aan een wachtwoordmanager te gebruiken. + + Privésleutel (nsec) gekopieerd naar klembord + Kopieer mijn privésleutel + Authenticatie mislukt + Error + "Gemaakt door %1$s" + "Badge award afbeelding voor %1$s" + Je hebt een nieuwe Badge award ontvangen + Badge award gegeven aan + Notitie tekst gekopieerd naar klembord + @npub auteur gekopieerd naar klembord + Notitie ID (@note1) gekopieerd naar klembord + Selecteer tekst + Selecteer + Deel browserlink + Delen + Auteur ID + Notitie ID + Kopieer tekst + Verwijderen + Ontvolgen + Volgen + Verzoek om te verwijderen + Amethyst zal vragen om uw notitie te verwijderen van de relays waarmee u momenteel verbonden bent. Er is geen garantie dat uw notitie permanent wordt verwijderd van deze relays, of van andere relays waar het kan worden opgeslagen. + From 4c495f027083dab237d2c873bda7f47ced88047c Mon Sep 17 00:00:00 2001 From: Bardesss <30936735+Bardesss@users.noreply.github.com> Date: Fri, 10 Mar 2023 10:11:37 +0000 Subject: [PATCH 06/20] Delete values-nl --- app/src/main/res/values-nl | 211 ------------------------------------- 1 file changed, 211 deletions(-) delete mode 100644 app/src/main/res/values-nl diff --git a/app/src/main/res/values-nl b/app/src/main/res/values-nl deleted file mode 100644 index d61578c79..000000000 --- a/app/src/main/res/values-nl +++ /dev/null @@ -1,211 +0,0 @@ - - Amethyst - Amethyst debug - Richt naar de QR-Code - QR tonen - Profielafbeelding - Scan QR - Laat evengoed zien - Bericht was gemarkeerd als ongepast door - Bericht niet gevonden - Kanaalafbeelding - Verwezen event niet gevonden - Kon het bericht niet ontcijferen - Groepafbeelding - Expliciete inhoud - Spam - Imitatie - Illegaal gedrag - Onbekend - Relay icoon - Onbekende auteur - Kopieer tekst - Kopieer auteur ID - Kopieer note ID - Verzenden - - Meld spam / scam - Meld imitatie - Rapporteer expliciete inhoud - Rapporteer illegaal gedrag - Login met een privésleutel om te reageren - Login met een privésleutel om berichten te boosten - Login met een privésleutel om berichten te liken - Geen Zap bedrag. Houdt ingedrukt om te veranderen - Login met een privésleutel om Zaps te versturen - Zaps - Bekijk telling - Boost - boosted - Quote - Nieuw bedrag in sats - Toevoegen - "reageren op " - " en " - "in kanaal " - Profielbanner - " Volgend" - " Volgers" - Profiel - Beveiligingsfilters - Uitloggen - Meer - Lightning invoice - Betalen - Lightning Tips - Notitie aan ontvanger - Hartelijk bedankt! - Bedrag in sats - Verstuur sats - "Nooit vertalen van " - "Foutieve parsing preview voor %1$s : %2$s" - "Voorbeeld kaartafbeelding voor %1$s" - Nieuw kanaal - Kanaalnaam - Mijn geweldige groep - Afbeelding URL - Omschrijving - "Over ons.. " - Waar denk je aan? - Verzenden - Opslaan - Maken - Annuleren - Het uploaden van de afbeelding is mislukt - Relay addres - Berichten - Errors - Beginfeed - Privéberichten - Publieke chats - Globale feed - Zoeken - AVoeg een relay toe - Naam - Mijn naam - Gebruikersnaam - Mijn gebruikersnaam - Over mij - Avatar URL - Banner URL - Website URL - LN Address - LN URL (verouderd) - Afbeelding opgeslagen in de galerij - De afbeelding is niet opgeslagen - Afbeelding uploaden - Uploaden… - De gebruiker heeft geen Lightning Adress ingesteld om sats te ontvangen - "hier reageren.. " - Kopieert de Notitie ID naar klembord om te delen - Kopieer kanaal ID (Notitie) naar klembord - Past de kanaal-metadata aan - Lid worden - Bekend - Nieuw verzoek - Geblokeerde gebruikers - Nieuwe draadjes - Gesprekken - Notities - Reacties - "Volgend" - "Rapporten" - Meer opties - " Relays" - Website - Lightning Address - Kopieert het NSec ID (uw wachtwoord) naar het klembord voor back-up. - Privésleutel kopiëren naar het klembord - Kopieert de publieke sleutel naar het klembord om te delen - Kopieer publieke sleutel (NPub) naar het klembord - Stuur een privébericht - Bewerkt de metagegevens van de gebruiker - Volgen - Deblokkeren - Kopieer gebruikers ID - Deblokkeer gebruiker - "npub, hex, gebruikersnaam " - Wissen - App logo - nsec / npub / hex privésleutel - Toon wachtwoord - Verberg wachtwoord - Ongeldige sleutel - "Ik accepteer de " - gebruiksvoorwaarden - Accepteren van de voorwaarden is vereist - Sleutel is vereist - Inloggen - Genereer een nieuwe sleutel - Feed laden - "Foutmelding bij het laden reacties: " - Opnieuw proberen - Feed is leeg. - Verversen - gemaakt - met beschrijving van - en afbeelding - heeft chatnaam veranderd naar - omschrijving naar - en afbeelding naar - Verlaten - Ontvolgen - Kanaal gemaakt - "Kanaalinformatie veranderd naar" - Publieke chat - berichten ontvangen - Verwijderen - sats - Auto - vertaald van - naar - Laten zien in - eerste - Altijd vertalen naar - NIP-05 - LNURL... - nooit - nu - h - m - d - Naaktheid - Godslastering / haatdragende taal - Haatdragende taal rapporteren - Naaktheid / porno rapporteren - anderen - Alle bekende als gelezen markeren - Alle nieuwe als gelezen markeren - Alles als gelezen markeren - Backup sleutels - - ## Sleutel back-up en veiligheidstips - \n\nUw account is beveiligd met een privésleutel. De sleutel is een lange, willekeurige reeks die begint met **nsec1**. Iedereen die toegang heeft tot uw privésleutel kan inhoud publiceren met uw identiteit. - \n\n- Voer uw privésleutel **nooit** in een website of software die u niet vertrouwt. - \n- Amethyst ontwikkelaars zullen u **nooit** om uw privésleutel vragen. - \n- **Bewaar** een veilige back-up van uw privésleutel voor accountherstel. Wij raden u aan een wachtwoordmanager te gebruiken. - - Privésleutel (nsec) gekopieerd naar klembord - Kopieer mijn privésleutel - Authenticatie mislukt - Error - "Gemaakt door %1$s" - "Badge award afbeelding voor %1$s" - Je hebt een nieuwe Badge award ontvangen - Badge award gegeven aan - Notitie tekst gekopieerd naar klembord - @npub auteur gekopieerd naar klembord - Notitie ID (@note1) gekopieerd naar klembord - Selecteer tekst - Selecteer - Deel browserlink - Delen - Auteur ID - Notitie ID - Kopieer tekst - Verwijderen - Ontvolgen - Volgen - Verzoek om te verwijderen - Amethyst zal vragen om uw notitie te verwijderen van de relays waarmee u momenteel verbonden bent. Er is geen garantie dat uw notitie permanent wordt verwijderd van deze relays, of van andere relays waar het kan worden opgeslagen. - From 844fb4ce3d51bbd4c6357c5a613e12bebaa86b55 Mon Sep 17 00:00:00 2001 From: Bardesss <30936735+Bardesss@users.noreply.github.com> Date: Fri, 10 Mar 2023 10:12:02 +0000 Subject: [PATCH 07/20] Create strings.xml Dutch translation --- app/src/main/res/values-nl/strings.xml | 211 +++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 app/src/main/res/values-nl/strings.xml diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml new file mode 100644 index 000000000..d61578c79 --- /dev/null +++ b/app/src/main/res/values-nl/strings.xml @@ -0,0 +1,211 @@ + + Amethyst + Amethyst debug + Richt naar de QR-Code + QR tonen + Profielafbeelding + Scan QR + Laat evengoed zien + Bericht was gemarkeerd als ongepast door + Bericht niet gevonden + Kanaalafbeelding + Verwezen event niet gevonden + Kon het bericht niet ontcijferen + Groepafbeelding + Expliciete inhoud + Spam + Imitatie + Illegaal gedrag + Onbekend + Relay icoon + Onbekende auteur + Kopieer tekst + Kopieer auteur ID + Kopieer note ID + Verzenden + + Meld spam / scam + Meld imitatie + Rapporteer expliciete inhoud + Rapporteer illegaal gedrag + Login met een privésleutel om te reageren + Login met een privésleutel om berichten te boosten + Login met een privésleutel om berichten te liken + Geen Zap bedrag. Houdt ingedrukt om te veranderen + Login met een privésleutel om Zaps te versturen + Zaps + Bekijk telling + Boost + boosted + Quote + Nieuw bedrag in sats + Toevoegen + "reageren op " + " en " + "in kanaal " + Profielbanner + " Volgend" + " Volgers" + Profiel + Beveiligingsfilters + Uitloggen + Meer + Lightning invoice + Betalen + Lightning Tips + Notitie aan ontvanger + Hartelijk bedankt! + Bedrag in sats + Verstuur sats + "Nooit vertalen van " + "Foutieve parsing preview voor %1$s : %2$s" + "Voorbeeld kaartafbeelding voor %1$s" + Nieuw kanaal + Kanaalnaam + Mijn geweldige groep + Afbeelding URL + Omschrijving + "Over ons.. " + Waar denk je aan? + Verzenden + Opslaan + Maken + Annuleren + Het uploaden van de afbeelding is mislukt + Relay addres + Berichten + Errors + Beginfeed + Privéberichten + Publieke chats + Globale feed + Zoeken + AVoeg een relay toe + Naam + Mijn naam + Gebruikersnaam + Mijn gebruikersnaam + Over mij + Avatar URL + Banner URL + Website URL + LN Address + LN URL (verouderd) + Afbeelding opgeslagen in de galerij + De afbeelding is niet opgeslagen + Afbeelding uploaden + Uploaden… + De gebruiker heeft geen Lightning Adress ingesteld om sats te ontvangen + "hier reageren.. " + Kopieert de Notitie ID naar klembord om te delen + Kopieer kanaal ID (Notitie) naar klembord + Past de kanaal-metadata aan + Lid worden + Bekend + Nieuw verzoek + Geblokeerde gebruikers + Nieuwe draadjes + Gesprekken + Notities + Reacties + "Volgend" + "Rapporten" + Meer opties + " Relays" + Website + Lightning Address + Kopieert het NSec ID (uw wachtwoord) naar het klembord voor back-up. + Privésleutel kopiëren naar het klembord + Kopieert de publieke sleutel naar het klembord om te delen + Kopieer publieke sleutel (NPub) naar het klembord + Stuur een privébericht + Bewerkt de metagegevens van de gebruiker + Volgen + Deblokkeren + Kopieer gebruikers ID + Deblokkeer gebruiker + "npub, hex, gebruikersnaam " + Wissen + App logo + nsec / npub / hex privésleutel + Toon wachtwoord + Verberg wachtwoord + Ongeldige sleutel + "Ik accepteer de " + gebruiksvoorwaarden + Accepteren van de voorwaarden is vereist + Sleutel is vereist + Inloggen + Genereer een nieuwe sleutel + Feed laden + "Foutmelding bij het laden reacties: " + Opnieuw proberen + Feed is leeg. + Verversen + gemaakt + met beschrijving van + en afbeelding + heeft chatnaam veranderd naar + omschrijving naar + en afbeelding naar + Verlaten + Ontvolgen + Kanaal gemaakt + "Kanaalinformatie veranderd naar" + Publieke chat + berichten ontvangen + Verwijderen + sats + Auto + vertaald van + naar + Laten zien in + eerste + Altijd vertalen naar + NIP-05 + LNURL... + nooit + nu + h + m + d + Naaktheid + Godslastering / haatdragende taal + Haatdragende taal rapporteren + Naaktheid / porno rapporteren + anderen + Alle bekende als gelezen markeren + Alle nieuwe als gelezen markeren + Alles als gelezen markeren + Backup sleutels + + ## Sleutel back-up en veiligheidstips + \n\nUw account is beveiligd met een privésleutel. De sleutel is een lange, willekeurige reeks die begint met **nsec1**. Iedereen die toegang heeft tot uw privésleutel kan inhoud publiceren met uw identiteit. + \n\n- Voer uw privésleutel **nooit** in een website of software die u niet vertrouwt. + \n- Amethyst ontwikkelaars zullen u **nooit** om uw privésleutel vragen. + \n- **Bewaar** een veilige back-up van uw privésleutel voor accountherstel. Wij raden u aan een wachtwoordmanager te gebruiken. + + Privésleutel (nsec) gekopieerd naar klembord + Kopieer mijn privésleutel + Authenticatie mislukt + Error + "Gemaakt door %1$s" + "Badge award afbeelding voor %1$s" + Je hebt een nieuwe Badge award ontvangen + Badge award gegeven aan + Notitie tekst gekopieerd naar klembord + @npub auteur gekopieerd naar klembord + Notitie ID (@note1) gekopieerd naar klembord + Selecteer tekst + Selecteer + Deel browserlink + Delen + Auteur ID + Notitie ID + Kopieer tekst + Verwijderen + Ontvolgen + Volgen + Verzoek om te verwijderen + Amethyst zal vragen om uw notitie te verwijderen van de relays waarmee u momenteel verbonden bent. Er is geen garantie dat uw notitie permanent wordt verwijderd van deze relays, of van andere relays waar het kan worden opgeslagen. + From 37b3da685dc96dd6d39ad12fcd07a86fece2bbfb Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 10 Mar 2023 09:35:06 -0500 Subject: [PATCH 08/20] Updates Readme for last versions new features. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 522bb9939..ff038543e 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ Amethyst brings the best social network to your Android phone. Just insert your - [x] Long-form Content (NIP-23) - [x] Parameterized Replaceable Events (NIP-33) - [x] Online Relay Search (NIP-50) +- [x] Internationalization +- [x] Badges (NIP-58) - [ ] Local Database - [ ] View Individual Reactions (Like, Boost, Zaps, Reports) per Post - [ ] Bookmarks, Pinned Posts, Muted Events (NIP-51) @@ -41,9 +43,7 @@ Amethyst brings the best social network to your Android phone. Just insert your - [ ] Events with a Subject (NIP-14) - [ ] Workspaces - [ ] Expiration Support (NIP-40) -- [ ] Internationalization - [ ] Infinity Scroll -- [ ] Badges (NIP-58) - [ ] Relay List Metadata (NIP-65) - [ ] Signing Requests (NIP-46) - [ ] Delegated Event Signing (NIP-26) From b9304aa1b5ac79c09b790ad0ff6e43ea9ee371e4 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 10 Mar 2023 09:35:25 -0500 Subject: [PATCH 09/20] Removing ContactList Log --- .../main/java/com/vitorpamplona/amethyst/model/LocalCache.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt index f12e48acc..1c06fec3e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -402,7 +402,7 @@ object LocalCache { e.printStackTrace() } - Log.d("CL", "AAA ${user.toBestDisplayName()} ${follows.size}") + // Log.d("CL", "AAA ${user.toBestDisplayName()} ${follows.size}") } } From ae1f0c554726940fb5729102dce36885cf023669 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 10 Mar 2023 09:35:50 -0500 Subject: [PATCH 10/20] Starts websockets on an IO Thread --- .../java/com/vitorpamplona/amethyst/ui/MainActivity.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index 9ea473a80..cdb3aab35 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -21,6 +21,9 @@ import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.ui.screen.AccountScreen import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel import com.vitorpamplona.amethyst.ui.theme.AmethystTheme +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch class MainActivity : FragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -66,7 +69,9 @@ class MainActivity : FragmentActivity() { super.onResume() // Only starts after login - ServiceManager.start() + GlobalScope.launch(Dispatchers.IO) { + ServiceManager.start() + } } override fun onPause() { From b1de2bf3262e71c18679a81526692efff5c1c7c3 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 10 Mar 2023 09:37:17 -0500 Subject: [PATCH 11/20] Moves MarkAsRead write and read to IO context. --- .../amethyst/ui/navigation/AppBottomBar.kt | 10 +++++++-- .../amethyst/ui/note/BadgeCompose.kt | 8 +++++-- .../amethyst/ui/note/BoostSetCompose.kt | 8 +++++-- .../amethyst/ui/note/ChatroomCompose.kt | 22 ++++++++++++------- .../ui/note/ChatroomMessageCompose.kt | 14 +++++++----- .../amethyst/ui/note/LikeSetCompose.kt | 8 +++++-- .../amethyst/ui/note/MessageSetCompose.kt | 9 ++++++-- .../amethyst/ui/note/MultiSetCompose.kt | 8 +++++-- .../amethyst/ui/note/NoteCompose.kt | 16 +++++++++----- .../amethyst/ui/note/ZapSetCompose.kt | 8 +++++-- 10 files changed, 78 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt index b83f06155..f59437670 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt @@ -40,7 +40,9 @@ import androidx.navigation.NavHostController import com.vitorpamplona.amethyst.NotificationCache import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext val bottomNavigationItems = listOf( Route.Home, @@ -157,11 +159,15 @@ private fun NotifiableIcon(item: Route, currentRoute: String?, accountViewModel: val context = LocalContext.current.applicationContext LaunchedEffect(key1 = notif) { - hasNewItems = item.hasNewItems(account, notif.cache, context) + withContext(Dispatchers.IO) { + hasNewItems = item.hasNewItems(account, notif.cache, context) + } } LaunchedEffect(key1 = db) { - hasNewItems = item.hasNewItems(account, notif.cache, context) + withContext(Dispatchers.IO) { + hasNewItems = item.hasNewItems(account, notif.cache, context) + } } if (hasNewItems) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt index 7cbf6a432..7d63a7df6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt @@ -35,6 +35,8 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent import com.vitorpamplona.amethyst.ui.screen.BadgeCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext @OptIn(ExperimentalFoundationApi::class) @Composable @@ -56,9 +58,11 @@ fun BadgeCompose(likeSetCard: BadgeCard, modifier: Modifier = Modifier, isInnerN var isNew by remember { mutableStateOf(false) } LaunchedEffect(key1 = likeSetCard) { - isNew = likeSetCard.createdAt() > NotificationCache.load(routeForLastRead, context) + withContext(Dispatchers.IO) { + isNew = likeSetCard.createdAt() > NotificationCache.load(routeForLastRead, context) - NotificationCache.markAsRead(routeForLastRead, likeSetCard.createdAt(), context) + NotificationCache.markAsRead(routeForLastRead, likeSetCard.createdAt(), context) + } } var backgroundColor = if (isNew) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BoostSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BoostSetCompose.kt index 718bb233e..053a2e253 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BoostSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BoostSetCompose.kt @@ -32,6 +32,8 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent import com.vitorpamplona.amethyst.ui.screen.BoostSetCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext @OptIn(ExperimentalFoundationApi::class) @Composable @@ -53,9 +55,11 @@ fun BoostSetCompose(boostSetCard: BoostSetCard, isInnerNote: Boolean = false, ro var isNew by remember { mutableStateOf(false) } LaunchedEffect(key1 = boostSetCard) { - isNew = boostSetCard.createdAt > NotificationCache.load(routeForLastRead, context) + withContext(Dispatchers.IO) { + isNew = boostSetCard.createdAt > NotificationCache.load(routeForLastRead, context) - NotificationCache.markAsRead(routeForLastRead, boostSetCard.createdAt, context) + NotificationCache.markAsRead(routeForLastRead, boostSetCard.createdAt, context) + } } var backgroundColor = if (isNew) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt index 785491414..48f2d9b9b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt @@ -50,6 +50,8 @@ import com.vitorpamplona.amethyst.service.model.ChannelMetadataEvent import com.vitorpamplona.amethyst.ui.components.AsyncImageProxy import com.vitorpamplona.amethyst.ui.components.ResizeImage import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext @Composable fun ChatroomCompose( @@ -90,9 +92,11 @@ fun ChatroomCompose( var hasNewMessages by remember { mutableStateOf(false) } LaunchedEffect(key1 = notificationCache, key2 = note) { - note.createdAt()?.let { - hasNewMessages = - it > notificationCache.cache.load("Channel/${channel.idHex}", context) + withContext(Dispatchers.IO) { + note.createdAt()?.let { + hasNewMessages = + it > notificationCache.cache.load("Channel/${channel.idHex}", context) + } } } @@ -152,11 +156,13 @@ fun ChatroomCompose( var hasNewMessages by remember { mutableStateOf(false) } LaunchedEffect(key1 = notificationCache, key2 = note) { - noteEvent?.let { - hasNewMessages = it.createdAt() > notificationCache.cache.load( - "Room/${userToComposeOn.pubkeyHex}", - context - ) + withContext(Dispatchers.IO) { + noteEvent?.let { + hasNewMessages = it.createdAt() > notificationCache.cache.load( + "Room/${userToComposeOn.pubkeyHex}", + context + ) + } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt index 437755f99..a4a619c1c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt @@ -64,6 +64,8 @@ import com.vitorpamplona.amethyst.ui.components.AsyncImageProxy import com.vitorpamplona.amethyst.ui.components.ResizeImage import com.vitorpamplona.amethyst.ui.components.TranslateableRichTextViewer import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext val ChatBubbleShapeMe = RoundedCornerShape(15.dp, 15.dp, 3.dp, 15.dp) val ChatBubbleShapeThem = RoundedCornerShape(3.dp, 15.dp, 15.dp, 15.dp) @@ -131,12 +133,14 @@ fun ChatroomMessageCompose( LaunchedEffect(key1 = routeForLastRead) { routeForLastRead?.let { - val lastTime = NotificationCache.load(it, context) + withContext(Dispatchers.IO) { + val lastTime = NotificationCache.load(it, context) - val createdAt = note.createdAt() - if (createdAt != null) { - NotificationCache.markAsRead(it, createdAt, context) - isNew = createdAt > lastTime + val createdAt = note.createdAt() + if (createdAt != null) { + NotificationCache.markAsRead(it, createdAt, context) + isNew = createdAt > lastTime + } } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/LikeSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/LikeSetCompose.kt index e25a270cf..722a74220 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/LikeSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/LikeSetCompose.kt @@ -32,6 +32,8 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent import com.vitorpamplona.amethyst.ui.screen.LikeSetCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext @OptIn(ExperimentalFoundationApi::class) @Composable @@ -53,9 +55,11 @@ fun LikeSetCompose(likeSetCard: LikeSetCard, modifier: Modifier = Modifier, isIn var isNew by remember { mutableStateOf(false) } LaunchedEffect(key1 = likeSetCard) { - isNew = likeSetCard.createdAt > NotificationCache.load(routeForLastRead, context) + withContext(Dispatchers.IO) { + isNew = likeSetCard.createdAt > NotificationCache.load(routeForLastRead, context) - NotificationCache.markAsRead(routeForLastRead, likeSetCard.createdAt, context) + NotificationCache.markAsRead(routeForLastRead, likeSetCard.createdAt, context) + } } var backgroundColor = if (isNew) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt index 5d7e07ab7..743b06e73 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt @@ -30,6 +30,8 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent import com.vitorpamplona.amethyst.ui.screen.MessageSetCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext @OptIn(ExperimentalFoundationApi::class) @Composable @@ -51,9 +53,12 @@ fun MessageSetCompose(messageSetCard: MessageSetCard, isInnerNote: Boolean = fal var isNew by remember { mutableStateOf(false) } LaunchedEffect(key1 = messageSetCard) { - isNew = messageSetCard.createdAt() > NotificationCache.load(routeForLastRead, context) + withContext(Dispatchers.IO) { + isNew = + messageSetCard.createdAt() > NotificationCache.load(routeForLastRead, context) - NotificationCache.markAsRead(routeForLastRead, messageSetCard.createdAt(), context) + NotificationCache.markAsRead(routeForLastRead, messageSetCard.createdAt(), context) + } } var backgroundColor = if (isNew) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt index bc6a7db78..f1fd8e8fa 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt @@ -36,6 +36,8 @@ import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent import com.vitorpamplona.amethyst.ui.screen.MultiSetCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext @OptIn(ExperimentalFoundationApi::class) @Composable @@ -57,9 +59,11 @@ fun MultiSetCompose(multiSetCard: MultiSetCard, modifier: Modifier = Modifier, r var isNew by remember { mutableStateOf(false) } LaunchedEffect(key1 = multiSetCard) { - isNew = multiSetCard.createdAt > NotificationCache.load(routeForLastRead, context) + withContext(Dispatchers.IO) { + isNew = multiSetCard.createdAt > NotificationCache.load(routeForLastRead, context) - NotificationCache.markAsRead(routeForLastRead, multiSetCard.createdAt, context) + NotificationCache.markAsRead(routeForLastRead, multiSetCard.createdAt, context) + } } var backgroundColor = if (isNew) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index 44a958db5..271120cf7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -60,6 +60,8 @@ import com.vitorpamplona.amethyst.ui.components.TranslateableRichTextViewer import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelHeader import com.vitorpamplona.amethyst.ui.theme.Following +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext @OptIn(ExperimentalFoundationApi::class) @Composable @@ -120,13 +122,15 @@ fun NoteCompose( var isNew by remember { mutableStateOf(false) } LaunchedEffect(key1 = routeForLastRead) { - routeForLastRead?.let { - val lastTime = NotificationCache.load(it, context) + withContext(Dispatchers.IO) { + routeForLastRead?.let { + val lastTime = NotificationCache.load(it, context) - val createdAt = note.createdAt() - if (createdAt != null) { - NotificationCache.markAsRead(it, createdAt, context) - isNew = createdAt > lastTime + val createdAt = note.createdAt() + if (createdAt != null) { + NotificationCache.markAsRead(it, createdAt, context) + isNew = createdAt > lastTime + } } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapSetCompose.kt index 6785d3599..98b0c1e09 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapSetCompose.kt @@ -34,6 +34,8 @@ import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent import com.vitorpamplona.amethyst.ui.screen.ZapSetCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext @OptIn(ExperimentalFoundationApi::class) @Composable @@ -55,9 +57,11 @@ fun ZapSetCompose(zapSetCard: ZapSetCard, modifier: Modifier = Modifier, isInner var isNew by remember { mutableStateOf(false) } LaunchedEffect(key1 = zapSetCard) { - isNew = zapSetCard.createdAt > NotificationCache.load(routeForLastRead, context) + withContext(Dispatchers.IO) { + isNew = zapSetCard.createdAt > NotificationCache.load(routeForLastRead, context) - NotificationCache.markAsRead(routeForLastRead, zapSetCard.createdAt, context) + NotificationCache.markAsRead(routeForLastRead, zapSetCard.createdAt, context) + } } var backgroundColor = if (isNew) { From 88e03c1a0a982f7cd7c13969ebcd308b8666287c Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 10 Mar 2023 09:37:43 -0500 Subject: [PATCH 12/20] Removes Account observer from ChatroomCompose --- .../com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt index 48f2d9b9b..c0dd8c182 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt @@ -62,9 +62,6 @@ fun ChatroomCompose( val noteState by baseNote.live().metadata.observeAsState() val note = noteState?.note - val accountState by accountViewModel.accountLiveData.observeAsState() - val account = accountState?.account ?: return - val notificationCacheState = NotificationCache.live.observeAsState() val notificationCache = notificationCacheState.value ?: return @@ -145,7 +142,7 @@ fun ChatroomCompose( var userToComposeOn = note.author!! if (replyAuthorBase != null) { - if (note.author == account.userProfile()) { + if (note.author == accountViewModel.userProfile()) { userToComposeOn = replyAuthorBase } } @@ -170,7 +167,7 @@ fun ChatroomCompose( channelPicture = { UserPicture( userToComposeOn, - account.userProfile(), + accountViewModel.userProfile(), size = 55.dp ) }, From 3d877fda2841b638abf1b3a3c3b953d7f75a457c Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 10 Mar 2023 09:38:33 -0500 Subject: [PATCH 13/20] Moves Zap amount Calculations to IO Thread --- .../amethyst/ui/note/ReactionsRow.kt | 23 ++++++++++++++++--- .../amethyst/ui/note/ZapNoteCompose.kt | 17 +++++++++++--- .../ui/screen/loggedIn/ProfileScreen.kt | 17 ++++++++++++-- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index b955120a7..a302ba1c6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -72,7 +72,9 @@ import com.vitorpamplona.amethyst.ui.actions.NewPostView import com.vitorpamplona.amethyst.ui.actions.SaveButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import java.math.BigDecimal import java.math.RoundingMode @@ -99,7 +101,9 @@ fun ReactionsRow(baseNote: Note, accountViewModel: AccountViewModel) { } Row( - modifier = Modifier.padding(top = 8.dp).fillMaxWidth(), + modifier = Modifier + .padding(top = 8.dp) + .fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween ) { @@ -350,7 +354,12 @@ fun ZapReaction( .show() } } else if (account.zapAmountChoices.size == 1) { - accountViewModel.zap(baseNote, account.zapAmountChoices.first() * 1000, "", context) { + accountViewModel.zap( + baseNote, + account.zapAmountChoices.first() * 1000, + "", + context + ) { scope.launch { Toast .makeText(context, it, Toast.LENGTH_SHORT) @@ -405,8 +414,16 @@ fun ZapReaction( } } + var zapAmount by remember { mutableStateOf(null) } + + LaunchedEffect(key1 = zappedNote) { + withContext(Dispatchers.IO) { + zapAmount = zappedNote?.zappedAmount() + } + } + Text( - showAmount(zappedNote?.zappedAmount()), + showAmount(zapAmount), fontSize = 14.sp, color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f), modifier = textModifier diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt index f4497bdc5..e26caff52 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt @@ -9,9 +9,13 @@ import androidx.compose.material.Divider import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState +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 @@ -31,6 +35,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.UnfollowButton import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.math.BigDecimal @Composable fun ZapNoteCompose(baseNote: Pair, accountViewModel: AccountViewModel, navController: NavController) { @@ -88,15 +94,20 @@ fun ZapNoteCompose(baseNote: Pair, accountViewModel: AccountViewMode ) } - val amount = - (noteZap.event as? LnZapEvent)?.amount + var zapAmount by remember { mutableStateOf(null) } + + LaunchedEffect(key1 = noteZap) { + withContext(Dispatchers.IO) { + zapAmount = (noteZap.event as? LnZapEvent)?.amount + } + } Column( modifier = Modifier.padding(start = 10.dp), verticalArrangement = Arrangement.Center ) { Text( - "${showAmount(amount)} ${stringResource(R.string.sats)}", + "${showAmount(zapAmount)} ${stringResource(R.string.sats)}", color = BitcoinOrange, fontSize = 20.sp, fontWeight = FontWeight.W500 diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index 387423e87..c13b232b2 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -89,6 +89,8 @@ import com.vitorpamplona.amethyst.ui.screen.UserFeedView import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.math.BigDecimal @OptIn(ExperimentalPagerApi::class) @Composable @@ -210,9 +212,20 @@ fun ProfileScreen(userId: String?, accountViewModel: AccountViewModel, navContro }, { val userState by baseUser.live().zaps.observeAsState() - val userZaps = userState?.user?.zappedAmount() + val userZaps = userState?.user - Text(text = "${showAmount(userZaps)} ${stringResource(id = R.string.zaps)}") + var zapAmount by remember { mutableStateOf(null) } + + LaunchedEffect(key1 = userState) { + withContext(Dispatchers.IO) { + val tempAmount = userZaps?.zappedAmount() + withContext(Dispatchers.Main) { + zapAmount = tempAmount + } + } + } + + Text(text = "${showAmount(zapAmount)} ${stringResource(id = R.string.zaps)}") }, { val userState by baseUser.live().reports.observeAsState() From 1d74bfb191b13aeede9f4b613775da0c12fed9ef Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 10 Mar 2023 09:38:56 -0500 Subject: [PATCH 14/20] Refines visibility of refresh functions --- app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt | 2 +- .../com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt | 3 +-- .../com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt index 8437d532b..6e5a87e19 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt @@ -370,7 +370,7 @@ class NoteLiveData(val note: Note) : LiveData(NoteState(note)) { } } - fun refresh() { + private fun refresh() { postValue(NoteState(note)) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt index 1b92b2ec0..c76a25966 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/LnZapFeedViewModel.kt @@ -63,7 +63,7 @@ open class LnZapFeedViewModel(val dataSource: FeedFilter>) : Vi var handlerWaiting = AtomicBoolean() - private fun invalidateData() { + fun invalidateData() { if (handlerWaiting.getAndSet(true)) return val scope = CoroutineScope(Job() + Dispatchers.Default) @@ -76,7 +76,6 @@ open class LnZapFeedViewModel(val dataSource: FeedFilter>) : Vi handlerWaiting.set(false) } } - handlerWaiting.set(false) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt index 8748a1f11..bab4039cd 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt @@ -67,7 +67,7 @@ open class UserFeedViewModel(val dataSource: FeedFilter) : ViewModel() { var handlerWaiting = AtomicBoolean() - private fun invalidateData() { + fun invalidateData() { if (handlerWaiting.getAndSet(true)) return val scope = CoroutineScope(Job() + Dispatchers.Default) From ad8d9cabe26ca600ac8439cf8573109e3825523a Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 10 Mar 2023 09:58:58 -0500 Subject: [PATCH 15/20] Refreshing inner user lists faster (instead of waiting for LocalCache to update) --- .../ui/screen/loggedIn/ProfileScreen.kt | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index c13b232b2..9de2a4381 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -695,11 +695,13 @@ fun TabNotesConversations(user: User, accountViewModel: AccountViewModel, navCon } @Composable -fun TabFollows(user: User, accountViewModel: AccountViewModel, navController: NavController) { +fun TabFollows(baseUser: User, accountViewModel: AccountViewModel, navController: NavController) { val feedViewModel: NostrUserProfileFollowsUserFeedViewModel = viewModel() - LaunchedEffect(Unit) { - feedViewModel.refresh() + val userState by baseUser.live().follows.observeAsState() + + LaunchedEffect(userState) { + feedViewModel.invalidateData() } Column(Modifier.fillMaxHeight()) { @@ -712,11 +714,13 @@ fun TabFollows(user: User, accountViewModel: AccountViewModel, navController: Na } @Composable -fun TabFollowers(user: User, accountViewModel: AccountViewModel, navController: NavController) { +fun TabFollowers(baseUser: User, accountViewModel: AccountViewModel, navController: NavController) { val feedViewModel: NostrUserProfileFollowersUserFeedViewModel = viewModel() - LaunchedEffect(Unit) { - feedViewModel.refresh() + val userState by baseUser.live().follows.observeAsState() + + LaunchedEffect(userState) { + feedViewModel.invalidateData() } Column(Modifier.fillMaxHeight()) { @@ -729,41 +733,39 @@ fun TabFollowers(user: User, accountViewModel: AccountViewModel, navController: } @Composable -fun TabReceivedZaps(user: User, accountViewModel: AccountViewModel, navController: NavController) { - val accountState by accountViewModel.accountLiveData.observeAsState() - if (accountState != null) { - val feedViewModel: NostrUserProfileZapsFeedViewModel = viewModel() +fun TabReceivedZaps(baseUser: User, accountViewModel: AccountViewModel, navController: NavController) { + val feedViewModel: NostrUserProfileZapsFeedViewModel = viewModel() - LaunchedEffect(Unit) { - feedViewModel.refresh() - } + val userState by baseUser.live().zaps.observeAsState() - Column(Modifier.fillMaxHeight()) { - Column( - modifier = Modifier.padding(vertical = 0.dp) - ) { - LnZapFeedView(feedViewModel, accountViewModel, navController) - } + LaunchedEffect(userState) { + feedViewModel.invalidateData() + } + + Column(Modifier.fillMaxHeight()) { + Column( + modifier = Modifier.padding(vertical = 0.dp) + ) { + LnZapFeedView(feedViewModel, accountViewModel, navController) } } } @Composable -fun TabReports(user: User, accountViewModel: AccountViewModel, navController: NavController) { - val accountState by accountViewModel.accountLiveData.observeAsState() - if (accountState != null) { - val feedViewModel: NostrUserProfileReportFeedViewModel = viewModel() +fun TabReports(baseUser: User, accountViewModel: AccountViewModel, navController: NavController) { + val feedViewModel: NostrUserProfileReportFeedViewModel = viewModel() - LaunchedEffect(Unit) { - feedViewModel.refresh() - } + val userState by baseUser.live().reports.observeAsState() - Column(Modifier.fillMaxHeight()) { - Column( - modifier = Modifier.padding(vertical = 0.dp) - ) { - FeedView(feedViewModel, accountViewModel, navController, null) - } + LaunchedEffect(userState) { + feedViewModel.invalidateData() + } + + Column(Modifier.fillMaxHeight()) { + Column( + modifier = Modifier.padding(vertical = 0.dp) + ) { + FeedView(feedViewModel, accountViewModel, navController, null) } } } From 57ee0ff1ff0aee454690b22520d38a889011a4b7 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 10 Mar 2023 10:14:54 -0500 Subject: [PATCH 16/20] BugFix for dark text on dark background. --- .../amethyst/ui/screen/loggedOff/LoginScreen.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt index c505c5738..ffa3c8ce4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt @@ -153,11 +153,16 @@ fun LoginPage(accountViewModel: AccountStateViewModel) { onCheckedChange = { acceptedTerms.value = it } ) + val regularText = + SpanStyle(color = MaterialTheme.colors.onBackground) + val clickableTextStyle = SpanStyle(color = MaterialTheme.colors.primary) val annotatedTermsString = buildAnnotatedString { - append(stringResource(R.string.i_accept_the)) + withStyle(regularText) { + append(stringResource(R.string.i_accept_the)) + } withStyle(clickableTextStyle) { pushStringAnnotation("openTerms", "") From 78261ccd9434e1423f8e0b887d44be3a78ebadf7 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 10 Mar 2023 10:15:32 -0500 Subject: [PATCH 17/20] Puts the ZapValue calculator inside a caching function. --- .../vitorpamplona/amethyst/service/model/LnZapEvent.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/model/LnZapEvent.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/model/LnZapEvent.kt index b8845b8d5..e30336284 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/model/LnZapEvent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/model/LnZapEvent.kt @@ -33,12 +33,17 @@ class LnZapEvent( } override fun amount(): BigDecimal? { - return lnInvoice()?.let { LnInvoiceUtil.getAmountInSats(it) } + return amount } // Keeps this as a field because it's a heavier function used everywhere. val amount by lazy { - lnInvoice()?.let { LnInvoiceUtil.getAmountInSats(it) } + try { + lnInvoice()?.let { LnInvoiceUtil.getAmountInSats(it) } + } catch (e: Exception) { + Log.e("LnZapEvent", "Failed to Parse LnInvoice ${description()}", e) + null + } } override fun containedPost(): Event? = try { From 5a45c6d25f4f254432154eb6c8821a534c349e6a Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 10 Mar 2023 10:34:27 -0500 Subject: [PATCH 18/20] Adds Reporting menu option to badge notifications --- .../amethyst/ui/note/BadgeCompose.kt | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt index 7d63a7df6..9901856a7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt @@ -11,10 +11,12 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.Divider import androidx.compose.material.Icon +import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.MilitaryTech +import androidx.compose.material.icons.filled.MoreVert import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -112,11 +114,33 @@ fun BadgeCompose(likeSetCard: BadgeCard, modifier: Modifier = Modifier, isInnerN } Column(modifier = Modifier.padding(start = if (!isInnerNote) 10.dp else 0.dp)) { - Text( - stringResource(R.string.new_badge_award_notif), - fontWeight = FontWeight.Bold, - modifier = Modifier.padding(bottom = 5.dp) - ) + Row() { + Text( + stringResource(R.string.new_badge_award_notif), + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(bottom = 5.dp).weight(1f) + ) + + Text( + timeAgo(note.createdAt(), context = context), + color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f), + maxLines = 1 + ) + + IconButton( + modifier = Modifier.then(Modifier.size(24.dp)), + onClick = { popupExpanded = true } + ) { + Icon( + imageVector = Icons.Default.MoreVert, + null, + modifier = Modifier.size(15.dp), + tint = MaterialTheme.colors.onSurface.copy(alpha = 0.32f) + ) + + NoteDropDownMenu(note, popupExpanded, { popupExpanded = false }, accountViewModel) + } + } note.replyTo?.firstOrNull()?.let { NoteCompose( @@ -129,8 +153,6 @@ fun BadgeCompose(likeSetCard: BadgeCard, modifier: Modifier = Modifier, isInnerN ) } - NoteDropDownMenu(note, popupExpanded, { popupExpanded = false }, accountViewModel) - Divider( modifier = Modifier.padding(top = 10.dp), thickness = 0.25.dp From 8eb37f9864dd7e5a7997c8fb1af6afec165cf086 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 10 Mar 2023 10:35:07 -0500 Subject: [PATCH 19/20] Using full banners on User Profile pages and Drawer Fixes: https://github.com/vitorpamplona/amethyst/issues/247 --- .../vitorpamplona/amethyst/ui/navigation/DrawerContent.kt | 5 +++-- .../amethyst/ui/screen/loggedIn/ProfileScreen.kt | 5 ++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index fe8d41930..9ac1cb2c4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -43,6 +43,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController import androidx.navigation.NavHostController +import coil.compose.AsyncImage import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.RoboHashCache @@ -114,8 +115,8 @@ fun ProfileContent(baseAccountUser: User, modifier: Modifier = Modifier, scaffol Box { val banner = accountUser.info?.banner if (banner != null && banner.isNotBlank()) { - AsyncImageProxy( - model = ResizeImage(banner, 150.dp), + AsyncImage( + model = banner, contentDescription = stringResource(id = R.string.profile_image), contentScale = ContentScale.FillWidth, modifier = Modifier diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index 9de2a4381..198b6c5ca 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -62,7 +62,6 @@ import com.vitorpamplona.amethyst.service.model.BadgeProfilesEvent import com.vitorpamplona.amethyst.service.model.IdentityClaim import com.vitorpamplona.amethyst.service.model.ReportEvent import com.vitorpamplona.amethyst.ui.actions.NewUserMetadataView -import com.vitorpamplona.amethyst.ui.components.AsyncImageProxy import com.vitorpamplona.amethyst.ui.components.DisplayNip05ProfileStatus import com.vitorpamplona.amethyst.ui.components.InvoiceRequest import com.vitorpamplona.amethyst.ui.components.ResizeImage @@ -623,8 +622,8 @@ private fun DrawBanner(baseUser: User) { var zoomImageDialogOpen by remember { mutableStateOf(false) } if (!banner.isNullOrBlank()) { - AsyncImageProxy( - model = ResizeImage(banner, 125.dp), + AsyncImage( + model = banner, contentDescription = stringResource(id = R.string.profile_image), contentScale = ContentScale.FillWidth, modifier = Modifier From b387808a02b5a6ca761d82aace676edfbf8520f8 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 10 Mar 2023 10:46:02 -0500 Subject: [PATCH 20/20] 0.24.2 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 878ecefcd..0477fed22 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "com.vitorpamplona.amethyst" minSdk 26 targetSdk 33 - versionCode 90 - versionName "0.24.1" + versionCode 91 + versionName "0.24.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables {