Added Blocking screen to account settings

Added capability to add call and message peers to blocked list
Fixed background color of bottom navigation bar on some screens
This commit is contained in:
Juha Heinanen
2026-06-21 19:54:48 +03:00
parent eb85a5ef1c
commit 09fdec99cb
16 changed files with 141 additions and 131 deletions

View File

@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
@ -56,7 +55,7 @@ fun AboutScreen(onBack: () -> Unit) {
} }
Scaffold( Scaffold(
modifier = Modifier.fillMaxSize().imePadding().navigationBarsPadding(), modifier = Modifier.fillMaxSize().imePadding(),
containerColor = MaterialTheme.colorScheme.background, containerColor = MaterialTheme.colorScheme.background,
topBar = { topBar = {
Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) { Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {

View File

@ -13,7 +13,6 @@ import androidx.compose.foundation.layout.WindowInsets
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.imePadding import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
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.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
@ -164,7 +163,7 @@ private fun AccountScreen(
} }
Scaffold( Scaffold(
modifier = Modifier.fillMaxSize().imePadding().navigationBarsPadding(), modifier = Modifier.fillMaxSize().imePadding(),
containerColor = MaterialTheme.colorScheme.background, containerColor = MaterialTheme.colorScheme.background,
topBar = { topBar = {
Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) { Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {
@ -604,55 +603,17 @@ private fun AccountContent(
} }
@Composable @Composable
fun BlockUnknown() { fun Blocking(navController: NavController, aor: String) {
val blockUnknownTitle = stringResource(R.string.block_unknown)
val blockUnknownHelp = stringResource(R.string.block_unknown_help)
val block by viewModel.blockUnknown.collectAsState()
Row( Row(
Modifier.fillMaxWidth().padding(end = 10.dp), Modifier.fillMaxWidth().padding(top = 8.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Start horizontalArrangement = Arrangement.Start
) { ) {
Text(text = blockUnknownTitle, Text(
modifier = Modifier text = stringResource(R.string.blocking),
.weight(1f) modifier = Modifier.weight(1f).clickable { navController.navigate("blocking/$aor") },
.clickable { fontSize = 18.sp,
alertTitle.value = blockUnknownTitle fontWeight = FontWeight.Bold
alertMessage.value = blockUnknownHelp
showAlert.value = true
},
fontSize = 18.sp
)
Switch(
checked = block,
onCheckedChange = { viewModel.blockUnknown.value = it }
)
}
}
@Composable
fun BlockHidden() {
val blockHiddenTitle = stringResource(R.string.block_hidden)
val blockHiddenHelp = stringResource(R.string.block_hidden_help)
val block by viewModel.blockHidden.collectAsState()
Row(
Modifier.fillMaxWidth().padding(end = 10.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Start
) {
Text(text = blockHiddenTitle,
modifier = Modifier
.weight(1f)
.clickable {
alertTitle.value = blockHiddenTitle
alertMessage.value = blockHiddenHelp
showAlert.value = true
},
fontSize = 18.sp
)
Switch(
checked = block,
onCheckedChange = { viewModel.blockHidden.value = it }
) )
} }
} }
@ -660,7 +621,7 @@ private fun AccountContent(
@Composable @Composable
fun AudioCodecs(navController: NavController, aor: String) { fun AudioCodecs(navController: NavController, aor: String) {
Row( Row(
Modifier.fillMaxWidth(), Modifier.fillMaxWidth().padding(top = 8.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Start horizontalArrangement = Arrangement.Start
) { ) {
@ -1343,8 +1304,7 @@ private fun AccountContent(
CheckOrigin() CheckOrigin()
} }
} }
BlockUnknown() Blocking(navController, aor)
BlockHidden()
if (!ua.account.isMobile) { if (!ua.account.isMobile) {
AudioCodecs(navController, aor) AudioCodecs(navController, aor)
MediaEnc() MediaEnc()

View File

@ -69,7 +69,7 @@ fun NavGraphBuilder.accountsScreenRoute(navController: NavController) {
@Composable @Composable
fun AccountsScreen(navController: NavController) { fun AccountsScreen(navController: NavController) {
Scaffold( Scaffold(
modifier = Modifier.fillMaxSize().imePadding().navigationBarsPadding(), modifier = Modifier.fillMaxSize().imePadding(),
containerColor = MaterialTheme.colorScheme.background, containerColor = MaterialTheme.colorScheme.background,
topBar = { topBar = {
Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) { Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {

View File

@ -20,7 +20,6 @@ import androidx.compose.foundation.layout.WindowInsets
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.imePadding import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
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.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
@ -101,7 +100,7 @@ private fun AudioScreen(
checkOnClick: () -> Unit, checkOnClick: () -> Unit,
) { ) {
Scaffold( Scaffold(
modifier = Modifier.fillMaxSize().imePadding().navigationBarsPadding(), modifier = Modifier.fillMaxSize().imePadding(),
containerColor = MaterialTheme.colorScheme.background, containerColor = MaterialTheme.colorScheme.background,
topBar = { topBar = {
Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) { Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {

View File

@ -553,6 +553,7 @@ class BaresipService: Service() {
} }
Blocked.restore() Blocked.restore()
BlockRule.restore()
val recordings = File(filesDir, "recordings") val recordings = File(filesDir, "recordings")
@ -988,6 +989,11 @@ class BaresipService: Service() {
) )
else if (ua.account.blockHidden && peerUri.contains("anonymous")) else if (ua.account.blockHidden && peerUri.contains("anonymous"))
getString(R.string.hidden_call_blocked) getString(R.string.hidden_call_blocked)
else if (isBlocked(peerUri))
String.format(
getString(R.string.call_blocked),
Utils.friendlyUri(this, peerUri, ua.account)
)
else if (!Utils.checkPermissions(this, arrayOf(RECORD_AUDIO))) else if (!Utils.checkPermissions(this, arrayOf(RECORD_AUDIO)))
getString(R.string.no_calls) getString(R.string.no_calls)
else else
@ -1452,6 +1458,28 @@ class BaresipService: Service() {
val aor = ua.account.aor val aor = ua.account.aor
if ((ua.account.blockUnknown && Contact.contactName(peerUri) == peerUri) ||
(ua.account.blockHidden && peerUri.contains("anonymous")) ||
isBlocked(peerUri)) {
Log.d(TAG, "Auto-rejecting blocked message from $peerUri")
toast(
if (ua.account.blockHidden && peerUri.contains("anonymous"))
getString(R.string.hidden_message_blocked)
else
String.format(
getString(R.string.message_blocked),
Utils.friendlyUri(this, peerUri, ua.account)
)
)
Blocked(
ua.account.aor,
peerUri,
"message",
GregorianCalendar().timeInMillis
).add()
return
}
// Check for duplicates // Check for duplicates
val lastMsg = messages.lastOrNull { m -> m.aor == aor } val lastMsg = messages.lastOrNull { m -> m.aor == aor }
if (lastMsg != null && lastMsg.timeStamp == timeStamp && lastMsg.peerUri == peerUri && if (lastMsg != null && lastMsg.timeStamp == timeStamp && lastMsg.peerUri == peerUri &&
@ -2958,6 +2986,14 @@ class BaresipService: Service() {
val calls = ArrayList<Call>() val calls = ArrayList<Call>()
var callHistory = ArrayList<CallHistoryNew>() var callHistory = ArrayList<CallHistoryNew>()
var blocked = ArrayList<Blocked>() var blocked = ArrayList<Blocked>()
var blockRules = mutableListOf<BlockRule>()
fun isBlocked(uri: String): Boolean {
for (rule in blockRules) {
if (rule.matches(uri)) return true
}
return false
}
var contactsMode by mutableStateOf("baresip") var contactsMode by mutableStateOf("baresip")
var addressFamily = "" var addressFamily = ""

View File

@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.WindowInsets
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.imePadding import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
@ -108,7 +107,7 @@ private fun BlockedScreen(navController: NavController, request: String, aor: St
} }
Scaffold( Scaffold(
modifier = Modifier.fillMaxSize().imePadding().navigationBarsPadding(), modifier = Modifier.fillMaxSize().imePadding(),
containerColor = MaterialTheme.colorScheme.background, containerColor = MaterialTheme.colorScheme.background,
topBar = { topBar = {
Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) { Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {
@ -220,7 +219,7 @@ private fun BlockedContent(
verticalArrangement = Arrangement.spacedBy(12.dp) verticalArrangement = Arrangement.spacedBy(12.dp)
) { ) {
Account(account) Account(account)
Blocked(ctx, navController, blocked) Blocked(ctx, navController, account, blocked)
} }
} }
@ -237,7 +236,12 @@ private fun Account(account: Account) {
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
private fun Blocked(ctx: Context, navController: NavController, blocked: MutableState<List<Blocked>>) { private fun Blocked(
ctx: Context,
navController: NavController,
acc: Account,
blocked: MutableState<List<Blocked>>
) {
val showDialog = remember { mutableStateOf(false) } val showDialog = remember { mutableStateOf(false) }
val message = remember { mutableStateOf("") } val message = remember { mutableStateOf("") }
val lastButtonText = remember { mutableStateOf("") } val lastButtonText = remember { mutableStateOf("") }
@ -286,7 +290,7 @@ private fun Blocked(ctx: Context, navController: NavController, blocked: Mutable
modifier = Modifier.padding(start = 8.dp, end = 4.dp), modifier = Modifier.padding(start = 8.dp, end = 4.dp),
fontSize = 18.sp) fontSize = 18.sp)
Text( Text(
text = peerUri.replace("sip:", ""), text = Utils.friendlyUri(ctx, peerUri, acc),
fontSize = 18.sp, fontSize = 18.sp,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis

View File

@ -22,7 +22,6 @@ 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.height
import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
@ -94,7 +93,7 @@ fun NavGraphBuilder.callDetailsScreenRoute(navController: NavController, viewMod
private fun CallDetailsScreen(navController: NavController, callRow: CallRow) { private fun CallDetailsScreen(navController: NavController, callRow: CallRow) {
val detailsState = remember { callRow.details.toMutableStateList() } val detailsState = remember { callRow.details.toMutableStateList() }
Scaffold( Scaffold(
modifier = Modifier.fillMaxSize().imePadding().navigationBarsPadding(), modifier = Modifier.fillMaxSize().imePadding(),
containerColor = MaterialTheme.colorScheme.background, containerColor = MaterialTheme.colorScheme.background,
topBar = { topBar = {
Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) { Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {
@ -294,8 +293,8 @@ private fun startTime(detail: Details, onDelete: (Details) -> Unit): String {
Text( Text(
text = startTimeText, text = startTimeText,
modifier = Modifier.combinedClickable( modifier = Modifier.combinedClickable(
onClick = {}, onClick = { showDialog.value = true },
onLongClick = { showDialog.value = true } onLongClick = { }
) )
) )

View File

@ -17,7 +17,6 @@ import androidx.compose.foundation.layout.WindowInsets
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.imePadding import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
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.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
@ -121,7 +120,7 @@ private fun CallsScreen(navController: NavController, viewModel: ViewModel, aor:
} }
Scaffold( Scaffold(
modifier = Modifier.fillMaxSize().imePadding().navigationBarsPadding(), modifier = Modifier.fillMaxSize().imePadding(),
containerColor = MaterialTheme.colorScheme.background, containerColor = MaterialTheme.colorScheme.background,
topBar = { topBar = {
Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) { Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {
@ -417,8 +416,7 @@ private fun Calls(
peerNameWithLabel, callText peerNameWithLabel, callText
) )
secondButtonText.value = "" secondButtonText.value = ""
thirdButtonText.value = ctx.getString(R.string.copy_uri) thirdButtonText.value = ""
thirdAction.value = { Utils.copyToClipboard(ctx, peerUri) }
lastButtonText.value = ctx.getString(R.string.delete) lastButtonText.value = ctx.getString(R.string.delete)
lastAction.value = { removeFromHistory(callHistory, callRow) } lastAction.value = { removeFromHistory(callHistory, callRow) }
} }
@ -433,8 +431,12 @@ private fun Calls(
val uri = Utils.sipToTel(peerUri) val uri = Utils.sipToTel(peerUri)
navController.navigate("contact/$uri/new") navController.navigate("contact/$uri/new")
} }
thirdButtonText.value = ctx.getString(R.string.copy_uri) thirdButtonText.value = ctx.getString(R.string.block)
thirdAction.value = { Utils.copyToClipboard(ctx, peerUri) thirdAction.value = {
if (!BlockRule.exists(peerUri)) {
BaresipService.blockRules.add(BlockRule(peerUri))
BlockRule.save()
}
} }
lastButtonText.value = ctx.getString(R.string.delete) lastButtonText.value = ctx.getString(R.string.delete)
lastAction.value = { removeFromHistory(callHistory, callRow) } lastAction.value = { removeFromHistory(callHistory, callRow) }

View File

@ -37,8 +37,6 @@ import androidx.compose.material.icons.automirrored.filled.Send
import androidx.compose.material.icons.outlined.Call import androidx.compose.material.icons.outlined.Call
import androidx.compose.material.icons.outlined.Clear import androidx.compose.material.icons.outlined.Clear
import androidx.compose.material.icons.outlined.Email import androidx.compose.material.icons.outlined.Email
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
@ -191,7 +189,6 @@ private fun ChatScreen(
if (areMessagesLoaded) if (areMessagesLoaded)
ChatContent( ChatContent(
ctx, ctx,
navController,
contentPadding, contentPadding,
account, peerUri, account, peerUri,
chatMessages, chatMessages,
@ -286,7 +283,6 @@ private fun TopAppBar(
@Composable @Composable
private fun ChatContent( private fun ChatContent(
ctx: Context, ctx: Context,
navController: NavController,
contentPadding: PaddingValues, contentPadding: PaddingValues,
account: Account, account: Account,
peerUri: String, peerUri: String,
@ -299,7 +295,7 @@ private fun ChatContent(
) { ) {
Account(ctx, account) Account(ctx, account)
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
Messages(ctx, navController, account, peerUri, messages, onMessageDeleted) Messages(ctx, account, peerUri, messages, onMessageDeleted)
} }
} }
@ -317,7 +313,6 @@ private fun Account(ctx: Context, account: Account) {
@Composable @Composable
private fun Messages( private fun Messages(
ctx: Context, ctx: Context,
navController: NavController,
account: Account, account: Account,
peerUri: String, peerUri: String,
messages: List<Message>, messages: List<Message>,
@ -389,42 +384,28 @@ private fun Messages(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(end = 12.dp) modifier = Modifier.padding(end = 12.dp)
) { ) {
Button( CustomElements.Button(
onClick = { onClick = {
if (Contact.findContact(peerUri) == null) { dialogMessage.value = ctx.getString(R.string.short_message_question)
dialogMessage.value = String.format( secondButtonText.value = ""
ctx.getString(R.string.long_message_question), lastButtonText.value = ctx.getString(R.string.delete)
peerUri lastAction.value = {
) message.delete()
secondButtonText.value = ctx.getString(R.string.add_contact) onMessageDeleted()
secondAction.value = { navController.navigate("contact/$peerUri/new") }
lastButtonText.value = ctx.getString(R.string.delete)
lastAction.value = {
message.delete()
onMessageDeleted()
}
} else {
dialogMessage.value = ctx.getString(R.string.short_message_question)
secondButtonText.value = ""
lastButtonText.value = ctx.getString(R.string.delete)
lastAction.value = {
message.delete()
onMessageDeleted()
}
} }
showDialog.value = true showDialog.value = true
}, },
onLongClick = {
},
shape = if (message.direction == MESSAGE_DOWN) shape = if (message.direction == MESSAGE_DOWN)
RoundedCornerShape(50.dp, 20.dp, 20.dp, 10.dp) RoundedCornerShape(50.dp, 20.dp, 20.dp, 10.dp)
else else
RoundedCornerShape(20.dp, 10.dp, 50.dp, 20.dp), RoundedCornerShape(20.dp, 10.dp, 50.dp, 20.dp),
colors = ButtonDefaults.buttonColors( color =
containerColor = if (message.direction == MESSAGE_DOWN)
if (message.direction == MESSAGE_DOWN) MaterialTheme.colorScheme.secondaryContainer
MaterialTheme.colorScheme.secondaryContainer else
else MaterialTheme.colorScheme.primaryContainer,
MaterialTheme.colorScheme.primaryContainer
),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.wrapContentHeight() .wrapContentHeight()

View File

@ -253,6 +253,8 @@ private fun Chats(
val dialogMessage = remember { mutableStateOf("") } val dialogMessage = remember { mutableStateOf("") }
val secondButtonText = remember { mutableStateOf("") } val secondButtonText = remember { mutableStateOf("") }
val secondAction = remember { mutableStateOf({}) } val secondAction = remember { mutableStateOf({}) }
val thirdButtonText = remember { mutableStateOf("") }
val thirdAction = remember { mutableStateOf({}) }
val lastButtonText = remember { mutableStateOf("") } val lastButtonText = remember { mutableStateOf("") }
val lastAction = remember { mutableStateOf({}) } val lastAction = remember { mutableStateOf({}) }
@ -264,6 +266,8 @@ private fun Chats(
firstButtonText = stringResource(R.string.cancel), firstButtonText = stringResource(R.string.cancel),
secondButtonText = secondButtonText.value, secondButtonText = secondButtonText.value,
onSecondClicked = secondAction.value, onSecondClicked = secondAction.value,
thirdButtonText = thirdButtonText.value,
onThirdClicked = thirdAction.value,
lastButtonText = lastButtonText.value, lastButtonText = lastButtonText.value,
onLastClicked = lastAction.value, onLastClicked = lastAction.value,
) )
@ -344,10 +348,17 @@ private fun Chats(
ctx.getString(R.string.long_chat_question), ctx.getString(R.string.long_chat_question),
peerName peerName
) )
secondButtonText.value = ctx.getString(R.string.delete) secondButtonText.value = ctx.getString(R.string.add_contact)
secondAction.value = { deleteMessages(uaMessages, account, message.peerUri) } secondAction.value = { navController.navigate("contact/${message.peerUri}/new") }
lastButtonText.value = ctx.getString(R.string.add_contact) thirdButtonText.value = ctx.getString(R.string.block)
lastAction.value = { navController.navigate("contact/${message.peerUri}/new") } thirdAction.value = {
if (!BlockRule.exists(message.peerUri)) {
BaresipService.blockRules.add(BlockRule(message.peerUri))
BlockRule.save()
}
}
lastButtonText.value = ctx.getString(R.string.delete)
lastAction.value = { deleteMessages(uaMessages, account, message.peerUri) }
} }
showDialog.value = true showDialog.value = true
}, },

View File

@ -10,7 +10,6 @@ import androidx.compose.foundation.layout.WindowInsets
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.imePadding import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
@ -118,7 +117,7 @@ private fun CodecsScreen(
} }
Scaffold( Scaffold(
modifier = Modifier.fillMaxSize().imePadding().navigationBarsPadding(), modifier = Modifier.fillMaxSize().imePadding(),
containerColor = MaterialTheme.colorScheme.background, containerColor = MaterialTheme.colorScheme.background,
topBar = { topBar = {
Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) { Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {

View File

@ -31,7 +31,6 @@ import androidx.compose.foundation.layout.WindowInsets
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.imePadding import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
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.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
@ -275,7 +274,7 @@ private fun ContactScreen(
BackHandler(enabled = true) { onBack() } BackHandler(enabled = true) { onBack() }
Scaffold( Scaffold(
modifier = Modifier.fillMaxSize().imePadding().navigationBarsPadding(), modifier = Modifier.fillMaxSize().imePadding(),
containerColor = MaterialTheme.colorScheme.background, containerColor = MaterialTheme.colorScheme.background,
topBar = { topBar = {
Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) { Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {

View File

@ -290,6 +290,7 @@ class MainActivity : ComponentActivity() {
callsScreenRoute(navController, viewModel) callsScreenRoute(navController, viewModel)
callDetailsScreenRoute(navController, viewModel) callDetailsScreenRoute(navController, viewModel)
blockedScreenRoute(navController) blockedScreenRoute(navController)
blockingScreenRoute(navController)
chatsScreenRoute(navController) chatsScreenRoute(navController)
chatScreenRoute(navController, viewModel) chatScreenRoute(navController, viewModel)
} }

View File

@ -30,7 +30,6 @@ import androidx.compose.foundation.layout.WindowInsets
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.imePadding import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
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.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
@ -156,7 +155,7 @@ private fun SettingsScreen(
} }
Scaffold( Scaffold(
modifier = Modifier.fillMaxSize().imePadding().navigationBarsPadding(), modifier = Modifier.fillMaxSize().imePadding(),
containerColor = MaterialTheme.colorScheme.background, containerColor = MaterialTheme.colorScheme.background,
topBar = { topBar = {
Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) { Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {

View File

@ -279,6 +279,17 @@
<string name="hidden_call_blocked">Estetty puhelu tuntemattomalta soittajalta</string> <string name="hidden_call_blocked">Estetty puhelu tuntemattomalta soittajalta</string>
<string name="message_blocked">Estetty viesti vieraalta lähettäjältä \`%1$s\`</string> <string name="message_blocked">Estetty viesti vieraalta lähettäjältä \`%1$s\`</string>
<string name="hidden_message_blocked">Estetty viesti tuntemattomalta lähettäjältä</string> <string name="hidden_message_blocked">Estetty viesti tuntemattomalta lähettäjältä</string>
<!-- Blocking Activity -->
<string name="blocking">Estot</string>
<string name="blocking_list">Estolista</string>
<string name="new_blocking_rule">Uusi estosääntö</string>
<string name="blocking_rule_help">Estosääntö voi olla joko merkkijono tai
säännöllinen lauseke. Jos merkkijono löytyy soittajan tai viestin
lähettäjän URI:sta tai jos säännöllinen lauseke sopii siihen, niin
puhelu tai viesti estetään.
</string>
<string name="blocking_delete_alert">Haluatko poistaa estosäännön \'%1$s\'\?</string>
<!-- Blocked Activity --> <!-- Blocked Activity -->
<string name="blocked">Estetyt</string> <string name="blocked">Estetyt</string>
<string name="blocked_calls">Estetyt puhelut</string> <string name="blocked_calls">Estetyt puhelut</string>
@ -294,11 +305,10 @@
<string name="peer">Kumppani</string> <string name="peer">Kumppani</string>
<string name="time">Aika</string> <string name="time">Aika</string>
<string name="calls_duration">Kesto</string> <string name="calls_duration">Kesto</string>
<string name="calls_add_delete_question">Haluatko luoda kohteelle \'%1$s\' uuden yhteystiedon, <string name="calls_add_delete_question">Haluatko lisätä URI:n \'%1$s\' yhteystietoihin tai
kopioida sen URI:n tai poistaa %2$s puheluhistoriasta\? estolistaan tai poistaa %2$s puheluhistoriasta\?
</string> </string>
<string name="calls_delete_question">Haluatko kopioida yhteystiedon \'%1$s\' URI:n tai poistaa <string name="calls_delete_question">Haluatko poistaa %2$s puheluhistoriasta\?</string>
%2$s puheluhistoriasta\?</string>
<string name="disable_history">Poista käytöstä</string> <string name="disable_history">Poista käytöstä</string>
<string name="enable_history">Ota käyttöön</string> <string name="enable_history">Ota käyttöön</string>
<string name="delete_history_alert">Haluatko tyhjentää tilin \'%1$s\' puheluhistorian\?</string> <string name="delete_history_alert">Haluatko tyhjentää tilin \'%1$s\' puheluhistorian\?</string>
@ -326,8 +336,9 @@
<string name="today">Tänään</string> <string name="today">Tänään</string>
<string name="you">Sinä</string> <string name="you">Sinä</string>
<string name="new_chat_peer">Uusi viestin kohde</string> <string name="new_chat_peer">Uusi viestin kohde</string>
<string name="long_chat_question">Haluatko poistaa viestiketjun tai <string name="long_chat_question">Haluatko lisätä URI:n \'%1$s\' yhteystietoihin tai estolistaan
luoda uuden yhteystiedon \'%1$s\'\?</string> tai poistaa tämän viestiketjun?
</string>
<string name="short_chat_question">Haluatko poistaa viestiketjun \'%1$s\'\?</string> <string name="short_chat_question">Haluatko poistaa viestiketjun \'%1$s\'\?</string>
<string name="delete_chats_alert">Haluatko tyhjentää tilin \'%1$s\' viestihistorian\?</string> <string name="delete_chats_alert">Haluatko tyhjentää tilin \'%1$s\' viestihistorian\?</string>
<!-- Codecs Activity --> <!-- Codecs Activity -->
@ -403,10 +414,10 @@
nimeltään \'ca_certs.crt\' ladataan Download-kansiosta. nimeltään \'ca_certs.crt\' ladataan Download-kansiosta.
</string> </string>
<string name="no_read_permission">Ei ulkoisen muistin lukuoikeutta</string> <string name="no_read_permission">Ei ulkoisen muistin lukuoikeutta</string>
<string name="unique_contact_uri">Uniikki Contact URI</string> <string name="unique_contact_uri">Uniikki kontakti-URI</string>
<string name="unique_contact_uri_help">Jos merkitty, Contact URI:n taataan olevan uniikki. <string name="unique_contact_uri_help">Jos merkitty, kontakti-URI:n taataan olevan uniikki.
Merkittävä, jos on useammalla tilillä on same SIP URI:n käyttäjäosa, mutta myös Merkittävä, jos on useammalla tilillä on sama SIP URI:n käyttäjäosa, mutta se myös
suojaa tilejä hyökkäyksiltä. parantaa tilien suojaa hyökkäyksiltä.
</string> </string>
<string name="audio_settings">Audio-asetukset</string> <string name="audio_settings">Audio-asetukset</string>
<string name="speaker_phone">Kaiutin</string> <string name="speaker_phone">Kaiutin</string>
@ -531,6 +542,7 @@
<string name="deny">Estä</string> <string name="deny">Estä</string>
<string name="add">Lisää</string> <string name="add">Lisää</string>
<string name="delete">Poista</string> <string name="delete">Poista</string>
<string name="block">Estä</string>
<string name="edit">Muokkaa</string> <string name="edit">Muokkaa</string>
<string name="copy_uri">Kopioi URI</string> <string name="copy_uri">Kopioi URI</string>
<string name="copied_to_clipboard">Kopioitu leikepöydälle</string> <string name="copied_to_clipboard">Kopioitu leikepöydälle</string>

View File

@ -271,6 +271,15 @@
<string name="hidden_call_blocked">Auto-rejected call from hidden caller</string> <string name="hidden_call_blocked">Auto-rejected call from hidden caller</string>
<string name="message_blocked">Auto-rejected blocked message from \`%1$s\`</string> <string name="message_blocked">Auto-rejected blocked message from \`%1$s\`</string>
<string name="hidden_message_blocked">Auto-rejected message from hidden sender</string> <string name="hidden_message_blocked">Auto-rejected message from hidden sender</string>
<!-- Blocking Activity -->
<string name="blocking">Blocking</string>
<string name="blocking_list">Blocking List</string>
<string name="new_blocking_rule">New Blocking Rule</string>
<string name="blocking_rule_help">Blocking rule can be either a string or a regular expression.
If the string is included in the peer URI or regular expression matches,
the call or message will be blocked.
</string>
<string name="blocking_delete_alert">Do you want to delete blocking rule \'%1$s\'\?</string>
<!-- Blocked Activity --> <!-- Blocked Activity -->
<string name="blocked">Blocked</string> <string name="blocked">Blocked</string>
<string name="blocked_calls">Blocked Calls</string> <string name="blocked_calls">Blocked Calls</string>
@ -287,10 +296,9 @@
<string name="direction">Direction</string> <string name="direction">Direction</string>
<string name="time">Time</string> <string name="time">Time</string>
<string name="calls_duration">Duration</string> <string name="calls_duration">Duration</string>
<string name="calls_add_delete_question">Do you want to add \'%1$s\' to contacts, copy its URI, <string name="calls_add_delete_question">Do you want to add \'%1$s\' to contacts, block it,
or delete this %2$s from call history\?</string> or delete %2$s from call history\?</string>
<string name="calls_delete_question">Do you want to copy URI of \'%1$s\' or delete this %2$s <string name="calls_delete_question">Do you want to delete %2$s from call history\?</string>
from call history\?</string>
<string name="disable_history">Disable</string> <string name="disable_history">Disable</string>
<string name="enable_history">Enable</string> <string name="enable_history">Enable</string>
<string name="delete_history_alert">Do you want to delete call history of account \'%1$s\'\?</string> <string name="delete_history_alert">Do you want to delete call history of account \'%1$s\'\?</string>
@ -308,7 +316,7 @@
<string name="chat_with">Chat with %1$s</string> <string name="chat_with">Chat with %1$s</string>
<string name="new_message">New message</string> <string name="new_message">New message</string>
<string name="long_message_question">Do you want to delete message or add peer \'%1$s\' to contacts\?</string> <string name="long_message_question">Do you want to delete message or add peer \'%1$s\' to contacts\?</string>
<string name="short_message_question">Do you want to delete message\?</string> <string name="short_message_question">Do you want to delete this message\?</string>
<string name="add_contact">Add Contact</string> <string name="add_contact">Add Contact</string>
<string name="sending_failed">Sending of message failed</string> <string name="sending_failed">Sending of message failed</string>
<string name="message_failed">Failed</string> <string name="message_failed">Failed</string>
@ -317,8 +325,8 @@
<string name="today">Today</string> <string name="today">Today</string>
<string name="you">You</string> <string name="you">You</string>
<string name="new_chat_peer">New Chat Peer</string> <string name="new_chat_peer">New Chat Peer</string>
<string name="long_chat_question">Do you want to delete chat with peer \'%1$s\' or <string name="long_chat_question">Do you want to add \'%1$s\' to contacts, block it, or
add peer to contacts\?</string> delete this chat?</string>
<string name="short_chat_question">Do you want to delete chat with \'%1$s\'\?</string> <string name="short_chat_question">Do you want to delete chat with \'%1$s\'\?</string>
<string name="delete_chats_alert">Do you want to delete chat history of account \'%1$s\'\?</string> <string name="delete_chats_alert">Do you want to delete chat history of account \'%1$s\'\?</string>
<!-- Codecs Activity --> <!-- Codecs Activity -->
@ -510,6 +518,7 @@
<string name="deny">Deny</string> <string name="deny">Deny</string>
<string name="add">Add</string> <string name="add">Add</string>
<string name="delete">Delete</string> <string name="delete">Delete</string>
<string name="block">Block</string>
<string name="edit">Edit</string> <string name="edit">Edit</string>
<string name="copy_uri">Copy URI</string> <string name="copy_uri">Copy URI</string>
<string name="copied_to_clipboard">Copied to clipboard</string> <string name="copied_to_clipboard">Copied to clipboard</string>