From 2b4b1d7683b35452489f7f60a4950f5a00c9547e Mon Sep 17 00:00:00 2001 From: andrekir Date: Sat, 6 Jul 2024 08:31:52 -0300 Subject: [PATCH] refactor: handle selected contacts in a local variable --- .../mesh/model/ContactsViewModel.kt | 20 +------- .../com/geeksville/mesh/ui/ContactItem.kt | 6 +-- .../geeksville/mesh/ui/ContactsFragment.kt | 46 +++++++++++-------- 3 files changed, 29 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/model/ContactsViewModel.kt b/app/src/main/java/com/geeksville/mesh/model/ContactsViewModel.kt index a5daf018..6023ae99 100644 --- a/app/src/main/java/com/geeksville/mesh/model/ContactsViewModel.kt +++ b/app/src/main/java/com/geeksville/mesh/model/ContactsViewModel.kt @@ -11,12 +11,9 @@ import com.geeksville.mesh.database.entity.Packet import com.geeksville.mesh.repository.datastore.ChannelSetRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed -import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.flow.updateAndGet import kotlinx.coroutines.launch import java.text.DateFormat import java.util.Date @@ -53,21 +50,6 @@ class ContactsViewModel @Inject constructor( private val packetRepository: PacketRepository, ) : ViewModel(), Logging { - private val _selectedContacts = MutableStateFlow(emptySet()) - val selectedContacts get() = _selectedContacts.asStateFlow() - - fun updateSelectedContacts(contact: String) = _selectedContacts.updateAndGet { - if (it.contains(contact)) { - it.minus(contact) - } else { - it.plus(contact) - } - } - - fun clearSelectedContacts() { - _selectedContacts.value = emptySet() - } - val contactList = combine( nodeDB.myNodeInfo, packetRepository.getContacts(), @@ -124,4 +106,4 @@ class ContactsViewModel @Inject constructor( fun deleteContacts(contacts: List) = viewModelScope.launch(Dispatchers.IO) { packetRepository.deleteContacts(contacts) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/geeksville/mesh/ui/ContactItem.kt b/app/src/main/java/com/geeksville/mesh/ui/ContactItem.kt index 07ae7101..1fe69b39 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/ContactItem.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/ContactItem.kt @@ -1,6 +1,5 @@ package com.geeksville.mesh.ui -import android.content.res.Configuration import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -27,7 +26,7 @@ import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp import com.geeksville.mesh.R import com.geeksville.mesh.model.Contact @@ -122,8 +121,7 @@ fun ContactItem( } } -@Preview(showBackground = true) -@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) +@PreviewLightDark @Composable private fun ContactItemPreview() { AppTheme { diff --git a/app/src/main/java/com/geeksville/mesh/ui/ContactsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/ContactsFragment.kt index dfc507e9..9da91023 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/ContactsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/ContactsFragment.kt @@ -18,13 +18,13 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.toMutableStateList import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.compose.ui.unit.dp import androidx.fragment.app.viewModels -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.geeksville.mesh.android.Logging import com.geeksville.mesh.R @@ -43,7 +43,7 @@ class ContactsFragment : ScreenFragment("Messages"), Logging { private val model: ContactsViewModel by viewModels() private val contacts get() = model.contactList.value - private val selectedList get() = model.selectedContacts.value.toList() + private val selectedList = emptyList().toMutableStateList() private val selectedContacts get() = contacts.filter { it.contactKey in selectedList } private val isAllMuted get() = selectedContacts.all { it.isMuted } @@ -63,13 +63,15 @@ class ContactsFragment : ScreenFragment("Messages"), Logging { actionMode = (activity as AppCompatActivity).startSupportActionMode(actionModeCallback) } - val selected = model.updateSelectedContacts(contact.contactKey) - if (selected.isEmpty()) { + selectedList.apply { + if (!remove(contact.contactKey)) add(contact.contactKey) + } + if (selectedList.isEmpty()) { // finish action mode when no items selected actionMode?.finish() } else { // show total items selected on action mode title - actionMode?.title = selected.size.toString() + actionMode?.title = selectedList.size.toString() } } @@ -86,8 +88,15 @@ class ContactsFragment : ScreenFragment("Messages"), Logging { return ComposeView(requireContext()).apply { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { + val contacts by model.contactList.collectAsStateWithLifecycle() + AppTheme { - ContactsScreen(model, ::onClick, ::onLongClick) + ContactListView( + contacts = contacts, + selectedList = selectedList, + onClick = ::onClick, + onLongClick = ::onLongClick, + ) } } } @@ -171,14 +180,12 @@ class ContactsFragment : ScreenFragment("Messages"), Logging { R.id.selectAllButton -> { // if all selected -> unselect all if (selectedList.size == contacts.size) { - model.clearSelectedContacts() + selectedList.clear() mode.finish() } else { // else --> select all - model.clearSelectedContacts() - contacts.forEach { - model.updateSelectedContacts(it.contactKey) - } + selectedList.clear() + selectedList.addAll(contacts.map { it.contactKey }) actionMode?.title = contacts.size.toString() } } @@ -187,7 +194,7 @@ class ContactsFragment : ScreenFragment("Messages"), Logging { } override fun onDestroyActionMode(mode: ActionMode) { - model.clearSelectedContacts() + selectedList.clear() actionMode = null } } @@ -195,26 +202,25 @@ class ContactsFragment : ScreenFragment("Messages"), Logging { @OptIn(ExperimentalFoundationApi::class) @Composable -fun ContactsScreen( - model: ContactsViewModel = hiltViewModel(), +fun ContactListView( + contacts: List, + selectedList: List, onClick: (Contact) -> Unit, onLongClick: (Contact) -> Unit, ) { - val contacts by model.contactList.collectAsStateWithLifecycle(emptyList()) - val selectedKeys by model.selectedContacts.collectAsStateWithLifecycle() - // val inSelectionMode by remember { derivedStateOf { selectedContacts.isNotEmpty() } } - LazyColumn( modifier = Modifier .fillMaxSize() .padding(6.dp), ) { items(contacts, key = { it.contactKey }) { contact -> - val selected = selectedKeys.contains(contact.contactKey) + val selected = selectedList.contains(contact.contactKey) + val selectedColor = if (selected) Color.Gray else MaterialTheme.colors.background + ContactItem( contact = contact, modifier = Modifier - .background(color = if (selected) Color.Gray else MaterialTheme.colors.background) + .background(color = selectedColor) .combinedClickable( onClick = { onClick(contact) }, onLongClick = { onLongClick(contact) },