Saves Contact List locally to avoid losing follows.
This commit is contained in:
@@ -8,6 +8,9 @@ import com.vitorpamplona.amethyst.model.toByteArray
|
|||||||
import com.vitorpamplona.amethyst.model.RelaySetupInfo
|
import com.vitorpamplona.amethyst.model.RelaySetupInfo
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import nostr.postr.Persona
|
import nostr.postr.Persona
|
||||||
|
import nostr.postr.events.ContactListEvent
|
||||||
|
import nostr.postr.events.Event
|
||||||
|
import nostr.postr.events.Event.Companion.getRefinedEvent
|
||||||
import nostr.postr.toHex
|
import nostr.postr.toHex
|
||||||
|
|
||||||
class LocalPreferences(context: Context) {
|
class LocalPreferences(context: Context) {
|
||||||
@@ -24,6 +27,7 @@ class LocalPreferences(context: Context) {
|
|||||||
remove("dontTranslateFrom")
|
remove("dontTranslateFrom")
|
||||||
remove("translateTo")
|
remove("translateTo")
|
||||||
remove("zapAmounts")
|
remove("zapAmounts")
|
||||||
|
remove("latestContactList")
|
||||||
}.apply()
|
}.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,6 +41,7 @@ class LocalPreferences(context: Context) {
|
|||||||
account.dontTranslateFrom.let { putStringSet("dontTranslateFrom", it) }
|
account.dontTranslateFrom.let { putStringSet("dontTranslateFrom", it) }
|
||||||
account.translateTo.let { putString("translateTo", it) }
|
account.translateTo.let { putString("translateTo", it) }
|
||||||
account.zapAmountChoices.let { putString("zapAmounts", gson.toJson(it)) }
|
account.zapAmountChoices.let { putString("zapAmounts", gson.toJson(it)) }
|
||||||
|
account.latestContactList.let { putString("latestContactList", Event.gson.toJson(it)) }
|
||||||
}.apply()
|
}.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +64,15 @@ class LocalPreferences(context: Context) {
|
|||||||
object : TypeToken<List<Long>>() {}.type
|
object : TypeToken<List<Long>>() {}.type
|
||||||
) ?: listOf(500L, 1000L, 5000L)
|
) ?: listOf(500L, 1000L, 5000L)
|
||||||
|
|
||||||
|
val latestContactList = try {
|
||||||
|
getString("latestContactList", null)?.let {
|
||||||
|
Event.gson.fromJson(it, Event::class.java).getRefinedEvent(true) as ContactListEvent
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
e.printStackTrace()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
if (pubKey != null) {
|
if (pubKey != null) {
|
||||||
return Account(
|
return Account(
|
||||||
Persona(privKey = privKey?.toByteArray(), pubKey = pubKey.toByteArray()),
|
Persona(privKey = privKey?.toByteArray(), pubKey = pubKey.toByteArray()),
|
||||||
@@ -67,7 +81,8 @@ class LocalPreferences(context: Context) {
|
|||||||
localRelays,
|
localRelays,
|
||||||
dontTranslateFrom,
|
dontTranslateFrom,
|
||||||
translateTo,
|
translateTo,
|
||||||
zapAmountChoices
|
zapAmountChoices,
|
||||||
|
latestContactList
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ class Account(
|
|||||||
var localRelays: Set<RelaySetupInfo> = Constants.defaultRelays.toSet(),
|
var localRelays: Set<RelaySetupInfo> = Constants.defaultRelays.toSet(),
|
||||||
var dontTranslateFrom: Set<String> = getLanguagesSpokenByUser(),
|
var dontTranslateFrom: Set<String> = getLanguagesSpokenByUser(),
|
||||||
var translateTo: String = Locale.getDefault().language,
|
var translateTo: String = Locale.getDefault().language,
|
||||||
var zapAmountChoices: List<Long> = listOf(500L, 1000L, 5000L)
|
var zapAmountChoices: List<Long> = listOf(500L, 1000L, 5000L),
|
||||||
|
var latestContactList: ContactListEvent? = null
|
||||||
) {
|
) {
|
||||||
var transientHiddenUsers: Set<String> = setOf()
|
var transientHiddenUsers: Set<String> = setOf()
|
||||||
|
|
||||||
@@ -80,18 +81,23 @@ class Account(
|
|||||||
fun sendNewRelayList(relays: Map<String, ContactListEvent.ReadWrite>) {
|
fun sendNewRelayList(relays: Map<String, ContactListEvent.ReadWrite>) {
|
||||||
if (!isWriteable()) return
|
if (!isWriteable()) return
|
||||||
|
|
||||||
val lastestContactList = userProfile().latestContactList
|
val contactList = latestContactList
|
||||||
val event = if (lastestContactList != null) {
|
|
||||||
ContactListEvent.create(
|
if (contactList != null && contactList.follows.size > 0) {
|
||||||
lastestContactList.follows,
|
val event = ContactListEvent.create(
|
||||||
|
contactList.follows,
|
||||||
relays,
|
relays,
|
||||||
loggedIn.privKey!!)
|
loggedIn.privKey!!)
|
||||||
} else {
|
|
||||||
ContactListEvent.create(listOf(), relays, loggedIn.privKey!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
Client.send(event)
|
Client.send(event)
|
||||||
LocalCache.consume(event)
|
LocalCache.consume(event)
|
||||||
|
} else {
|
||||||
|
val event = ContactListEvent.create(listOf(), relays, loggedIn.privKey!!)
|
||||||
|
|
||||||
|
// Keep this local to avoid erasing a good contact list.
|
||||||
|
// Client.send(event)
|
||||||
|
LocalCache.consume(event)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendNewUserMetadata(toString: String) {
|
fun sendNewUserMetadata(toString: String) {
|
||||||
@@ -208,10 +214,11 @@ class Account(
|
|||||||
fun follow(user: User) {
|
fun follow(user: User) {
|
||||||
if (!isWriteable()) return
|
if (!isWriteable()) return
|
||||||
|
|
||||||
val lastestContactList = userProfile().latestContactList
|
val contactList = latestContactList
|
||||||
val event = if (lastestContactList != null) {
|
|
||||||
|
val event = if (contactList != null && contactList.follows.size > 0) {
|
||||||
ContactListEvent.create(
|
ContactListEvent.create(
|
||||||
lastestContactList.follows.plus(Contact(user.pubkeyHex, null)),
|
contactList.follows.plus(Contact(user.pubkeyHex, null)),
|
||||||
userProfile().relays,
|
userProfile().relays,
|
||||||
loggedIn.privKey!!)
|
loggedIn.privKey!!)
|
||||||
} else {
|
} else {
|
||||||
@@ -230,12 +237,14 @@ class Account(
|
|||||||
fun unfollow(user: User) {
|
fun unfollow(user: User) {
|
||||||
if (!isWriteable()) return
|
if (!isWriteable()) return
|
||||||
|
|
||||||
val lastestContactList = userProfile().latestContactList
|
val contactList = latestContactList
|
||||||
if (lastestContactList != null) {
|
|
||||||
|
if (contactList != null && contactList.follows.size > 0) {
|
||||||
val event = ContactListEvent.create(
|
val event = ContactListEvent.create(
|
||||||
lastestContactList.follows.filter { it.pubKeyHex != user.pubkeyHex },
|
contactList.follows.filter { it.pubKeyHex != user.pubkeyHex },
|
||||||
userProfile().relays,
|
userProfile().relays,
|
||||||
loggedIn.privKey!!)
|
loggedIn.privKey!!)
|
||||||
|
|
||||||
Client.send(event)
|
Client.send(event)
|
||||||
LocalCache.consume(event)
|
LocalCache.consume(event)
|
||||||
}
|
}
|
||||||
@@ -309,28 +318,35 @@ class Account(
|
|||||||
|
|
||||||
fun joinChannel(idHex: String) {
|
fun joinChannel(idHex: String) {
|
||||||
followingChannels = followingChannels + idHex
|
followingChannels = followingChannels + idHex
|
||||||
invalidateData(live)
|
live.invalidateData()
|
||||||
|
|
||||||
|
saveable.invalidateData()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun leaveChannel(idHex: String) {
|
fun leaveChannel(idHex: String) {
|
||||||
followingChannels = followingChannels - idHex
|
followingChannels = followingChannels - idHex
|
||||||
invalidateData(live)
|
live.invalidateData()
|
||||||
|
|
||||||
|
saveable.invalidateData()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hideUser(pubkeyHex: String) {
|
fun hideUser(pubkeyHex: String) {
|
||||||
hiddenUsers = hiddenUsers + pubkeyHex
|
hiddenUsers = hiddenUsers + pubkeyHex
|
||||||
invalidateData(live)
|
live.invalidateData()
|
||||||
|
saveable.invalidateData()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showUser(pubkeyHex: String) {
|
fun showUser(pubkeyHex: String) {
|
||||||
hiddenUsers = hiddenUsers - pubkeyHex
|
hiddenUsers = hiddenUsers - pubkeyHex
|
||||||
transientHiddenUsers = transientHiddenUsers - pubkeyHex
|
transientHiddenUsers = transientHiddenUsers - pubkeyHex
|
||||||
invalidateData(live)
|
live.invalidateData()
|
||||||
|
saveable.invalidateData()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun changeZapAmounts(newAmounts: List<Long>) {
|
fun changeZapAmounts(newAmounts: List<Long>) {
|
||||||
zapAmountChoices = newAmounts
|
zapAmountChoices = newAmounts
|
||||||
invalidateData(live)
|
live.invalidateData()
|
||||||
|
saveable.invalidateData()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendChangeChannel(name: String, about: String, picture: String, channel: Channel) {
|
fun sendChangeChannel(name: String, about: String, picture: String, channel: Channel) {
|
||||||
@@ -384,12 +400,23 @@ class Account(
|
|||||||
|
|
||||||
fun addDontTranslateFrom(languageCode: String) {
|
fun addDontTranslateFrom(languageCode: String) {
|
||||||
dontTranslateFrom = dontTranslateFrom.plus(languageCode)
|
dontTranslateFrom = dontTranslateFrom.plus(languageCode)
|
||||||
invalidateData(liveLanguages)
|
liveLanguages.invalidateData()
|
||||||
|
|
||||||
|
saveable.invalidateData()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateTranslateTo(languageCode: String) {
|
fun updateTranslateTo(languageCode: String) {
|
||||||
translateTo = languageCode
|
translateTo = languageCode
|
||||||
invalidateData(liveLanguages)
|
liveLanguages.invalidateData()
|
||||||
|
|
||||||
|
saveable.invalidateData()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateContactListTo(newContactList: ContactListEvent?) {
|
||||||
|
if ((newContactList?.follows?.size ?: 0) > 0 && latestContactList != newContactList) {
|
||||||
|
latestContactList = newContactList
|
||||||
|
saveable.invalidateData()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun activeRelays(): Array<Relay>? {
|
fun activeRelays(): Array<Relay>? {
|
||||||
@@ -415,11 +442,28 @@ class Account(
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
latestContactList?.let {
|
||||||
|
println("Loading saved contacts ${it.toJson()}")
|
||||||
|
if (userProfile().latestContactList == null) {
|
||||||
|
LocalCache.consume(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observes relays to restart connections
|
||||||
userProfile().live().relays.observeForever {
|
userProfile().live().relays.observeForever {
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
reconnectIfRelaysHaveChanged()
|
reconnectIfRelaysHaveChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// saves contact list for the next time.
|
||||||
|
userProfile().live().follows.observeForever {
|
||||||
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
updateContactListTo(userProfile().latestContactList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// imports transient blocks due to spam.
|
||||||
LocalCache.antiSpam.liveSpam.observeForever {
|
LocalCache.antiSpam.liveSpam.observeForever {
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
it.cache.spamMessages.snapshot().values.forEach {
|
it.cache.spamMessages.snapshot().values.forEach {
|
||||||
@@ -437,26 +481,7 @@ class Account(
|
|||||||
// Observers line up here.
|
// Observers line up here.
|
||||||
val live: AccountLiveData = AccountLiveData(this)
|
val live: AccountLiveData = AccountLiveData(this)
|
||||||
val liveLanguages: AccountLiveData = AccountLiveData(this)
|
val liveLanguages: AccountLiveData = AccountLiveData(this)
|
||||||
|
val saveable: AccountLiveData = AccountLiveData(this)
|
||||||
var handlerWaiting = AtomicBoolean()
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
private fun invalidateData(live: AccountLiveData) {
|
|
||||||
if (handlerWaiting.getAndSet(true)) return
|
|
||||||
|
|
||||||
handlerWaiting.set(true)
|
|
||||||
val scope = CoroutineScope(Job() + Dispatchers.Default)
|
|
||||||
scope.launch {
|
|
||||||
try {
|
|
||||||
delay(100)
|
|
||||||
live.refresh()
|
|
||||||
} finally {
|
|
||||||
withContext(NonCancellable) {
|
|
||||||
handlerWaiting.set(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isHidden(user: User) = user in hiddenUsers()
|
fun isHidden(user: User) = user in hiddenUsers()
|
||||||
|
|
||||||
@@ -496,10 +521,32 @@ class Account(
|
|||||||
fun saveRelayList(value: List<RelaySetupInfo>) {
|
fun saveRelayList(value: List<RelaySetupInfo>) {
|
||||||
localRelays = value.toSet()
|
localRelays = value.toSet()
|
||||||
sendNewRelayList(value.associate { it.url to ContactListEvent.ReadWrite(it.read, it.write) } )
|
sendNewRelayList(value.associate { it.url to ContactListEvent.ReadWrite(it.read, it.write) } )
|
||||||
|
|
||||||
|
saveable.invalidateData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccountLiveData(private val account: Account): LiveData<AccountState>(AccountState(account)) {
|
class AccountLiveData(private val account: Account): LiveData<AccountState>(AccountState(account)) {
|
||||||
|
var handlerWaiting = AtomicBoolean()
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun invalidateData() {
|
||||||
|
if (handlerWaiting.getAndSet(true)) return
|
||||||
|
|
||||||
|
handlerWaiting.set(true)
|
||||||
|
val scope = CoroutineScope(Job() + Dispatchers.Default)
|
||||||
|
scope.launch {
|
||||||
|
try {
|
||||||
|
delay(100)
|
||||||
|
refresh()
|
||||||
|
} finally {
|
||||||
|
withContext(NonCancellable) {
|
||||||
|
handlerWaiting.set(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun refresh() {
|
fun refresh() {
|
||||||
postValue(AccountState(account))
|
postValue(AccountState(account))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package com.vitorpamplona.amethyst.ui
|
package com.vitorpamplona.amethyst.ui
|
||||||
|
|
||||||
import android.content.ComponentCallbacks2
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build.VERSION.SDK_INT
|
import android.os.Build.VERSION.SDK_INT
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
@@ -16,24 +14,13 @@ import coil.ImageLoader
|
|||||||
import coil.decode.GifDecoder
|
import coil.decode.GifDecoder
|
||||||
import coil.decode.ImageDecoderDecoder
|
import coil.decode.ImageDecoderDecoder
|
||||||
import coil.decode.SvgDecoder
|
import coil.decode.SvgDecoder
|
||||||
import coil.disk.DiskCache
|
|
||||||
import coil.memory.MemoryCache
|
|
||||||
import coil.request.CachePolicy
|
|
||||||
import coil.util.DebugLogger
|
|
||||||
import com.vitorpamplona.amethyst.EncryptedStorage
|
|
||||||
import com.vitorpamplona.amethyst.LocalPreferences
|
import com.vitorpamplona.amethyst.LocalPreferences
|
||||||
import com.vitorpamplona.amethyst.ServiceManager
|
import com.vitorpamplona.amethyst.ServiceManager
|
||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
|
||||||
import com.vitorpamplona.amethyst.model.decodePublicKey
|
|
||||||
import com.vitorpamplona.amethyst.model.toHexKey
|
|
||||||
import com.vitorpamplona.amethyst.service.Nip19
|
import com.vitorpamplona.amethyst.service.Nip19
|
||||||
import com.vitorpamplona.amethyst.service.relays.Client
|
import com.vitorpamplona.amethyst.service.relays.Client
|
||||||
import com.vitorpamplona.amethyst.ui.screen.AccountScreen
|
import com.vitorpamplona.amethyst.ui.screen.AccountScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
|
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.theme.AmethystTheme
|
import com.vitorpamplona.amethyst.ui.theme.AmethystTheme
|
||||||
import fr.acinq.secp256k1.Hex
|
|
||||||
import nostr.postr.Persona
|
|
||||||
import nostr.postr.bechToBytes
|
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@@ -64,11 +51,11 @@ class MainActivity : ComponentActivity() {
|
|||||||
// A surface container using the 'background' color from the theme
|
// A surface container using the 'background' color from the theme
|
||||||
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
|
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
|
||||||
|
|
||||||
val accountViewModel: AccountStateViewModel = viewModel {
|
val accountStateViewModel: AccountStateViewModel = viewModel {
|
||||||
AccountStateViewModel(LocalPreferences(applicationContext))
|
AccountStateViewModel(LocalPreferences(applicationContext))
|
||||||
}
|
}
|
||||||
|
|
||||||
AccountScreen(accountViewModel, startingPage)
|
AccountScreen(accountStateViewModel, startingPage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,6 +65,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
// Only starts after login
|
// Only starts after login
|
||||||
ServiceManager.start()
|
ServiceManager.start()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,8 +38,6 @@ class NewChannelViewModel: ViewModel() {
|
|||||||
channelDescription.value.text,
|
channelDescription.value.text,
|
||||||
channelPicture.value.text
|
channelPicture.value.text
|
||||||
)
|
)
|
||||||
|
|
||||||
LocalPreferences(context).saveToEncryptedStorage(account)
|
|
||||||
} else
|
} else
|
||||||
account.sendChangeChannel(
|
account.sendChangeChannel(
|
||||||
channelName.value.text,
|
channelName.value.text,
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ class NewRelayListViewModel: ViewModel() {
|
|||||||
fun create(ctx: Context) {
|
fun create(ctx: Context) {
|
||||||
relays.let {
|
relays.let {
|
||||||
account.saveRelayList(it.value)
|
account.saveRelayList(it.value)
|
||||||
LocalPreferences(ctx).saveToEncryptedStorage(account)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clear(ctx)
|
clear(ctx)
|
||||||
|
|||||||
@@ -540,7 +540,6 @@ fun UpdateZapAmountDialog(onClose: () -> Unit, account: Account) {
|
|||||||
SaveButton(
|
SaveButton(
|
||||||
onPost = {
|
onPost = {
|
||||||
postViewModel.sendPost()
|
postViewModel.sendPost()
|
||||||
LocalPreferences(ctx).saveToEncryptedStorage(account)
|
|
||||||
onClose()
|
onClose()
|
||||||
},
|
},
|
||||||
isActive = postViewModel.amounts.text.isNotBlank()
|
isActive = postViewModel.amounts.text.isNotBlank()
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ fun UserCompose(baseUser: User, accountViewModel: AccountViewModel, navControlle
|
|||||||
if (account.isHidden(baseUser)) {
|
if (account.isHidden(baseUser)) {
|
||||||
ShowUserButton {
|
ShowUserButton {
|
||||||
account.showUser(baseUser.pubkeyHex)
|
account.showUser(baseUser.pubkeyHex)
|
||||||
LocalPreferences(ctx).saveToEncryptedStorage(account)
|
|
||||||
}
|
}
|
||||||
} else if (userFollows.isFollowing(baseUser)) {
|
} else if (userFollows.isFollowing(baseUser)) {
|
||||||
UnfollowButton { account.unfollow(baseUser) }
|
UnfollowButton { account.unfollow(baseUser) }
|
||||||
|
|||||||
@@ -102,7 +102,6 @@ fun ZapNoteCompose(baseNote: Pair<Note, Note>, accountViewModel: AccountViewMode
|
|||||||
if (account.isHidden(baseAuthor)) {
|
if (account.isHidden(baseAuthor)) {
|
||||||
ShowUserButton {
|
ShowUserButton {
|
||||||
account.showUser(baseAuthor.pubkeyHex)
|
account.showUser(baseAuthor.pubkeyHex)
|
||||||
LocalPreferences(ctx).saveToEncryptedStorage(account)
|
|
||||||
}
|
}
|
||||||
} else if (userFollows.isFollowing(baseAuthor)) {
|
} else if (userFollows.isFollowing(baseAuthor)) {
|
||||||
UnfollowButton { account.unfollow(baseAuthor) }
|
UnfollowButton { account.unfollow(baseAuthor) }
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.screen
|
package com.vitorpamplona.amethyst.ui.screen
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import com.vitorpamplona.amethyst.LocalPreferences
|
import com.vitorpamplona.amethyst.LocalPreferences
|
||||||
import com.vitorpamplona.amethyst.ServiceManager
|
import com.vitorpamplona.amethyst.ServiceManager
|
||||||
import com.vitorpamplona.amethyst.model.Account
|
import com.vitorpamplona.amethyst.model.Account
|
||||||
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
import fr.acinq.secp256k1.Hex
|
import fr.acinq.secp256k1.Hex
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
@@ -70,9 +69,35 @@ class AccountStateViewModel(private val localPreferences: LocalPreferences): Vie
|
|||||||
scope.launch {
|
scope.launch {
|
||||||
ServiceManager.start(account)
|
ServiceManager.start(account)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GlobalScope.launch(Dispatchers.Main) {
|
||||||
|
account.saveable.observeForever(saveListener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val saveListener: (com.vitorpamplona.amethyst.model.AccountState) -> Unit = {
|
||||||
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
localPreferences.saveToEncryptedStorage(it.account)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun logOff() {
|
fun logOff() {
|
||||||
|
val state = accountContent.value
|
||||||
|
|
||||||
|
when (state) {
|
||||||
|
is AccountState.LoggedIn -> {
|
||||||
|
GlobalScope.launch(Dispatchers.Main) {
|
||||||
|
state.account.saveable.removeObserver(saveListener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is AccountState.LoggedInViewOnly -> {
|
||||||
|
GlobalScope.launch(Dispatchers.Main) {
|
||||||
|
state.account.saveable.removeObserver(saveListener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
|
||||||
_accountContent.update { AccountState.LoggedOff }
|
_accountContent.update { AccountState.LoggedOff }
|
||||||
|
|
||||||
localPreferences.clearEncryptedStorage()
|
localPreferences.clearEncryptedStorage()
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import com.vitorpamplona.amethyst.LocalPreferences
|
|||||||
import com.vitorpamplona.amethyst.lnurl.LightningAddressResolver
|
import com.vitorpamplona.amethyst.lnurl.LightningAddressResolver
|
||||||
import com.vitorpamplona.amethyst.model.Account
|
import com.vitorpamplona.amethyst.model.Account
|
||||||
import com.vitorpamplona.amethyst.model.AccountState
|
import com.vitorpamplona.amethyst.model.AccountState
|
||||||
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
|
import com.vitorpamplona.amethyst.model.LocalCacheState
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.amethyst.service.model.ReportEvent
|
import com.vitorpamplona.amethyst.service.model.ReportEvent
|
||||||
@@ -67,21 +69,17 @@ class AccountViewModel(private val account: Account): ViewModel() {
|
|||||||
|
|
||||||
fun hide(user: User, ctx: Context) {
|
fun hide(user: User, ctx: Context) {
|
||||||
account.hideUser(user.pubkeyHex)
|
account.hideUser(user.pubkeyHex)
|
||||||
LocalPreferences(ctx).saveToEncryptedStorage(account)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun show(user: User, ctx: Context) {
|
fun show(user: User, ctx: Context) {
|
||||||
account.showUser(user.pubkeyHex)
|
account.showUser(user.pubkeyHex)
|
||||||
LocalPreferences(ctx).saveToEncryptedStorage(account)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun translateTo(lang: Locale, ctx: Context) {
|
fun translateTo(lang: Locale, ctx: Context) {
|
||||||
account.updateTranslateTo(lang.language)
|
account.updateTranslateTo(lang.language)
|
||||||
LocalPreferences(ctx).saveToEncryptedStorage(account)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dontTranslateFrom(lang: String, ctx: Context) {
|
fun dontTranslateFrom(lang: String, ctx: Context) {
|
||||||
account.addDontTranslateFrom(lang)
|
account.addDontTranslateFrom(lang)
|
||||||
LocalPreferences(ctx).saveToEncryptedStorage(account)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -306,13 +306,10 @@ private fun EditButton(account: Account, channel: Channel) {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun JoinButton(account: Account, channel: Channel, navController: NavController) {
|
private fun JoinButton(account: Account, channel: Channel, navController: NavController) {
|
||||||
val context = LocalContext.current.applicationContext
|
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
modifier = Modifier.padding(horizontal = 3.dp),
|
modifier = Modifier.padding(horizontal = 3.dp),
|
||||||
onClick = {
|
onClick = {
|
||||||
account.joinChannel(channel.idHex)
|
account.joinChannel(channel.idHex)
|
||||||
LocalPreferences(context).saveToEncryptedStorage(account)
|
|
||||||
navController.navigate(Route.Message.route)
|
navController.navigate(Route.Message.route)
|
||||||
},
|
},
|
||||||
shape = RoundedCornerShape(20.dp),
|
shape = RoundedCornerShape(20.dp),
|
||||||
@@ -328,13 +325,10 @@ private fun JoinButton(account: Account, channel: Channel, navController: NavCon
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun LeaveButton(account: Account, channel: Channel, navController: NavController) {
|
private fun LeaveButton(account: Account, channel: Channel, navController: NavController) {
|
||||||
val context = LocalContext.current.applicationContext
|
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
modifier = Modifier.padding(horizontal = 3.dp),
|
modifier = Modifier.padding(horizontal = 3.dp),
|
||||||
onClick = {
|
onClick = {
|
||||||
account.leaveChannel(channel.idHex)
|
account.leaveChannel(channel.idHex)
|
||||||
LocalPreferences(context).saveToEncryptedStorage(account)
|
|
||||||
navController.navigate(Route.Message.route)
|
navController.navigate(Route.Message.route)
|
||||||
},
|
},
|
||||||
shape = RoundedCornerShape(20.dp),
|
shape = RoundedCornerShape(20.dp),
|
||||||
|
|||||||
@@ -323,7 +323,6 @@ private fun ProfileHeader(
|
|||||||
if (account.isHidden(baseUser)) {
|
if (account.isHidden(baseUser)) {
|
||||||
ShowUserButton {
|
ShowUserButton {
|
||||||
account.showUser(baseUser.pubkeyHex)
|
account.showUser(baseUser.pubkeyHex)
|
||||||
LocalPreferences(ctx).saveToEncryptedStorage(account)
|
|
||||||
}
|
}
|
||||||
} else if (accountUser.isFollowing(baseUser)) {
|
} else if (accountUser.isFollowing(baseUser)) {
|
||||||
UnfollowButton { account.unfollow(baseUser) }
|
UnfollowButton { account.unfollow(baseUser) }
|
||||||
|
|||||||
Reference in New Issue
Block a user