diff --git a/app/src/main/java/com/example/sw0b_001/ui/modals/ConfirmationModal.kt b/app/src/main/java/com/example/sw0b_001/ui/modals/ConfirmationModal.kt index 700dd2e5..342f2461 100644 --- a/app/src/main/java/com/example/sw0b_001/ui/modals/ConfirmationModal.kt +++ b/app/src/main/java/com/example/sw0b_001/ui/modals/ConfirmationModal.kt @@ -1,7 +1,6 @@ package com.example.sw0b_001.ui.modals import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -20,11 +19,7 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.rememberStandardBottomSheetState import androidx.compose.runtime.Composable -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 import androidx.compose.ui.draw.clip @@ -41,7 +36,7 @@ import kotlinx.coroutines.launch fun ConfirmationModal( showBottomSheet: Boolean = true, message: String = stringResource(R.string.click_continue_to_confirm_this_action_do_not_worry_it_has_no_dangerous_effects), - + confirmButtonText: String = stringResource(R.string.continue_text), onContinue: () -> Unit, onCancel: () -> Unit, ) { @@ -93,7 +88,7 @@ fun ConfirmationModal( colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.errorContainer) ) { Text( - text = stringResource(R.string.continue_text), + text = confirmButtonText, color = MaterialTheme.colorScheme.onErrorContainer ) } diff --git a/app/src/main/java/com/example/sw0b_001/ui/modals/PlatformOptionsModal.kt b/app/src/main/java/com/example/sw0b_001/ui/modals/PlatformOptionsModal.kt index 5a0bbad5..4225a5ce 100644 --- a/app/src/main/java/com/example/sw0b_001/ui/modals/PlatformOptionsModal.kt +++ b/app/src/main/java/com/example/sw0b_001/ui/modals/PlatformOptionsModal.kt @@ -1,19 +1,32 @@ package com.example.sw0b_001.ui.modals import android.content.Context +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.Delete import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.SheetValue @@ -27,10 +40,12 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.navigation.NavController @@ -46,7 +61,6 @@ import com.example.sw0b_001.ui.viewModels.TokensUiState import uniffi.relaysms_spec_payload.V1ContentCategories import uniffi.relaysms_spec_payload.v1ContentCategoryFromU8 - @OptIn(ExperimentalMaterial3Api::class, ExperimentalGlideComposeApi::class) @Composable fun PlatformOptionsModal( @@ -93,6 +107,8 @@ fun PlatformOptionsModal( else if(revokeAccountConfirmationRequested) { ConfirmationModal( showBottomSheet = revokeAccountConfirmationRequested, + message = "Are you sure you want to remove this account\n${selectedAccount?.account}?", + confirmButtonText = "Yes, remove.", onContinue = { revokeAccountConfirmationRequested = false revokeCallback(selectedAccount!!) @@ -118,40 +134,28 @@ fun PlatformOptionsModal( AddAccountLoading(platform!!) } else { - GlideImage( - model = platform?.icon_png, - contentDescription = stringResource(R.string.platform_image), - modifier = Modifier - .size(50.dp), - loading = placeholder(R.drawable.logo), // Shows while loading - failure = placeholder(R.drawable.logo) // Shows if download fails - ) { - it.diskCacheStrategy(DiskCacheStrategy.ALL) // Caches both original and resized images - .circleCrop() // Makes the image a circle - } - Spacer(modifier = Modifier.height(16.dp)) - Text( - text = if (isCompose) { - getServiceBasedComposeDescriptions( - context, - if(platform?.cat_id == null) V1ContentCategories.BRIDGE - else v1ContentCategoryFromU8( - platform.cat_id.toUByte()) - ) - } else { - getServiceBasedAvailableDescription( + if (isCompose) { + GlideImage( + model = platform?.icon_png, + contentDescription = stringResource(R.string.platform_image), + modifier = Modifier.size(50.dp), + loading = placeholder(R.drawable.logo), + failure = placeholder(R.drawable.logo) + ) { + it.diskCacheStrategy(DiskCacheStrategy.ALL).circleCrop() + } + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = getServiceBasedComposeDescriptions( context, if(platform?.cat_id == null) V1ContentCategories.BRIDGE - else v1ContentCategoryFromU8( - platform.cat_id.toUByte()) - ) - }, - style = MaterialTheme.typography.bodyMedium, - textAlign = TextAlign.Center - ) - Spacer(modifier = Modifier.height(24.dp)) + else v1ContentCategoryFromU8(platform.cat_id.toUByte()) + ), + style = MaterialTheme.typography.bodyMedium, + textAlign = TextAlign.Center + ) + Spacer(modifier = Modifier.height(24.dp)) - if (isCompose) { ComposeMessages( navController = navController, isOnboarding = isOnboarding, @@ -161,15 +165,20 @@ fun PlatformOptionsModal( onDismissRequest() } } else { - ManageAccounts( - isActive, - isOnboarding = isOnboarding, - addAccountsCallback = storeCallback, - removeAccountsCallback = { removeAccountRequested = true } + AccountsListView( + platform = platform, + accounts = accounts, + onAddNew = storeCallback, + onDeleteAccount = { account -> + selectedAccount = account + revokeAccountConfirmationRequested = true + }, + onDismissRequest = onDismissRequest ) } Spacer(modifier = Modifier.height(16.dp)) } + } } } @@ -301,4 +310,98 @@ private fun getServiceBasedComposeDescriptions( } V1ContentCategories.BRIDGE -> context.getString(R.string.your_relaysms_account_is_an_alias_of_your_phone_number_with_the_domain_relaysms_me_you_can_receive_replies_by_sms_whenever_a_message_is_sent_to_your_alias_you_can_choose_a_message_forwarding_country_from_the_countries_tab_below_continue_to_send_message) } +} + +@Composable +private fun AccountsListView( + platform: SupportedPlatforms?, + accounts: List, + onAddNew: () -> Unit, + onDeleteAccount: (Tokens) -> Unit, + onDismissRequest: () -> Unit, +) { + Column(modifier = Modifier.fillMaxWidth()) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "Your ${platform?.display_name ?: ""} account(s)", + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.SemiBold + ) + IconButton(onClick = onDismissRequest) { + Icon( + imageVector = Icons.Default.Close, + contentDescription = "Close" + ) + } + } + + Spacer(modifier = Modifier.height(16.dp)) + + Button( + onClick = onAddNew, + modifier = Modifier.align(Alignment.End), + shape = RoundedCornerShape(20.dp) + ) { + Icon( + imageVector = Icons.Default.Add, + contentDescription = null, + modifier = Modifier.size(18.dp) + ) + Spacer(modifier = Modifier.width(4.dp)) + Text("Add New") + } + + Spacer(modifier = Modifier.height(16.dp)) + + if (accounts.isEmpty()) { + Text( + text = "You have not saved any account yet. Click the add button to connect your ${platform?.display_name ?: ""} account.", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + textAlign = TextAlign.Center, + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 24.dp) + ) + } else { + accounts.forEach { account -> + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .size(40.dp) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.surfaceVariant) + ) + Spacer(modifier = Modifier.width(12.dp)) + Column(modifier = Modifier.weight(1f)) { + Text( + text = account.account, + style = MaterialTheme.typography.bodyMedium + ) + Text( + text = platform?.display_name ?: "", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + IconButton(onClick = { onDeleteAccount(account) }) { + Icon( + imageVector = Icons.Default.Delete, + contentDescription = "Delete account", + tint = Color.Red + ) + } + } + } + } + } } \ No newline at end of file