Merge branch 'vitorpamplona:main' into profiles-list-management
This commit is contained in:
@@ -2632,7 +2632,7 @@ object LocalCache : ILocalCache {
|
|||||||
// updates relay with a new event.
|
// updates relay with a new event.
|
||||||
getAddressableNoteIfExists(event.address())?.let { note ->
|
getAddressableNoteIfExists(event.address())?.let { note ->
|
||||||
note.event?.let { existingEvent ->
|
note.event?.let { existingEvent ->
|
||||||
if (existingEvent.createdAt > event.createdAt && !note.hasRelay(relay.url) && !deletionIndex.hasBeenDeleted(event)) {
|
if (existingEvent.createdAt > event.createdAt && !note.hasRelay(relay.url) && !deletionIndex.hasBeenDeleted(event) && !event.isExpired()) {
|
||||||
if (isDebug) {
|
if (isDebug) {
|
||||||
Log.d("LocalCache", "Updating ${relay.url.url} with a new version of ${event.kind} ${event.id} to ${existingEvent.id}")
|
Log.d("LocalCache", "Updating ${relay.url.url} with a new version of ${event.kind} ${event.id} to ${existingEvent.id}")
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-4
@@ -57,10 +57,11 @@ class SearchRelayListState(
|
|||||||
|
|
||||||
fun getSearchRelayList(): SearchRelayListEvent? = getSearchRelayListNote().event as? SearchRelayListEvent
|
fun getSearchRelayList(): SearchRelayListEvent? = getSearchRelayListNote().event as? SearchRelayListEvent
|
||||||
|
|
||||||
suspend fun normalizeSearchRelayListWithBackup(note: Note): Set<NormalizedRelayUrl> {
|
fun searchListEvent(note: Note) = note.event as? SearchRelayListEvent ?: settings.backupSearchRelayList
|
||||||
val event = note.event as? SearchRelayListEvent ?: settings.backupSearchRelayList
|
|
||||||
return event?.let { decryptionCache.relays(it) } ?: DefaultSearchRelayList
|
suspend fun normalizeSearchRelayListWithBackup(note: Note): Set<NormalizedRelayUrl> = searchListEvent(note)?.let { decryptionCache.relays(it) }?.ifEmpty { null } ?: DefaultSearchRelayList
|
||||||
}
|
|
||||||
|
suspend fun normalizeSearchRelayListWithBackupNoDefaults(note: Note): Set<NormalizedRelayUrl> = searchListEvent(note)?.let { decryptionCache.relays(it) } ?: emptySet()
|
||||||
|
|
||||||
val flow =
|
val flow =
|
||||||
getSearchRelayListFlow()
|
getSearchRelayListFlow()
|
||||||
@@ -73,6 +74,17 @@ class SearchRelayListState(
|
|||||||
emptySet(),
|
emptySet(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val flowNoDefaults =
|
||||||
|
getSearchRelayListFlow()
|
||||||
|
.map { normalizeSearchRelayListWithBackupNoDefaults(it.note) }
|
||||||
|
.onStart { emit(normalizeSearchRelayListWithBackupNoDefaults(getSearchRelayListNote())) }
|
||||||
|
.flowOn(Dispatchers.Default)
|
||||||
|
.stateIn(
|
||||||
|
scope,
|
||||||
|
SharingStarted.Companion.Eagerly,
|
||||||
|
emptySet(),
|
||||||
|
)
|
||||||
|
|
||||||
suspend fun saveRelayList(searchRelays: List<NormalizedRelayUrl>): SearchRelayListEvent {
|
suspend fun saveRelayList(searchRelays: List<NormalizedRelayUrl>): SearchRelayListEvent {
|
||||||
val relayListForSearch = getSearchRelayList()
|
val relayListForSearch = getSearchRelayList()
|
||||||
|
|
||||||
|
|||||||
+18
-12
@@ -57,20 +57,15 @@ class Nip65RelayListState(
|
|||||||
|
|
||||||
fun getNIP65RelayList(): AdvertisedRelayListEvent? = getNIP65RelayListNote().event as? AdvertisedRelayListEvent
|
fun getNIP65RelayList(): AdvertisedRelayListEvent? = getNIP65RelayListNote().event as? AdvertisedRelayListEvent
|
||||||
|
|
||||||
fun normalizeNIP65WriteRelayListWithBackup(note: Note): Set<NormalizedRelayUrl> {
|
fun nip65Event(note: Note) = note.event as? AdvertisedRelayListEvent ?: settings.backupNIP65RelayList
|
||||||
val event = note.event as? AdvertisedRelayListEvent ?: settings.backupNIP65RelayList
|
|
||||||
return event?.writeRelaysNorm()?.toSet() ?: Constants.eventFinderRelays
|
|
||||||
}
|
|
||||||
|
|
||||||
fun normalizeNIP65ReadRelayListWithBackup(note: Note): Set<NormalizedRelayUrl> {
|
fun normalizeNIP65WriteRelayListWithBackup(note: Note): Set<NormalizedRelayUrl> = nip65Event(note)?.writeRelaysNorm()?.toSet() ?: Constants.eventFinderRelays
|
||||||
val event = note.event as? AdvertisedRelayListEvent ?: settings.backupNIP65RelayList
|
|
||||||
return event?.readRelaysNorm()?.toSet() ?: Constants.eventFinderRelays
|
|
||||||
}
|
|
||||||
|
|
||||||
fun normalizeNIP65AllRelayListWithBackup(note: Note): Set<NormalizedRelayUrl> {
|
fun normalizeNIP65ReadRelayListWithBackup(note: Note): Set<NormalizedRelayUrl> = nip65Event(note)?.readRelaysNorm()?.toSet() ?: Constants.eventFinderRelays
|
||||||
val event = note.event as? AdvertisedRelayListEvent ?: settings.backupNIP65RelayList
|
|
||||||
return event?.relays()?.map { it.relayUrl }?.toSet() ?: Constants.eventFinderRelays
|
fun normalizeNIP65AllRelayListWithBackup(note: Note): Set<NormalizedRelayUrl> = nip65Event(note)?.relays()?.map { it.relayUrl }?.toSet() ?: Constants.eventFinderRelays
|
||||||
}
|
|
||||||
|
fun normalizeNIP65AllRelayListWithBackupNoDefaults(note: Note): Set<NormalizedRelayUrl> = nip65Event(note)?.relays()?.map { it.relayUrl }?.toSet() ?: emptySet()
|
||||||
|
|
||||||
val outboxFlow =
|
val outboxFlow =
|
||||||
getNIP65RelayListFlow()
|
getNIP65RelayListFlow()
|
||||||
@@ -105,6 +100,17 @@ class Nip65RelayListState(
|
|||||||
emptySet(),
|
emptySet(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val allFlowNoDefaults =
|
||||||
|
getNIP65RelayListFlow()
|
||||||
|
.map { normalizeNIP65AllRelayListWithBackupNoDefaults(it.note) }
|
||||||
|
.onStart { emit(normalizeNIP65AllRelayListWithBackupNoDefaults(getNIP65RelayListNote())) }
|
||||||
|
.flowOn(Dispatchers.Default)
|
||||||
|
.stateIn(
|
||||||
|
scope,
|
||||||
|
SharingStarted.Eagerly,
|
||||||
|
emptySet(),
|
||||||
|
)
|
||||||
|
|
||||||
suspend fun saveRelayList(relays: List<AdvertisedRelayInfo>): AdvertisedRelayListEvent {
|
suspend fun saveRelayList(relays: List<AdvertisedRelayInfo>): AdvertisedRelayListEvent {
|
||||||
val nip65RelayList = getNIP65RelayList()
|
val nip65RelayList = getNIP65RelayList()
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -52,11 +52,11 @@ class TrustedRelayListsState(
|
|||||||
val flow: StateFlow<Set<NormalizedRelayUrl>> =
|
val flow: StateFlow<Set<NormalizedRelayUrl>> =
|
||||||
combine(
|
combine(
|
||||||
listOf(
|
listOf(
|
||||||
nip65RelayList.allFlow,
|
nip65RelayList.allFlowNoDefaults,
|
||||||
privateOutboxRelayList.flow,
|
privateOutboxRelayList.flow,
|
||||||
localRelayList.flow,
|
localRelayList.flow,
|
||||||
dmRelayList.flow,
|
dmRelayList.flow,
|
||||||
searchRelayListState.flow,
|
searchRelayListState.flowNoDefaults,
|
||||||
trustedRelayList.flow,
|
trustedRelayList.flow,
|
||||||
broadcastRelayList.flow,
|
broadcastRelayList.flow,
|
||||||
),
|
),
|
||||||
|
|||||||
+1
-1
@@ -167,7 +167,7 @@ class EventNotificationConsumer(
|
|||||||
|
|
||||||
// this is not verifiable
|
// this is not verifiable
|
||||||
if (LocalCache.justConsume(inner, null, true)) {
|
if (LocalCache.justConsume(inner, null, true)) {
|
||||||
event
|
inner
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-10
@@ -20,9 +20,11 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.ActivityNotFoundException
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
@@ -30,11 +32,13 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.lifecycle.compose.LifecycleResumeEffect
|
import androidx.lifecycle.compose.LifecycleResumeEffect
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||||
|
import com.google.accompanist.permissions.isGranted
|
||||||
|
import com.google.accompanist.permissions.rememberPermissionState
|
||||||
import com.vitorpamplona.amethyst.Amethyst
|
import com.vitorpamplona.amethyst.Amethyst
|
||||||
import com.vitorpamplona.amethyst.LocalPreferences
|
import com.vitorpamplona.amethyst.LocalPreferences
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
@@ -43,6 +47,7 @@ import com.vitorpamplona.amethyst.service.notifications.PushNotificationUtils
|
|||||||
import com.vitorpamplona.amethyst.service.relayClient.authCommand.compose.RelayAuthSubscription
|
import com.vitorpamplona.amethyst.service.relayClient.authCommand.compose.RelayAuthSubscription
|
||||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountFilterAssemblerSubscription
|
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountFilterAssemblerSubscription
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.AppNavigation
|
import com.vitorpamplona.amethyst.ui.navigation.AppNavigation
|
||||||
|
import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav.scope
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||||
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
|
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel
|
import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel
|
||||||
@@ -51,7 +56,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.datasource.Discove
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.HomeFilterAssemblerSubscription
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.HomeFilterAssemblerSubscription
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.datasource.VideoFilterAssemblerSubscription
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.datasource.VideoFilterAssemblerSubscription
|
||||||
import com.vitorpamplona.quartz.nip55AndroidSigner.client.IActivityLauncher
|
import com.vitorpamplona.quartz.nip55AndroidSigner.client.IActivityLauncher
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -140,15 +144,31 @@ fun ManageRelayServices(accountViewModel: AccountViewModel) {
|
|||||||
.collectAsStateWithLifecycle()
|
.collectAsStateWithLifecycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalPermissionsApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun NotificationRegistration(accountViewModel: AccountViewModel) {
|
fun NotificationRegistration(accountViewModel: AccountViewModel) {
|
||||||
val scope = rememberCoroutineScope()
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
var job = remember<Job?> { null }
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
LifecycleResumeEffect(key1 = accountViewModel) {
|
val notificationPermissionState = rememberPermissionState(Manifest.permission.POST_NOTIFICATIONS)
|
||||||
Log.d("RegisterAccounts", "Registering for push notifications")
|
|
||||||
job?.cancel()
|
if (notificationPermissionState.status.isGranted) {
|
||||||
job =
|
LifecycleResumeEffect(key1 = accountViewModel, notificationPermissionState.status.isGranted) {
|
||||||
|
Log.d("RegisterAccounts", "Registering for push notifications $notificationPermissionState")
|
||||||
|
scope.launch {
|
||||||
|
PushNotificationUtils.checkAndInit(
|
||||||
|
LocalPreferences.allSavedAccounts(),
|
||||||
|
accountViewModel::okHttpClientForTrustedRelays,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
onPauseOrDispose {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// no need for push permissions before 33
|
||||||
|
LifecycleResumeEffect(key1 = accountViewModel) {
|
||||||
|
Log.d("RegisterAccounts", "Registering for push notifications")
|
||||||
scope.launch {
|
scope.launch {
|
||||||
PushNotificationUtils.checkAndInit(
|
PushNotificationUtils.checkAndInit(
|
||||||
LocalPreferences.allSavedAccounts(),
|
LocalPreferences.allSavedAccounts(),
|
||||||
@@ -156,8 +176,7 @@ fun NotificationRegistration(accountViewModel: AccountViewModel) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
onPauseOrDispose {
|
onPauseOrDispose {}
|
||||||
job.cancel()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-5
@@ -68,11 +68,8 @@ class ChatMessageRelayListEvent(
|
|||||||
val tags =
|
val tags =
|
||||||
earlierVersion.tags
|
earlierVersion.tags
|
||||||
.filter(RelayTag::notMatch)
|
.filter(RelayTag::notMatch)
|
||||||
.plus(
|
.plus(relays.map { RelayTag.assemble(it) })
|
||||||
relays.map {
|
.toTypedArray()
|
||||||
RelayTag.assemble(it)
|
|
||||||
},
|
|
||||||
).toTypedArray()
|
|
||||||
|
|
||||||
return signer.sign(createdAt, KIND, tags, earlierVersion.content)
|
return signer.sign(createdAt, KIND, tags, earlierVersion.content)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class RelayTag {
|
|||||||
fun match(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
fun match(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun notMatch(tag: Array<String>) = tag.has(0) && tag[0] == TAG_NAME
|
fun notMatch(tag: Array<String>) = !(tag.has(0) && tag[0] == TAG_NAME)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun parse(tag: Array<String>): NormalizedRelayUrl? {
|
fun parse(tag: Array<String>): NormalizedRelayUrl? {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class RelayTag {
|
|||||||
fun match(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
fun match(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun notMatch(tag: Array<String>) = tag.has(0) && tag[0] == TAG_NAME
|
fun notMatch(tag: Array<String>) = !(tag.has(0) && tag[0] == TAG_NAME)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun parse(tag: Array<String>): NormalizedRelayUrl? {
|
fun parse(tag: Array<String>): NormalizedRelayUrl? {
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ class RelayTag {
|
|||||||
fun match(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
fun match(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun notMatch(tag: Array<String>) = tag.has(0) && tag[0] == TAG_NAME
|
fun notMatch(tag: Array<String>) = !(tag.has(0) && tag[0] == TAG_NAME)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun parse(tag: Array<String>): NormalizedRelayUrl? {
|
fun parse(tag: Array<String>): NormalizedRelayUrl? {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class RelayTag {
|
|||||||
fun match(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
fun match(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun notMatch(tag: Array<String>) = tag.has(0) && tag[0] == TAG_NAME
|
fun notMatch(tag: Array<String>) = !(tag.has(0) && tag[0] == TAG_NAME)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun parse(tag: Array<String>): NormalizedRelayUrl? {
|
fun parse(tag: Array<String>): NormalizedRelayUrl? {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class RelayTag {
|
|||||||
fun match(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
fun match(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun notMatch(tag: Array<String>) = tag.has(0) && tag[0] == TAG_NAME
|
fun notMatch(tag: Array<String>) = !(tag.has(0) && tag[0] == TAG_NAME)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun shouldVanishFrom(
|
fun shouldVanishFrom(
|
||||||
|
|||||||
+1
-1
@@ -38,7 +38,7 @@ class AdvertisedRelayInfo(
|
|||||||
|
|
||||||
fun match(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
fun match(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
||||||
|
|
||||||
fun notMatch(tag: Array<String>) = !match(tag)
|
fun notMatch(tag: Array<String>) = !(tag.has(0) && tag[0] == TAG_NAME)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun parse(tag: Array<String>): AdvertisedRelayInfo? {
|
fun parse(tag: Array<String>): AdvertisedRelayInfo? {
|
||||||
|
|||||||
Reference in New Issue
Block a user