From 0b92ff64412d9537f13555d467f45e959dfa95a7 Mon Sep 17 00:00:00 2001 From: andrekir Date: Thu, 2 Jan 2025 20:26:34 -0300 Subject: [PATCH] refactor: migrate `ShareFragment` to Compose --- .../main/java/com/geeksville/mesh/ui/Main.kt | 6 +- .../java/com/geeksville/mesh/ui/NavGraph.kt | 10 ++ .../com/geeksville/mesh/ui/ShareFragment.kt | 168 ++++++++---------- app/src/main/res/drawable/cloud_off.xml | 14 -- app/src/main/res/drawable/cloud_on.xml | 14 -- .../drawable/ic_twotone_cloud_upload_24.xml | 15 -- .../drawable/ic_twotone_contactless_24.xml | 25 --- .../main/res/drawable/ic_twotone_map_24.xml | 15 -- .../res/drawable/ic_twotone_message_24.xml | 14 -- .../res/drawable/ic_twotone_people_24.xml | 18 -- .../main/res/drawable/ic_twotone_send_24.xml | 16 -- .../ic_twotone_settings_applications_24.xml | 14 -- app/src/main/res/layout/share_fragment.xml | 63 ------- 13 files changed, 93 insertions(+), 299 deletions(-) delete mode 100644 app/src/main/res/drawable/cloud_off.xml delete mode 100644 app/src/main/res/drawable/cloud_on.xml delete mode 100644 app/src/main/res/drawable/ic_twotone_cloud_upload_24.xml delete mode 100644 app/src/main/res/drawable/ic_twotone_contactless_24.xml delete mode 100644 app/src/main/res/drawable/ic_twotone_map_24.xml delete mode 100644 app/src/main/res/drawable/ic_twotone_message_24.xml delete mode 100644 app/src/main/res/drawable/ic_twotone_people_24.xml delete mode 100644 app/src/main/res/drawable/ic_twotone_send_24.xml delete mode 100644 app/src/main/res/drawable/ic_twotone_settings_applications_24.xml delete mode 100644 app/src/main/res/layout/share_fragment.xml diff --git a/app/src/main/java/com/geeksville/mesh/ui/Main.kt b/app/src/main/java/com/geeksville/mesh/ui/Main.kt index fd631f66..9416acf2 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/Main.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/Main.kt @@ -173,7 +173,8 @@ private fun MainAppBar( TopAppBar( title = { when { - currentDestination == null || isTopLevelRoute -> { + currentDestination == null || isTopLevelRoute || + currentDestination.hasRoute() -> { Row(verticalAlignment = Alignment.CenterVertically) { Icon( imageVector = ImageVector.vectorResource(id = R.drawable.app_icon), @@ -192,6 +193,9 @@ private fun MainAppBar( currentDestination.hasRoute() -> Text(stringResource(id = R.string.quick_chat)) + currentDestination.hasRoute() -> + Text(stringResource(id = R.string.share_to)) + else -> Text("Node name here") // TODO show destNode longName } }, diff --git a/app/src/main/java/com/geeksville/mesh/ui/NavGraph.kt b/app/src/main/java/com/geeksville/mesh/ui/NavGraph.kt index 9bea9d67..5f6ad823 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/NavGraph.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/NavGraph.kt @@ -111,6 +111,8 @@ sealed interface Route { @Serializable data class Messages(val contactKey: String, val message: String = "") : Route @Serializable data object QuickChat : Route + @Serializable + data class Share(val message: String) : Route @Serializable data class RadioConfig(val destNum: Int? = null) : Route @@ -386,5 +388,13 @@ fun NavGraph( val parentEntry = remember { navController.getBackStackEntry() } PaxcounterConfigScreen(hiltViewModel(parentEntry)) } + composable { backStackEntry -> + val message = backStackEntry.toRoute().message + ShareScreen(model) { + navController.navigate(Route.Messages(it, message)) { + popUpTo { inclusive = true } + } + } + } } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/ShareFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/ShareFragment.kt index 0a32baf9..99e9e8ee 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/ShareFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/ShareFragment.kt @@ -17,116 +17,104 @@ package com.geeksville.mesh.ui -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.material.Button +import androidx.compose.material.Icon +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.Send import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.PreviewScreenSizes import androidx.compose.ui.unit.dp -import androidx.fragment.app.activityViewModels +import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.geeksville.mesh.android.Logging -import com.geeksville.mesh.databinding.ShareFragmentBinding +import com.geeksville.mesh.R import com.geeksville.mesh.model.Contact import com.geeksville.mesh.model.UIViewModel import com.geeksville.mesh.ui.theme.AppTheme -import dagger.hilt.android.AndroidEntryPoint -@AndroidEntryPoint -class ShareFragment : ScreenFragment("Messages"), Logging { +@Composable +fun ShareScreen( + viewModel: UIViewModel = hiltViewModel(), + onConfirm: (String) -> Unit +) { + val contactList by viewModel.contactList.collectAsStateWithLifecycle() - private val model: UIViewModel by activityViewModels() - private var _binding: ShareFragmentBinding? = null - - // This property is only valid between onCreateView and onDestroyView. - private val binding get() = _binding!! - - private val contacts get() = model.contactList.value - private var selectedContact = mutableStateOf("") - - private fun shareMessage(contact: Contact) { - debug("calling MessagesFragment filter:${contact.contactKey}") -// parentFragmentManager.navigateToMessages( -// contact.contactKey, -// arguments?.getString("message").toString() -// ) - } - - private fun onClick(contact: Contact) { - if (selectedContact.value == contact.contactKey) { - selectedContact.value = "" - binding.shareButton.isEnabled = false - } else { - selectedContact.value = contact.contactKey - binding.shareButton.isEnabled = true - } - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - _binding = ShareFragmentBinding.inflate(inflater, container, false) - return binding.root - } - - @Suppress("LongMethod", "CyclomaticComplexMethod") - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - binding.toolbar.setNavigationOnClickListener { - parentFragmentManager.popBackStack() - } - - binding.shareButton.isEnabled = false - - binding.shareButton.setOnClickListener { - debug("User clicked shareButton") - val contact = contacts.find { c -> c.contactKey == selectedContact.value } - if (contact != null) { - shareMessage(contact) - } - } - - binding.contactListView.setContent { - val contacts by model.contactList.collectAsStateWithLifecycle() - AppTheme { - ShareContactListView( - contacts = contacts, - selectedContact = selectedContact.value, - onClick = ::onClick, - ) - } - } - } + ShareScreen( + contacts = contactList, + onConfirm = onConfirm, + ) } @Composable -fun ShareContactListView( +fun ShareScreen( contacts: List, - selectedContact: String, - onClick: (Contact) -> Unit, + onConfirm: (String) -> Unit ) { - LazyColumn( - modifier = Modifier - .fillMaxSize(), - contentPadding = PaddingValues(6.dp), - ) { - items(contacts, key = { it.contactKey }) { contact -> - val selected = contact.contactKey == selectedContact - ContactItem( - contact = contact, - selected = selected, - onClick = { onClick(contact) }, - onLongClick = {}, + var selectedContact by remember { mutableStateOf("") } + + Column { + LazyColumn( + modifier = Modifier.weight(1f), + contentPadding = PaddingValues(6.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + items(contacts, key = { it.contactKey }) { contact -> + val selected = contact.contactKey == selectedContact + ContactItem( + contact = contact, + selected = selected, + onClick = { selectedContact = contact.contactKey }, + ) + } + } + + Button( + onClick = { + onConfirm(selectedContact) + }, + modifier = Modifier + .fillMaxWidth() + .padding(24.dp), + enabled = selectedContact.isNotEmpty(), + ) { + Icon( + imageVector = Icons.AutoMirrored.Default.Send, + contentDescription = stringResource(id = R.string.share) ) } } } + +@PreviewScreenSizes +@Composable +private fun ShareScreenPreview() { + AppTheme { + ShareScreen( + contacts = listOf( + Contact( + contactKey = "0^all", + shortName = stringResource(R.string.some_username), + longName = stringResource(R.string.unknown_username), + lastMessageTime = "3 minutes ago", + lastMessageText = stringResource(R.string.sample_message), + unreadCount = 2, + messageCount = 10, + isMuted = true, + ), + ), + onConfirm = {}, + ) + } +} diff --git a/app/src/main/res/drawable/cloud_off.xml b/app/src/main/res/drawable/cloud_off.xml deleted file mode 100644 index 92b0aa54..00000000 --- a/app/src/main/res/drawable/cloud_off.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/cloud_on.xml b/app/src/main/res/drawable/cloud_on.xml deleted file mode 100644 index 0c9bcd4d..00000000 --- a/app/src/main/res/drawable/cloud_on.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_twotone_cloud_upload_24.xml b/app/src/main/res/drawable/ic_twotone_cloud_upload_24.xml deleted file mode 100644 index 8982a35a..00000000 --- a/app/src/main/res/drawable/ic_twotone_cloud_upload_24.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_twotone_contactless_24.xml b/app/src/main/res/drawable/ic_twotone_contactless_24.xml deleted file mode 100644 index 8a999651..00000000 --- a/app/src/main/res/drawable/ic_twotone_contactless_24.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/drawable/ic_twotone_map_24.xml b/app/src/main/res/drawable/ic_twotone_map_24.xml deleted file mode 100644 index bd96aeb9..00000000 --- a/app/src/main/res/drawable/ic_twotone_map_24.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_twotone_message_24.xml b/app/src/main/res/drawable/ic_twotone_message_24.xml deleted file mode 100644 index 9ad22351..00000000 --- a/app/src/main/res/drawable/ic_twotone_message_24.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_twotone_people_24.xml b/app/src/main/res/drawable/ic_twotone_people_24.xml deleted file mode 100644 index 74a346d8..00000000 --- a/app/src/main/res/drawable/ic_twotone_people_24.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_twotone_send_24.xml b/app/src/main/res/drawable/ic_twotone_send_24.xml deleted file mode 100644 index ee3e89f7..00000000 --- a/app/src/main/res/drawable/ic_twotone_send_24.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_twotone_settings_applications_24.xml b/app/src/main/res/drawable/ic_twotone_settings_applications_24.xml deleted file mode 100644 index e2368d7a..00000000 --- a/app/src/main/res/drawable/ic_twotone_settings_applications_24.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/app/src/main/res/layout/share_fragment.xml b/app/src/main/res/layout/share_fragment.xml deleted file mode 100644 index 80965051..00000000 --- a/app/src/main/res/layout/share_fragment.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - -