From cbf34886c70fc180f7691e4024c8dded317a34d6 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Mon, 27 Nov 2023 21:34:02 +0100 Subject: [PATCH] feat: automatically split sms into multiple if too long (closes #337) --- .../contacts/ui/screens/SmsThreadScreen.kt | 26 ++++++++++++++----- .../java/com/bnyro/contacts/util/SmsUtil.kt | 22 +++++++++++++++- app/src/main/res/values/strings.xml | 1 + .../com/bnyro/contacts/ExampleUnitTest.kt | 24 +++++++++++++++-- 4 files changed, 63 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/bnyro/contacts/ui/screens/SmsThreadScreen.kt b/app/src/main/java/com/bnyro/contacts/ui/screens/SmsThreadScreen.kt index 04c885f7..be39cbc9 100644 --- a/app/src/main/java/com/bnyro/contacts/ui/screens/SmsThreadScreen.kt +++ b/app/src/main/java/com/bnyro/contacts/ui/screens/SmsThreadScreen.kt @@ -36,7 +36,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.PlainTooltipBox import androidx.compose.material3.Scaffold -import androidx.compose.material3.SearchBar import androidx.compose.material3.SwipeToDismiss import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar @@ -267,6 +266,10 @@ fun SmsThreadScreen( .padding(start = 10.dp, end = 5.dp, bottom = 20.dp), verticalAlignment = Alignment.CenterVertically ) { + var showConfirmSendMultipleSmsDialog by remember { + mutableStateOf(false) + } + var text by remember { mutableStateOf(initialText) } @@ -288,12 +291,7 @@ fun SmsThreadScreen( onClick = { if (text.isBlank()) return@FilledIconButton if (!SmsUtil.isShortEnoughForSms(text)) { - Toast.makeText( - context, - R.string.message_too_long, - Toast.LENGTH_SHORT - ) - .show() + showConfirmSendMultipleSmsDialog = true return@FilledIconButton } @@ -307,6 +305,20 @@ fun SmsThreadScreen( contentDescription = stringResource(R.string.send) ) } + + if (showConfirmSendMultipleSmsDialog) { + ConfirmationDialog( + onDismissRequest = { showConfirmSendMultipleSmsDialog = false }, + title = stringResource(R.string.message_too_long), + text = stringResource(R.string.send_message_as_multiple) + ) { + SmsUtil.splitSmsText(text).forEach { + smsModel.sendSms(context, address, it) + } + + text = "" + } + } } } } diff --git a/app/src/main/java/com/bnyro/contacts/util/SmsUtil.kt b/app/src/main/java/com/bnyro/contacts/util/SmsUtil.kt index a0c62b93..aa4af563 100644 --- a/app/src/main/java/com/bnyro/contacts/util/SmsUtil.kt +++ b/app/src/main/java/com/bnyro/contacts/util/SmsUtil.kt @@ -18,7 +18,7 @@ import java.lang.Character.UnicodeBlock import java.util.Calendar object SmsUtil { - private const val MAX_CHAR_LIMIT = 160 + const val MAX_CHAR_LIMIT = 160 private const val MAX_CHAR_LIMIT_WITH_UNICODE = 70 lateinit var smsRepo: SmsRepository @@ -109,4 +109,24 @@ object SmsUtil { return true } + + fun splitSmsText(text: String): List { + var currentIndex = 0 + val splits = mutableListOf() + + while (currentIndex < text.length) { + var fullPart = text.substring(currentIndex, minOf(currentIndex + MAX_CHAR_LIMIT, text.length)) + + if (isShortEnoughForSms(fullPart)) { + currentIndex += MAX_CHAR_LIMIT + } else { + fullPart = text.substring(currentIndex, minOf(currentIndex + MAX_CHAR_LIMIT_WITH_UNICODE, text.length)) + currentIndex += MAX_CHAR_LIMIT_WITH_UNICODE + } + + splits.add(fullPart) + } + + return splits + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3f7be6e5..a5783795 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -84,6 +84,7 @@ Reply Could not connect. Please ensure airplane mode is off. Message is too long! + Do you want to send the message as multiple smaller ones? Private SMS Database The SMS will only be stored within the app and not be accessible in other apps. Delete thread diff --git a/app/src/test/java/com/bnyro/contacts/ExampleUnitTest.kt b/app/src/test/java/com/bnyro/contacts/ExampleUnitTest.kt index 6471e642..af668cca 100644 --- a/app/src/test/java/com/bnyro/contacts/ExampleUnitTest.kt +++ b/app/src/test/java/com/bnyro/contacts/ExampleUnitTest.kt @@ -1,6 +1,7 @@ package com.bnyro.contacts import com.bnyro.contacts.util.CalendarUtils +import com.bnyro.contacts.util.SmsUtil import org.junit.Assert.assertEquals import org.junit.Test @@ -13,7 +14,26 @@ class ExampleUnitTest { @Test fun dateConversion() { val date = "2023-05-09" - val str = CalendarUtils.dateToMillis(date) - assertEquals(date, CalendarUtils.millisToDate(str.toString(), CalendarUtils.isoDateFormat)) + val millis = CalendarUtils.dateToMillis(date)!! + assertEquals(date, CalendarUtils.millisToDate(millis, CalendarUtils.isoDateFormat)) + } + + @Test + fun splitLongSms() { + val text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ornare lectus sit amet est placerat in egestas. Lectus sit amet est placerat. Molestie a iaculis at erat pellentesque adipiscing commodo elit. Sociis natoque penatibus et magnis dis parturient montes. Non enim praesent elementum facilisis leo vel fringilla est. Ut morbi tincidunt augue interdum velit euismod. Pharetra massa massa ultricies mi quis hendrerit. At erat pellentesque adipiscing commodo elit at imperdiet. Risus commodo viverra maecenas accumsan lacus vel facilisis volutpat est. In hac habitasse platea dictumst quisque sagittis purus. Netus et malesuada fames ac turpis egestas sed tempus. Neque volutpat ac tincidunt vitae semper quis lectus. Dui faucibus in ornare quam viverra.\n" + + "\n" + + "Tempor id eu nisl nunc mi ipsum. Nulla porttitor massa id neque aliquam vestibulum morbi. Sit amet nulla facilisi morbi tempus iaculis urna id. Aliquet bibendum enim facilisis gravida. Velit scelerisque in dictum non consectetur a erat. Sit amet facilisis magna etiam tempor orci eu lobortis. Vulputate enim nulla aliquet porttitor lacus luctus. Ipsum nunc aliquet bibendum enim facilisis gravida neque convallis. Luctus accumsan tortor posuere ac ut consequat semper viverra. Cras adipiscing enim eu turpis egestas pretium aenean pharetra magna. Tristique sollicitudin nibh sit amet commodo nulla facilisi nullam vehicula. Montes nascetur ridiculus mus mauris vitae ultricies leo integer malesuada. Nulla facilisi nullam vehicula ipsum. Turpis egestas sed tempus urna et. Leo integer malesuada nunc vel. Aliquet nec ullamcorper sit amet risus nullam eget felis. Consequat nisl vel pretium lectus quam id leo. Magnis dis parturient montes nascetur ridiculus mus mauris vitae ultricies.\n" + + "\n" + + "In nisl nisi scelerisque eu ultrices vitae auctor eu. Eu nisl nunc mi ipsum faucibus vitae aliquet nec ullamcorper. Dictum varius duis at consectetur lorem donec massa. Purus in mollis nunc sed id semper. Euismod nisi porta lorem mollis aliquam ut. Aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices sagittis. Volutpat maecenas volutpat blandit aliquam etiam erat. Velit laoreet id donec ultrices tincidunt arcu non sodales neque. Vel elit scelerisque mauris pellentesque pulvinar pellentesque habitant morbi. Viverra mauris in aliquam sem fringilla ut morbi tincidunt augue.\n" + + "\n" + + "Viverra orci sagittis eu volutpat odio facilisis mauris. Mi eget mauris pharetra et ultrices neque ornare aenean euismod. Facilisis leo vel fringilla est. Vulputate odio ut enim blandit volutpat maecenas. Volutpat commodo sed egestas egestas fringilla phasellus faucibus scelerisque eleifend. Risus at ultrices mi tempus imperdiet nulla. Praesent elementum facilisis leo vel. Eros in cursus turpis massa tincidunt dui ut. Elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus. Nulla aliquet porttitor lacus luctus accumsan tortor posuere. Vestibulum rhoncus est pellentesque elit ullamcorper dignissim cras tincidunt lobortis. Quis blandit turpis cursus in hac habitasse platea dictumst. Id aliquet risus feugiat in. Condimentum mattis pellentesque id nibh tortor id. Ac tortor dignissim convallis aenean et tortor at risus viverra. Vehicula ipsum a arcu cursus vitae congue mauris rhoncus.\n" + + "\n" + + "Porttitor rhoncus dolor purus non. Vel elit scelerisque mauris pellentesque. Semper auctor neque vitae tempus quam. Elementum nibh tellus molestie nunc non blandit massa enim nec. Dictum non consectetur a erat nam at lectus. Vestibulum sed arcu non odio euismod lacinia. Semper auctor neque vitae tempus quam pellentesque nec nam aliquam. Massa placerat duis ultricies lacus sed turpis. Arcu non odio euismod lacinia at quis risus sed vulputate. Mauris in aliquam sem fringilla. Odio tempor orci dapibus ultrices in iaculis. Nec ultrices dui sapien eget mi proin. Nisi quis eleifend quam adipiscing. Morbi tristique senectus et netus et. Neque laoreet suspendisse interdum consectetur.\n" + + "\n" + + "Nunc lobortis mattis aliquam faucibus purus in. Augue eget arcu dictum varius duis. Et egestas quis ipsum suspendisse ultrices gravida dictum fusce. Sodales ut etiam sit amet nisl purus. Viverra orci sagittis eu volutpat odio facilisis mauris sit. Turpis cursus in hac habitasse platea. Aenean euismod elementum nisi quis eleifend. Sagittis id consectetur purus ut faucibus pulvinar elementum integer. Turpis egestas pretium aenean pharetra magna ac placerat vestibulum. Et malesuada fames ac turpis egestas sed. Velit egestas dui id ornare arcu odio ut sem. Ut enim blandit volutpat maecenas. Et netus et malesuada fames ac turpis egestas. Cursus eget nunc scelerisque viverra. Eros donec ac odio tempor. Suscipit tellus mauris a diam." + + SmsUtil.splitSmsText(text).forEach { + assert(it.length <= SmsUtil.MAX_CHAR_LIMIT) + } } }