Redesign contact results
This commit is contained in:
+482
-149
@@ -1,75 +1,83 @@
|
||||
package de.mm20.launcher2.ui.launcher.search.contacts
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.SharedTransitionLayout
|
||||
import androidx.compose.animation.core.MutableTransitionState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.core.updateTransition
|
||||
import androidx.compose.animation.expandIn
|
||||
import androidx.compose.animation.shrinkOut
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
|
||||
import androidx.compose.material.icons.automirrored.rounded.Message
|
||||
import androidx.compose.material.icons.rounded.ArrowBack
|
||||
import androidx.compose.material.icons.rounded.Call
|
||||
import androidx.compose.material.icons.automirrored.rounded.NavigateNext
|
||||
import androidx.compose.material.icons.automirrored.rounded.OpenInNew
|
||||
import androidx.compose.material.icons.rounded.Directions
|
||||
import androidx.compose.material.icons.rounded.Edit
|
||||
import androidx.compose.material.icons.rounded.Email
|
||||
import androidx.compose.material.icons.rounded.Home
|
||||
import androidx.compose.material.icons.rounded.MoreHoriz
|
||||
import androidx.compose.material.icons.rounded.OpenInNew
|
||||
import androidx.compose.material.icons.rounded.Phone
|
||||
import androidx.compose.material.icons.rounded.Place
|
||||
import androidx.compose.material.icons.rounded.Star
|
||||
import androidx.compose.material.icons.rounded.StarOutline
|
||||
import androidx.compose.material.icons.rounded.Visibility
|
||||
import androidx.compose.material.icons.rounded.VisibilityOff
|
||||
import androidx.compose.material.icons.rounded.Whatsapp
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SnackbarDuration
|
||||
import androidx.compose.material3.SnackbarResult
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.VerticalDivider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
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.draw.clip
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.graphics.TransformOrigin
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.roundToIntRect
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import coil.compose.AsyncImage
|
||||
import de.mm20.launcher2.ktx.tryStartActivity
|
||||
import de.mm20.launcher2.search.Contact
|
||||
import de.mm20.launcher2.search.ContactInfoType
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.animation.animateTextStyleAsState
|
||||
import de.mm20.launcher2.ui.component.Chip
|
||||
import de.mm20.launcher2.ui.component.DefaultToolbarAction
|
||||
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
|
||||
import de.mm20.launcher2.ui.component.Toolbar
|
||||
import de.mm20.launcher2.ui.component.ToolbarAction
|
||||
import de.mm20.launcher2.icons.Signal
|
||||
import de.mm20.launcher2.icons.Telegram
|
||||
import de.mm20.launcher2.ui.ktx.toPixels
|
||||
import de.mm20.launcher2.ui.launcher.search.common.SearchableItemVM
|
||||
import de.mm20.launcher2.ui.launcher.search.listItemViewModel
|
||||
import de.mm20.launcher2.ui.launcher.sheets.LocalBottomSheetManager
|
||||
import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled
|
||||
import de.mm20.launcher2.ui.locals.LocalGridSettings
|
||||
import de.mm20.launcher2.ui.locals.LocalSnackbarHostState
|
||||
import de.mm20.launcher2.ui.modifier.scale
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
|
||||
@Composable
|
||||
fun ContactItem(
|
||||
@@ -87,158 +95,483 @@ fun ContactItem(
|
||||
viewModel.init(contact, iconSize.toInt())
|
||||
}
|
||||
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
val snackbarHostState = LocalSnackbarHostState.current
|
||||
val icon by viewModel.icon.collectAsStateWithLifecycle()
|
||||
val badge by viewModel.badge.collectAsState(null)
|
||||
|
||||
val transition = updateTransition(showDetails, label = "ContactItem")
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
val icon by viewModel.icon.collectAsStateWithLifecycle()
|
||||
val padding = 16.dp
|
||||
ShapedLauncherIcon(
|
||||
size = 48.dp,
|
||||
modifier = Modifier
|
||||
.padding(start = padding, top = padding, bottom = padding),
|
||||
icon = { icon },
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
) {
|
||||
val textStyle by animateTextStyleAsState(
|
||||
if (showDetails) MaterialTheme.typography.titleLarge
|
||||
else MaterialTheme.typography.titleSmall
|
||||
)
|
||||
Text(
|
||||
text = contact.labelOverride ?: contact.label,
|
||||
style = textStyle,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
AnimatedVisibility(!showDetails) {
|
||||
Text(
|
||||
contact.summary,
|
||||
modifier = Modifier.padding(top = 2.dp),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(showDetails) {
|
||||
val tags by viewModel.tags.collectAsState(emptyList())
|
||||
if (tags.isNotEmpty()) {
|
||||
Text(
|
||||
modifier = Modifier.padding(top = 1.dp),
|
||||
text = tags.joinToString(separator = " #", prefix = "#"),
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
style = MaterialTheme.typography.labelSmall
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AnimatedVisibility(showDetails) {
|
||||
val groups = remember {
|
||||
contact.contactInfos.groupBy { it.type }
|
||||
}
|
||||
Column {
|
||||
|
||||
for ((type, items) in groups) {
|
||||
SharedTransitionLayout {
|
||||
AnimatedContent(showDetails) { showDetails ->
|
||||
if (showDetails) {
|
||||
Column {
|
||||
Row(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
modifier = Modifier.padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(when(type) {
|
||||
ContactInfoType.Phone -> Icons.Rounded.Call
|
||||
ContactInfoType.Message -> Icons.AutoMirrored.Rounded.Message
|
||||
ContactInfoType.Email -> Icons.Rounded.Email
|
||||
ContactInfoType.Postal -> Icons.Rounded.Home
|
||||
ContactInfoType.Telegram -> Icons.Rounded.Telegram
|
||||
ContactInfoType.Whatsapp -> Icons.Rounded.Whatsapp
|
||||
ContactInfoType.Signal -> Icons.Rounded.Signal
|
||||
ContactInfoType.Other -> Icons.Rounded.MoreHoriz
|
||||
}, contentDescription = null)
|
||||
LazyRow(
|
||||
ShapedLauncherIcon(
|
||||
size = 48.dp,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(start = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
items(items.toList()) {
|
||||
Chip(
|
||||
modifier = Modifier.padding(end = 16.dp),
|
||||
text = it.label,
|
||||
onClick = {
|
||||
context.tryStartActivity(it.intent)
|
||||
.padding(end = 16.dp)
|
||||
.sharedElement(
|
||||
rememberSharedContentState("icon"),
|
||||
this@AnimatedContent,
|
||||
),
|
||||
icon = { icon },
|
||||
badge = { badge }
|
||||
)
|
||||
Text(
|
||||
text = contact.labelOverride ?: contact.label,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
modifier = Modifier.sharedBounds(
|
||||
rememberSharedContentState("label"),
|
||||
this@AnimatedContent,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
val canNavigate = remember {
|
||||
context.packageManager.queryIntentActivities(
|
||||
Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse("google.navigation:q=")
|
||||
),
|
||||
0
|
||||
).isNotEmpty()
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
) {
|
||||
var expandedSection by remember { mutableStateOf(-1) }
|
||||
if (contact.phoneNumbers.isNotEmpty()) {
|
||||
ContactInfo(
|
||||
icon = Icons.Rounded.Phone,
|
||||
label = pluralStringResource(
|
||||
R.plurals.contact_phone_numbers,
|
||||
contact.phoneNumbers.size,
|
||||
contact.phoneNumbers.size
|
||||
),
|
||||
items = contact.phoneNumbers,
|
||||
itemLabel = { it.number },
|
||||
itemSubLabel = { it.type.toString(context) },
|
||||
expanded = expandedSection == 0,
|
||||
modifier = Modifier
|
||||
.padding(vertical = 4.dp)
|
||||
.fillMaxWidth(),
|
||||
secondaryAction = {
|
||||
IconButton(onClick = {
|
||||
context.tryStartActivity(
|
||||
Intent(Intent.ACTION_SENDTO).apply {
|
||||
data = Uri.parse("smsto:${it.number}")
|
||||
}
|
||||
)
|
||||
}) {
|
||||
Icon(
|
||||
Icons.AutoMirrored.Rounded.Message,
|
||||
null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
)
|
||||
},
|
||||
onExpand = {
|
||||
expandedSection = if (it) 0 else -1
|
||||
},
|
||||
onContact = {
|
||||
context.tryStartActivity(
|
||||
Intent(Intent.ACTION_DIAL).apply {
|
||||
data = Uri.parse("tel:${it.number}")
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
if (contact.emailAddresses.isNotEmpty()) {
|
||||
ContactInfo(
|
||||
icon = Icons.Rounded.Email,
|
||||
label = pluralStringResource(
|
||||
R.plurals.contact_email_addresses,
|
||||
contact.emailAddresses.size,
|
||||
contact.emailAddresses.size
|
||||
),
|
||||
items = contact.emailAddresses,
|
||||
itemLabel = { it.address },
|
||||
itemSubLabel = { it.type.toString(context) },
|
||||
expanded = expandedSection == 1,
|
||||
modifier = Modifier
|
||||
.padding(vertical = 4.dp)
|
||||
.fillMaxWidth(),
|
||||
onExpand = {
|
||||
expandedSection = if (it) 1 else -1
|
||||
},
|
||||
onContact = {
|
||||
context.tryStartActivity(
|
||||
Intent(Intent.ACTION_SENDTO).apply {
|
||||
data = Uri.parse("mailto:${it.address}")
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
if (contact.postalAddresses.isNotEmpty()) {
|
||||
ContactInfo(
|
||||
icon = Icons.Rounded.Place,
|
||||
label = pluralStringResource(
|
||||
R.plurals.contact_postal_addresses,
|
||||
contact.postalAddresses.size,
|
||||
contact.postalAddresses.size
|
||||
),
|
||||
items = contact.postalAddresses,
|
||||
itemLabel = { it.address },
|
||||
itemSubLabel = { it.type.toString(context) },
|
||||
secondaryAction = if (canNavigate) {
|
||||
{
|
||||
IconButton(onClick = {
|
||||
context.tryStartActivity(
|
||||
Intent(Intent.ACTION_VIEW).apply {
|
||||
data = Uri.parse("google.navigation:q=${it.address}")
|
||||
}
|
||||
)
|
||||
}) {
|
||||
Icon(
|
||||
Icons.Rounded.Directions,
|
||||
null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else null,
|
||||
expanded = expandedSection == 2,
|
||||
modifier = Modifier
|
||||
.padding(vertical = 4.dp)
|
||||
.fillMaxWidth(),
|
||||
onExpand = {
|
||||
expandedSection = if (it) 2 else -1
|
||||
},
|
||||
onContact = {
|
||||
context.tryStartActivity(
|
||||
Intent(Intent.ACTION_VIEW).apply {
|
||||
data = Uri.parse("geo:0,0?q=${it.address}")
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
val apps = remember(contact) {
|
||||
contact.contactApps.groupBy { it.packageName }
|
||||
}
|
||||
for ((i, app) in apps.entries.withIndex()) {
|
||||
val packageName = remember(app) {
|
||||
context.packageManager.queryIntentActivities(
|
||||
Intent(Intent.ACTION_VIEW).apply {
|
||||
setDataAndType(
|
||||
app.value.first().uri,
|
||||
app.value.first().mimeType
|
||||
)
|
||||
},
|
||||
0,
|
||||
).firstOrNull()?.activityInfo?.packageName
|
||||
} ?: continue
|
||||
val appIcon by remember(app) {
|
||||
flow {
|
||||
try {
|
||||
emit(context.packageManager.getApplicationIcon(packageName))
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
emit(null)
|
||||
}
|
||||
}.flowOn(Dispatchers.IO)
|
||||
}.collectAsState(null)
|
||||
val label = remember(app) {
|
||||
try {
|
||||
context.packageManager.getApplicationInfo(packageName, 0)
|
||||
.loadLabel(context.packageManager).toString()
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
app.key
|
||||
}
|
||||
}
|
||||
ContactInfo(
|
||||
icon = Icons.AutoMirrored.Rounded.OpenInNew,
|
||||
customIcon = appIcon,
|
||||
label = label,
|
||||
items = app.value,
|
||||
itemLabel = { it.label },
|
||||
expanded = expandedSection == 3 + i,
|
||||
modifier = Modifier
|
||||
.padding(vertical = 4.dp)
|
||||
.fillMaxWidth(),
|
||||
onExpand = {
|
||||
expandedSection = if (it) 3 + i else -1
|
||||
},
|
||||
onContact = {
|
||||
context.tryStartActivity(
|
||||
Intent(Intent.ACTION_VIEW).apply {
|
||||
setDataAndType(
|
||||
it.uri,
|
||||
it.mimeType
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val toolbarActions = mutableListOf<ToolbarAction>()
|
||||
val toolbarActions = mutableListOf<ToolbarAction>()
|
||||
|
||||
if (LocalFavoritesEnabled.current) {
|
||||
val isPinned by viewModel.isPinned.collectAsState(false)
|
||||
val favAction = if (isPinned) {
|
||||
if (LocalFavoritesEnabled.current) {
|
||||
val isPinned by viewModel.isPinned.collectAsState(false)
|
||||
val favAction = if (isPinned) {
|
||||
DefaultToolbarAction(
|
||||
label = stringResource(R.string.menu_favorites_unpin),
|
||||
icon = Icons.Rounded.Star,
|
||||
action = {
|
||||
viewModel.unpin()
|
||||
}
|
||||
)
|
||||
} else {
|
||||
DefaultToolbarAction(
|
||||
label = stringResource(R.string.menu_favorites_pin),
|
||||
icon = Icons.Rounded.StarOutline,
|
||||
action = {
|
||||
viewModel.pin()
|
||||
})
|
||||
}
|
||||
toolbarActions.add(favAction)
|
||||
}
|
||||
|
||||
toolbarActions.add(
|
||||
DefaultToolbarAction(
|
||||
label = stringResource(R.string.menu_favorites_unpin),
|
||||
icon = Icons.Rounded.Star,
|
||||
label = stringResource(R.string.menu_contacts_open_externally),
|
||||
icon = Icons.Rounded.OpenInNew,
|
||||
action = {
|
||||
viewModel.unpin()
|
||||
viewModel.launch(context)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
DefaultToolbarAction(
|
||||
label = stringResource(R.string.menu_favorites_pin),
|
||||
icon = Icons.Rounded.StarOutline,
|
||||
action = {
|
||||
viewModel.pin()
|
||||
})
|
||||
}
|
||||
toolbarActions.add(favAction)
|
||||
}
|
||||
|
||||
toolbarActions.add(
|
||||
DefaultToolbarAction(
|
||||
label = stringResource(R.string.menu_contacts_open_externally),
|
||||
icon = Icons.Rounded.OpenInNew,
|
||||
action = {
|
||||
viewModel.launch(context)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
val sheetManager = LocalBottomSheetManager.current
|
||||
toolbarActions.add(DefaultToolbarAction(
|
||||
label = stringResource(R.string.menu_customize),
|
||||
icon = Icons.Rounded.Edit,
|
||||
action = { sheetManager.showCustomizeSearchableModal(contact) }
|
||||
))
|
||||
val sheetManager = LocalBottomSheetManager.current
|
||||
toolbarActions.add(DefaultToolbarAction(
|
||||
label = stringResource(R.string.menu_customize),
|
||||
icon = Icons.Rounded.Edit,
|
||||
action = { sheetManager.showCustomizeSearchableModal(contact) }
|
||||
))
|
||||
|
||||
|
||||
Toolbar(
|
||||
leftActions = listOf(
|
||||
DefaultToolbarAction(
|
||||
label = stringResource(id = R.string.menu_back),
|
||||
icon = Icons.Rounded.ArrowBack
|
||||
) {
|
||||
onBack()
|
||||
}
|
||||
),
|
||||
rightActions = toolbarActions
|
||||
)
|
||||
Toolbar(
|
||||
leftActions = listOf(
|
||||
DefaultToolbarAction(
|
||||
label = stringResource(id = R.string.menu_back),
|
||||
icon = Icons.AutoMirrored.Rounded.ArrowBack
|
||||
) {
|
||||
onBack()
|
||||
}
|
||||
),
|
||||
rightActions = toolbarActions
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
start = 8.dp,
|
||||
top = 8.dp,
|
||||
bottom = 8.dp,
|
||||
end = 16.dp
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
ShapedLauncherIcon(
|
||||
size = 48.dp,
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.sharedElement(
|
||||
rememberSharedContentState("icon"),
|
||||
this@AnimatedContent,
|
||||
),
|
||||
icon = { icon },
|
||||
badge = { badge }
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(start = 8.dp)
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.sharedBounds(
|
||||
rememberSharedContentState("label"),
|
||||
this@AnimatedContent,
|
||||
),
|
||||
text = contact.labelOverride ?: contact.label,
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
Text(
|
||||
contact.summary,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.padding(top = 2.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun <T> ContactInfo(
|
||||
label: String,
|
||||
modifier: Modifier = Modifier,
|
||||
items: List<T>,
|
||||
itemLabel: (T) -> String,
|
||||
itemSubLabel: (T) -> String? = { null },
|
||||
itemIcon: (T) -> ImageVector? = { null },
|
||||
secondaryAction: (@Composable (T) -> Unit)? = null,
|
||||
icon: ImageVector,
|
||||
customIcon: Drawable? = null,
|
||||
expanded: Boolean,
|
||||
onExpand: (Boolean) -> Unit,
|
||||
onContact: (T) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.clip(MaterialTheme.shapes.small)
|
||||
.clickable(
|
||||
enabled = !expanded && items.size != 1
|
||||
) {
|
||||
if (items.size > 1) {
|
||||
onExpand(true)
|
||||
} else {
|
||||
onContact(items.first())
|
||||
}
|
||||
}
|
||||
.border(
|
||||
1.dp,
|
||||
MaterialTheme.colorScheme.outlineVariant,
|
||||
MaterialTheme.shapes.small
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
AnimatedContent(expanded || items.size == 1) { exp ->
|
||||
if (exp) {
|
||||
Column {
|
||||
for (item in items) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(end = if (secondaryAction != null) 8.dp else 0.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Row(
|
||||
modifier =
|
||||
Modifier
|
||||
.weight(1f)
|
||||
.clickable {
|
||||
onContact(item)
|
||||
}
|
||||
.padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
if (customIcon != null) {
|
||||
AsyncImage(
|
||||
model = customIcon,
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 4.dp)
|
||||
.size(24.dp)
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
itemIcon(item) ?: icon,
|
||||
null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(horizontal = 4.dp),
|
||||
)
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 16.dp),
|
||||
) {
|
||||
itemSubLabel(item)?.let {
|
||||
Text(
|
||||
text = it,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
modifier = Modifier.padding(bottom = 2.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = itemLabel(item),
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
if (secondaryAction != null) {
|
||||
VerticalDivider(
|
||||
modifier = Modifier
|
||||
.height(24.dp)
|
||||
.padding(end = 4.dp)
|
||||
)
|
||||
secondaryAction(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
if (customIcon != null) {
|
||||
AsyncImage(
|
||||
model = customIcon,
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 4.dp)
|
||||
.size(24.dp)
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
icon,
|
||||
null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(horizontal = 4.dp)
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = label,
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
Icon(
|
||||
Icons.AutoMirrored.Rounded.NavigateNext,
|
||||
null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun ContactInfoType.toString(context: Context): String? {
|
||||
return when (this) {
|
||||
ContactInfoType.Home -> context.getString(R.string.contact_info_home)
|
||||
ContactInfoType.Mobile -> context.getString(R.string.contact_info_mobile)
|
||||
ContactInfoType.Work -> context.getString(R.string.contact_info_work)
|
||||
ContactInfoType.Other -> null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun ContactItemGridPopup(
|
||||
contact: Contact,
|
||||
|
||||
Reference in New Issue
Block a user