refactor
This commit is contained in:
@@ -51,6 +51,7 @@ import su.reya.coop.screens.UpdateProfileScreen
|
||||
import su.reya.coop.viewmodel.AuthViewModel
|
||||
import su.reya.coop.viewmodel.ChatViewModel
|
||||
import su.reya.coop.viewmodel.NostrViewModel
|
||||
import su.reya.coop.viewmodel.RelayViewModel
|
||||
|
||||
val LocalNostrViewModel = staticCompositionLocalOf<NostrViewModel> {
|
||||
error("No NostrViewModel provided")
|
||||
@@ -64,6 +65,10 @@ val LocalAuthViewModel = staticCompositionLocalOf<AuthViewModel> {
|
||||
error("No AuthViewModel provided")
|
||||
}
|
||||
|
||||
val LocalRelayViewModel = staticCompositionLocalOf<RelayViewModel> {
|
||||
error("No RelayViewModel provided")
|
||||
}
|
||||
|
||||
val LocalSnackbarHostState = staticCompositionLocalOf<SnackbarHostState> {
|
||||
error("No SnackbarHostState provided")
|
||||
}
|
||||
@@ -80,6 +85,7 @@ val LocalScanResult = staticCompositionLocalOf<QrScanResult> {
|
||||
@Composable
|
||||
fun App(
|
||||
nostrViewModel: NostrViewModel,
|
||||
relayViewModel: RelayViewModel,
|
||||
chatViewModel: ChatViewModel,
|
||||
authViewModel: AuthViewModel,
|
||||
) {
|
||||
@@ -133,6 +139,11 @@ fun App(
|
||||
snackbarHostState.showSnackbar(message)
|
||||
}
|
||||
}
|
||||
launch {
|
||||
relayViewModel.errorEvents.collect { message ->
|
||||
snackbarHostState.showSnackbar(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(activity) {
|
||||
@@ -174,6 +185,7 @@ fun App(
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalNostrViewModel provides nostrViewModel,
|
||||
LocalRelayViewModel provides relayViewModel,
|
||||
LocalChatViewModel provides chatViewModel,
|
||||
LocalAuthViewModel provides authViewModel,
|
||||
LocalSnackbarHostState provides snackbarHostState,
|
||||
|
||||
@@ -4,12 +4,15 @@ import android.content.Intent
|
||||
import androidx.activity.result.ActivityResult
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class ExternalSignerLauncher {
|
||||
class ExternalSignerLauncher(
|
||||
private val mainDispatcher: CoroutineDispatcher = Dispatchers.Main,
|
||||
) {
|
||||
private var launcher: ActivityResultLauncher<Intent>? = null
|
||||
private var pendingResult: CompletableDeferred<ActivityResult>? = null
|
||||
private val mutex = Mutex()
|
||||
@@ -19,7 +22,7 @@ class ExternalSignerLauncher {
|
||||
}
|
||||
|
||||
suspend fun launch(intent: Intent): ActivityResult = mutex.withLock {
|
||||
withContext(Dispatchers.Main) {
|
||||
withContext(mainDispatcher) {
|
||||
val deferred = CompletableDeferred<ActivityResult>()
|
||||
pendingResult = deferred
|
||||
launcher?.launch(intent) ?: throw IllegalStateException("Signer not registered")
|
||||
|
||||
@@ -17,6 +17,7 @@ import su.reya.coop.repository.MediaRepository
|
||||
import su.reya.coop.viewmodel.AuthViewModel
|
||||
import su.reya.coop.viewmodel.ChatViewModel
|
||||
import su.reya.coop.viewmodel.NostrViewModel
|
||||
import su.reya.coop.viewmodel.RelayViewModel
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
@@ -29,6 +30,7 @@ class MainActivity : ComponentActivity() {
|
||||
private val storage = AppStore(this@MainActivity)
|
||||
private val mediaRepository = MediaRepository()
|
||||
private val nostrViewModel = NostrViewModel(NostrManager.instance, mediaRepository)
|
||||
private val relayViewModel = RelayViewModel(NostrManager.instance)
|
||||
private val chatViewModel = ChatViewModel(NostrManager.instance, mediaRepository)
|
||||
private val androidSigner =
|
||||
AndroidExternalSigner(this@MainActivity, externalSignerLauncher)
|
||||
@@ -38,6 +40,7 @@ class MainActivity : ComponentActivity() {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return when {
|
||||
modelClass.isAssignableFrom(NostrViewModel::class.java) -> nostrViewModel
|
||||
modelClass.isAssignableFrom(RelayViewModel::class.java) -> relayViewModel
|
||||
modelClass.isAssignableFrom(ChatViewModel::class.java) -> chatViewModel
|
||||
modelClass.isAssignableFrom(AuthViewModel::class.java) -> authViewModel
|
||||
else -> throw IllegalArgumentException("Unknown ViewModel class")
|
||||
@@ -47,6 +50,7 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
private val nostrViewModel: NostrViewModel by viewModels { factory }
|
||||
private val relayViewModel: RelayViewModel by viewModels { factory }
|
||||
private val chatViewModel: ChatViewModel by viewModels { factory }
|
||||
private val authViewModel: AuthViewModel by viewModels { factory }
|
||||
|
||||
@@ -93,6 +97,7 @@ class MainActivity : ComponentActivity() {
|
||||
setContent {
|
||||
App(
|
||||
nostrViewModel = nostrViewModel,
|
||||
relayViewModel = relayViewModel,
|
||||
chatViewModel = chatViewModel,
|
||||
authViewModel = authViewModel,
|
||||
)
|
||||
|
||||
@@ -14,6 +14,7 @@ import androidx.core.app.NotificationCompat
|
||||
import androidx.core.net.toUri
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -27,6 +28,8 @@ private const val GROUP_KEY_MESSAGES = "su.reya.coop.MESSAGES"
|
||||
|
||||
class NostrForegroundService : Service() {
|
||||
private val serviceScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
|
||||
var ioDispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||
private val nostr by lazy { NostrManager.instance }
|
||||
private var notificationJob: Job? = null
|
||||
|
||||
|
||||
@@ -265,10 +265,8 @@ fun AddContactDialog(onDismissRequest: () -> Unit) {
|
||||
},
|
||||
actions = {
|
||||
IconButton(onClick = {
|
||||
scope.launch {
|
||||
val success = nostrViewModel.addContact(contact)
|
||||
if (success) onDismissRequest()
|
||||
}
|
||||
nostrViewModel.addContact(contact)
|
||||
onDismissRequest()
|
||||
}) {
|
||||
Icon(
|
||||
painter = painterResource(Res.drawable.ic_check),
|
||||
|
||||
@@ -93,6 +93,7 @@ import su.reya.coop.LocalAuthViewModel
|
||||
import su.reya.coop.LocalChatViewModel
|
||||
import su.reya.coop.LocalNavigator
|
||||
import su.reya.coop.LocalNostrViewModel
|
||||
import su.reya.coop.LocalRelayViewModel
|
||||
import su.reya.coop.LocalScanResult
|
||||
import su.reya.coop.LocalSnackbarHostState
|
||||
import su.reya.coop.Room
|
||||
@@ -114,6 +115,7 @@ fun HomeScreen() {
|
||||
val nostrViewModel = LocalNostrViewModel.current
|
||||
val chatViewModel = LocalChatViewModel.current
|
||||
val authViewModel = LocalAuthViewModel.current
|
||||
val relayViewModel = LocalRelayViewModel.current
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
val sheetState = rememberModalBottomSheetState(true)
|
||||
@@ -123,7 +125,7 @@ fun HomeScreen() {
|
||||
val userProfile by nostrViewModel.currentUserProfile.collectAsStateWithLifecycle()
|
||||
val chatRooms by chatViewModel.chatRooms.collectAsStateWithLifecycle()
|
||||
|
||||
val isRelayListEmpty by nostrViewModel.isRelayListEmpty.collectAsStateWithLifecycle()
|
||||
val isRelayListEmpty by relayViewModel.isRelayListEmpty.collectAsStateWithLifecycle()
|
||||
val isSyncing by chatViewModel.isSyncing.collectAsStateWithLifecycle()
|
||||
val isPartialProcessedGiftWrap by chatViewModel.isPartialProcessedGiftWrap.collectAsStateWithLifecycle()
|
||||
|
||||
@@ -319,11 +321,9 @@ fun HomeScreen() {
|
||||
isRefreshing = isRefreshing,
|
||||
state = pullToRefreshState,
|
||||
onRefresh = {
|
||||
scope.launch {
|
||||
isRefreshing = true
|
||||
chatViewModel.refreshChatRooms()
|
||||
isRefreshing = false
|
||||
}
|
||||
isRefreshing = true
|
||||
chatViewModel.refreshChatRooms()
|
||||
isRefreshing = false
|
||||
},
|
||||
indicator = {
|
||||
PullToRefreshDefaults.LoadingIndicator(
|
||||
@@ -469,7 +469,7 @@ fun HomeScreen() {
|
||||
// Show the relay setup dialog if the msg relay list is empty
|
||||
if (isRelayListEmpty) {
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = { nostrViewModel.dismissRelayWarning() },
|
||||
onDismissRequest = { relayViewModel.dismissRelayWarning() },
|
||||
sheetState = sheetState,
|
||||
containerColor = MaterialTheme.colorScheme.surfaceContainer,
|
||||
) {
|
||||
@@ -573,15 +573,9 @@ fun HomeScreen() {
|
||||
TextButton(
|
||||
enabled = !isBusy,
|
||||
onClick = {
|
||||
scope.launch {
|
||||
isBusy = true
|
||||
try {
|
||||
nostrViewModel.refetchMsgRelays()
|
||||
} catch (e: Exception) {
|
||||
snackbarHostState.showSnackbar("Failed to refresh metadata: ${e.message}")
|
||||
}
|
||||
isBusy = false
|
||||
}
|
||||
isBusy = true
|
||||
relayViewModel.refetchMsgRelays()
|
||||
isBusy = false
|
||||
},
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
@@ -595,10 +589,8 @@ fun HomeScreen() {
|
||||
Button(
|
||||
enabled = !isBusy,
|
||||
onClick = {
|
||||
scope.launch {
|
||||
nostrViewModel.useDefaultMsgRelayList()
|
||||
sheetState.hide()
|
||||
}
|
||||
relayViewModel.useDefaultMsgRelayList()
|
||||
scope.launch { sheetState.hide() }
|
||||
},
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
|
||||
@@ -96,14 +96,16 @@ fun NewChatScreen() {
|
||||
selectedReceivers.add(pubkey)
|
||||
}
|
||||
} else if (query.contains("@")) {
|
||||
val pubkey = nostrViewModel.searchByAddress(query)
|
||||
if (pubkey != null) {
|
||||
selectedReceivers.add(pubkey)
|
||||
nostrViewModel.searchByAddress(query) { pubkey ->
|
||||
if (pubkey != null) {
|
||||
selectedReceivers.add(pubkey)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val results = nostrViewModel.searchByNostr(query)
|
||||
searchResults.clear()
|
||||
searchResults.addAll(results)
|
||||
nostrViewModel.searchByNostr(query) { results ->
|
||||
searchResults.clear()
|
||||
searchResults.addAll(results)
|
||||
}
|
||||
}
|
||||
|
||||
query = ""
|
||||
|
||||
@@ -56,6 +56,7 @@ import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import coop.composeapp.generated.resources.Res
|
||||
import coop.composeapp.generated.resources.ic_arrow_back
|
||||
import coop.composeapp.generated.resources.ic_check
|
||||
@@ -67,14 +68,16 @@ import rust.nostr.sdk.RelayMetadata
|
||||
import rust.nostr.sdk.RelayUrl
|
||||
import su.reya.coop.LocalNavigator
|
||||
import su.reya.coop.LocalNostrViewModel
|
||||
import su.reya.coop.LocalRelayViewModel
|
||||
import su.reya.coop.LocalSnackbarHostState
|
||||
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
fun RelayScreen() {
|
||||
val navigator = LocalNavigator.current
|
||||
val snackbarHostState = LocalSnackbarHostState.current
|
||||
val nostrViewModel = LocalNostrViewModel.current
|
||||
val relayViewModel = LocalRelayViewModel.current
|
||||
val snackbarHostState = LocalSnackbarHostState.current
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
val msgRelayList = remember { mutableStateListOf<RelayUrl>() }
|
||||
@@ -96,8 +99,25 @@ fun RelayScreen() {
|
||||
var relayToDelete by remember { mutableStateOf<String?>(null) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
relayList.putAll(nostrViewModel.currentUserRelayList())
|
||||
msgRelayList.addAll(nostrViewModel.currentUserMsgRelayList())
|
||||
relayViewModel.loadCurrentUserRelayList()
|
||||
relayViewModel.loadCurrentUserMsgRelayList()
|
||||
}
|
||||
|
||||
val loadedRelayList by relayViewModel.currentUserRelayList.collectAsStateWithLifecycle()
|
||||
val loadedMsgRelayList by relayViewModel.currentUserMsgRelayList.collectAsStateWithLifecycle()
|
||||
|
||||
LaunchedEffect(loadedRelayList) {
|
||||
if (loadedRelayList.isNotEmpty()) {
|
||||
relayList.clear()
|
||||
relayList.putAll(loadedRelayList)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(loadedMsgRelayList) {
|
||||
if (loadedMsgRelayList.isNotEmpty()) {
|
||||
msgRelayList.clear()
|
||||
msgRelayList.addAll(loadedMsgRelayList)
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
@@ -314,20 +334,16 @@ fun RelayScreen() {
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
scope.launch {
|
||||
if (msgRelayList.size == 1) {
|
||||
if (msgRelayList.size == 1) {
|
||||
scope.launch {
|
||||
snackbarHostState.showSnackbar("You must have at least one relay")
|
||||
relayToDelete = null
|
||||
return@launch
|
||||
}
|
||||
try {
|
||||
nostrViewModel.removeMsgRelay(relayToDelete!!)
|
||||
msgRelayList.removeIf { it.toString() == relayToDelete }
|
||||
relayToDelete = null
|
||||
} catch (e: Exception) {
|
||||
snackbarHostState.showSnackbar("Failed to remove relay: ${e.message}")
|
||||
}
|
||||
relayToDelete = null
|
||||
return@TextButton
|
||||
}
|
||||
relayViewModel.removeMsgRelay(relayToDelete!!)
|
||||
msgRelayList.removeIf { it.toString() == relayToDelete }
|
||||
relayToDelete = null
|
||||
}
|
||||
) {
|
||||
Text("Confirm")
|
||||
@@ -349,7 +365,7 @@ fun AddRelayDialog(
|
||||
onMsgRelayAdded: (newRelay: String) -> Unit,
|
||||
onRelayAdded: (newRelay: String, metadata: RelayMetadata?) -> Unit,
|
||||
) {
|
||||
val nostrViewModel = LocalNostrViewModel.current
|
||||
val relayViewModel = LocalRelayViewModel.current
|
||||
val snackbarHostState = LocalSnackbarHostState.current
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
@@ -397,26 +413,24 @@ fun AddRelayDialog(
|
||||
},
|
||||
actions = {
|
||||
IconButton(onClick = {
|
||||
scope.launch {
|
||||
if (!isError) {
|
||||
when (selected) {
|
||||
"Messaging" -> {
|
||||
nostrViewModel.addMsgRelay(relayAddress)
|
||||
onMsgRelayAdded(relayAddress)
|
||||
}
|
||||
|
||||
"Inbox" -> {
|
||||
nostrViewModel.addInboxRelay(relayAddress)
|
||||
onRelayAdded(relayAddress, RelayMetadata.WRITE)
|
||||
}
|
||||
|
||||
"Outbox" -> {
|
||||
nostrViewModel.addOutboxRelay(relayAddress)
|
||||
onRelayAdded(relayAddress, RelayMetadata.READ)
|
||||
}
|
||||
if (!isError) {
|
||||
when (selected) {
|
||||
"Messaging" -> {
|
||||
relayViewModel.addMsgRelay(relayAddress)
|
||||
onMsgRelayAdded(relayAddress)
|
||||
}
|
||||
|
||||
"Inbox" -> {
|
||||
relayViewModel.addInboxRelay(relayAddress)
|
||||
onRelayAdded(relayAddress, RelayMetadata.WRITE)
|
||||
}
|
||||
|
||||
"Outbox" -> {
|
||||
relayViewModel.addOutboxRelay(relayAddress)
|
||||
onRelayAdded(relayAddress, RelayMetadata.READ)
|
||||
}
|
||||
onDismissRequest()
|
||||
}
|
||||
onDismissRequest()
|
||||
}
|
||||
}) {
|
||||
Icon(
|
||||
|
||||
@@ -101,11 +101,9 @@ fun RequestListScreen() {
|
||||
isRefreshing = isRefreshing,
|
||||
state = pullToRefreshState,
|
||||
onRefresh = {
|
||||
scope.launch {
|
||||
isRefreshing = true
|
||||
chatViewModel.refreshChatRooms()
|
||||
isRefreshing = false
|
||||
}
|
||||
isRefreshing = true
|
||||
chatViewModel.refreshChatRooms()
|
||||
isRefreshing = false
|
||||
},
|
||||
indicator = {
|
||||
PullToRefreshDefaults.LoadingIndicator(
|
||||
|
||||
@@ -18,7 +18,6 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -29,7 +28,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import coop.composeapp.generated.resources.Res
|
||||
import coop.composeapp.generated.resources.ic_cancel
|
||||
import coop.composeapp.generated.resources.ic_check_circle
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import rust.nostr.sdk.PublicKey
|
||||
import rust.nostr.sdk.Timestamp
|
||||
@@ -46,7 +44,6 @@ fun ScreenerCard(room: Room) {
|
||||
val pubkey = room.members.firstOrNull() ?: return
|
||||
|
||||
val nostrViewModel = LocalNostrViewModel.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
var isContact by remember { mutableStateOf(false) }
|
||||
var mutualContacts by remember { mutableStateOf<Set<PublicKey>>(emptySet()) }
|
||||
@@ -56,14 +53,12 @@ fun ScreenerCard(room: Room) {
|
||||
val profile by profileFlow.collectAsStateWithLifecycle()
|
||||
|
||||
LaunchedEffect(pubkey) {
|
||||
scope.launch {
|
||||
// Check contact
|
||||
nostrViewModel.verifyContact(pubkey).let { isContact = it }
|
||||
// Get mutual contacts
|
||||
nostrViewModel.mutualContacts(pubkey).let { mutualContacts = it }
|
||||
// Get the last activity
|
||||
nostrViewModel.verifyActivity(pubkey)?.let { lastActivity = it }
|
||||
}
|
||||
// Check contact
|
||||
nostrViewModel.verifyContact(pubkey) { isContact = it }
|
||||
// Get mutual contacts
|
||||
nostrViewModel.mutualContacts(pubkey) { mutualContacts = it }
|
||||
// Get the last activity
|
||||
nostrViewModel.verifyActivity(pubkey) { lastActivity = it }
|
||||
}
|
||||
|
||||
Column(
|
||||
|
||||
@@ -59,6 +59,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import coop.composeapp.generated.resources.Res
|
||||
import coop.composeapp.generated.resources.ic_arrow_back
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -77,7 +78,11 @@ import su.reya.coop.shared.Avatar
|
||||
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
fun ChatScreen(id: Long, screening: Boolean = false) {
|
||||
fun ChatScreen(
|
||||
id: Long,
|
||||
screening: Boolean = false,
|
||||
coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val snackbarHostState = LocalSnackbarHostState.current
|
||||
val navigator = LocalNavigator.current
|
||||
@@ -121,7 +126,7 @@ fun ChatScreen(id: Long, screening: Boolean = false) {
|
||||
val sendFile = { uri: Uri ->
|
||||
scope.launch {
|
||||
// Read file on IO dispatcher
|
||||
val file = withContext(Dispatchers.IO) {
|
||||
val file = withContext(coroutineDispatcher) {
|
||||
context.contentResolver.openInputStream(uri)?.use { it.readBytes() }
|
||||
}
|
||||
|
||||
@@ -149,12 +154,13 @@ fun ChatScreen(id: Long, screening: Boolean = false) {
|
||||
|
||||
LaunchedEffect(id) {
|
||||
// Get messages
|
||||
val initialMessages = chatViewModel.getChatRoomMessages(id)
|
||||
messages.clear()
|
||||
messages.addAll(initialMessages)
|
||||
chatViewModel.loadChatRoomMessages(id) { initialMessages ->
|
||||
messages.clear()
|
||||
messages.addAll(initialMessages)
|
||||
|
||||
// Stop loading spinner
|
||||
loading = false
|
||||
// Stop loading spinner
|
||||
loading = false
|
||||
}
|
||||
|
||||
// Get msg relays for each member
|
||||
chatViewModel.chatRoomConnect(id)
|
||||
|
||||
@@ -54,6 +54,7 @@ import coil3.compose.AsyncImage
|
||||
import coop.composeapp.generated.resources.Res
|
||||
import coop.composeapp.generated.resources.ic_arrow_back
|
||||
import coop.composeapp.generated.resources.ic_plus
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -69,7 +70,8 @@ fun ProfileEditor(
|
||||
initialBio: String = "",
|
||||
initialPicture: Any? = null, // Accepts Uri (picked) or String (current URL)
|
||||
onBack: () -> Unit,
|
||||
onConfirm: (name: String, bio: String, pictureBytes: ByteArray?, contentType: String?) -> Unit
|
||||
onConfirm: (name: String, bio: String, pictureBytes: ByteArray?, contentType: String?) -> Unit,
|
||||
ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val snackbarHostState = LocalSnackbarHostState.current
|
||||
@@ -269,7 +271,7 @@ fun ProfileEditor(
|
||||
scope.launch {
|
||||
isBusy = true
|
||||
try {
|
||||
val bytes = withContext(Dispatchers.IO) {
|
||||
val bytes = withContext(ioDispatcher) {
|
||||
(picture as? Uri)?.let {
|
||||
context.contentResolver.openInputStream(it)?.readBytes()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user