Add copy tags to clipboard feature (#9063)
(cherry picked from commit d02b0ca2db744b0eca48dfca86811d653fd3bdaf) # Conflicts: # app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt # app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt
This commit is contained in:
parent
829452bc03
commit
57113014ec
@ -85,6 +85,7 @@ import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||
import eu.kanade.tachiyomi.ui.manga.PagePreviewState
|
||||
import eu.kanade.tachiyomi.ui.manga.chapterDecimalFormat
|
||||
import eu.kanade.tachiyomi.util.lang.toRelativeString
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import exh.metadata.MetadataUtil
|
||||
import exh.source.MERGED_SOURCE_ID
|
||||
import exh.source.getMainSource
|
||||
@ -115,7 +116,10 @@ fun MangaScreen(
|
||||
onWebViewClicked: (() -> Unit)?,
|
||||
onWebViewLongClicked: (() -> Unit)?,
|
||||
onTrackingClicked: (() -> Unit)?,
|
||||
onTagClicked: (String) -> Unit,
|
||||
|
||||
// For tags menu
|
||||
onTagSearch: (String) -> Unit,
|
||||
|
||||
onFilterButtonClicked: () -> Unit,
|
||||
onRefresh: () -> Unit,
|
||||
onContinueReading: () -> Unit,
|
||||
@ -151,6 +155,13 @@ fun MangaScreen(
|
||||
onAllChapterSelected: (Boolean) -> Unit,
|
||||
onInvertSelection: () -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val onCopyTagToClipboard: (tag: String) -> Unit = {
|
||||
if (it.isNotEmpty()) {
|
||||
context.copyToClipboard(it, it)
|
||||
}
|
||||
}
|
||||
|
||||
if (!isTabletUi) {
|
||||
MangaScreenSmallImpl(
|
||||
state = state,
|
||||
@ -164,7 +175,8 @@ fun MangaScreen(
|
||||
onWebViewClicked = onWebViewClicked,
|
||||
onWebViewLongClicked = onWebViewLongClicked,
|
||||
onTrackingClicked = onTrackingClicked,
|
||||
onTagClicked = onTagClicked,
|
||||
onTagSearch = onTagSearch,
|
||||
onCopyTagToClipboard = onCopyTagToClipboard,
|
||||
onFilterClicked = onFilterButtonClicked,
|
||||
onRefresh = onRefresh,
|
||||
onContinueReading = onContinueReading,
|
||||
@ -205,7 +217,8 @@ fun MangaScreen(
|
||||
onWebViewClicked = onWebViewClicked,
|
||||
onWebViewLongClicked = onWebViewLongClicked,
|
||||
onTrackingClicked = onTrackingClicked,
|
||||
onTagClicked = onTagClicked,
|
||||
onTagSearch = onTagSearch,
|
||||
onCopyTagToClipboard = onCopyTagToClipboard,
|
||||
onFilterButtonClicked = onFilterButtonClicked,
|
||||
onRefresh = onRefresh,
|
||||
onContinueReading = onContinueReading,
|
||||
@ -249,7 +262,11 @@ private fun MangaScreenSmallImpl(
|
||||
onWebViewClicked: (() -> Unit)?,
|
||||
onWebViewLongClicked: (() -> Unit)?,
|
||||
onTrackingClicked: (() -> Unit)?,
|
||||
onTagClicked: (String) -> Unit,
|
||||
|
||||
// For tags menu
|
||||
onTagSearch: (String) -> Unit,
|
||||
onCopyTagToClipboard: (tag: String) -> Unit,
|
||||
|
||||
onFilterClicked: () -> Unit,
|
||||
onRefresh: () -> Unit,
|
||||
onContinueReading: () -> Unit,
|
||||
@ -454,7 +471,8 @@ private fun MangaScreenSmallImpl(
|
||||
defaultExpandState = state.isFromSource,
|
||||
description = state.manga.description,
|
||||
tagsProvider = { state.manga.genre },
|
||||
onTagClicked = onTagClicked,
|
||||
onTagSearch = onTagSearch,
|
||||
onCopyTagToClipboard = onCopyTagToClipboard,
|
||||
// SY -->
|
||||
doSearch = onSearch,
|
||||
searchMetadataChips = remember(state.meta, state.source.id, state.manga.genre) {
|
||||
@ -535,7 +553,11 @@ fun MangaScreenLargeImpl(
|
||||
onWebViewClicked: (() -> Unit)?,
|
||||
onWebViewLongClicked: (() -> Unit)?,
|
||||
onTrackingClicked: (() -> Unit)?,
|
||||
onTagClicked: (String) -> Unit,
|
||||
|
||||
// For tags menu
|
||||
onTagSearch: (String) -> Unit,
|
||||
onCopyTagToClipboard: (tag: String) -> Unit,
|
||||
|
||||
onFilterButtonClicked: () -> Unit,
|
||||
onRefresh: () -> Unit,
|
||||
onContinueReading: () -> Unit,
|
||||
@ -714,7 +736,8 @@ fun MangaScreenLargeImpl(
|
||||
defaultExpandState = true,
|
||||
description = state.manga.description,
|
||||
tagsProvider = { state.manga.genre },
|
||||
onTagClicked = onTagClicked,
|
||||
onTagSearch = onTagSearch,
|
||||
onCopyTagToClipboard = onCopyTagToClipboard,
|
||||
// SY -->
|
||||
doSearch = onSearch,
|
||||
searchMetadataChips = remember(state.meta, state.source.id, state.manga.genre) {
|
||||
|
@ -36,6 +36,7 @@ import androidx.compose.material.icons.outlined.Pause
|
||||
import androidx.compose.material.icons.outlined.Public
|
||||
import androidx.compose.material.icons.outlined.Schedule
|
||||
import androidx.compose.material.icons.outlined.Sync
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@ -70,6 +71,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil.compose.AsyncImage
|
||||
import com.google.accompanist.flowlayout.FlowRow
|
||||
import eu.kanade.presentation.components.DropdownMenu
|
||||
import eu.kanade.presentation.components.MangaCover
|
||||
import eu.kanade.presentation.components.TextButton
|
||||
import eu.kanade.presentation.util.clickableNoIndication
|
||||
@ -221,7 +223,8 @@ fun ExpandableMangaDescription(
|
||||
defaultExpandState: Boolean,
|
||||
description: String?,
|
||||
tagsProvider: () -> List<String>?,
|
||||
onTagClicked: (String) -> Unit,
|
||||
onTagSearch: (String) -> Unit,
|
||||
onCopyTagToClipboard: (tag: String) -> Unit,
|
||||
// SY -->
|
||||
searchMetadataChips: SearchMetadataChips?,
|
||||
doSearch: (query: String, global: Boolean) -> Unit,
|
||||
@ -255,13 +258,45 @@ fun ExpandableMangaDescription(
|
||||
.padding(vertical = 12.dp)
|
||||
.animateContentSize(),
|
||||
) {
|
||||
var showMenu by remember { mutableStateOf(false) }
|
||||
var tagSelected by remember { mutableStateOf("") }
|
||||
DropdownMenu(
|
||||
expanded = showMenu,
|
||||
onDismissRequest = { showMenu = false },
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(R.string.action_search)) },
|
||||
onClick = {
|
||||
onTagSearch(tagSelected)
|
||||
showMenu = false
|
||||
},
|
||||
)
|
||||
// SY -->
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(R.string.action_global_search)) },
|
||||
onClick = {
|
||||
doSearch(tagSelected, true)
|
||||
showMenu = false
|
||||
},
|
||||
)
|
||||
// SY <--
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(R.string.action_copy_to_clipboard)) },
|
||||
onClick = {
|
||||
onCopyTagToClipboard(tagSelected)
|
||||
showMenu = false
|
||||
},
|
||||
)
|
||||
}
|
||||
if (expanded) {
|
||||
// SY -->
|
||||
if (searchMetadataChips != null) {
|
||||
NamespaceTags(
|
||||
tags = searchMetadataChips,
|
||||
onClick = onTagClicked,
|
||||
onLongClick = { doSearch(it, true) },
|
||||
onClick = {
|
||||
tagSelected = it
|
||||
showMenu = true
|
||||
},
|
||||
)
|
||||
} else {
|
||||
// SY <--
|
||||
@ -273,10 +308,10 @@ fun ExpandableMangaDescription(
|
||||
tags.forEach {
|
||||
TagsChip(
|
||||
text = it,
|
||||
onClick = { onTagClicked(it) },
|
||||
// SY -->
|
||||
onLongClick = { doSearch(it, true) },
|
||||
// SY <--
|
||||
onClick = {
|
||||
tagSelected = it
|
||||
showMenu = true
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -289,10 +324,10 @@ fun ExpandableMangaDescription(
|
||||
items(items = tags) {
|
||||
TagsChip(
|
||||
text = it,
|
||||
onClick = { onTagClicked(it) },
|
||||
// SY -->
|
||||
onLongClick = { doSearch(it, true) },
|
||||
// SY <--
|
||||
onClick = {
|
||||
tagSelected = it
|
||||
showMenu = true
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,6 @@ value class SearchMetadataChips(
|
||||
fun NamespaceTags(
|
||||
tags: SearchMetadataChips,
|
||||
onClick: (item: String) -> Unit,
|
||||
onLongClick: (item: String) -> Unit,
|
||||
) {
|
||||
Column(Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
tags.tags.forEach { (namespace, tags) ->
|
||||
@ -116,7 +115,6 @@ fun NamespaceTags(
|
||||
TagsChip(
|
||||
text = text,
|
||||
onClick = { onClick(search) },
|
||||
onLongClick = { onLongClick(search) },
|
||||
border = borderDp?.let {
|
||||
SuggestionChipDefaults.suggestionChipBorder(borderWidth = it)
|
||||
},
|
||||
@ -135,7 +133,7 @@ fun NamespaceTags(
|
||||
fun TagsChip(
|
||||
text: String,
|
||||
onClick: (() -> Unit)?,
|
||||
onLongClick: (() -> Unit)?,
|
||||
onLongClick: (() -> Unit)? = null,
|
||||
border: ChipBorder? = null,
|
||||
borderM3: ChipBorderM3? = null,
|
||||
) {
|
||||
@ -243,7 +241,6 @@ fun NamespaceTagsPreview() {
|
||||
}.let { SearchMetadataChips(it, EHentai(EXH_SOURCE_ID, true, context), emptyList()) }!!
|
||||
},
|
||||
onClick = {},
|
||||
onLongClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +225,7 @@ open class BrowseSourceScreenModel(
|
||||
.combineMetadata(dbManga, metadata)
|
||||
// SY <--
|
||||
.stateIn(coroutineScope)
|
||||
}
|
||||
}
|
||||
}
|
||||
.cachedIn(coroutineScope)
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ class MangaScreen(
|
||||
// SY <--
|
||||
onWebViewLongClicked = { copyMangaUrl(context, screenModel.manga, screenModel.source) }.takeIf { isHttpSource },
|
||||
onTrackingClicked = screenModel::showTrackDialog.takeIf { successState.trackingAvailable },
|
||||
onTagClicked = { scope.launch { performGenreSearch(navigator, it, screenModel.source!!) } },
|
||||
onTagSearch = { scope.launch { performGenreSearch(navigator, it, screenModel.source!!) } },
|
||||
onFilterButtonClicked = screenModel::showSettingsDialog,
|
||||
onRefresh = screenModel::fetchAllFromSource,
|
||||
onContinueReading = { continueReading(context, screenModel.getNextUnreadChapter()) },
|
||||
|
@ -96,6 +96,7 @@
|
||||
<string name="action_resume">Resume</string>
|
||||
<string name="action_open_in_browser">Open in browser</string>
|
||||
<string name="action_show_manga">Show entry</string>
|
||||
<string name="action_copy_to_clipboard">Copy to clipboard</string>
|
||||
<!-- Do not translate "WebView" -->
|
||||
<string name="action_open_in_web_view">Open in WebView</string>
|
||||
<string name="action_web_view" translatable="false">WebView</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user