Created AlertDialog composable and used it in calls activity

This commit is contained in:
Juha Heinanen
2025-04-11 14:49:55 +03:00
parent ce3039ea83
commit e7823ffab1
2 changed files with 244 additions and 159 deletions
@@ -2,11 +2,9 @@ package com.tutpro.baresip
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.os.Bundle import android.os.Bundle
import android.os.SystemClock
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
@@ -61,7 +59,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import coil.compose.AsyncImage import coil.compose.AsyncImage
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.tutpro.baresip.CustomElements.AlertDialog
import com.tutpro.baresip.CustomElements.ImageAvatar import com.tutpro.baresip.CustomElements.ImageAvatar
import com.tutpro.baresip.CustomElements.TextAvatar import com.tutpro.baresip.CustomElements.TextAvatar
import com.tutpro.baresip.CustomElements.verticalScrollbar import com.tutpro.baresip.CustomElements.verticalScrollbar
@@ -71,7 +69,6 @@ class CallsActivity : ComponentActivity() {
private lateinit var account: Account private lateinit var account: Account
private var aor = "" private var aor = ""
private var lastClick: Long = 0
private val onBackPressedCallback = object : OnBackPressedCallback(true) { private val onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() { override fun handleOnBackPressed() {
@@ -136,6 +133,18 @@ class CallsActivity : ComponentActivity() {
val disable = String.format(getString(R.string.disable_history)) val disable = String.format(getString(R.string.disable_history))
val enable = String.format(getString(R.string.enable_history)) val enable = String.format(getString(R.string.enable_history))
val openDialog = remember { mutableStateOf(false) }
val positiveAction = remember { mutableStateOf({}) }
AlertDialog(
openDialog = openDialog,
title = getString(R.string.confirmation),
message = String.format(getString(R.string.delete_history_alert), aor.substringAfter(":")),
positiveButtonText = getString(R.string.delete),
negativeButtonText = getString(R.string.cancel),
onPositiveClicked = positiveAction.value,
)
TopAppBar( TopAppBar(
title = { title = {
Text( Text(
@@ -172,29 +181,14 @@ class CallsActivity : ComponentActivity() {
onItemClick = { selectedItem -> onItemClick = { selectedItem ->
expanded = false expanded = false
when (selectedItem) { when (selectedItem) {
delete -> delete -> {
with( positiveAction.value = {
MaterialAlertDialogBuilder(this@CallsActivity, R.style.AlertDialogTheme)
) {
setTitle(R.string.confirmation)
setMessage(
String.format(
getString(R.string.delete_history_alert),
aor.substringAfter(":")
)
)
setPositiveButton(delete) { dialog, _ ->
CallHistoryNew.clear(aor) CallHistoryNew.clear(aor)
CallHistoryNew.save() CallHistoryNew.save()
uaHistory.value = emptyList() uaHistory.value = emptyList()
dialog.dismiss()
} }
setNeutralButton(getText(R.string.cancel)) { dialog, _ -> openDialog.value = true
dialog.dismiss()
} }
show()
}
disable, enable -> { disable, enable -> {
account.callHistory = !account.callHistory account.callHistory = !account.callHistory
AccountsActivity.saveAccounts() AccountsActivity.saveAccounts()
@@ -242,6 +236,25 @@ class CallsActivity : ComponentActivity() {
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
fun Calls(ctx: Context, account: Account) { fun Calls(ctx: Context, account: Account) {
val openDialog = remember { mutableStateOf(false) }
val message = remember { mutableStateOf("") }
val positiveButtonText = remember { mutableStateOf("") }
val positiveAction = remember { mutableStateOf({}) }
val neutralButtonText = remember { mutableStateOf("") }
val neutralAction = remember { mutableStateOf({}) }
AlertDialog(
openDialog = openDialog,
title = getString(R.string.confirmation),
message = message.value,
positiveButtonText = positiveButtonText.value,
onPositiveClicked = positiveAction.value,
neutralButtonText = neutralButtonText.value,
onNeutralClicked = neutralAction.value,
negativeButtonText = getString(R.string.cancel)
)
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
LazyColumn( LazyColumn(
modifier = Modifier modifier = Modifier
@@ -268,10 +281,76 @@ class CallsActivity : ComponentActivity() {
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.combinedClickable( modifier = Modifier.combinedClickable(
onClick = { onClick = {
callMessageClick(ctx, callRow) val peerUri = callRow.peerUri
val peerName = Utils.friendlyUri(ctx, peerUri, account)
message.value = String.format(ctx.getString(R.string.contact_action_question), peerName)
positiveButtonText.value = ctx.getString(R.string.call)
positiveAction.value = {
BaresipService.activities.remove("calls,$aor")
MainActivity.activityAor = aor
returnResult()
val i = Intent(this@CallsActivity, MainActivity::class.java)
i.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
i.putExtra("action", "call")
i.putExtra("uap", UserAgent.ofAor(aor)!!.uap)
i.putExtra("peer", peerUri)
startActivity(i)
}
neutralButtonText.value = ctx.getString(R.string.send_message)
neutralAction.value = {
BaresipService.activities.remove("calls,$aor")
MainActivity.activityAor = aor
returnResult()
val i = Intent(this@CallsActivity, MainActivity::class.java)
i.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
i.putExtra("action", "message")
i.putExtra("uap", UserAgent.ofAor(aor)!!.uap)
i.putExtra("peer", peerUri)
startActivity(i)
}
openDialog.value = true
}, },
onLongClick = { onLongClick = {
callMessageLongClick(ctx, callRow) val peerUri = callRow.peerUri
val peerName = Utils.friendlyUri(ctx, peerUri, account)
val callText: String = if (callRow.details.size > 1)
getString(R.string.calls_calls)
else
getString(R.string.calls_call)
val contactExists = Contact.nameExists(peerName, BaresipService.contacts, false)
if (contactExists) {
message.value = String.format(
getString(R.string.calls_delete_question),
peerName, callText
)
positiveButtonText.value = getString(R.string.delete)
positiveAction.value = {
removeFromHistory(callRow)
CallHistoryNew.save()
}
neutralButtonText.value = ""
}
else {
message.value = String.format(
getString(R.string.calls_add_delete_question),
peerName, callText
)
positiveButtonText.value = getString(R.string.add_contact)
positiveAction.value = {
val i = Intent(ctx, BaresipContactActivity::class.java)
val b = Bundle()
b.putBoolean("new", true)
b.putString("uri", callRow.peerUri)
i.putExtras(b)
ctx.startActivity(i)
}
neutralButtonText.value = getString(R.string.delete)
neutralAction.value = {
removeFromHistory(callRow)
CallHistoryNew.save()
}
}
openDialog.value = true
} }
) )
) { ) {
@@ -291,7 +370,9 @@ class CallsActivity : ComponentActivity() {
model = thumbNailUri, model = thumbNailUri,
contentDescription = "Avatar", contentDescription = "Avatar",
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
modifier = Modifier.size(36.dp).clip(CircleShape), modifier = Modifier
.size(36.dp)
.clip(CircleShape),
) )
else else
TextAvatar(contact.name, contact.color) TextAvatar(contact.name, contact.color)
@@ -334,7 +415,9 @@ class CallsActivity : ComponentActivity() {
LocalCustomColors.current.accent LocalCustomColors.current.accent
else else
LocalCustomColors.current.itemText, LocalCustomColors.current.itemText,
modifier = Modifier.padding(end = 16.dp).width(64.dp) modifier = Modifier
.padding(end = 16.dp)
.width(64.dp)
.clickable(onClick = { .clickable(onClick = {
val i = Intent(ctx, CallDetailsActivity::class.java) val i = Intent(ctx, CallDetailsActivity::class.java)
val b = Bundle() val b = Bundle()
@@ -351,130 +434,6 @@ class CallsActivity : ComponentActivity() {
} }
} }
private fun callMessageClick(ctx: Context, callRow: CallRow) {
val peerUri = callRow.peerUri
val peerName = Utils.friendlyUri(ctx, peerUri, account)
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
when (which) {
DialogInterface.BUTTON_POSITIVE, DialogInterface.BUTTON_NEGATIVE -> {
BaresipService.activities.remove("calls,$aor")
MainActivity.activityAor = aor
returnResult()
val i = Intent(this@CallsActivity, MainActivity::class.java)
i.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
if (which == DialogInterface.BUTTON_NEGATIVE)
i.putExtra("action", "call")
else
i.putExtra("action", "message")
i.putExtra("uap", UserAgent.ofAor(aor)!!.uap)
i.putExtra("peer", peerUri)
startActivity(i)
}
DialogInterface.BUTTON_NEUTRAL -> {
}
}
}
if (SystemClock.elapsedRealtime() - lastClick > 1000) {
lastClick = SystemClock.elapsedRealtime()
with(
MaterialAlertDialogBuilder(ctx, R.style.AlertDialogTheme)
) {
setTitle(R.string.confirmation)
setMessage(
String.format(ctx.getString(R.string.contact_action_question), peerName)
)
setNeutralButton(
ctx.getText(R.string.cancel),
dialogClickListener
)
setNegativeButton(
ctx.getText(R.string.call),
dialogClickListener
)
setPositiveButton(
ctx.getText(R.string.send_message),
dialogClickListener
)
show()
}
}
}
private fun callMessageLongClick(ctx: Context, callRow: CallRow) {
val peerUri = callRow.peerUri
val peerName = Utils.friendlyUri(ctx, peerUri, account)
val dialogClickListener =
DialogInterface.OnClickListener { _, which ->
when (which) {
DialogInterface.BUTTON_NEGATIVE -> {
val i = Intent(ctx, BaresipContactActivity::class.java)
val b = Bundle()
b.putBoolean("new", true)
b.putString("uri", peerUri)
i.putExtras(b)
ctx.startActivity(i)
}
DialogInterface.BUTTON_POSITIVE -> {
removeFromHistory(callRow)
CallHistoryNew.save()
}
DialogInterface.BUTTON_NEUTRAL -> {
}
}
}
val callText: String = if (callRow.details.size > 1)
getString(R.string.calls_calls)
else
getString(R.string.calls_call)
val builder = MaterialAlertDialogBuilder(
this@CallsActivity,
R.style.AlertDialogTheme
)
if (!Contact.nameExists(peerName, BaresipService.contacts, false))
with(builder) {
setTitle(R.string.confirmation)
setMessage(
String.format(
getString(R.string.calls_add_delete_question),
peerName, callText
)
)
setNeutralButton(
getString(R.string.cancel),
dialogClickListener
)
setPositiveButton(
getString(R.string.delete),
dialogClickListener
)
setNegativeButton(
getString(R.string.add_contact),
dialogClickListener
)
show()
}
else
with(builder) {
setTitle(R.string.confirmation)
setMessage(
String.format(
getString(R.string.calls_delete_question),
peerName, callText
)
)
setNeutralButton(
getString(R.string.cancel),
dialogClickListener
)
setPositiveButton(
getString(R.string.delete),
dialogClickListener
)
show()
}
}
private fun goBack() { private fun goBack() {
BaresipService.activities.remove("calls,$aor") BaresipService.activities.remove("calls,$aor")
returnResult() returnResult()
@@ -19,16 +19,19 @@ import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.AlertDialogDefaults import androidx.compose.material3.AlertDialogDefaults
import androidx.compose.material3.BasicAlertDialog import androidx.compose.material3.BasicAlertDialog
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.Checkbox import androidx.compose.material3.Checkbox
import androidx.compose.material3.CheckboxDefaults import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
@@ -120,11 +123,13 @@ object CustomElements {
Surface( Surface(
shape = shape, shape = shape,
color = color, color = color,
modifier = modifier.pointerInput(Unit) { modifier = modifier
.pointerInput(Unit) {
detectTapGestures( detectTapGestures(
onTap = { onClick() }, onTap = { onClick() },
onLongPress = { onLongClick() }, onLongPress = { onLongClick() },
) } )
}
.then(modifier), .then(modifier),
) { ) {
Row( Row(
@@ -310,6 +315,126 @@ object CustomElements {
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AlertDialog(
openDialog: MutableState<Boolean>,
title: String,
message: String,
positiveButtonText: String,
onPositiveClicked: () -> Unit,
negativeButtonText: String = "",
onNegativeClicked: () -> Unit = {},
neutralButtonText: String = "",
onNeutralClicked: () -> Unit = {}
) {
if (openDialog.value) {
BasicAlertDialog(
onDismissRequest = {
openDialog.value = false
},
content = {
Card(
modifier = Modifier.fillMaxWidth()
.padding(top = 16.dp, start = 16.dp, end = 16.dp, bottom = 0.dp),
shape = RoundedCornerShape(16.dp),
) {
Column(modifier = Modifier.padding(16.dp)) {
androidx.compose.material3.Text(
text = title,
fontSize = 20.sp,
color = LocalCustomColors.current.alert,
)
Spacer(modifier = Modifier.height(16.dp))
androidx.compose.material3.Text(
text = message,
fontSize = 16.sp,
color = LocalCustomColors.current.itemText,
)
Spacer(modifier = Modifier.height(16.dp))
if (negativeButtonText.isNotEmpty() && neutralButtonText.isNotEmpty()) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.End
) {
TextButton(onClick = {
onPositiveClicked()
openDialog.value = false
}) {
androidx.compose.material3.Text(
text = positiveButtonText.uppercase(),
fontSize = 14.sp,
color = LocalCustomColors.current.alert,
)
}
TextButton(onClick = {
onNeutralClicked()
openDialog.value = false
}) {
androidx.compose.material3.Text(
text = neutralButtonText.uppercase(),
fontSize = 14.sp,
color = LocalCustomColors.current.alert
)
}
TextButton(onClick = {
onNegativeClicked()
openDialog.value = false
}) {
androidx.compose.material3.Text(
text = negativeButtonText.uppercase(),
fontSize = 14.sp,
color = LocalCustomColors.current.gray
)
}
}
}
else {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End
) {
if (negativeButtonText.isNotEmpty())
TextButton(onClick = {
onNegativeClicked()
openDialog.value = false
}) {
androidx.compose.material3.Text(
text = negativeButtonText.uppercase(),
fontSize = 14.sp,
color = LocalCustomColors.current.gray
)
}
if (neutralButtonText.isNotEmpty())
TextButton(onClick = {
onNeutralClicked()
openDialog.value = false
}) {
androidx.compose.material3.Text(
text = neutralButtonText.uppercase(),
fontSize = 14.sp,
color = LocalCustomColors.current.alert
)
}
TextButton(onClick = {
onPositiveClicked()
openDialog.value = false
}) {
androidx.compose.material3.Text(
text = positiveButtonText.uppercase(),
fontSize = 14.sp,
color = LocalCustomColors.current.alert,
)
}
}
}
}
}
}
)
}
}
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun PasswordDialog( fun PasswordDialog(
@@ -448,4 +573,5 @@ object CustomElements {
} }
} }
} }
} }