update
This commit is contained in:
@@ -1,9 +1,7 @@
|
|||||||
package su.reya.coop.screens
|
package su.reya.coop.screens
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import su.reya.coop.LocalAuthViewModel
|
import su.reya.coop.LocalAuthViewModel
|
||||||
import su.reya.coop.LocalNavigator
|
import su.reya.coop.LocalNavigator
|
||||||
@@ -16,13 +14,9 @@ fun NewIdentityScreen() {
|
|||||||
val navigator = LocalNavigator.current
|
val navigator = LocalNavigator.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
val authState by authViewModel.state.collectAsStateWithLifecycle()
|
|
||||||
val isBusy = authState.isBusy
|
|
||||||
|
|
||||||
ProfileEditor(
|
ProfileEditor(
|
||||||
title = "Create a new identity",
|
title = "Create a new identity",
|
||||||
buttonLabel = "Continue",
|
buttonLabel = "Continue",
|
||||||
isBusy = isBusy,
|
|
||||||
onBack = { navigator.goBack() },
|
onBack = { navigator.goBack() },
|
||||||
onConfirm = { name, bio, bytes, type ->
|
onConfirm = { name, bio, bytes, type ->
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ fun ProfileEditor(
|
|||||||
initialName: String = "",
|
initialName: String = "",
|
||||||
initialBio: String = "",
|
initialBio: String = "",
|
||||||
initialPicture: Any? = null, // Accepts Uri (picked) or String (current URL)
|
initialPicture: Any? = null, // Accepts Uri (picked) or String (current URL)
|
||||||
isBusy: Boolean = false,
|
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
onConfirm: (name: String, bio: String, pictureBytes: ByteArray?, contentType: String?) -> Unit
|
onConfirm: (name: String, bio: String, pictureBytes: ByteArray?, contentType: String?) -> Unit
|
||||||
) {
|
) {
|
||||||
@@ -80,6 +79,7 @@ fun ProfileEditor(
|
|||||||
var name by remember(initialName) { mutableStateOf(initialName) }
|
var name by remember(initialName) { mutableStateOf(initialName) }
|
||||||
var bio by remember(initialBio) { mutableStateOf(initialBio) }
|
var bio by remember(initialBio) { mutableStateOf(initialBio) }
|
||||||
var picture by remember(initialPicture) { mutableStateOf(initialPicture) }
|
var picture by remember(initialPicture) { mutableStateOf(initialPicture) }
|
||||||
|
var isBusy by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val hasPicture = remember(picture) {
|
val hasPicture = remember(picture) {
|
||||||
when (picture) {
|
when (picture) {
|
||||||
@@ -267,14 +267,20 @@ fun ProfileEditor(
|
|||||||
.size(ButtonDefaults.MediumContainerHeight),
|
.size(ButtonDefaults.MediumContainerHeight),
|
||||||
onClick = {
|
onClick = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
val bytes = withContext(Dispatchers.IO) {
|
isBusy = true
|
||||||
(picture as? Uri)?.let {
|
try {
|
||||||
context.contentResolver.openInputStream(it)?.readBytes()
|
val bytes = withContext(Dispatchers.IO) {
|
||||||
|
(picture as? Uri)?.let {
|
||||||
|
context.contentResolver.openInputStream(it)?.readBytes()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
val type =
|
||||||
|
(picture as? Uri)?.let { context.contentResolver.getType(it) }
|
||||||
|
onConfirm(name, bio, bytes, type)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
snackbarHostState.showSnackbar(e.message ?: "Error")
|
||||||
}
|
}
|
||||||
val type =
|
isBusy = false
|
||||||
(picture as? Uri)?.let { context.contentResolver.getType(it) }
|
|
||||||
onConfirm(name, bio, bytes, type)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
enabled = name.isNotBlank() && !isBusy
|
enabled = name.isNotBlank() && !isBusy
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import su.reya.coop.storage.SecretStorage
|
|||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
data class AuthState(
|
data class AuthState(
|
||||||
val isBusy: Boolean = false,
|
|
||||||
val signerRequired: Boolean? = null,
|
val signerRequired: Boolean? = null,
|
||||||
val isNotificationBannerDismissed: Boolean = false,
|
val isNotificationBannerDismissed: Boolean = false,
|
||||||
)
|
)
|
||||||
@@ -88,8 +87,6 @@ class AuthViewModel(
|
|||||||
fun logout(onLogout: () -> Unit = {}) {
|
fun logout(onLogout: () -> Unit = {}) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
_state.update { it.copy(isBusy = true) }
|
|
||||||
|
|
||||||
// Reset the nostr signer and prune the database
|
// Reset the nostr signer and prune the database
|
||||||
nostr.signer.switch(Keys.generate())
|
nostr.signer.switch(Keys.generate())
|
||||||
nostr.prune()
|
nostr.prune()
|
||||||
@@ -99,11 +96,10 @@ class AuthViewModel(
|
|||||||
// Clear credentials from persistent storage
|
// Clear credentials from persistent storage
|
||||||
secretStore.clear(KEY_USER_SIGNER)
|
secretStore.clear(KEY_USER_SIGNER)
|
||||||
secretStore.clear(KEY_BANNER_DISMISSED)
|
secretStore.clear(KEY_BANNER_DISMISSED)
|
||||||
|
|
||||||
// Call cleanup callback (e.g. to reset other ViewModels)
|
// Call cleanup callback (e.g. to reset other ViewModels)
|
||||||
onLogout()
|
onLogout()
|
||||||
|
// Reset local states
|
||||||
_state.update { it.copy(isBusy = false, signerRequired = true) }
|
_state.update { it.copy(signerRequired = true) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,27 +203,16 @@ class AuthViewModel(
|
|||||||
picture: ByteArray?,
|
picture: ByteArray?,
|
||||||
contentType: String? = null
|
contentType: String? = null
|
||||||
) {
|
) {
|
||||||
_state.update { it.copy(isBusy = true) }
|
|
||||||
|
|
||||||
val keys = Keys.generate()
|
val keys = Keys.generate()
|
||||||
val secret = keys.secretKey().toBech32()
|
val secret = keys.secretKey().toBech32()
|
||||||
|
val avatarUrl = picture?.let {
|
||||||
try {
|
mediaRepository.blossomUpload(nostr.signer.get(), it, contentType ?: "image/jpeg")
|
||||||
val avatarUrl = picture?.let {
|
|
||||||
mediaRepository.blossomUpload(nostr.signer.get(), it, contentType ?: "image/jpeg")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create identity
|
|
||||||
nostr.profiles.createIdentity(keys = keys, name = name, bio = bio, picture = avatarUrl)
|
|
||||||
|
|
||||||
// Persist the secret in the secret storage
|
|
||||||
secretStore.set(KEY_USER_SIGNER, secret)
|
|
||||||
|
|
||||||
// Update local states
|
|
||||||
_state.update { it.copy(isBusy = false, signerRequired = false) }
|
|
||||||
} catch (e: Exception) {
|
|
||||||
showError("Error: ${e.message}")
|
|
||||||
_state.update { it.copy(isBusy = false) }
|
|
||||||
}
|
}
|
||||||
|
// Create identity
|
||||||
|
nostr.profiles.createIdentity(keys = keys, name = name, bio = bio, picture = avatarUrl)
|
||||||
|
// Persist the secret in the secret storage
|
||||||
|
secretStore.set(KEY_USER_SIGNER, secret)
|
||||||
|
// Update local states
|
||||||
|
_state.update { it.copy(signerRequired = false) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user