Simplified MainScreen bottom bar implementation

This commit is contained in:
Juha Heinanen
2025-10-21 09:50:00 +03:00
parent ee98e890f5
commit 3afc40cfca
5 changed files with 75 additions and 136 deletions

View File

@ -223,7 +223,7 @@ private fun MainScreen(
val ua = UserAgent.ofAor(viewModel.selectedAor.value)
if (ua != null) {
showCall(ctx, viewModel, ua)
updateIcons(viewModel, ua.account)
viewModel.triggerAccountUpdate()
}
}
Lifecycle.Event.ON_PAUSE -> {
@ -447,8 +447,7 @@ private fun MainScreen(
LaunchedEffect(currentRoute, viewModel.selectedAor.collectAsState()) {
if (currentRoute == "main") {
Log.d(TAG, "Updating icons for AOR: ${viewModel.selectedAor.value}")
val account = Account.ofAor(viewModel.selectedAor.value)
updateIcons(viewModel, account)
viewModel.triggerAccountUpdate()
}
}
@ -673,41 +672,56 @@ private fun TopAppBar(
@Composable
private fun BottomBar(ctx: Context, viewModel: ViewModel, navController: NavController) {
val vmIcon by viewModel.vmIcon.collectAsState()
val showVmIcon by viewModel.showVmIcon.collectAsState()
val messagesIcon by viewModel.messagesIcon.collectAsState()
val callsIcon by viewModel.callsIcon.collectAsState()
// ... (the top part of your function is the same) ...
val dialpadIcon by viewModel.dialpadIcon.collectAsState()
val aor by viewModel.selectedAor.collectAsState()
val accountUpdate by viewModel.accountUpdate.collectAsState()
val showVmIcon = remember(aor, accountUpdate) {
if (aor.isNotEmpty()) Account.ofAor(aor)?.vmUri?.isNotEmpty() ?: false else false
}
val hasNewVoicemail = remember(aor, accountUpdate) {
if (aor.isNotEmpty()) (Account.ofAor(aor)?.vmNew ?: 0) > 0 else false
}
val hasUnreadMessages = remember(aor, accountUpdate) {
if (aor.isNotEmpty()) Account.ofAor(aor)?.unreadMessages ?: false else false
}
val hasMissedCalls = remember(aor, accountUpdate) {
if (aor.isNotEmpty()) Account.ofAor(aor)?.missedCalls ?: false else false
}
val buttonSize = 48.dp
Row( modifier = Modifier
.fillMaxWidth()
.navigationBarsPadding()
.padding(bottom = 16.dp),
Row(
modifier = Modifier
.fillMaxWidth()
.navigationBarsPadding()
.padding(bottom = 16.dp),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically
) {
if (showVmIcon)
IconButton(
// Disable the button if no account is selected
enabled = aor.isNotEmpty(),
onClick = {
if (viewModel.selectedAor.value != "") {
val ua = UserAgent.ofAor(viewModel.selectedAor.value)!!
val acc = ua.account
if (acc.vmUri != "") {
dialogTitle.value = ctx.getString(R.string.voicemail_messages)
dialogMessage.value = acc.vmMessages(ctx)
positiveText.value = ctx.getString(R.string.listen)
onPositiveClicked.value = {
val intent = Intent(ctx, MainActivity::class.java)
intent.putExtra("uap", ua.uap)
intent.putExtra("peer", acc.vmUri)
handleIntent(ctx, viewModel, intent, "call")
}
negativeText.value = ctx.getString(R.string.cancel)
onNegativeClicked.value = {}
showDialog.value = true
// No need for an 'if' check here anymore
val ua = UserAgent.ofAor(aor)!!
val acc = ua.account
if (acc.vmUri.isNotEmpty()) {
dialogTitle.value = ctx.getString(R.string.voicemail_messages)
dialogMessage.value = acc.vmMessages(ctx)
positiveText.value = ctx.getString(R.string.listen)
onPositiveClicked.value = {
val intent = Intent(ctx, MainActivity::class.java)
intent.putExtra("uap", ua.uap)
intent.putExtra("peer", acc.vmUri)
handleIntent(ctx, viewModel, intent, "call")
}
negativeText.value = ctx.getString(R.string.cancel)
onNegativeClicked.value = {}
showDialog.value = true
}
},
modifier = Modifier
@ -715,13 +729,10 @@ private fun BottomBar(ctx: Context, viewModel: ViewModel, navController: NavCont
.size(buttonSize)
) {
Icon(
imageVector = ImageVector.vectorResource(vmIcon),
imageVector = ImageVector.vectorResource(R.drawable.voicemail),
contentDescription = null,
Modifier.size(buttonSize),
tint = if (vmIcon == R.drawable.voicemail)
MaterialTheme.colorScheme.secondary
else
MaterialTheme.colorScheme.error
tint = if (hasNewVoicemail) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.secondary
)
}
@ -740,52 +751,49 @@ private fun BottomBar(ctx: Context, viewModel: ViewModel, navController: NavCont
}
IconButton(
// Disable the button if no account is selected
enabled = aor.isNotEmpty(),
onClick = {
if (viewModel.selectedAor.value != "")
navController.navigate("chats/${viewModel.selectedAor.value}")
// No need for an 'if' check here anymore
navController.navigate("chats/$aor")
},
modifier = Modifier
.weight(1f)
.size(buttonSize)
) {
Icon(
imageVector = ImageVector.vectorResource(messagesIcon),
imageVector = ImageVector.vectorResource(R.drawable.messages),
contentDescription = null,
Modifier.size(buttonSize),
tint = if (messagesIcon == R.drawable.messages)
MaterialTheme.colorScheme.secondary
else
MaterialTheme.colorScheme.error
tint = if (hasUnreadMessages) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.secondary
)
}
IconButton(
// Disable the button if no account is selected
enabled = aor.isNotEmpty(),
onClick = {
if (viewModel.selectedAor.value != "")
navController.navigate("calls/${viewModel.selectedAor.value}")
// No need for an 'if' check here anymore
navController.navigate("calls/$aor")
},
modifier = Modifier
.weight(1f)
.size(buttonSize)
) {
Icon(
imageVector = ImageVector.vectorResource(callsIcon),
imageVector = ImageVector.vectorResource(R.drawable.calls),
contentDescription = null,
Modifier.size(buttonSize),
tint = if (callsIcon == R.drawable.calls)
MaterialTheme.colorScheme.secondary
else
MaterialTheme.colorScheme.error
tint = if (hasMissedCalls) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.secondary
)
}
IconButton(
onClick = { viewModel.updateDialpadIcon(
if (dialpadIcon == R.drawable.dialpad_off)
R.drawable.dialpad_on
else
R.drawable.dialpad_off
) },
onClick = {
viewModel.updateDialpadIcon(
if (dialpadIcon == R.drawable.dialpad_off) R.drawable.dialpad_on else R.drawable.dialpad_off
)
},
modifier = Modifier
.weight(1f)
.size(buttonSize),
@ -795,14 +803,10 @@ private fun BottomBar(ctx: Context, viewModel: ViewModel, navController: NavCont
imageVector = ImageVector.vectorResource(dialpadIcon),
contentDescription = null,
modifier = Modifier.size(buttonSize),
tint = if (dialpadIcon == R.drawable.dialpad_off)
MaterialTheme.colorScheme.secondary
else
MaterialTheme.colorScheme.error
tint = if (dialpadIcon == R.drawable.dialpad_off) MaterialTheme.colorScheme.secondary else MaterialTheme.colorScheme.error
)
}
}
}
private val callUri = mutableStateOf("")
@ -973,8 +977,7 @@ private fun AccountSpinner(ctx: Context, viewModel: ViewModel, navController: Na
}
showCall(ctx, viewModel, UserAgent.ofAor(selected))
updateIcons(viewModel, Account.ofAor(selected))
viewModel.triggerAccountUpdate()
if (selected == "") {
OutlinedButton(
@ -1103,7 +1106,7 @@ private fun AccountSpinner(ctx: Context, viewModel: ViewModel, navController: Na
expanded = false
viewModel.updateSelectedAor(acc.aor)
showCall(ctx, viewModel, ua)
updateIcons(viewModel, acc)
viewModel.triggerAccountUpdate()
},
text = { Text(
text = acc.text(),
@ -1831,7 +1834,7 @@ private fun OnHoldNotice() {
private fun spinToAor(viewModel: ViewModel, aor: String) {
if (aor != viewModel.selectedAor.value)
viewModel.updateSelectedAor(aor)
updateIcons(viewModel, Account.ofAor(aor))
viewModel.triggerAccountUpdate()
}
private fun callClick(ctx: Context, viewModel: ViewModel) {
@ -2193,7 +2196,7 @@ fun handleServiceEvent(ctx: Context, viewModel: ViewModel, event: String, params
when (ev[0]) {
"call rejected" -> {
if (aor == viewModel.selectedAor.value)
viewModel.updateCallsIcon(R.drawable.calls_missed)
viewModel.triggerAccountUpdate()
}
"call incoming", "call outgoing" -> {
val callp = params[1] as Long
@ -2336,7 +2339,7 @@ fun handleServiceEvent(ctx: Context, viewModel: ViewModel, event: String, params
ua.account.resumeUri = ""
showCall(ctx, viewModel, ua)
if (acc.missedCalls)
viewModel.updateCallsIcon(R.drawable.calls_missed)
viewModel.triggerAccountUpdate()
}
//if (kgm.isDeviceLocked)
// this.setShowWhenLocked(false)
@ -2356,13 +2359,8 @@ fun handleServiceEvent(ctx: Context, viewModel: ViewModel, event: String, params
break
}
}
if (aor == viewModel.selectedAor.value) {
viewModel.updateVmIcon(if (acc.vmNew > 0)
R.drawable.voicemail_new
else
R.drawable.voicemail
)
}
if (aor == viewModel.selectedAor.value)
viewModel.triggerAccountUpdate()
}
else -> Log.e(TAG, "Unknown event '${ev[0]}'")
}
@ -2536,36 +2534,6 @@ private fun acceptTransfer(ctx: Context, viewModel: ViewModel, ua: UserAgent, ca
}
}
private fun updateIcons(viewModel: ViewModel, acc: Account?) {
if (acc == null) {
viewModel.updateShowVmIcon(false)
viewModel.updateMessagesIcon(R.drawable.messages)
viewModel.updateCallsIcon(R.drawable.calls)
}
else {
if (acc.vmUri != "") {
viewModel.updateShowVmIcon(true)
viewModel.updateVmIcon(if (acc.vmNew > 0)
R.drawable.voicemail_new
else
R.drawable.voicemail
)
} else
viewModel.updateShowVmIcon(false)
viewModel.updateMessagesIcon(if (acc.unreadMessages)
R.drawable.messages_unread
else
R.drawable.messages)
viewModel.updateCallsIcon(if (acc.missedCalls)
R.drawable.calls_missed
else
R.drawable.calls)
}
}
private fun backup(ctx: Context, password: String) {
val files = arrayListOf("accounts", "config", "contacts", "call_history",
"messages", "uuid", "gzrtp.zid", "cert.pem", "ca_cert", "ca_certs.crt")

View File

@ -30,6 +30,13 @@ class ViewModel(application: Application) : AndroidViewModel(application) {
_selectedAor.value = newValue
}
private val _accountUpdate = MutableStateFlow(0)
val accountUpdate: StateFlow<Int> = _accountUpdate
fun triggerAccountUpdate() {
_accountUpdate.value++
}
private val _aorPeerMessage = MutableStateFlow(mutableMapOf<AorPeer, String>())
fun updateAorPeerMessage(aor: String, peerUri: String, message: String) {
@ -73,13 +80,6 @@ class ViewModel(application: Application) : AndroidViewModel(application) {
_micIcon.value = iconResId
}
private val _vmIcon = MutableStateFlow(R.drawable.voicemail)
val vmIcon: StateFlow<Int> = _vmIcon.asStateFlow()
fun updateVmIcon(newIcon: Int) {
_vmIcon.value = newIcon
}
private val _showVmIcon = MutableStateFlow(false)
val showVmIcon: StateFlow<Boolean> = _showVmIcon.asStateFlow()
@ -87,20 +87,6 @@ class ViewModel(application: Application) : AndroidViewModel(application) {
_showVmIcon.value = show
}
private val _messagesIcon = MutableStateFlow(R.drawable.messages)
val messagesIcon: StateFlow<Int> = _messagesIcon.asStateFlow()
fun updateMessagesIcon(newIcon: Int) {
_messagesIcon.value = newIcon
}
private val _callsIcon = MutableStateFlow(R.drawable.calls)
val callsIcon: StateFlow<Int> = _callsIcon.asStateFlow()
fun updateCallsIcon(newIcon: Int) {
_callsIcon.value = newIcon
}
private val _dialpadIcon = MutableStateFlow(R.drawable.dialpad_off)
val dialpadIcon: StateFlow<Int> = _dialpadIcon.asStateFlow()

View File

@ -1,5 +0,0 @@
<vector android:height="48dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z"/>
</vector>

View File

@ -1,5 +0,0 @@
<vector android:height="44dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="44dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM6,9h12v2L6,11L6,9zM14,14L6,14v-2h8v2zM18,8L6,8L6,6h12v2z"/>
</vector>

View File

@ -1,5 +0,0 @@
<vector android:height="48dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M18.5,6C15.46,6 13,8.46 13,11.5c0,1.33 0.47,2.55 1.26,3.5L9.74,15c0.79,-0.95 1.26,-2.17 1.26,-3.5C11,8.46 8.54,6 5.5,6S0,8.46 0,11.5 2.46,17 5.5,17h13c3.04,0 5.5,-2.46 5.5,-5.5S21.54,6 18.5,6zM5.5,15C3.57,15 2,13.43 2,11.5S3.57,8 5.5,8 9,9.57 9,11.5 7.43,15 5.5,15zM18.5,15c-1.93,0 -3.5,-1.57 -3.5,-3.5S16.57,8 18.5,8 22,9.57 22,11.5 20.43,15 18.5,15z"/>
</vector>