[track-search] Added context menu for copy and open-in-web (#10352)
This commit is contained in:
parent
f60782f11f
commit
a8040cb21a
1 changed files with 69 additions and 22 deletions
|
@ -7,6 +7,7 @@ import androidx.compose.animation.slideInVertically
|
||||||
import androidx.compose.animation.slideOutVertically
|
import androidx.compose.animation.slideOutVertically
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
@ -22,7 +23,6 @@ import androidx.compose.foundation.layout.paddingFromBaseline
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.selection.selectable
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.BasicTextField
|
import androidx.compose.foundation.text.BasicTextField
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
|
@ -33,6 +33,7 @@ import androidx.compose.material.icons.filled.CheckCircle
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
|
@ -40,7 +41,10 @@ import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
@ -48,7 +52,11 @@ import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.SolidColor
|
import androidx.compose.ui.graphics.SolidColor
|
||||||
|
import androidx.compose.ui.platform.ClipboardManager
|
||||||
|
import androidx.compose.ui.platform.LocalClipboardManager
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalFocusManager
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
import androidx.compose.ui.text.capitalize
|
import androidx.compose.ui.text.capitalize
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.input.TextFieldValue
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
|
@ -58,9 +66,11 @@ import androidx.compose.ui.text.toLowerCase
|
||||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import eu.kanade.presentation.components.DropdownMenu
|
||||||
import eu.kanade.presentation.manga.components.MangaCover
|
import eu.kanade.presentation.manga.components.MangaCover
|
||||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
|
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
|
@ -188,13 +198,7 @@ fun TrackerSearch(
|
||||||
key = { it.hashCode() },
|
key = { it.hashCode() },
|
||||||
) {
|
) {
|
||||||
SearchResultItem(
|
SearchResultItem(
|
||||||
title = it.title,
|
trackSearch = it,
|
||||||
coverUrl = it.cover_url,
|
|
||||||
type = it.publishing_type.toLowerCase(Locale.current).capitalize(Locale.current),
|
|
||||||
startDate = it.start_date,
|
|
||||||
status = it.publishing_status.toLowerCase(Locale.current).capitalize(Locale.current),
|
|
||||||
score = it.score,
|
|
||||||
description = it.summary.trim(),
|
|
||||||
selected = it == selected,
|
selected = it == selected,
|
||||||
onClick = { onSelectedChange(it) },
|
onClick = { onSelectedChange(it) },
|
||||||
)
|
)
|
||||||
|
@ -214,18 +218,18 @@ fun TrackerSearch(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SearchResultItem(
|
private fun SearchResultItem(
|
||||||
title: String,
|
trackSearch: TrackSearch,
|
||||||
coverUrl: String,
|
|
||||||
type: String,
|
|
||||||
startDate: String,
|
|
||||||
status: String,
|
|
||||||
score: Float,
|
|
||||||
description: String,
|
|
||||||
selected: Boolean,
|
selected: Boolean,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val clipboardManager: ClipboardManager = LocalClipboardManager.current
|
||||||
|
val type = trackSearch.publishing_type.toLowerCase(Locale.current).capitalize(Locale.current)
|
||||||
|
val status = trackSearch.publishing_status.toLowerCase(Locale.current).capitalize(Locale.current)
|
||||||
|
val description = trackSearch.summary.trim()
|
||||||
val shape = RoundedCornerShape(16.dp)
|
val shape = RoundedCornerShape(16.dp)
|
||||||
val borderColor = if (selected) MaterialTheme.colorScheme.outline else Color.Transparent
|
val borderColor = if (selected) MaterialTheme.colorScheme.outline else Color.Transparent
|
||||||
|
var dropDownMenuExpanded by remember { mutableStateOf(false) }
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
@ -237,7 +241,10 @@ private fun SearchResultItem(
|
||||||
color = borderColor,
|
color = borderColor,
|
||||||
shape = shape,
|
shape = shape,
|
||||||
)
|
)
|
||||||
.selectable(selected = selected, onClick = onClick)
|
.combinedClickable(
|
||||||
|
onLongClick = { dropDownMenuExpanded = true },
|
||||||
|
onClick = onClick,
|
||||||
|
)
|
||||||
.padding(12.dp),
|
.padding(12.dp),
|
||||||
) {
|
) {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
|
@ -251,28 +258,41 @@ private fun SearchResultItem(
|
||||||
Column {
|
Column {
|
||||||
Row {
|
Row {
|
||||||
MangaCover.Book(
|
MangaCover.Book(
|
||||||
data = coverUrl,
|
data = trackSearch.cover_url,
|
||||||
modifier = Modifier.height(96.dp),
|
modifier = Modifier.height(96.dp),
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(12.dp))
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
Column {
|
Column {
|
||||||
Text(
|
Text(
|
||||||
text = title,
|
text = trackSearch.title,
|
||||||
modifier = Modifier.padding(end = 28.dp),
|
modifier = Modifier.padding(end = 28.dp),
|
||||||
maxLines = 2,
|
maxLines = 2,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
style = MaterialTheme.typography.titleMedium,
|
style = MaterialTheme.typography.titleMedium,
|
||||||
)
|
)
|
||||||
|
SearchResultItemDropDownMenu(
|
||||||
|
expanded = dropDownMenuExpanded,
|
||||||
|
onCollapseMenu = { dropDownMenuExpanded = false },
|
||||||
|
onCopyName = {
|
||||||
|
clipboardManager.setText(AnnotatedString(trackSearch.title))
|
||||||
|
},
|
||||||
|
onOpenInBrowser = {
|
||||||
|
val url = trackSearch.tracking_url
|
||||||
|
if (url.isNotBlank()) {
|
||||||
|
context.openInBrowser(url)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
if (type.isNotBlank()) {
|
if (type.isNotBlank()) {
|
||||||
SearchResultItemDetails(
|
SearchResultItemDetails(
|
||||||
title = stringResource(MR.strings.track_type),
|
title = stringResource(MR.strings.track_type),
|
||||||
text = type,
|
text = type,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (startDate.isNotBlank()) {
|
if (trackSearch.start_date.isNotBlank()) {
|
||||||
SearchResultItemDetails(
|
SearchResultItemDetails(
|
||||||
title = stringResource(MR.strings.label_started),
|
title = stringResource(MR.strings.label_started),
|
||||||
text = startDate,
|
text = trackSearch.start_date,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (status.isNotBlank()) {
|
if (status.isNotBlank()) {
|
||||||
|
@ -281,10 +301,10 @@ private fun SearchResultItem(
|
||||||
text = status,
|
text = status,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (score != -1f) {
|
if (trackSearch.score != -1f) {
|
||||||
SearchResultItemDetails(
|
SearchResultItemDetails(
|
||||||
title = stringResource(MR.strings.score),
|
title = stringResource(MR.strings.score),
|
||||||
text = score.toString(),
|
text = trackSearch.score.toString(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,6 +324,33 @@ private fun SearchResultItem(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SearchResultItemDropDownMenu(
|
||||||
|
expanded: Boolean,
|
||||||
|
onCollapseMenu: () -> Unit,
|
||||||
|
onCopyName: () -> Unit,
|
||||||
|
onOpenInBrowser: () -> Unit,
|
||||||
|
) {
|
||||||
|
DropdownMenu(
|
||||||
|
expanded = expanded,
|
||||||
|
onDismissRequest = onCollapseMenu,
|
||||||
|
) {
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(stringResource(MR.strings.action_copy_to_clipboard)) },
|
||||||
|
onClick = {
|
||||||
|
onCopyName()
|
||||||
|
onCollapseMenu()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(stringResource(MR.strings.action_open_in_browser)) },
|
||||||
|
onClick = {
|
||||||
|
onOpenInBrowser()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SearchResultItemDetails(
|
private fun SearchResultItemDetails(
|
||||||
title: String,
|
title: String,
|
||||||
|
|
Reference in a new issue