diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 158fd37d..22bf5752 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,8 @@ + + diff --git a/app/src/main/java/com/afkanerd/deku/DefaultSMS/AdaptersViewModels/ConversationsViewModel.kt b/app/src/main/java/com/afkanerd/deku/DefaultSMS/AdaptersViewModels/ConversationsViewModel.kt index f15ceb74..8e02f3e1 100644 --- a/app/src/main/java/com/afkanerd/deku/DefaultSMS/AdaptersViewModels/ConversationsViewModel.kt +++ b/app/src/main/java/com/afkanerd/deku/DefaultSMS/AdaptersViewModels/ConversationsViewModel.kt @@ -13,14 +13,18 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import androidx.navigation.NavController import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData import androidx.paging.cachedIn import androidx.paging.liveData import androidx.window.layout.WindowLayoutInfo +import com.afkanerd.deku.ConversationsScreen import com.afkanerd.deku.Datastore +import com.afkanerd.deku.DefaultSMS.Commons.Helpers import com.afkanerd.deku.DefaultSMS.Models.Conversations.Conversation +import com.afkanerd.deku.DefaultSMS.Models.Conversations.ThreadedConversationsHandler import com.afkanerd.deku.DefaultSMS.Models.NativeSMSDB import com.afkanerd.deku.DefaultSMS.Models.SMSDatabaseWrapper import com.afkanerd.deku.DefaultSMS.Models.ThreadsConfigurations @@ -38,22 +42,18 @@ import kotlinx.serialization.json.Json class ConversationsViewModel : ViewModel() { -// var threadId by mutableStateOf("") -// var address by mutableStateOf("") -// var text by mutableStateOf("") -// var searchQuery by mutableStateOf("") -// var subscriptionId: Int by mutableIntStateOf(-1) - - var threadId = "" - var address = "" - var text = "" - var searchQuery = "" - var subscriptionId = -1 + var threadId by mutableStateOf("") + var address by mutableStateOf("") + var text by mutableStateOf("") + var encryptedText by mutableStateOf("") + var searchQuery by mutableStateOf("") + var subscriptionId: Int by mutableIntStateOf(-1) var importDetails by mutableStateOf("") var selectedItems = mutableStateListOf() var retryDeleteItem: MutableList = arrayListOf() + var selectedMessage: Conversation? = null var liveData: LiveData>? = null var remoteListenersLiveData: LiveData>? = null @@ -475,4 +475,69 @@ class ConversationsViewModel : ViewModel() { Telephony.Sms.MESSAGE_TYPE_DRAFT Datastore.getDatastore(context).conversationDao().deleteEvery() } + + fun getMessage(context: Context, messageId: String): Conversation { + return Datastore.getDatastore(context).conversationDao().getMessage(messageId) + } + + fun processIntents( + context: Context, + intent: Intent, + defaultRegion: String, + ): Triple?{ + if(intent.action != null && + ((intent.action == Intent.ACTION_SENDTO) || (intent.action == Intent.ACTION_SEND))) { + val text = if(intent.hasExtra("sms_body")) intent.getStringExtra("sms_body") + else if(intent.hasExtra("android.intent.extra.TEXT")) { + intent.getStringExtra("android.intent.extra.TEXT") + } else "" + + val sendToString = intent.dataString + + if ((sendToString != null && + (sendToString.contains("smsto:") || + sendToString.contains("sms:"))) || intent.hasExtra("address") + ) { + val address = Helpers.getFormatCompleteNumber( + if(intent.hasExtra("address")) intent.getStringExtra("address") + else sendToString, defaultRegion + ) + val threadId = ThreadedConversationsHandler.get(context, address).thread_id + return Triple(address, threadId, text) + } + } + else if(intent.hasExtra("address")) { + var text = if(intent.hasExtra("android.intent.extra.TEXT")) + intent.getStringExtra("android.intent.extra.TEXT") else "" + + val address = intent.getStringExtra("address") + val threadId = intent.getStringExtra("thread_id") + return Triple(address, threadId, text) + } + return null + } + + fun navigateToConversation( + conversationsViewModel: ConversationsViewModel, + address: String, + threadId: String, + subscriptionId: Int?, + navController: NavController, + searchQuery: String? = "" + ) { + conversationsViewModel.address = address + conversationsViewModel.threadId = threadId + conversationsViewModel.searchQuery = searchQuery ?: "" + conversationsViewModel.subscriptionId = subscriptionId ?: -1 + conversationsViewModel.liveData = null + if(conversationsViewModel.newLayoutInfo?.displayFeatures!!.isEmpty()) + navController.navigate(ConversationsScreen) + } + + fun loadNatives(context: Context, conversationViewModel: ConversationsViewModel) { + CoroutineScope(Dispatchers.Default).launch { + conversationViewModel.reset(context) + } + } + } diff --git a/app/src/main/java/com/afkanerd/deku/DefaultSMS/Extensions/Activities.kt b/app/src/main/java/com/afkanerd/deku/DefaultSMS/Extensions/Activities.kt new file mode 100644 index 00000000..3941b135 --- /dev/null +++ b/app/src/main/java/com/afkanerd/deku/DefaultSMS/Extensions/Activities.kt @@ -0,0 +1,12 @@ +package com.afkanerd.deku.DefaultSMS.Extensions + +import android.content.Context +import android.content.ContextWrapper +import androidx.activity.ComponentActivity + + +fun Context.getActivity(): ComponentActivity? = when (this) { + is ComponentActivity -> this + is ContextWrapper -> baseContext.getActivity() + else -> null +} \ No newline at end of file diff --git a/app/src/main/java/com/afkanerd/deku/DefaultSMS/Models/DevMode.kt b/app/src/main/java/com/afkanerd/deku/DefaultSMS/Models/DevMode.kt new file mode 100644 index 00000000..99c40cf3 --- /dev/null +++ b/app/src/main/java/com/afkanerd/deku/DefaultSMS/Models/DevMode.kt @@ -0,0 +1,5 @@ +package com.afkanerd.deku.DefaultSMS.Models + +object DevMode { + val viewLogCat = "viewLogCat" +} diff --git a/app/src/main/java/com/afkanerd/deku/DefaultSMS/Models/Encryption.kt b/app/src/main/java/com/afkanerd/deku/DefaultSMS/Models/Encryption.kt new file mode 100644 index 00000000..f337dde7 --- /dev/null +++ b/app/src/main/java/com/afkanerd/deku/DefaultSMS/Models/Encryption.kt @@ -0,0 +1,16 @@ +package com.afkanerd.deku.DefaultSMS.Models + +open class Encryption { + + var id: Int = 0 + + var state: ByteArray? = null + + var peerPublicKey: ByteArray? = null + + var publicKey: ByteArray? = null + + var peerAddress: String? = null + + var version: Int = 0 +} \ No newline at end of file diff --git a/app/src/main/java/com/afkanerd/deku/DefaultSMS/Settings/SettingsFragment.kt b/app/src/main/java/com/afkanerd/deku/DefaultSMS/Settings/SettingsFragment.kt index 73b68c46..32b0b474 100644 --- a/app/src/main/java/com/afkanerd/deku/DefaultSMS/Settings/SettingsFragment.kt +++ b/app/src/main/java/com/afkanerd/deku/DefaultSMS/Settings/SettingsFragment.kt @@ -1,7 +1,14 @@ package com.afkanerd.deku.DefaultSMS.Settings +import android.content.Intent +import android.preference.Preference import androidx.appcompat.app.AppCompatDelegate +import androidx.navigation.fragment.NavHostFragment +import androidx.navigation.fragment.findNavController import androidx.preference.PreferenceFragmentCompat +import com.afkanerd.deku.DefaultSMS.Models.DevMode +import com.afkanerd.deku.DefaultSMS.R +import com.afkanerd.deku.MainActivity class SettingsFragment : PreferenceFragmentCompat() { override fun onCreatePreferences( @@ -13,6 +20,9 @@ class SettingsFragment : PreferenceFragmentCompat() { val languagePreference = findPreference(getString(com.afkanerd.deku.DefaultSMS.R.string.settings_locale)) + val devModeLogCatPreference = + findPreference("dev_mode") + languagePreference!!.onPreferenceChangeListener = object : androidx.preference.Preference.OnPreferenceChangeListener { override fun onPreferenceChange( @@ -33,5 +43,20 @@ class SettingsFragment : PreferenceFragmentCompat() { return true } } + + devModeLogCatPreference!!.onPreferenceClickListener = object: + androidx.preference.Preference.OnPreferenceClickListener { + override fun onPreferenceClick(preference: androidx.preference.Preference): Boolean { + startActivity( + Intent(requireContext(), MainActivity::class.java).apply { + setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_TASK_ON_HOME) + action = Intent.ACTION_VIEW + putExtra("view", DevMode.viewLogCat) + } + ) + requireActivity().finish() + return true + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/afkanerd/deku/DefaultSMS/SettingsActivity.kt b/app/src/main/java/com/afkanerd/deku/DefaultSMS/SettingsActivity.kt index be7b6944..0a4055d2 100644 --- a/app/src/main/java/com/afkanerd/deku/DefaultSMS/SettingsActivity.kt +++ b/app/src/main/java/com/afkanerd/deku/DefaultSMS/SettingsActivity.kt @@ -6,6 +6,8 @@ import android.view.MenuItem import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar +import androidx.navigation.findNavController +import androidx.navigation.fragment.NavHostFragment import com.afkanerd.deku.DefaultSMS.Settings.SettingsFragment import com.afkanerd.deku.MainActivity diff --git a/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/Components/Conversations.kt b/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/Components/Conversations.kt index ee98badf..4d118c77 100644 --- a/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/Components/Conversations.kt +++ b/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/Components/Conversations.kt @@ -27,36 +27,22 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.TextLinkStyles -import androidx.compose.ui.text.buildAnnotatedString -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.style.TextDecoration -import androidx.compose.ui.text.withStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.core.net.toUri -import androidx.navigation.compose.rememberNavController import com.afkanerd.deku.DefaultSMS.AdaptersViewModels.ConversationsViewModel import com.afkanerd.deku.DefaultSMS.Commons.Helpers import com.afkanerd.deku.DefaultSMS.Models.Conversations.Conversation import com.afkanerd.deku.DefaultSMS.Models.SMSHandler.sendTextMessage -import com.afkanerd.deku.DefaultSMS.ui.Conversations import com.example.compose.AppTheme -import sh.calvin.autolinktext.rememberAutoLinkText enum class ConversationPositionTypes(val value: Int) { NORMAL(0), @@ -467,15 +453,15 @@ fun ConversationsMainDropDownMenu( } } -private fun getPredefinedType(type: Int) : PredefinedTypes? { +private fun getPredefinedType(type: Int) : ConversationsPredefinedTypes? { when(type) { Telephony.Sms.MESSAGE_TYPE_OUTBOX, Telephony.Sms.MESSAGE_TYPE_QUEUED, Telephony.Sms.MESSAGE_TYPE_SENT -> { - return PredefinedTypes.OUTGOING + return ConversationsPredefinedTypes.OUTGOING } Telephony.Sms.MESSAGE_TYPE_INBOX -> { - return PredefinedTypes.INCOMING + return ConversationsPredefinedTypes.INCOMING } } return null @@ -590,7 +576,7 @@ fun sendSMS( ) } -enum class PredefinedTypes { +enum class ConversationsPredefinedTypes { OUTGOING, INCOMING } diff --git a/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/Components/ConversationsComponents.kt b/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/Components/ConversationsComponents.kt index 476a2a4d..e3401f19 100644 --- a/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/Components/ConversationsComponents.kt +++ b/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/Components/ConversationsComponents.kt @@ -8,6 +8,7 @@ import android.content.Context.CLIPBOARD_SERVICE import android.content.Intent import android.graphics.PorterDuff import android.graphics.PorterDuffColorFilter +import android.provider.Telephony import android.telephony.SmsManager import android.util.Base64 import android.widget.Toast @@ -27,6 +28,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawingPadding import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape @@ -45,6 +47,7 @@ import androidx.compose.material.icons.automirrored.filled.Send import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.ContentCopy import androidx.compose.material.icons.filled.Delete +import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.Share import androidx.compose.material.icons.outlined.SimCard import androidx.compose.material3.BottomAppBar @@ -57,6 +60,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.SheetValue +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults @@ -89,17 +93,27 @@ import androidx.compose.ui.tooling.preview.datasource.LoremIpsum import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.core.content.ContextCompat +import androidx.navigation.compose.rememberNavController import com.afkanerd.deku.DefaultSMS.AdaptersViewModels.ConversationsViewModel import com.afkanerd.deku.DefaultSMS.BuildConfig import com.afkanerd.deku.DefaultSMS.Models.Conversations.Conversation import com.afkanerd.deku.DefaultSMS.Models.SIMHandler import com.afkanerd.deku.DefaultSMS.R +import com.afkanerd.deku.DefaultSMS.ui.Conversations import com.afkanerd.deku.MainActivity +import com.example.compose.AppTheme import com.jakewharton.rxbinding.view.RxMenuItem.icon +import io.getstream.avatarview.AvatarView import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.nio.file.WatchEvent +import java.text.SimpleDateFormat +import java.time.Instant +import java.time.ZoneId +import java.time.format.DateTimeFormatter +import java.util.Date +import java.util.Locale @Preview(showBackground = true) @Composable @@ -295,7 +309,7 @@ fun ChatCompose( fontSize = 12.sp, modifier = Modifier .align(Alignment.End) - .padding(end=8.dp) + .padding(end = 8.dp) ) } } @@ -450,6 +464,83 @@ fun ShortCodeAlert( ) } +@Composable +fun MessageInfoAlert( + conversation: Conversation, + dismissCallback: (() -> Unit)? = null, +) { + val type = stringResource(R.string.text_message_1) + val priority = stringResource(R.string.normal) + AlertDialog( + backgroundColor = MaterialTheme.colorScheme.secondary, + title = { + Text( + stringResource(R.string.message_details), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.onSecondary + ) + }, + text = { + Column { + Text( + stringResource(R.string.type, type), + color = MaterialTheme.colorScheme.onSecondary + ) + Text( + stringResource(R.string.priority, priority), + color = MaterialTheme.colorScheme.onSecondary + ) + if(conversation.type == Telephony.Sms.MESSAGE_TYPE_INBOX) + Text( + stringResource(R.string.from, conversation.address ?: ""), + color = MaterialTheme.colorScheme.onSecondary + ) + Text( + stringResource( + R.string.to, if (conversation.type == Telephony.Sms.MESSAGE_TYPE_OUTBOX) + conversation.address ?: "" + else "N/A" + ), + color = MaterialTheme.colorScheme.onSecondary + ) + Text( + stringResource( + R.string.sent, if (conversation.type == Telephony.Sms.MESSAGE_TYPE_OUTBOX) + formatDate(conversation.date?.toLong() ?: 0L) + else formatDate(conversation.date_sent?.toLong() ?: 0L) + ), + color = MaterialTheme.colorScheme.onSecondary + ) + if(conversation.type == Telephony.Sms.MESSAGE_TYPE_INBOX) + Text( + stringResource( + R.string.received, + formatDate(conversation.date?.toLong() ?: 0L) + ), + color = MaterialTheme.colorScheme.onSecondary + ) + } + }, + onDismissRequest = { dismissCallback?.invoke() }, + confirmButton = {}, + dismissButton = { + TextButton( + onClick = { dismissCallback?.invoke() } + ) { + Text( + stringResource(R.string.close), + color = MaterialTheme.colorScheme.tertiaryContainer + ) + } + } + ) +} + +fun formatDate(timestamp: Long): String { + val date = Date(timestamp) + val format = SimpleDateFormat("yyyy-MM-dd HH:ss", Locale.getDefault()) + return format.format(date) +} @Preview @Composable @@ -506,6 +597,7 @@ fun SimChooser( fun ConversationCrudBottomBar( viewModel: ConversationsViewModel = ConversationsViewModel(), items: List = emptyList(), + onInfoRequested: (Conversation) -> Unit = {}, onCompleted: (() -> Unit)? = null, onCancel: (() -> Unit)? = null, ) { @@ -530,6 +622,15 @@ fun ConversationCrudBottomBar( Spacer(Modifier.weight(1f)) if(viewModel.selectedItems.size < 2) { + IconButton(onClick = { + val conversations = items.first { + it.message_id in viewModel.selectedItems + } + onInfoRequested(conversations) + }) { + Icon(Icons.Filled.Info, stringResource(R.string.message_information)) + } + IconButton(onClick = { val conversation = items.firstOrNull { it.message_id in viewModel.selectedItems @@ -606,3 +707,17 @@ private fun shareItem(context: Context, text: String) { context.startActivity(shareIntent) } +@Preview +@Composable +fun MessageInfoAlert_Preview() { + AppTheme(darkTheme = true) { + val conversation = Conversation() + conversation.address = "+2371234567" + conversation.date = System.currentTimeMillis().toString() + conversation.date_sent = System.currentTimeMillis().toString() + conversation.type = Telephony.Sms.MESSAGE_TYPE_INBOX + MessageInfoAlert( + conversation + ) {} + } +} diff --git a/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/Components/ThreadsConversation.kt b/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/Components/ThreadsConversation.kt index b4969412..aa3ccd5f 100644 --- a/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/Components/ThreadsConversation.kt +++ b/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/Components/ThreadsConversation.kt @@ -80,6 +80,7 @@ import coil3.compose.AsyncImage import com.afkanerd.deku.DefaultSMS.AboutActivity import com.afkanerd.deku.DefaultSMS.AdaptersViewModels.ConversationsViewModel import com.afkanerd.deku.DefaultSMS.BuildConfig +import com.afkanerd.deku.DefaultSMS.Extensions.getActivity import com.afkanerd.deku.DefaultSMS.Extensions.toHslColor import com.afkanerd.deku.DefaultSMS.Models.Contacts import com.afkanerd.deku.DefaultSMS.Models.Conversations.Conversation @@ -610,6 +611,7 @@ fun ThreadsMainDropDown( setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_TASK_ON_HOME) } ) + context.getActivity()?.finish() } ) diff --git a/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/ComposeNewMain.kt b/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/ComposeNewMain.kt index 57b0380a..32f360a7 100644 --- a/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/ComposeNewMain.kt +++ b/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/ComposeNewMain.kt @@ -150,7 +150,7 @@ fun ComposeNewMessage( conversationsViewModel.threadId = ThreadedConversationsHandler.get(context, conversationsViewModel.address).thread_id - navigateToConversation( + conversationsViewModel.navigateToConversation( conversationsViewModel = conversationsViewModel, address = conversationsViewModel.address, threadId = conversationsViewModel.threadId, diff --git a/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/ConversationsMain.kt b/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/ConversationsMain.kt index 882bf086..cccb3371 100644 --- a/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/ConversationsMain.kt +++ b/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/ConversationsMain.kt @@ -117,6 +117,7 @@ import androidx.paging.compose.itemKey import com.afkanerd.deku.DefaultSMS.Models.Conversations.ThreadedConversationsHandler.call import com.afkanerd.deku.DefaultSMS.ui.Components.ConvenientMethods.deriveMetaDate import com.afkanerd.deku.DefaultSMS.ui.Components.ConversationsMainDropDownMenu +import com.afkanerd.deku.DefaultSMS.ui.Components.MessageInfoAlert import com.afkanerd.deku.DefaultSMS.ui.Components.getConversationType import com.afkanerd.deku.DefaultSMS.ui.Components.sendSMS import kotlinx.coroutines.withContext @@ -204,12 +205,12 @@ fun Conversations( val isShortCode = if(inPreviewMode) false else Helpers.isShortCode(viewModel.address) val defaultRegion = if(inPreviewMode) "cm" else Helpers.getUserCountry( context ) - var encryptedText by remember { mutableStateOf("") } var shouldPulse by remember { mutableStateOf(false) } val pulseRateMs by remember { mutableLongStateOf(3000L) } var rememberDeleteAlert by remember { mutableStateOf(false) } + var openInfoAlert by remember { mutableStateOf(false) } LaunchedEffect(inboxMessagesItems.loadState) { println("Checking search...") @@ -279,7 +280,7 @@ fun Conversations( if(isSecured) { LaunchedEffect(viewModel.text) { if(viewModel.text.isBlank()) { - encryptedText = "" + viewModel.encryptedText = "" shouldPulse = false } else shouldPulse = true } @@ -288,7 +289,7 @@ fun Conversations( if(shouldPulse) coroutineScope.launch { delay(pulseRateMs) - encryptedText = E2EEHandler.encryptMessage( + viewModel.encryptedText = E2EEHandler.encryptMessage( context = context, text = viewModel.text, address = viewModel.address @@ -457,10 +458,15 @@ fun Conversations( ) }, bottomBar = { - if(!selectedItems.isEmpty()) { + if(selectedItems.isNotEmpty()) { ConversationCrudBottomBar( viewModel, inboxMessagesItems.itemSnapshotList.items, + onInfoRequested = { + openInfoAlert = true + viewModel.selectedMessage = it + selectedItems.clear() + }, onCompleted = { selectedItems.clear() } ) { selectedItems.clear() @@ -519,7 +525,7 @@ fun Conversations( ) { ChatCompose( value = viewModel.text, - encryptedValue = encryptedText, + encryptedValue = viewModel.encryptedText, subscriptionId = viewModel.subscriptionId, shouldPulse = shouldPulse, simCardChooserCallback = if(dualSim) { @@ -539,7 +545,7 @@ fun Conversations( conversationsViewModel = viewModel ) { viewModel.text = "" - encryptedText = "" + viewModel.encryptedText = "" viewModel.clearDraft(context) } } @@ -711,10 +717,19 @@ fun Conversations( } if(openAlertDialog) { - ShortCodeAlert() { + ShortCodeAlert { openAlertDialog = false } } + + if(openInfoAlert) { + MessageInfoAlert( + viewModel.selectedMessage!! + ) { + viewModel.selectedMessage = null + openInfoAlert = false + } + } } if(showFailedRetryModal) { diff --git a/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/LogcatMain.kt b/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/LogcatMain.kt new file mode 100644 index 00000000..186447eb --- /dev/null +++ b/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/LogcatMain.kt @@ -0,0 +1,9 @@ +package com.afkanerd.deku.DefaultSMS.ui + +import androidx.compose.runtime.Composable + +@Composable +fun LogcatMain() { + +} + diff --git a/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/ThreadsConversationMain.kt b/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/ThreadsConversationMain.kt index c50056e6..6baca9bd 100644 --- a/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/ThreadsConversationMain.kt +++ b/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/ThreadsConversationMain.kt @@ -117,66 +117,6 @@ enum class InboxType(val value: Int) { } } -fun processIntents( - context: Context, - intent: Intent, - defaultRegion: String, -): Triple?{ - if(intent.action != null && - ((intent.action == Intent.ACTION_SENDTO) || (intent.action == Intent.ACTION_SEND))) { - val text = if(intent.hasExtra("sms_body")) intent.getStringExtra("sms_body") - else if(intent.hasExtra("android.intent.extra.TEXT")) { - intent.getStringExtra("android.intent.extra.TEXT") - } else "" - - val sendToString = intent.dataString - - if ((sendToString != null && - (sendToString.contains("smsto:") || - sendToString.contains("sms:"))) || intent.hasExtra("address") - ) { - val address = Helpers.getFormatCompleteNumber( - if(intent.hasExtra("address")) intent.getStringExtra("address") - else sendToString, defaultRegion - ) - val threadId = ThreadedConversationsHandler.get(context, address).thread_id - return Triple(address, threadId, text) - } - } - else if(intent.hasExtra("address")) { - var text = if(intent.hasExtra("android.intent.extra.TEXT")) - intent.getStringExtra("android.intent.extra.TEXT") else "" - - val address = intent.getStringExtra("address") - val threadId = intent.getStringExtra("thread_id") - return Triple(address, threadId, text) - } - return null -} - -fun navigateToConversation( - conversationsViewModel: ConversationsViewModel, - address: String, - threadId: String, - subscriptionId: Int?, - navController: NavController, - searchQuery: String? = "" -) { - conversationsViewModel.address = address - conversationsViewModel.threadId = threadId - conversationsViewModel.searchQuery = searchQuery ?: "" - conversationsViewModel.subscriptionId = subscriptionId ?: -1 - conversationsViewModel.liveData = null - if(conversationsViewModel.newLayoutInfo?.displayFeatures!!.isEmpty()) - navController.navigate(ConversationsScreen) -} - -private fun loadNatives(context: Context, conversationViewModel: ConversationsViewModel) { - CoroutineScope(Dispatchers.Default).launch { - conversationViewModel.reset(context) - } -} - @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class, ExperimentalFoundationApi::class, ExperimentalPermissionsApi::class ) @@ -199,14 +139,14 @@ fun ThreadConversationLayout( LaunchedEffect(newIntent) { newIntent?.let { val defaultRegion = if(inPreviewMode) "cm" else Helpers.getUserCountry(context) - processIntents(context, it, defaultRegion)?.let { + conversationsViewModel.processIntents(context, it, defaultRegion)?.let { conversationsViewModel.setNewIntent(null) it.first?.let{ address -> it.second?.let { threadId -> it.third?.let{ message -> conversationsViewModel.text = message } - navigateToConversation( + conversationsViewModel.navigateToConversation( conversationsViewModel = conversationsViewModel, address = address, threadId = threadId, @@ -310,7 +250,7 @@ fun ThreadConversationLayout( var rememberMenuExpanded by remember { mutableStateOf( false)} ThreadsMainDropDown( expanded=rememberMenuExpanded, - conversationViewModel = conversationsViewModel + conversationViewModel = conversationsViewModel, ) { rememberMenuExpanded = it } @@ -561,7 +501,7 @@ fun ThreadConversationLayout( ) { if(!isDefault && inboxType != InboxType.REMOTE_LISTENER) { DefaultCheckMain { - loadNatives(context, conversationsViewModel) + conversationsViewModel.loadNatives(context, conversationsViewModel) isDefault = true } } @@ -749,8 +689,8 @@ fun ThreadConversationLayout( modifier = Modifier.combinedClickable( onClick = { if(selectedItems.isEmpty()) { - navigateToConversation( - conversationsViewModel = conversationsViewModel, + conversationsViewModel.navigateToConversation( + conversationsViewModel, address = message.address!!, threadId = message.thread_id!!, subscriptionId = diff --git a/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/ThreadsSearchMain.kt b/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/ThreadsSearchMain.kt index 0e8ce7b2..e1963201 100644 --- a/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/ThreadsSearchMain.kt +++ b/app/src/main/java/com/afkanerd/deku/DefaultSMS/ui/ThreadsSearchMain.kt @@ -93,7 +93,7 @@ fun SearchThreadsMain( if(viewModel.threadId != null) { viewModel.liveData = MutableLiveData() viewModel.threadId = null - navigateToConversation( + conversationsViewModel.navigateToConversation( conversationsViewModel = conversationsViewModel, address = message.address!!, threadId = message.thread_id!!, @@ -179,7 +179,7 @@ fun SearchThreadsMain( modifier = Modifier.combinedClickable( onClick = { viewModel.liveData = MutableLiveData() - navigateToConversation( + conversationsViewModel.navigateToConversation( conversationsViewModel = conversationsViewModel, address = message.address!!, threadId = message.thread_id!!, diff --git a/app/src/main/java/com/afkanerd/deku/MainActivity.kt b/app/src/main/java/com/afkanerd/deku/MainActivity.kt index 55eb814c..539fa4ff 100644 --- a/app/src/main/java/com/afkanerd/deku/MainActivity.kt +++ b/app/src/main/java/com/afkanerd/deku/MainActivity.kt @@ -1,8 +1,10 @@ package com.afkanerd.deku import android.app.ComponentCaller +import android.content.Context import android.content.Intent import android.os.Bundle +import android.util.Log import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.viewModels @@ -44,12 +46,20 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.sp +import com.afkanerd.deku.DefaultSMS.Models.DevMode import com.afkanerd.deku.DefaultSMS.R +import com.afkanerd.deku.DefaultSMS.ui.LogcatMain import com.afkanerd.deku.RemoteListeners.Models.RemoteListener.RemoteListenerQueuesViewModel import com.afkanerd.deku.RemoteListeners.Models.RemoteListener.RemoteListenersViewModel import com.afkanerd.deku.RemoteListeners.ui.RMQAddComposable import com.afkanerd.deku.RemoteListeners.ui.RMQMainComposable import com.afkanerd.deku.RemoteListeners.ui.RMQQueuesComposable +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader class MainActivity : AppCompatActivity(){ @@ -87,8 +97,14 @@ class MainActivity : AppCompatActivity(){ } private fun handleIntent(intent: Intent) { - intent.let { - conversationViewModel.setNewIntent(it) + if(intent.action == Intent.ACTION_VIEW && + intent.getStringExtra("view") == DevMode.viewLogCat) { + navController.navigate(LogcatScreen) + } + else { + intent.let { + conversationViewModel.setNewIntent(it) + } } } @@ -97,7 +113,6 @@ class MainActivity : AppCompatActivity(){ setContent { AppTheme { navController = rememberNavController() - Surface(Modifier .fillMaxSize() ) { @@ -146,6 +161,9 @@ class MainActivity : AppCompatActivity(){ navController = navController ) } + composable{ + LogcatMain() + } } else { composable{ @@ -246,4 +264,34 @@ class MainActivity : AppCompatActivity(){ conversationViewModel.insertDraft(applicationContext) } } -} \ No newline at end of file + + override fun onResume() { + super.onResume() + readLogcat(applicationContext) + } +} + +fun readLogcat(context: Context): Flow = flow { + val logBuilder = StringBuilder() + try { + // Execute logcat command with filter for app's logs + val process = Runtime.getRuntime().exec("logcat -d *:V") + val bufferedReader = BufferedReader(InputStreamReader(process.inputStream)) + + // Get app's package name to filter logs + val packageName = context.packageName + + var line: String? + while (bufferedReader.readLine().also { line = it } != null) { + // Filter logs containing app's package name + if (line?.contains(packageName) == true) { + emit(line) + } + } + bufferedReader.close() + process.destroy() + } catch (e: IOException) { + e.printStackTrace() + emit(e.message.toString()) + } +}.flowOn(Dispatchers.IO) \ No newline at end of file diff --git a/app/src/main/java/com/afkanerd/deku/screens.kt b/app/src/main/java/com/afkanerd/deku/screens.kt index 0ca96891..3121b042 100644 --- a/app/src/main/java/com/afkanerd/deku/screens.kt +++ b/app/src/main/java/com/afkanerd/deku/screens.kt @@ -20,3 +20,6 @@ object RemoteListenersScreen object RemoteListenersQueuesScreen @Serializable object RemoteListenersAddScreen + +@Serializable +object LogcatScreen diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 975d890d..8a1bcba7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -397,5 +397,17 @@ Disabling would turn off swipe gestures in the threads screen (to archive and delete). This is enabled by default Enable Swipe Behaviour + message information + Close + Message Details + Type: %1$s + Priority: %1$s + Text message + Normal + From: %1$s + To: %1$s + Sent: %1$s + Received: %1$s + Dev mode \ No newline at end of file diff --git a/app/src/main/res/xml/settings_preferences.xml b/app/src/main/res/xml/settings_preferences.xml index fc9b9427..0645a398 100644 --- a/app/src/main/res/xml/settings_preferences.xml +++ b/app/src/main/res/xml/settings_preferences.xml @@ -26,6 +26,15 @@ + + + + + diff --git a/version.properties b/version.properties index 9ff5056c..67bcddf6 100644 --- a/version.properties +++ b/version.properties @@ -2,4 +2,4 @@ releaseVersion=0 stagingVersion=61 nightlyVersion=0 versionName=0.61.0 -tagVersion=67 \ No newline at end of file +tagVersion=67