refactor: handle selected contacts in a local variable

pull/1128/head
andrekir 2024-07-06 08:31:52 -03:00
rodzic 56d9f03748
commit 2b4b1d7683
3 zmienionych plików z 29 dodań i 43 usunięć

Wyświetl plik

@ -11,12 +11,9 @@ import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.repository.datastore.ChannelSetRepository import com.geeksville.mesh.repository.datastore.ChannelSetRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.updateAndGet
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.text.DateFormat import java.text.DateFormat
import java.util.Date import java.util.Date
@ -53,21 +50,6 @@ class ContactsViewModel @Inject constructor(
private val packetRepository: PacketRepository, private val packetRepository: PacketRepository,
) : ViewModel(), Logging { ) : ViewModel(), Logging {
private val _selectedContacts = MutableStateFlow(emptySet<String>())
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( val contactList = combine(
nodeDB.myNodeInfo, nodeDB.myNodeInfo,
packetRepository.getContacts(), packetRepository.getContacts(),
@ -124,4 +106,4 @@ class ContactsViewModel @Inject constructor(
fun deleteContacts(contacts: List<String>) = viewModelScope.launch(Dispatchers.IO) { fun deleteContacts(contacts: List<String>) = viewModelScope.launch(Dispatchers.IO) {
packetRepository.deleteContacts(contacts) packetRepository.deleteContacts(contacts)
} }
} }

Wyświetl plik

@ -1,6 +1,5 @@
package com.geeksville.mesh.ui package com.geeksville.mesh.ui
import android.content.res.Configuration
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement 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.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow 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 androidx.compose.ui.unit.dp
import com.geeksville.mesh.R import com.geeksville.mesh.R
import com.geeksville.mesh.model.Contact import com.geeksville.mesh.model.Contact
@ -122,8 +121,7 @@ fun ContactItem(
} }
} }
@Preview(showBackground = true) @PreviewLightDark
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable @Composable
private fun ContactItemPreview() { private fun ContactItemPreview() {
AppTheme { AppTheme {

Wyświetl plik

@ -18,13 +18,13 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.toMutableStateList
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.android.Logging import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.R import com.geeksville.mesh.R
@ -43,7 +43,7 @@ class ContactsFragment : ScreenFragment("Messages"), Logging {
private val model: ContactsViewModel by viewModels() private val model: ContactsViewModel by viewModels()
private val contacts get() = model.contactList.value private val contacts get() = model.contactList.value
private val selectedList get() = model.selectedContacts.value.toList() private val selectedList = emptyList<String>().toMutableStateList()
private val selectedContacts get() = contacts.filter { it.contactKey in selectedList } private val selectedContacts get() = contacts.filter { it.contactKey in selectedList }
private val isAllMuted get() = selectedContacts.all { it.isMuted } private val isAllMuted get() = selectedContacts.all { it.isMuted }
@ -63,13 +63,15 @@ class ContactsFragment : ScreenFragment("Messages"), Logging {
actionMode = (activity as AppCompatActivity).startSupportActionMode(actionModeCallback) actionMode = (activity as AppCompatActivity).startSupportActionMode(actionModeCallback)
} }
val selected = model.updateSelectedContacts(contact.contactKey) selectedList.apply {
if (selected.isEmpty()) { if (!remove(contact.contactKey)) add(contact.contactKey)
}
if (selectedList.isEmpty()) {
// finish action mode when no items selected // finish action mode when no items selected
actionMode?.finish() actionMode?.finish()
} else { } else {
// show total items selected on action mode title // 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 { return ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent { setContent {
val contacts by model.contactList.collectAsStateWithLifecycle()
AppTheme { 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 -> { R.id.selectAllButton -> {
// if all selected -> unselect all // if all selected -> unselect all
if (selectedList.size == contacts.size) { if (selectedList.size == contacts.size) {
model.clearSelectedContacts() selectedList.clear()
mode.finish() mode.finish()
} else { } else {
// else --> select all // else --> select all
model.clearSelectedContacts() selectedList.clear()
contacts.forEach { selectedList.addAll(contacts.map { it.contactKey })
model.updateSelectedContacts(it.contactKey)
}
actionMode?.title = contacts.size.toString() actionMode?.title = contacts.size.toString()
} }
} }
@ -187,7 +194,7 @@ class ContactsFragment : ScreenFragment("Messages"), Logging {
} }
override fun onDestroyActionMode(mode: ActionMode) { override fun onDestroyActionMode(mode: ActionMode) {
model.clearSelectedContacts() selectedList.clear()
actionMode = null actionMode = null
} }
} }
@ -195,26 +202,25 @@ class ContactsFragment : ScreenFragment("Messages"), Logging {
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
fun ContactsScreen( fun ContactListView(
model: ContactsViewModel = hiltViewModel(), contacts: List<Contact>,
selectedList: List<String>,
onClick: (Contact) -> Unit, onClick: (Contact) -> Unit,
onLongClick: (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( LazyColumn(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(6.dp), .padding(6.dp),
) { ) {
items(contacts, key = { it.contactKey }) { contact -> 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( ContactItem(
contact = contact, contact = contact,
modifier = Modifier modifier = Modifier
.background(color = if (selected) Color.Gray else MaterialTheme.colors.background) .background(color = selectedColor)
.combinedClickable( .combinedClickable(
onClick = { onClick(contact) }, onClick = { onClick(contact) },
onLongClick = { onLongClick(contact) }, onLongClick = { onLongClick(contact) },