kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
refactor: handle selected contacts in a local variable
rodzic
56d9f03748
commit
2b4b1d7683
|
@ -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(),
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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) },
|
||||||
|
|
Ładowanie…
Reference in New Issue