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 51f7a456f..beda7ef2f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -592,7 +592,7 @@ class Account( return keyPair.privKey != null || signer is NostrSignerExternal } - fun sendNewRelayList(relays: Map) { + fun sendKind3RelayList(relays: Map) { if (!isWriteable()) return val contactList = userProfile().latestContactList @@ -2685,10 +2685,10 @@ class Account( .toSet() } - fun saveRelayList(value: List) { + fun saveKind3RelayList(value: List) { try { localRelays = value.toSet() - return sendNewRelayList( + return sendKind3RelayList( value.associate { it.url to ContactListEvent.ReadWrite(it.read, it.write) }, ) } finally { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoModel.kt new file mode 100644 index 000000000..da4339aaf --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/BasicRelaySetupInfoModel.kt @@ -0,0 +1,121 @@ +/** + * Copyright (c) 2024 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.ui.actions.relays + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.service.Nip11CachedRetriever +import com.vitorpamplona.amethyst.service.relays.RelayPool +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch + +abstract class BasicRelaySetupInfoModel : ViewModel() { + lateinit var account: Account + + private val _relays = MutableStateFlow>(emptyList()) + val relays = _relays.asStateFlow() + + var hasModified = false + + fun load(account: Account) { + this.account = account + clear() + loadRelayDocuments() + } + + abstract fun getRelayList(): List? + + abstract fun saveRelayList(urlList: List) + + fun create() { + if (hasModified) { + viewModelScope.launch(Dispatchers.IO) { + saveRelayList(_relays.value.map { it.url }) + clear() + } + } + } + + fun loadRelayDocuments() { + viewModelScope.launch(Dispatchers.IO) { + _relays.value.forEach { item -> + Nip11CachedRetriever.loadRelayInfo( + dirtyUrl = item.url, + onInfo = { + togglePaidRelay(item, it.limitation?.payment_required ?: false) + }, + onError = { url, errorCode, exceptionMessage -> }, + ) + } + } + } + + fun clear() { + var hasModified = false + _relays.update { + val relayList = getRelayList() ?: emptyList() + + relayList.map { relayUrl -> + val liveRelay = RelayPool.getRelay(relayUrl) + val errorCounter = liveRelay?.errorCounter ?: 0 + val eventDownloadCounter = liveRelay?.eventDownloadCounterInBytes ?: 0 + val eventUploadCounter = liveRelay?.eventUploadCounterInBytes ?: 0 + val spamCounter = liveRelay?.spamCounter ?: 0 + + BasicRelaySetupInfo( + relayUrl, + errorCounter, + eventDownloadCounter, + eventUploadCounter, + spamCounter, + ) + }.distinctBy { it.url }.sortedBy { it.downloadCountInBytes }.reversed() + } + } + + fun addRelay(relay: BasicRelaySetupInfo) { + if (relays.value.any { it.url == relay.url }) return + + _relays.update { it.plus(relay) } + hasModified = true + } + + fun deleteRelay(relay: BasicRelaySetupInfo) { + _relays.update { it.minus(relay) } + hasModified = true + } + + fun deleteAll() { + _relays.update { relays -> emptyList() } + hasModified = true + } + + fun togglePaidRelay( + relay: BasicRelaySetupInfo, + paid: Boolean, + ) { + _relays.update { it.updated(relay, relay.copy(paidRelay = paid)) } + } +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListViewModel.kt index 40b8ab83b..27c0534ec 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/DMRelayListViewModel.kt @@ -20,90 +20,12 @@ */ package com.vitorpamplona.amethyst.ui.actions.relays -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.Nip11CachedRetriever -import com.vitorpamplona.amethyst.service.relays.RelayPool -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch - -class DMRelayListViewModel : ViewModel() { - private lateinit var account: Account - - private val _relays = MutableStateFlow>(emptyList()) - val relays = _relays.asStateFlow() - - fun load(account: Account) { - this.account = account - clear() - loadRelayDocuments() +class DMRelayListViewModel : BasicRelaySetupInfoModel() { + override fun getRelayList(): List? { + return account.getDMRelayList()?.relays() } - fun create() { - viewModelScope.launch(Dispatchers.IO) { - account.saveDMRelayList(_relays.value.map { it.url }) - clear() - } - } - - fun loadRelayDocuments() { - viewModelScope.launch(Dispatchers.IO) { - _relays.value.forEach { item -> - Nip11CachedRetriever.loadRelayInfo( - dirtyUrl = item.url, - onInfo = { - togglePaidRelay(item, it.limitation?.payment_required ?: false) - }, - onError = { url, errorCode, exceptionMessage -> }, - ) - } - } - } - - fun clear() { - _relays.update { - val relayList = account.getDMRelayList()?.relays() ?: emptyList() - - relayList.map { relayUrl -> - val liveRelay = RelayPool.getRelay(relayUrl) - val errorCounter = liveRelay?.errorCounter ?: 0 - val eventDownloadCounter = liveRelay?.eventDownloadCounterInBytes ?: 0 - val eventUploadCounter = liveRelay?.eventUploadCounterInBytes ?: 0 - val spamCounter = liveRelay?.spamCounter ?: 0 - - BasicRelaySetupInfo( - relayUrl, - errorCounter, - eventDownloadCounter, - eventUploadCounter, - spamCounter, - ) - }.distinctBy { it.url }.sortedBy { it.downloadCountInBytes }.reversed() - } - } - - fun addRelay(relay: BasicRelaySetupInfo) { - if (relays.value.any { it.url == relay.url }) return - - _relays.update { it.plus(relay) } - } - - fun deleteRelay(relay: BasicRelaySetupInfo) { - _relays.update { it.minus(relay) } - } - - fun deleteAll() { - _relays.update { relays -> emptyList() } - } - - fun togglePaidRelay( - relay: BasicRelaySetupInfo, - paid: Boolean, - ) { - _relays.update { it.updated(relay, relay.copy(paidRelay = paid)) } + override fun saveRelayList(urlList: List) { + account.saveDMRelayList(urlList) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListViewModel.kt index 15cad6913..b98e0b409 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Kind3RelayListViewModel.kt @@ -41,6 +41,8 @@ class Kind3RelayListViewModel : ViewModel() { private val _relays = MutableStateFlow>(emptyList()) val relays = _relays.asStateFlow() + var hasModified = false + fun load(account: Account) { this.account = account clear() @@ -48,9 +50,9 @@ class Kind3RelayListViewModel : ViewModel() { } fun create() { - relays.let { + if (hasModified) { viewModelScope.launch(Dispatchers.IO) { - account.saveRelayList(it.value) + account.saveKind3RelayList(relays.value) clear() } } @@ -71,6 +73,7 @@ class Kind3RelayListViewModel : ViewModel() { } fun clear() { + hasModified = false _relays.update { var relayFile = account.userProfile().latestContactList?.relays() @@ -140,47 +143,58 @@ class Kind3RelayListViewModel : ViewModel() { if (relays.value.any { it.url == relay.url }) return _relays.update { it.plus(relay) } + + hasModified = true } fun deleteRelay(relay: RelaySetupInfo) { _relays.update { it.minus(relay) } + hasModified = true } fun deleteAll() { _relays.update { relays -> emptyList() } + hasModified = true } fun toggleDownload(relay: RelaySetupInfo) { _relays.update { it.updated(relay, relay.copy(read = !relay.read)) } + hasModified = true } fun toggleUpload(relay: RelaySetupInfo) { _relays.update { it.updated(relay, relay.copy(write = !relay.write)) } + hasModified = true } fun toggleFollows(relay: RelaySetupInfo) { val newTypes = togglePresenceInSet(relay.feedTypes, FeedType.FOLLOWS) _relays.update { it.updated(relay, relay.copy(feedTypes = newTypes)) } + hasModified = true } fun toggleMessages(relay: RelaySetupInfo) { val newTypes = togglePresenceInSet(relay.feedTypes, FeedType.PRIVATE_DMS) _relays.update { it.updated(relay, relay.copy(feedTypes = newTypes)) } + hasModified = true } fun togglePublicChats(relay: RelaySetupInfo) { val newTypes = togglePresenceInSet(relay.feedTypes, FeedType.PUBLIC_CHATS) _relays.update { it.updated(relay, relay.copy(feedTypes = newTypes)) } + hasModified = true } fun toggleGlobal(relay: RelaySetupInfo) { val newTypes = togglePresenceInSet(relay.feedTypes, FeedType.GLOBAL) _relays.update { it.updated(relay, relay.copy(feedTypes = newTypes)) } + hasModified = true } fun toggleSearch(relay: RelaySetupInfo) { val newTypes = togglePresenceInSet(relay.feedTypes, FeedType.SEARCH) _relays.update { it.updated(relay, relay.copy(feedTypes = newTypes)) } + hasModified = true } fun togglePaidRelay( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListViewModel.kt index d26c7e3ee..6c5359b36 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/LocalRelayListViewModel.kt @@ -20,90 +20,12 @@ */ package com.vitorpamplona.amethyst.ui.actions.relays -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.Nip11CachedRetriever -import com.vitorpamplona.amethyst.service.relays.RelayPool -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch - -class LocalRelayListViewModel : ViewModel() { - private lateinit var account: Account - - private val _relays = MutableStateFlow>(emptyList()) - val relays = _relays.asStateFlow() - - fun load(account: Account) { - this.account = account - clear() - loadRelayDocuments() +class LocalRelayListViewModel : BasicRelaySetupInfoModel() { + override fun getRelayList(): List? { + return account.localRelayServers.toList() } - fun create() { - viewModelScope.launch(Dispatchers.IO) { - account.updateLocalRelayServers(_relays.value.map { it.url }.toSet()) - clear() - } - } - - fun loadRelayDocuments() { - viewModelScope.launch(Dispatchers.IO) { - _relays.value.forEach { item -> - Nip11CachedRetriever.loadRelayInfo( - dirtyUrl = item.url, - onInfo = { - togglePaidRelay(item, it.limitation?.payment_required ?: false) - }, - onError = { url, errorCode, exceptionMessage -> }, - ) - } - } - } - - fun clear() { - _relays.update { - val relayList = account.localRelayServers ?: emptyList() - - relayList.map { relayUrl -> - val liveRelay = RelayPool.getRelay(relayUrl) - val errorCounter = liveRelay?.errorCounter ?: 0 - val eventDownloadCounter = liveRelay?.eventDownloadCounterInBytes ?: 0 - val eventUploadCounter = liveRelay?.eventUploadCounterInBytes ?: 0 - val spamCounter = liveRelay?.spamCounter ?: 0 - - BasicRelaySetupInfo( - relayUrl, - errorCounter, - eventDownloadCounter, - eventUploadCounter, - spamCounter, - ) - }.distinctBy { it.url }.sortedBy { it.downloadCountInBytes }.reversed() - } - } - - fun addRelay(relay: BasicRelaySetupInfo) { - if (relays.value.any { it.url == relay.url }) return - - _relays.update { it.plus(relay) } - } - - fun deleteRelay(relay: BasicRelaySetupInfo) { - _relays.update { it.minus(relay) } - } - - fun deleteAll() { - _relays.update { relays -> emptyList() } - } - - fun togglePaidRelay( - relay: BasicRelaySetupInfo, - paid: Boolean, - ) { - _relays.update { it.updated(relay, relay.copy(paidRelay = paid)) } + override fun saveRelayList(urlList: List) { + account.updateLocalRelayServers(urlList.toSet()) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListViewModel.kt index b71f18b0a..0fcd184b8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/Nip65RelayListViewModel.kt @@ -41,6 +41,8 @@ class Nip65RelayListViewModel : ViewModel() { private val _notificationRelays = MutableStateFlow>(emptyList()) val notificationRelays = _notificationRelays.asStateFlow() + var hasModified = false + fun load(account: Account) { this.account = account clear() @@ -48,26 +50,28 @@ class Nip65RelayListViewModel : ViewModel() { } fun create() { - viewModelScope.launch(Dispatchers.IO) { - val writes = _homeRelays.value.map { it.url }.toSet() - val reads = _notificationRelays.value.map { it.url }.toSet() + if (hasModified) { + viewModelScope.launch(Dispatchers.IO) { + val writes = _homeRelays.value.map { it.url }.toSet() + val reads = _notificationRelays.value.map { it.url }.toSet() - val urls = writes.union(reads) + val urls = writes.union(reads) - account.sendNip65RelayList( - urls.map { - val type = - if (writes.contains(it) && reads.contains(it)) { - AdvertisedRelayListEvent.AdvertisedRelayType.BOTH - } else if (writes.contains(it)) { - AdvertisedRelayListEvent.AdvertisedRelayType.WRITE - } else { - AdvertisedRelayListEvent.AdvertisedRelayType.READ - } - AdvertisedRelayListEvent.AdvertisedRelayInfo(it, type) - }, - ) - clear() + account.sendNip65RelayList( + urls.map { + val type = + if (writes.contains(it) && reads.contains(it)) { + AdvertisedRelayListEvent.AdvertisedRelayType.BOTH + } else if (writes.contains(it)) { + AdvertisedRelayListEvent.AdvertisedRelayType.WRITE + } else { + AdvertisedRelayListEvent.AdvertisedRelayType.READ + } + AdvertisedRelayListEvent.AdvertisedRelayInfo(it, type) + }, + ) + clear() + } } } @@ -96,18 +100,19 @@ class Nip65RelayListViewModel : ViewModel() { } fun clear() { + hasModified = false _homeRelays.update { - val relayList = account.getNIP65RelayList()?.relays() ?: emptyList() + val relayList = account.getNIP65RelayList()?.writeRelays() ?: emptyList() - relayList.filter { it.type == AdvertisedRelayListEvent.AdvertisedRelayType.BOTH || it.type == AdvertisedRelayListEvent.AdvertisedRelayType.WRITE }.map { relayUrl -> - val liveRelay = RelayPool.getRelay(relayUrl.relayUrl) + relayList.map { relayUrl -> + val liveRelay = RelayPool.getRelay(relayUrl) val errorCounter = liveRelay?.errorCounter ?: 0 val eventDownloadCounter = liveRelay?.eventDownloadCounterInBytes ?: 0 val eventUploadCounter = liveRelay?.eventUploadCounterInBytes ?: 0 val spamCounter = liveRelay?.spamCounter ?: 0 BasicRelaySetupInfo( - relayUrl.relayUrl, + relayUrl, errorCounter, eventDownloadCounter, eventUploadCounter, @@ -117,17 +122,17 @@ class Nip65RelayListViewModel : ViewModel() { } _notificationRelays.update { - val relayList = account.getNIP65RelayList()?.relays() ?: emptyList() + val relayList = account.getNIP65RelayList()?.readRelays() ?: emptyList() - relayList.filter { it.type == AdvertisedRelayListEvent.AdvertisedRelayType.BOTH || it.type == AdvertisedRelayListEvent.AdvertisedRelayType.READ }.map { relayUrl -> - val liveRelay = RelayPool.getRelay(relayUrl.relayUrl) + relayList.map { relayUrl -> + val liveRelay = RelayPool.getRelay(relayUrl) val errorCounter = liveRelay?.errorCounter ?: 0 val eventDownloadCounter = liveRelay?.eventDownloadCounterInBytes ?: 0 val eventUploadCounter = liveRelay?.eventUploadCounterInBytes ?: 0 val spamCounter = liveRelay?.spamCounter ?: 0 BasicRelaySetupInfo( - relayUrl.relayUrl, + relayUrl, errorCounter, eventDownloadCounter, eventUploadCounter, @@ -141,14 +146,17 @@ class Nip65RelayListViewModel : ViewModel() { if (_homeRelays.value.any { it.url == relay.url }) return _homeRelays.update { it.plus(relay) } + hasModified = true } fun deleteHomeRelay(relay: BasicRelaySetupInfo) { _homeRelays.update { it.minus(relay) } + hasModified = true } fun deleteHomeAll() { _homeRelays.update { relays -> emptyList() } + hasModified = true } fun toggleHomePaidRelay( @@ -162,14 +170,17 @@ class Nip65RelayListViewModel : ViewModel() { if (_notificationRelays.value.any { it.url == relay.url }) return _notificationRelays.update { it.plus(relay) } + hasModified = true } fun deleteNotifRelay(relay: BasicRelaySetupInfo) { _notificationRelays.update { it.minus(relay) } + hasModified = true } fun deleteNotifAll() { _notificationRelays.update { relays -> emptyList() } + hasModified = true } fun toggleNotifPaidRelay( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListViewModel.kt index c84f5b88f..8d5ce7837 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/PrivateOutboxRelayListViewModel.kt @@ -20,90 +20,12 @@ */ package com.vitorpamplona.amethyst.ui.actions.relays -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.Nip11CachedRetriever -import com.vitorpamplona.amethyst.service.relays.RelayPool -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch - -class PrivateOutboxRelayListViewModel : ViewModel() { - private lateinit var account: Account - - private val _relays = MutableStateFlow>(emptyList()) - val relays = _relays.asStateFlow() - - fun load(account: Account) { - this.account = account - clear() - loadRelayDocuments() +class PrivateOutboxRelayListViewModel : BasicRelaySetupInfoModel() { + override fun getRelayList(): List? { + return account.getPrivateOutboxRelayList()?.relays() } - fun create() { - viewModelScope.launch(Dispatchers.IO) { - account.savePrivateOutboxRelayList(_relays.value.map { it.url }) - clear() - } - } - - fun loadRelayDocuments() { - viewModelScope.launch(Dispatchers.IO) { - _relays.value.forEach { item -> - Nip11CachedRetriever.loadRelayInfo( - dirtyUrl = item.url, - onInfo = { - togglePaidRelay(item, it.limitation?.payment_required ?: false) - }, - onError = { url, errorCode, exceptionMessage -> }, - ) - } - } - } - - fun clear() { - _relays.update { - val relayList = account.getPrivateOutboxRelayList()?.relays() ?: emptyList() - - relayList.map { relayUrl -> - val liveRelay = RelayPool.getRelay(relayUrl) - val errorCounter = liveRelay?.errorCounter ?: 0 - val eventDownloadCounter = liveRelay?.eventDownloadCounterInBytes ?: 0 - val eventUploadCounter = liveRelay?.eventUploadCounterInBytes ?: 0 - val spamCounter = liveRelay?.spamCounter ?: 0 - - BasicRelaySetupInfo( - relayUrl, - errorCounter, - eventDownloadCounter, - eventUploadCounter, - spamCounter, - ) - }.distinctBy { it.url }.sortedBy { it.downloadCountInBytes }.reversed() - } - } - - fun addRelay(relay: BasicRelaySetupInfo) { - if (relays.value.any { it.url == relay.url }) return - - _relays.update { it.plus(relay) } - } - - fun deleteRelay(relay: BasicRelaySetupInfo) { - _relays.update { it.minus(relay) } - } - - fun deleteAll() { - _relays.update { relays -> emptyList() } - } - - fun togglePaidRelay( - relay: BasicRelaySetupInfo, - paid: Boolean, - ) { - _relays.update { it.updated(relay, relay.copy(paidRelay = paid)) } + override fun saveRelayList(urlList: List) { + account.savePrivateOutboxRelayList(urlList) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListViewModel.kt index ee0944365..da89cd245 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/relays/SearchRelayListViewModel.kt @@ -20,90 +20,12 @@ */ package com.vitorpamplona.amethyst.ui.actions.relays -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.Nip11CachedRetriever -import com.vitorpamplona.amethyst.service.relays.RelayPool -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch - -class SearchRelayListViewModel : ViewModel() { - private lateinit var account: Account - - private val _relays = MutableStateFlow>(emptyList()) - val relays = _relays.asStateFlow() - - fun load(account: Account) { - this.account = account - clear() - loadRelayDocuments() +class SearchRelayListViewModel : BasicRelaySetupInfoModel() { + override fun getRelayList(): List? { + return account.getSearchRelayList()?.relays() } - fun create() { - viewModelScope.launch(Dispatchers.IO) { - account.saveSearchRelayList(_relays.value.map { it.url }) - clear() - } - } - - fun loadRelayDocuments() { - viewModelScope.launch(Dispatchers.IO) { - _relays.value.forEach { item -> - Nip11CachedRetriever.loadRelayInfo( - dirtyUrl = item.url, - onInfo = { - togglePaidRelay(item, it.limitation?.payment_required ?: false) - }, - onError = { url, errorCode, exceptionMessage -> }, - ) - } - } - } - - fun clear() { - _relays.update { - val relayList = account.getSearchRelayList()?.relays() ?: emptyList() - - relayList.map { relayUrl -> - val liveRelay = RelayPool.getRelay(relayUrl) - val errorCounter = liveRelay?.errorCounter ?: 0 - val eventDownloadCounter = liveRelay?.eventDownloadCounterInBytes ?: 0 - val eventUploadCounter = liveRelay?.eventUploadCounterInBytes ?: 0 - val spamCounter = liveRelay?.spamCounter ?: 0 - - BasicRelaySetupInfo( - relayUrl, - errorCounter, - eventDownloadCounter, - eventUploadCounter, - spamCounter, - ) - }.distinctBy { it.url }.sortedBy { it.downloadCountInBytes }.reversed() - } - } - - fun addRelay(relay: BasicRelaySetupInfo) { - if (relays.value.any { it.url == relay.url }) return - - _relays.update { it.plus(relay) } - } - - fun deleteRelay(relay: BasicRelaySetupInfo) { - _relays.update { it.minus(relay) } - } - - fun deleteAll() { - _relays.update { relays -> emptyList() } - } - - fun togglePaidRelay( - relay: BasicRelaySetupInfo, - paid: Boolean, - ) { - _relays.update { it.updated(relay, relay.copy(paidRelay = paid)) } + override fun saveRelayList(urlList: List) { + account.saveSearchRelayList(urlList) } }