From 63e4506df91dc6fa1f56454815b8244495eb3046 Mon Sep 17 00:00:00 2001 From: Juha Heinanen Date: Fri, 4 Apr 2025 19:21:40 +0300 Subject: [PATCH] Added and used PasswordDialog composable --- .../com/tutpro/baresip/AccountActivity.kt | 160 +++--------------- .../com/tutpro/baresip/CustomElements.kt | 151 +++++++++++++++++ .../kotlin/com/tutpro/baresip/MainActivity.kt | 152 +++-------------- 3 files changed, 198 insertions(+), 265 deletions(-) diff --git a/app/src/main/kotlin/com/tutpro/baresip/AccountActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/AccountActivity.kt index 573638d6..4ef1150f 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/AccountActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/AccountActivity.kt @@ -3,7 +3,6 @@ package com.tutpro.baresip import android.content.Context import android.content.Intent import android.os.Bundle -import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.OnBackPressedCallback import androidx.activity.compose.setContent @@ -14,35 +13,27 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawingPadding -import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Check -import androidx.compose.material3.AlertDialogDefaults -import androidx.compose.material3.BasicAlertDialog import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text -import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable @@ -53,8 +44,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalSoftwareKeyboardController @@ -130,6 +119,7 @@ class AccountActivity : ComponentActivity() { private var oldDefaultAccount = false private var newDefaultAccount = false private var arrowTint = Color.Unspecified + private var password = mutableStateOf("") private var showPasswordDialog = mutableStateOf(false) private var keyboardController: SoftwareKeyboardController? = null @@ -1166,137 +1156,25 @@ class AccountActivity : ComponentActivity() { @OptIn(ExperimentalMaterial3Api::class) @Composable fun AskPassword(ctx: Context) { - if (showPasswordDialog.value) { - val showPassword = remember { mutableStateOf(false) } - BasicAlertDialog( - onDismissRequest = { - keyboardController?.hide() - showPasswordDialog.value = false + if (showPasswordDialog.value) + CustomElements.PasswordDialog( + ctx = ctx, + showPasswordDialog = showPasswordDialog, + password = password, + keyboardController = keyboardController, + title = getString(R.string.authentication_password), + okAction = { + BaresipService.aorPasswords[acc.aor] = password.value + Api.account_set_auth_pass(acc.accp, password.value) + password.value = "" + reRegister = true + finishActivity() + }, + cancelAction = { + reRegister = true + finishActivity() } - ) { - Surface( - modifier = Modifier - .wrapContentWidth() - .wrapContentHeight(), - color = LocalCustomColors.current.background, - shape = MaterialTheme.shapes.large, - tonalElevation = AlertDialogDefaults.TonalElevation - ) { - Column(modifier = Modifier.padding(16.dp)) { - CustomElements.Text( - text = getString(R.string.authentication_password), - fontSize = 20.sp, - modifier = Modifier.padding(top = 16.dp, bottom = 16.dp), - color = LocalCustomColors.current.alert, - ) - val message = getString(R.string.account) + " " + Utils.plainAor(acc.aor) - CustomElements.Text( - text = message, - fontSize = 16.sp, - modifier = Modifier.padding(16.dp), - color = LocalCustomColors.current.itemText, - ) - var password by remember { mutableStateOf("") } - val focusRequester = remember { FocusRequester() } - OutlinedTextField( - value = password, - singleLine = true, - colors = OutlinedTextFieldDefaults.colors( - focusedContainerColor = LocalCustomColors.current.textFieldBackground, - unfocusedContainerColor = LocalCustomColors.current.textFieldBackground, - cursorColor = LocalCustomColors.current.primary, - ), - onValueChange = { - password = it - }, - visualTransformation = if (showPassword.value) - VisualTransformation.None - else - PasswordVisualTransformation(), - trailingIcon = { - IconButton(onClick = { - showPassword.value = !showPassword.value - }) { - Icon( - if (showPassword.value) - ImageVector.vectorResource(R.drawable.visibility) - else - ImageVector.vectorResource(R.drawable.visibility_off), - contentDescription = "Visibility", - tint = LocalCustomColors.current.grayDark - - ) - } - }, - modifier = Modifier - .fillMaxWidth() - .padding( - start = 4.dp, - end = 4.dp, - top = 12.dp, - bottom = 2.dp - ) - .focusRequester(focusRequester), - textStyle = TextStyle( - fontSize = 18.sp, - color = LocalCustomColors.current.dark - ), - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text) - ) - Row( - horizontalArrangement = Arrangement.Start - ) { - TextButton( - onClick = { - keyboardController?.hide() - showPasswordDialog.value = false - reRegister = true - finishActivity() - }, - modifier = Modifier.padding(8.dp), - ) { - CustomElements.Text( - text = stringResource(R.string.cancel), - color = LocalCustomColors.current.gray - ) - } - Spacer(modifier = Modifier.weight(1f)) - TextButton( - onClick = { - keyboardController?.hide() - showPasswordDialog.value = false - password = password.trim() - if (!Account.checkAuthPass(password)) { - Toast.makeText( - ctx, - String.format( - getString(R.string.invalid_authentication_password), - password - ), - Toast.LENGTH_SHORT - ).show() - password = "" - showPasswordDialog.value = true - } - else { - BaresipService.aorPasswords[acc.aor] = password - Api.account_set_auth_pass(acc.accp, password) - reRegister = true - finishActivity() - } - }, - modifier = Modifier.padding(8.dp), - ) { - CustomElements.Text( - text = stringResource(R.string.ok), - color = LocalCustomColors.current.alert - ) - } - } - } - } - } - } + ) } private fun updateAccount() { diff --git a/app/src/main/kotlin/com/tutpro/baresip/CustomElements.kt b/app/src/main/kotlin/com/tutpro/baresip/CustomElements.kt index 94e688ba..ab37f961 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/CustomElements.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/CustomElements.kt @@ -1,6 +1,8 @@ package com.tutpro.baresip +import android.content.Context import android.graphics.Bitmap +import android.widget.Toast import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.foundation.Canvas @@ -11,13 +13,19 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.AlertDialogDefaults +import androidx.compose.material3.BasicAlertDialog import androidx.compose.material3.Button import androidx.compose.material3.Card import androidx.compose.material3.Checkbox @@ -26,11 +34,19 @@ import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.OutlinedTextFieldDefaults +import androidx.compose.material3.Surface import androidx.compose.material3.TextButton import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults.Indicator import androidx.compose.material3.pulltorefresh.pullToRefresh import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -39,15 +55,25 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawWithContent +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.SoftwareKeyboardController import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp @@ -55,6 +81,8 @@ import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import androidx.core.content.ContextCompat.getString import com.tutpro.baresip.CustomElements.ThreeButtonAlertDialog object CustomElements { @@ -232,6 +260,129 @@ object CustomElements { } } + @OptIn(ExperimentalMaterial3Api::class) + @Composable + fun PasswordDialog( + ctx: Context, + showPasswordDialog: MutableState, + password: MutableState, + keyboardController:SoftwareKeyboardController?, + title: String, + okAction: () -> Unit, + cancelAction: () -> Unit + ) { + val showPassword = remember { mutableStateOf(false) } + val focusRequester = remember { FocusRequester() } + BasicAlertDialog( + properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false), + onDismissRequest = { + keyboardController?.hide() + showPasswordDialog.value = false + } + ) { + Surface( + modifier = Modifier + .wrapContentWidth() + .wrapContentHeight(), + color = LocalCustomColors.current.background, + shape = MaterialTheme.shapes.large, + tonalElevation = AlertDialogDefaults.TonalElevation + ) { + Column(modifier = Modifier.padding(16.dp)) { + Text( + text = title, + fontSize = 20.sp, + modifier = Modifier.padding(top = 16.dp, bottom = 16.dp), + color = LocalCustomColors.current.alert, + ) + OutlinedTextField( + value = password.value, + singleLine = true, + colors = OutlinedTextFieldDefaults.colors( + focusedContainerColor = LocalCustomColors.current.textFieldBackground, + unfocusedContainerColor = LocalCustomColors.current.textFieldBackground, + cursorColor = LocalCustomColors.current.primary, + ), + onValueChange = { + password.value = it + }, + visualTransformation = if (showPassword.value) + VisualTransformation.None + else + PasswordVisualTransformation(), + trailingIcon = { + IconButton(onClick = { + showPassword.value = !showPassword.value + showPasswordDialog.value = true + }) { + Icon( + if (showPassword.value) + ImageVector.vectorResource(R.drawable.visibility) + else + ImageVector.vectorResource(R.drawable.visibility_off), + contentDescription = "Visibility", + tint = LocalCustomColors.current.grayDark + + ) + } + }, + modifier = Modifier + .fillMaxWidth() + .padding(start = 4.dp, end = 4.dp, top = 12.dp, bottom = 2.dp) + .focusRequester(focusRequester), + textStyle = TextStyle( + fontSize = 18.sp, + color = LocalCustomColors.current.dark + ), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text) + ) + LaunchedEffect(key1 = Unit) { + focusRequester.requestFocus() + keyboardController?.show() + } + Row( + horizontalArrangement = Arrangement.Start + ) { + TextButton( + onClick = { + keyboardController?.hide() + showPasswordDialog.value = false + cancelAction() + }, + ) { + Text( + text = stringResource(R.string.cancel), + color = LocalCustomColors.current.gray + ) + } + Spacer(modifier = Modifier.weight(1f)) + TextButton( + onClick = { + keyboardController?.hide() + showPasswordDialog.value = false + password.value = password.value.trim() + if (!Account.checkAuthPass(password.value)) { + Toast.makeText(ctx, + String.format(getString(ctx, R.string.invalid_authentication_password), password.value), + Toast.LENGTH_SHORT + ).show() + password.value = "" + } + if (password.value != "") + okAction() + }, + ) { + Text( + text = stringResource(R.string.ok), + color = LocalCustomColors.current.alert + ) + } + } + } + } + } + } + @Composable fun ThreeButtonAlertDialog( onDismissRequest: () -> Unit, diff --git a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt index 84c0d286..c9168f7e 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/MainActivity.kt @@ -130,6 +130,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.viewinterop.AndroidView +import androidx.compose.ui.window.DialogProperties import androidx.core.content.ContextCompat import androidx.core.net.toUri import androidx.lifecycle.Observer @@ -202,6 +203,7 @@ class MainActivity : ComponentActivity() { private var showHangupButton = mutableStateOf(false) private var showOnHoldNotice = mutableStateOf(false) private var showPasswordDialog = mutableStateOf(false) + private var password = mutableStateOf("") private var showPasswordsDialog = mutableStateOf(false) private var holdIcon = mutableIntStateOf(R.drawable.call_hold) private var transferButtonEnabled = mutableStateOf(false) @@ -1814,7 +1816,9 @@ class MainActivity : ComponentActivity() { if (Utils.paramValue(params, "auth_user") != "" && Utils.paramValue(params, "auth_pass") == "") { val aor = account.substringAfter("<").substringBefore(">") val showPassword = remember { mutableStateOf(false) } + val focusRequester = remember { FocusRequester() } BasicAlertDialog( + properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false), onDismissRequest = { keyboardController?.hide() showPasswordsDialog.value = false @@ -1844,7 +1848,6 @@ class MainActivity : ComponentActivity() { color = LocalCustomColors.current.itemText, ) var password by remember { mutableStateOf("") } - val focusRequester = remember { FocusRequester() } OutlinedTextField( value = password, singleLine = true, @@ -1877,19 +1880,18 @@ class MainActivity : ComponentActivity() { }, modifier = Modifier .fillMaxWidth() - .padding( - start = 4.dp, - end = 4.dp, - top = 12.dp, - bottom = 2.dp - ) + .padding(start = 4.dp, end = 4.dp, top = 12.dp, bottom = 2.dp) .focusRequester(focusRequester), - textStyle = TextStyle( + textStyle = TextStyle( fontSize = 18.sp, color = LocalCustomColors.current.dark ), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text) ) + LaunchedEffect(key1 = Unit) { + focusRequester.requestFocus() + keyboardController?.show() + } Row( horizontalArrangement = Arrangement.Start ) { @@ -1951,124 +1953,26 @@ class MainActivity : ComponentActivity() { @Composable fun AskPassword(ctx: Context) { - if (showPasswordDialog.value) { - val showPassword = remember { mutableStateOf(false) } - BasicAlertDialog( - onDismissRequest = { - keyboardController?.hide() - showPasswordDialog.value = false - } - ) { - Surface( - modifier = Modifier - .wrapContentWidth() - .wrapContentHeight(), - color = LocalCustomColors.current.background, - shape = MaterialTheme.shapes.large, - tonalElevation = AlertDialogDefaults.TonalElevation - ) { - Column(modifier = Modifier.padding(16.dp)) { - Text( - text = passwordTitle, - fontSize = 20.sp, - modifier = Modifier.padding(top = 16.dp, bottom = 16.dp), - color = LocalCustomColors.current.alert, - ) - var password by remember { mutableStateOf("") } - val focusRequester = remember { FocusRequester() } - OutlinedTextField( - value = password, - singleLine = true, - colors = OutlinedTextFieldDefaults.colors( - focusedContainerColor = LocalCustomColors.current.textFieldBackground, - unfocusedContainerColor = LocalCustomColors.current.textFieldBackground, - cursorColor = LocalCustomColors.current.primary, - ), - onValueChange = { - password = it - }, - visualTransformation = if (showPassword.value) - VisualTransformation.None - else - PasswordVisualTransformation(), - trailingIcon = { - IconButton(onClick = { - showPassword.value = !showPassword.value - }) { - Icon( - if (showPassword.value) - ImageVector.vectorResource(R.drawable.visibility) - else - ImageVector.vectorResource(R.drawable.visibility_off), - contentDescription = "Visibility", - tint = LocalCustomColors.current.grayDark - - ) - } - }, - modifier = Modifier - .fillMaxWidth() - .padding( - start = 4.dp, - end = 4.dp, - top = 12.dp, - bottom = 2.dp - ) - .focusRequester(focusRequester), - textStyle = TextStyle( - fontSize = 18.sp, - color = LocalCustomColors.current.dark - ), - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text) - ) - Row( - horizontalArrangement = Arrangement.Start - ) { - TextButton( - onClick = { - keyboardController?.hide() - showPasswordDialog.value = false - if (downloadsOutputUri != null) { - Utils.deleteFile(ctx, downloadsOutputUri!!) - } - }, - ) { - Text( - text = stringResource(R.string.cancel), - color = LocalCustomColors.current.gray - ) - } - Spacer(modifier = Modifier.weight(1f)) - TextButton( - onClick = { - keyboardController?.hide() - showPasswordDialog.value = false - password = password.trim() - if (!Account.checkAuthPass(password)) { - Toast.makeText(ctx, - String.format(getString(R.string.invalid_authentication_password), password), - Toast.LENGTH_SHORT - ).show() - password = "" - } - if (password != "") { - if (passwordTitle == getString(R.string.encrypt_password)) - backup(password) - else - restore(password) - } - }, - ) { - Text( - text = stringResource(R.string.ok), - color = LocalCustomColors.current.alert - ) - } - } + if (showPasswordDialog.value) + CustomElements.PasswordDialog( + ctx = ctx, + showPasswordDialog = showPasswordDialog, + password = password, + keyboardController = keyboardController, + title = passwordTitle, + okAction = { + if (passwordTitle == getString(R.string.encrypt_password)) + backup(password.value) + else + restore(password.value) + password.value = "" + }, + cancelAction = { + if (downloadsOutputUri != null) { + Utils.deleteFile(ctx, downloadsOutputUri!!) } } - } - } + ) } private fun calls(ctx: Context) {