diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index fe63bb677..148fdd246 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 8f1ca7d69..d4b1f7955 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -143,7 +143,7 @@ android {
composeOptions {
// Should match compose version : https://developer.android.com/jetpack/androidx/releases/compose-kotlin
- kotlinCompilerExtensionVersion "1.5.11"
+ kotlinCompilerExtensionVersion "1.5.14"
}
packagingOptions {
resources {
diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt
index 8e84dee15..86e0cb618 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt
@@ -2161,17 +2161,6 @@ class Account(
return LocalCache.getOrCreateAddressableNote(aTag)
}
- fun getFileServersNote(): AddressableNote {
- val aTag =
- ATag(
- FileServersEvent.KIND,
- userProfile().pubkeyHex,
- "",
- null,
- )
- return LocalCache.getOrCreateAddressableNote(aTag)
- }
-
fun getBlockList(): PeopleListEvent? {
return getBlockListNote().event as? PeopleListEvent
}
@@ -2180,10 +2169,6 @@ class Account(
return getMuteListNote().event as? MuteListEvent
}
- fun getFileServersList(): FileServersEvent? {
- return getFileServersNote().event as? FileServersEvent
- }
-
fun hideWord(word: String) {
val muteList = getMuteList()
@@ -2688,10 +2673,7 @@ class Account(
fun saveSearchRelayList(searchRelays: List) {
if (!isWriteable()) return
- val relayListForSearch =
- LocalCache.getOrCreateAddressableNote(
- SearchRelayListEvent.createAddressATag(signer.pubKey),
- ).event as? SearchRelayListEvent
+ val relayListForSearch = getSearchRelayList()
if (relayListForSearch != null && relayListForSearch.tags.isNotEmpty()) {
SearchRelayListEvent.updateRelayList(
@@ -2730,10 +2712,7 @@ class Account(
fun sendNip65RelayList(relays: List) {
if (!isWriteable()) return
- val nip65RelayList =
- LocalCache.getOrCreateAddressableNote(
- AdvertisedRelayListEvent.createAddressATag(signer.pubKey),
- ).event as? AdvertisedRelayListEvent
+ val nip65RelayList = getNIP65RelayList()
if (nip65RelayList != null) {
AdvertisedRelayListEvent.updateRelayList(
@@ -2755,6 +2734,43 @@ class Account(
}
}
+ fun getFileServersList(): FileServersEvent? {
+ return getFileServersNote().event as? FileServersEvent
+ }
+
+ fun getFileServersListFlow(): StateFlow {
+ return getFileServersNote().flow().metadata.stateFlow
+ }
+
+ fun getFileServersNote(): AddressableNote {
+ return LocalCache.getOrCreateAddressableNote(FileServersEvent.createAddressATag(userProfile().pubkeyHex))
+ }
+
+ fun sendFileServersList(servers: List) {
+ if (!isWriteable()) return
+
+ val serverList = getFileServersList()
+
+ if (serverList != null && serverList.tags.isNotEmpty()) {
+ FileServersEvent.updateRelayList(
+ earlierVersion = serverList,
+ relays = servers,
+ signer = signer,
+ ) {
+ Client.send(it)
+ LocalCache.justConsume(it, null)
+ }
+ } else {
+ FileServersEvent.createFromScratch(
+ relays = servers,
+ signer = signer,
+ ) {
+ Client.send(it)
+ LocalCache.justConsume(it, null)
+ }
+ }
+ }
+
fun setHideDeleteRequestDialog() {
hideDeleteRequestDialog = true
saveable.invalidateData()
diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt
index b63052cb2..d7dfc7268 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt
@@ -45,6 +45,7 @@ import com.vitorpamplona.quartz.events.DraftEvent
import com.vitorpamplona.quartz.events.EmojiPackSelectionEvent
import com.vitorpamplona.quartz.events.Event
import com.vitorpamplona.quartz.events.EventInterface
+import com.vitorpamplona.quartz.events.FileServersEvent
import com.vitorpamplona.quartz.events.GenericRepostEvent
import com.vitorpamplona.quartz.events.GiftWrapEvent
import com.vitorpamplona.quartz.events.GitIssueEvent
@@ -123,6 +124,7 @@ object NostrAccountDataSource : NostrDataSource("AccountData") {
AdvertisedRelayListEvent.KIND,
ChatMessageRelayListEvent.KIND,
SearchRelayListEvent.KIND,
+ FileServersEvent.KIND,
MuteListEvent.KIND,
PeopleListEvent.KIND,
),
diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt
index 420daa637..c37b11250 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomListScreen.kt
@@ -42,7 +42,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.Text
-import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
@@ -80,7 +79,6 @@ import com.vitorpamplona.amethyst.ui.theme.placeholderText
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
@Composable
fun ChatroomListScreen(
knownFeedViewModel: NostrChatroomListKnownFeedViewModel,
diff --git a/commons/build.gradle b/commons/build.gradle
index c139a70c8..21921a446 100644
--- a/commons/build.gradle
+++ b/commons/build.gradle
@@ -38,7 +38,7 @@ android {
}
composeOptions {
// Should match compose version : https://developer.android.com/jetpack/androidx/releases/compose-kotlin
- kotlinCompilerExtensionVersion "1.5.11"
+ kotlinCompilerExtensionVersion "1.5.14"
}
}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 90369520a..53b76b619 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -3,11 +3,10 @@ accompanistAdaptive = "0.34.0"
activityCompose = "1.9.0"
agp = "8.4.1"
androidKotlinGeohash = "1.0"
-androidLifecycle = "2.7.0"
androidxJunit = "1.2.0-beta01"
-appcompat = "1.6.1"
+appcompat = "1.7.0"
audiowaveform = "1.1.1"
-benchmark = "1.2.3"
+benchmark = "1.2.4"
benchmarkJunit4 = "1.2.4"
biometricKtx = "1.2.0-alpha05"
blurhash = "1.0.0"
@@ -21,10 +20,11 @@ gms = "4.4.1"
jacksonModuleKotlin = "2.17.1"
jna = "5.14.0"
junit = "4.13.2"
-kotlin = "1.9.23"
+kotlin = "1.9.24"
kotlinxCollectionsImmutable = "0.3.7"
languageId = "17.0.5"
lazysodiumAndroid = "5.1.0"
+lifecycleRuntimeKtx = "2.7.0"
lightcompressor = "1.3.2"
markdown = "077a2cde64"
media3 = "1.3.1"
@@ -59,10 +59,10 @@ androidx-fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", ve
androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidxJunit" }
androidx-junit-ktx = { group = "androidx.test.ext", name = "junit-ktx", version.ref = "androidxJunit" }
-androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "androidLifecycle" }
-androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidLifecycle" }
-androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "androidLifecycle" }
-androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidLifecycle" }
+androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleRuntimeKtx" }
+androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycleRuntimeKtx" }
+androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
+androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycleRuntimeKtx" }
androidx-material-icons = { group = "androidx.compose.material", name = "material-icons-extended" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-material3-windowSize = { group = "androidx.compose.material3", name = "material3-window-size-class" }
diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/FileServersEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/FileServersEvent.kt
index a2825b805..2bdbcab03 100644
--- a/quartz/src/main/java/com/vitorpamplona/quartz/events/FileServersEvent.kt
+++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/FileServersEvent.kt
@@ -21,6 +21,7 @@
package com.vitorpamplona.quartz.events
import androidx.compose.runtime.Immutable
+import com.vitorpamplona.quartz.encoders.ATag
import com.vitorpamplona.quartz.encoders.HexKey
import com.vitorpamplona.quartz.signers.NostrSigner
import com.vitorpamplona.quartz.utils.TimeUtils
@@ -36,24 +37,68 @@ class FileServersEvent(
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
override fun dTag() = FIXED_D_TAG
+ fun servers(): List {
+ return tags.mapNotNull {
+ if (it.size > 1 && it[0] == "relay") {
+ it[1]
+ } else {
+ null
+ }
+ }
+ }
+
companion object {
const val KIND = 10096
const val FIXED_D_TAG = ""
const val ALT = "File servers used by the author"
- fun create(
- listOfServers: List,
+ fun createAddressATag(pubKey: HexKey): ATag {
+ return ATag(KIND, pubKey, FIXED_D_TAG, null)
+ }
+
+ fun createAddressTag(pubKey: HexKey): String {
+ return ATag.assembleATag(KIND, pubKey, FIXED_D_TAG)
+ }
+
+ fun createTagArray(servers: List): Array> {
+ return servers.map {
+ arrayOf("server", it)
+ }.plusElement(arrayOf("alt", "Relay list to use for Search")).toTypedArray()
+ }
+
+ fun updateRelayList(
+ earlierVersion: FileServersEvent,
+ relays: List,
signer: NostrSigner,
createdAt: Long = TimeUtils.now(),
onReady: (FileServersEvent) -> Unit,
) {
- val msg = ""
- val tags = mutableListOf>()
+ val tags =
+ earlierVersion.tags.filter { it[0] != "server" }.plus(
+ relays.map {
+ arrayOf("server", it)
+ },
+ ).toTypedArray()
- listOfServers.forEach { tags.add(arrayOf("server", it)) }
- tags.add(arrayOf("alt", ALT))
+ signer.sign(createdAt, KIND, tags, earlierVersion.content, onReady)
+ }
- signer.sign(createdAt, KIND, tags.toTypedArray(), msg, onReady)
+ fun createFromScratch(
+ relays: List,
+ signer: NostrSigner,
+ createdAt: Long = TimeUtils.now(),
+ onReady: (FileServersEvent) -> Unit,
+ ) {
+ create(relays, signer, createdAt, onReady)
+ }
+
+ fun create(
+ servers: List,
+ signer: NostrSigner,
+ createdAt: Long = TimeUtils.now(),
+ onReady: (FileServersEvent) -> Unit,
+ ) {
+ signer.sign(createdAt, KIND, createTagArray(servers), "", onReady)
}
}
}