Restore new message after pause/resume
This commit is contained in:
@@ -61,25 +61,31 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||||
import androidx.compose.ui.platform.SoftwareKeyboardController
|
import androidx.compose.ui.platform.SoftwareKeyboardController
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.res.vectorResource
|
import androidx.compose.ui.res.vectorResource
|
||||||
|
import androidx.compose.ui.text.TextRange
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
|
||||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||||
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
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 androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import com.tutpro.baresip.CustomElements.AlertDialog
|
import com.tutpro.baresip.CustomElements.AlertDialog
|
||||||
|
import com.tutpro.baresip.CustomElements.EventListener
|
||||||
import com.tutpro.baresip.CustomElements.LabelText
|
import com.tutpro.baresip.CustomElements.LabelText
|
||||||
import com.tutpro.baresip.CustomElements.verticalScrollbar
|
import com.tutpro.baresip.CustomElements.verticalScrollbar
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -99,7 +105,6 @@ class ChatActivity : ComponentActivity() {
|
|||||||
private var chatMessages : List<Message> by _chatMessages
|
private var chatMessages : List<Message> by _chatMessages
|
||||||
private var focus = false
|
private var focus = false
|
||||||
private var lastCall: Long = 0
|
private var lastCall: Long = 0
|
||||||
private var unsentMessage = ""
|
|
||||||
private var keyboardController: SoftwareKeyboardController? = null
|
private var keyboardController: SoftwareKeyboardController? = null
|
||||||
|
|
||||||
private var backInvokedCallback: OnBackInvokedCallback? = null
|
private var backInvokedCallback: OnBackInvokedCallback? = null
|
||||||
@@ -267,7 +272,9 @@ class ChatActivity : ComponentActivity() {
|
|||||||
aor.split(":")[1]
|
aor.split(":")[1]
|
||||||
Text(
|
Text(
|
||||||
text = headerText,
|
text = headerText,
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 8.dp, bottom = 8.dp),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(top = 8.dp, bottom = 8.dp),
|
||||||
fontSize = 18.sp,
|
fontSize = 18.sp,
|
||||||
fontWeight = FontWeight.SemiBold,
|
fontWeight = FontWeight.SemiBold,
|
||||||
textAlign = TextAlign.Center
|
textAlign = TextAlign.Center
|
||||||
@@ -406,8 +413,10 @@ class ChatActivity : ComponentActivity() {
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.wrapContentHeight()
|
.wrapContentHeight()
|
||||||
.padding(start = if (message.direction == MESSAGE_DOWN) 0.dp else 24.dp,
|
.padding(
|
||||||
end = if (message.direction == MESSAGE_DOWN) 24.dp else 0.dp)
|
start = if (message.direction == MESSAGE_DOWN) 0.dp else 24.dp,
|
||||||
|
end = if (message.direction == MESSAGE_DOWN) 24.dp else 0.dp
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
Column {
|
Column {
|
||||||
Row {
|
Row {
|
||||||
@@ -449,6 +458,36 @@ class ChatActivity : ComponentActivity() {
|
|||||||
@Composable
|
@Composable
|
||||||
fun NewMessage(ctx: Context, peerUri: String) {
|
fun NewMessage(ctx: Context, peerUri: String) {
|
||||||
|
|
||||||
|
var newMessage = rememberSaveable(stateSaver = TextFieldValue.Saver) {
|
||||||
|
mutableStateOf(TextFieldValue(""))
|
||||||
|
}
|
||||||
|
var textFieldLoaded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
EventListener {
|
||||||
|
when (it) {
|
||||||
|
Lifecycle.Event.ON_RESUME -> {
|
||||||
|
val chatText = BaresipService.chatTexts["$aor::$peerUri"]
|
||||||
|
if (chatText != null) {
|
||||||
|
Log.d(TAG, "Restoring newMessage '$chatText' for $aor::$peerUri")
|
||||||
|
newMessage.value = TextFieldValue(
|
||||||
|
text = chatText,
|
||||||
|
selection = TextRange(chatText.length)
|
||||||
|
)
|
||||||
|
BaresipService.chatTexts.remove("$aor::$peerUri")
|
||||||
|
}
|
||||||
|
_chatMessages.value = uaPeerMessages(aor, peerUri)
|
||||||
|
}
|
||||||
|
Lifecycle.Event.ON_PAUSE -> {
|
||||||
|
if (newMessage.value != TextFieldValue("")) {
|
||||||
|
Log.d(TAG, "Saving newMessage '${newMessage.value.text}' for $aor::$peerUri")
|
||||||
|
BaresipService.chatTexts["$aor::$peerUri"] = newMessage.value.text
|
||||||
|
}
|
||||||
|
MainActivity.activityAor = aor
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val showDialog = remember { mutableStateOf(false) }
|
val showDialog = remember { mutableStateOf(false) }
|
||||||
val dialogMessage = remember { mutableStateOf("") }
|
val dialogMessage = remember { mutableStateOf("") }
|
||||||
|
|
||||||
@@ -459,7 +498,6 @@ class ChatActivity : ComponentActivity() {
|
|||||||
positiveButtonText = stringResource(R.string.ok),
|
positiveButtonText = stringResource(R.string.ok),
|
||||||
)
|
)
|
||||||
|
|
||||||
var newMessage by remember { mutableStateOf("") }
|
|
||||||
Row(modifier = Modifier
|
Row(modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.navigationBarsPadding()
|
.navigationBarsPadding()
|
||||||
@@ -468,16 +506,27 @@ class ChatActivity : ComponentActivity() {
|
|||||||
) {
|
) {
|
||||||
val keyboardController = LocalSoftwareKeyboardController.current
|
val keyboardController = LocalSoftwareKeyboardController.current
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = newMessage,
|
value = newMessage.value.text,
|
||||||
placeholder = { Text(stringResource(R.string.new_message)) },
|
placeholder = { Text(stringResource(R.string.new_message)) },
|
||||||
onValueChange = { newMessage = it },
|
onValueChange = {
|
||||||
|
newMessage.value = newMessage.value.copy(text = it)
|
||||||
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.padding(end = 8.dp)
|
.padding(end = 8.dp)
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
|
.onGloballyPositioned {
|
||||||
|
if (!textFieldLoaded) {
|
||||||
|
textFieldLoaded = true
|
||||||
|
//val textLength = newMessage.value.text.length
|
||||||
|
//newMessage.value = newMessage.value.copy(
|
||||||
|
// selection = TextRange(textLength)
|
||||||
|
//)
|
||||||
|
}
|
||||||
|
}
|
||||||
.combinedClickable(
|
.combinedClickable(
|
||||||
onClick = {
|
onClick = {
|
||||||
val msgText = newMessage
|
val msgText = newMessage.value.text
|
||||||
if (msgText.isNotEmpty()) {
|
if (msgText.isNotEmpty()) {
|
||||||
keyboardController?.hide()
|
keyboardController?.hide()
|
||||||
val time = System.currentTimeMillis()
|
val time = System.currentTimeMillis()
|
||||||
@@ -498,7 +547,8 @@ class ChatActivity : ComponentActivity() {
|
|||||||
if (ua.account.telProvider == "") {
|
if (ua.account.telProvider == "") {
|
||||||
dialogMessage.value = String.format(
|
dialogMessage.value = String.format(
|
||||||
getString(R.string.no_telephony_provider),
|
getString(R.string.no_telephony_provider),
|
||||||
Utils.plainAor(aor))
|
Utils.plainAor(aor)
|
||||||
|
)
|
||||||
showDialog.value = true
|
showDialog.value = true
|
||||||
} else {
|
} else {
|
||||||
msgUri = Utils.telToSip(peerUri, ua.account)
|
msgUri = Utils.telToSip(peerUri, ua.account)
|
||||||
@@ -513,12 +563,14 @@ class ChatActivity : ComponentActivity() {
|
|||||||
time.toString()
|
time.toString()
|
||||||
) != 0
|
) != 0
|
||||||
) {
|
) {
|
||||||
Toast.makeText(ctx, "${getString(R.string.message_failed)}!", Toast.LENGTH_SHORT).show()
|
Toast.makeText(
|
||||||
|
ctx, "${getString(R.string.message_failed)}!",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
msg.direction = MESSAGE_UP_FAIL
|
msg.direction = MESSAGE_UP_FAIL
|
||||||
msg.responseReason = getString(R.string.message_failed)
|
msg.responseReason = getString(R.string.message_failed)
|
||||||
} else {
|
} else {
|
||||||
newMessage = ""
|
newMessage.value = TextFieldValue("")
|
||||||
unsentMessage = ""
|
|
||||||
keyboardController?.hide()
|
keyboardController?.hide()
|
||||||
BaresipService.chatTexts.remove("$aor::$peerUri")
|
BaresipService.chatTexts.remove("$aor::$peerUri")
|
||||||
}
|
}
|
||||||
@@ -531,7 +583,7 @@ class ChatActivity : ComponentActivity() {
|
|||||||
val clipData = clipboardManager.primaryClip
|
val clipData = clipboardManager.primaryClip
|
||||||
if (clipData != null && clipData.itemCount > 0) {
|
if (clipData != null && clipData.itemCount > 0) {
|
||||||
val pastedText = clipData.getItemAt(0).text.toString()
|
val pastedText = clipData.getItemAt(0).text.toString()
|
||||||
newMessage = pastedText
|
newMessage.value = TextFieldValue(pastedText)
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(ctx, "Nothing to paste", Toast.LENGTH_SHORT).show()
|
Toast.makeText(ctx, "Nothing to paste", Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
@@ -539,11 +591,11 @@ class ChatActivity : ComponentActivity() {
|
|||||||
),
|
),
|
||||||
singleLine = false,
|
singleLine = false,
|
||||||
trailingIcon = {
|
trailingIcon = {
|
||||||
if (newMessage.isNotEmpty()) {
|
if (newMessage.value.text.isNotEmpty()) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Outlined.Clear,
|
Icons.Outlined.Clear,
|
||||||
contentDescription = "Clear",
|
contentDescription = "Clear",
|
||||||
modifier = Modifier.clickable { newMessage = "" }
|
modifier = Modifier.clickable { newMessage.value = TextFieldValue("") }
|
||||||
)
|
)
|
||||||
} },
|
} },
|
||||||
label = { LabelText(stringResource(R.string.new_message)) },
|
label = { LabelText(stringResource(R.string.new_message)) },
|
||||||
@@ -554,26 +606,21 @@ class ChatActivity : ComponentActivity() {
|
|||||||
autoCorrectEnabled = true
|
autoCorrectEnabled = true
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
}
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(id = R.drawable.send),
|
painter = painterResource(id = R.drawable.send),
|
||||||
contentDescription = "Send",
|
contentDescription = "Send",
|
||||||
contentScale = ContentScale.Crop,
|
contentScale = ContentScale.Crop,
|
||||||
modifier = Modifier.size(36.dp)
|
modifier = Modifier
|
||||||
|
.size(36.dp)
|
||||||
.clickable {
|
.clickable {
|
||||||
val msgText = newMessage
|
val msgText = newMessage.value.text
|
||||||
if (msgText.isNotEmpty()) {
|
if (msgText.isNotEmpty()) {
|
||||||
keyboardController?.hide()
|
keyboardController?.hide()
|
||||||
val time = System.currentTimeMillis()
|
val time = System.currentTimeMillis()
|
||||||
val msg = Message(
|
val msg =
|
||||||
aor,
|
Message(aor, peerUri, msgText, time, MESSAGE_UP_WAIT, 0, "", true)
|
||||||
peerUri,
|
|
||||||
msgText,
|
|
||||||
time,
|
|
||||||
MESSAGE_UP_WAIT,
|
|
||||||
0,
|
|
||||||
"",
|
|
||||||
true
|
|
||||||
)
|
|
||||||
msg.add()
|
msg.add()
|
||||||
var msgUri = ""
|
var msgUri = ""
|
||||||
_chatMessages.value += msg
|
_chatMessages.value += msg
|
||||||
@@ -581,7 +628,8 @@ class ChatActivity : ComponentActivity() {
|
|||||||
if (ua.account.telProvider == "") {
|
if (ua.account.telProvider == "") {
|
||||||
dialogMessage.value = String.format(
|
dialogMessage.value = String.format(
|
||||||
getString(R.string.no_telephony_provider),
|
getString(R.string.no_telephony_provider),
|
||||||
Utils.plainAor(aor))
|
Utils.plainAor(aor)
|
||||||
|
)
|
||||||
showDialog.value = true
|
showDialog.value = true
|
||||||
} else {
|
} else {
|
||||||
msgUri = Utils.telToSip(peerUri, ua.account)
|
msgUri = Utils.telToSip(peerUri, ua.account)
|
||||||
@@ -589,19 +637,16 @@ class ChatActivity : ComponentActivity() {
|
|||||||
else
|
else
|
||||||
msgUri = peerUri
|
msgUri = peerUri
|
||||||
if (msgUri != "")
|
if (msgUri != "")
|
||||||
if (Api.message_send(
|
if (Api.message_send(ua.uap, msgUri, msgText, time.toString()) != 0
|
||||||
ua.uap,
|
|
||||||
msgUri,
|
|
||||||
msgText,
|
|
||||||
time.toString()
|
|
||||||
) != 0
|
|
||||||
) {
|
) {
|
||||||
Toast.makeText(ctx, "${getString(R.string.message_failed)}!", Toast.LENGTH_SHORT).show()
|
Toast.makeText(
|
||||||
|
ctx, "${getString(R.string.message_failed)}!",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
msg.direction = MESSAGE_UP_FAIL
|
msg.direction = MESSAGE_UP_FAIL
|
||||||
msg.responseReason = getString(R.string.message_failed)
|
msg.responseReason = getString(R.string.message_failed)
|
||||||
} else {
|
} else {
|
||||||
newMessage = ""
|
newMessage.value = TextFieldValue("")
|
||||||
unsentMessage = ""
|
|
||||||
keyboardController?.hide()
|
keyboardController?.hide()
|
||||||
BaresipService.chatTexts.remove("$aor::$peerUri")
|
BaresipService.chatTexts.remove("$aor::$peerUri")
|
||||||
}
|
}
|
||||||
@@ -611,27 +656,6 @@ class ChatActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
val chatText = BaresipService.chatTexts["$aor::$peerUri"]
|
|
||||||
if (chatText != null) {
|
|
||||||
Log.d(TAG, "Restoring newMessage $chatText for $aor::$peerUri")
|
|
||||||
unsentMessage = chatText
|
|
||||||
//newMessage.requestFocus()
|
|
||||||
BaresipService.chatTexts.remove("$aor::$peerUri")
|
|
||||||
}
|
|
||||||
_chatMessages.value = uaPeerMessages(aor, peerUri)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
if (unsentMessage != "") {
|
|
||||||
Log.d(TAG, "Saving newMessage $unsentMessage for $aor::$peerUri")
|
|
||||||
BaresipService.chatTexts["$aor::$peerUri"] = unsentMessage
|
|
||||||
}
|
|
||||||
MainActivity.activityAor = aor
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
if (Build.VERSION.SDK_INT >= 33) {
|
if (Build.VERSION.SDK_INT >= 33) {
|
||||||
if (backInvokedCallback != null)
|
if (backInvokedCallback != null)
|
||||||
|
|||||||
@@ -44,11 +44,13 @@ import androidx.compose.material3.Surface
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberUpdatedState
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
@@ -82,6 +84,9 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import androidx.core.content.ContextCompat.getString
|
import androidx.core.content.ContextCompat.getString
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
|
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||||
|
|
||||||
object CustomElements {
|
object CustomElements {
|
||||||
|
|
||||||
@@ -609,4 +614,20 @@ object CustomElements {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun EventListener(onEvent : (event: Lifecycle.Event) -> Unit) {
|
||||||
|
val eventHandler = rememberUpdatedState(newValue = onEvent)
|
||||||
|
val lifecycleOwner = rememberUpdatedState(newValue = LocalLifecycleOwner.current)
|
||||||
|
DisposableEffect(lifecycleOwner.value ){
|
||||||
|
val lifecycle = lifecycleOwner.value.lifecycle
|
||||||
|
val observer = LifecycleEventObserver{source, event ->
|
||||||
|
eventHandler.value(event)
|
||||||
|
}
|
||||||
|
lifecycle.addObserver(observer)
|
||||||
|
onDispose {
|
||||||
|
lifecycle.removeObserver(observer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user