|
@@ -4,7 +4,6 @@ import android.content.ClipData
|
|
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
|
|
import androidx.activity.result.contract.ActivityResultContracts
|
|
import androidx.activity.result.contract.ActivityResultContracts
|
|
|
import androidx.compose.foundation.background
|
|
import androidx.compose.foundation.background
|
|
|
-import androidx.compose.foundation.clickable
|
|
|
|
|
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
|
|
@@ -13,17 +12,20 @@ import androidx.compose.foundation.layout.fillMaxHeight
|
|
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
|
import androidx.compose.foundation.layout.height
|
|
import androidx.compose.foundation.layout.height
|
|
|
|
|
+import androidx.compose.foundation.layout.heightIn
|
|
|
import androidx.compose.foundation.layout.padding
|
|
import androidx.compose.foundation.layout.padding
|
|
|
import androidx.compose.foundation.layout.width
|
|
import androidx.compose.foundation.layout.width
|
|
|
import androidx.compose.foundation.lazy.grid.GridCells
|
|
import androidx.compose.foundation.lazy.grid.GridCells
|
|
|
import androidx.compose.foundation.lazy.grid.GridItemSpan
|
|
import androidx.compose.foundation.lazy.grid.GridItemSpan
|
|
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
|
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
|
|
|
|
+import androidx.compose.foundation.selection.selectable
|
|
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
|
|
import androidx.compose.material3.SnackbarHostState
|
|
import androidx.compose.material3.SnackbarHostState
|
|
|
import androidx.compose.material3.SnackbarResult
|
|
import androidx.compose.material3.SnackbarResult
|
|
|
|
|
+import androidx.compose.material3.minimumInteractiveComponentSize
|
|
|
import androidx.compose.runtime.Composable
|
|
import androidx.compose.runtime.Composable
|
|
|
import androidx.compose.runtime.LaunchedEffect
|
|
import androidx.compose.runtime.LaunchedEffect
|
|
|
import androidx.compose.runtime.getValue
|
|
import androidx.compose.runtime.getValue
|
|
@@ -37,6 +39,10 @@ import androidx.compose.ui.platform.ClipEntry
|
|
|
import androidx.compose.ui.platform.LocalClipboard
|
|
import androidx.compose.ui.platform.LocalClipboard
|
|
|
import androidx.compose.ui.platform.LocalContext
|
|
import androidx.compose.ui.platform.LocalContext
|
|
|
import androidx.compose.ui.res.stringResource
|
|
import androidx.compose.ui.res.stringResource
|
|
|
|
|
+import androidx.compose.ui.semantics.Role
|
|
|
|
|
+import androidx.compose.ui.semantics.heading
|
|
|
|
|
+import androidx.compose.ui.semantics.selected
|
|
|
|
|
+import androidx.compose.ui.semantics.semantics
|
|
|
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.unit.dp
|
|
import androidx.compose.ui.unit.dp
|
|
@@ -233,6 +239,7 @@ fun BookSourceScreen(
|
|
|
topBarActions = {
|
|
topBarActions = {
|
|
|
Box {
|
|
Box {
|
|
|
SmallPlainButton(
|
|
SmallPlainButton(
|
|
|
|
|
+ modifier = Modifier.minimumInteractiveComponentSize(),
|
|
|
icon = AppIcons.MoreVert,
|
|
icon = AppIcons.MoreVert,
|
|
|
contentDescription = stringResource(R.string.menu),
|
|
contentDescription = stringResource(R.string.menu),
|
|
|
onClick = { showImportOptions = true },
|
|
onClick = { showImportOptions = true },
|
|
@@ -247,16 +254,25 @@ fun BookSourceScreen(
|
|
|
RoundDropdownMenuItem(
|
|
RoundDropdownMenuItem(
|
|
|
text = stringResource(R.string.keep_original_name),
|
|
text = stringResource(R.string.keep_original_name),
|
|
|
isSelected = importSuccess?.keepOriginalName == true,
|
|
isSelected = importSuccess?.keepOriginalName == true,
|
|
|
|
|
+ modifier = Modifier.semantics {
|
|
|
|
|
+ this.selected = importSuccess?.keepOriginalName == true
|
|
|
|
|
+ },
|
|
|
onClick = { onIntent(BookSourceIntent.SetImportKeepName(importSuccess?.keepOriginalName != true)) },
|
|
onClick = { onIntent(BookSourceIntent.SetImportKeepName(importSuccess?.keepOriginalName != true)) },
|
|
|
)
|
|
)
|
|
|
RoundDropdownMenuItem(
|
|
RoundDropdownMenuItem(
|
|
|
text = stringResource(R.string.keep_group),
|
|
text = stringResource(R.string.keep_group),
|
|
|
isSelected = importSuccess?.keepOriginalGroup == true,
|
|
isSelected = importSuccess?.keepOriginalGroup == true,
|
|
|
|
|
+ modifier = Modifier.semantics {
|
|
|
|
|
+ this.selected = importSuccess?.keepOriginalGroup == true
|
|
|
|
|
+ },
|
|
|
onClick = { onIntent(BookSourceIntent.SetImportKeepGroup(importSuccess?.keepOriginalGroup != true)) },
|
|
onClick = { onIntent(BookSourceIntent.SetImportKeepGroup(importSuccess?.keepOriginalGroup != true)) },
|
|
|
)
|
|
)
|
|
|
RoundDropdownMenuItem(
|
|
RoundDropdownMenuItem(
|
|
|
text = stringResource(R.string.keep_enable),
|
|
text = stringResource(R.string.keep_enable),
|
|
|
isSelected = importSuccess?.keepOriginalEnable == true,
|
|
isSelected = importSuccess?.keepOriginalEnable == true,
|
|
|
|
|
+ modifier = Modifier.semantics {
|
|
|
|
|
+ this.selected = importSuccess?.keepOriginalEnable == true
|
|
|
|
|
+ },
|
|
|
onClick = { onIntent(BookSourceIntent.SetImportKeepEnable(importSuccess?.keepOriginalEnable != true)) },
|
|
onClick = { onIntent(BookSourceIntent.SetImportKeepEnable(importSuccess?.keepOriginalEnable != true)) },
|
|
|
)
|
|
)
|
|
|
RoundDropdownMenuItem(stringResource(R.string.diy_source_group), onClick = {
|
|
RoundDropdownMenuItem(stringResource(R.string.diy_source_group), onClick = {
|
|
@@ -489,6 +505,7 @@ fun BookSourceScreen(
|
|
|
RoundDropdownMenuItem(
|
|
RoundDropdownMenuItem(
|
|
|
text = stringResource(R.string.group_sources_by_domain),
|
|
text = stringResource(R.string.group_sources_by_domain),
|
|
|
isSelected = state.groupByDomain,
|
|
isSelected = state.groupByDomain,
|
|
|
|
|
+ modifier = Modifier.semantics { this.selected = state.groupByDomain },
|
|
|
onClick = { dismiss(); onIntent(BookSourceIntent.ToggleGroupByDomain) },
|
|
onClick = { dismiss(); onIntent(BookSourceIntent.ToggleGroupByDomain) },
|
|
|
)
|
|
)
|
|
|
PillDivider()
|
|
PillDivider()
|
|
@@ -514,6 +531,7 @@ fun BookSourceScreen(
|
|
|
RoundDropdownMenuItem(
|
|
RoundDropdownMenuItem(
|
|
|
text = stringResource(R.string.sort_desc),
|
|
text = stringResource(R.string.sort_desc),
|
|
|
isSelected = !state.sortAscending,
|
|
isSelected = !state.sortAscending,
|
|
|
|
|
+ modifier = Modifier.semantics { this.selected = !state.sortAscending },
|
|
|
onClick = { dismiss(); onIntent(BookSourceIntent.ToggleSortDirection) },
|
|
onClick = { dismiss(); onIntent(BookSourceIntent.ToggleSortDirection) },
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
@@ -537,11 +555,38 @@ fun BookSourceScreen(
|
|
|
color = LegadoTheme.colorScheme.primary,
|
|
color = LegadoTheme.colorScheme.primary,
|
|
|
modifier = Modifier
|
|
modifier = Modifier
|
|
|
.fillMaxWidth()
|
|
.fillMaxWidth()
|
|
|
|
|
+ .semantics { heading() }
|
|
|
.padding(horizontal = 16.dp, vertical = 8.dp),
|
|
.padding(horizontal = 16.dp, vertical = 8.dp),
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
item(key = item.id, contentType = "book-source") {
|
|
item(key = item.id, contentType = "book-source") {
|
|
|
|
|
+ val canReorder = state.sort == BookSourceSort.Default && !state.groupByDomain
|
|
|
|
|
+ val enabledState = stringResource(
|
|
|
|
|
+ if (item.enabled) R.string.enabled else R.string.disabled
|
|
|
|
|
+ )
|
|
|
|
|
+ val discoveryState = if (item.hasExploreUrl) {
|
|
|
|
|
+ stringResource(
|
|
|
|
|
+ if (item.enabledExplore) R.string.enabled_explore
|
|
|
|
|
+ else R.string.disabled_explore
|
|
|
|
|
+ )
|
|
|
|
|
+ } else {
|
|
|
|
|
+ null
|
|
|
|
|
+ }
|
|
|
|
|
+ val reorderHint = if (canReorder) {
|
|
|
|
|
+ stringResource(R.string.a11y_long_press_reorder)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ null
|
|
|
|
|
+ }
|
|
|
|
|
+ val itemDescription = listOfNotNull(
|
|
|
|
|
+ item.name,
|
|
|
|
|
+ item.domain.takeUnless { it == "#" },
|
|
|
|
|
+ item.group,
|
|
|
|
|
+ enabledState,
|
|
|
|
|
+ discoveryState,
|
|
|
|
|
+ item.checkMessage,
|
|
|
|
|
+ reorderHint,
|
|
|
|
|
+ ).joinToString()
|
|
|
ReorderableSelectionItem(
|
|
ReorderableSelectionItem(
|
|
|
state = reorderState,
|
|
state = reorderState,
|
|
|
key = item.id,
|
|
key = item.id,
|
|
@@ -567,7 +612,7 @@ fun BookSourceScreen(
|
|
|
).joinToString(" · ").ifBlank { null },
|
|
).joinToString(" · ").ifBlank { null },
|
|
|
isEnabled = item.enabled,
|
|
isEnabled = item.enabled,
|
|
|
isSelected = item.id in selectedIds,
|
|
isSelected = item.id in selectedIds,
|
|
|
- canReorder = state.sort == BookSourceSort.Default && !state.groupByDomain,
|
|
|
|
|
|
|
+ canReorder = canReorder,
|
|
|
inSelectionMode = selectedIds.isNotEmpty(),
|
|
inSelectionMode = selectedIds.isNotEmpty(),
|
|
|
onToggleSelection = { onIntent(BookSourceIntent.ToggleSelection(item.id)) },
|
|
onToggleSelection = { onIntent(BookSourceIntent.ToggleSelection(item.id)) },
|
|
|
onEnabledChange = {
|
|
onEnabledChange = {
|
|
@@ -578,11 +623,17 @@ fun BookSourceScreen(
|
|
|
)
|
|
)
|
|
|
)
|
|
)
|
|
|
},
|
|
},
|
|
|
- onClickEdit = { onEditSource(item.id) },
|
|
|
|
|
|
|
+ contentDescription = itemDescription,
|
|
|
trailingAction = {
|
|
trailingAction = {
|
|
|
|
|
+ SmallPlainButton(
|
|
|
|
|
+ modifier = Modifier.minimumInteractiveComponentSize(),
|
|
|
|
|
+ icon = AppIcons.Edit,
|
|
|
|
|
+ contentDescription = stringResource(R.string.edit),
|
|
|
|
|
+ onClick = { onEditSource(item.id) },
|
|
|
|
|
+ )
|
|
|
BookSourceItemMenu(
|
|
BookSourceItemMenu(
|
|
|
item = item,
|
|
item = item,
|
|
|
- canMoveToEdge = state.sort == BookSourceSort.Default && !state.groupByDomain,
|
|
|
|
|
|
|
+ canMoveToEdge = canReorder,
|
|
|
onMoveToEdge = { toTop ->
|
|
onMoveToEdge = { toTop ->
|
|
|
onIntent(BookSourceIntent.MoveToEdge(setOf(item.id), toTop))
|
|
onIntent(BookSourceIntent.MoveToEdge(setOf(item.id), toTop))
|
|
|
},
|
|
},
|
|
@@ -697,6 +748,7 @@ private fun CheckBookSourceSheet(
|
|
|
|
|
|
|
|
private enum class CheckSheet { Run, Settings }
|
|
private enum class CheckSheet { Run, Settings }
|
|
|
|
|
|
|
|
|
|
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
|
|
@Composable
|
|
@Composable
|
|
|
private fun BookSourceItemMenu(
|
|
private fun BookSourceItemMenu(
|
|
|
item: BookSourceItemUi,
|
|
item: BookSourceItemUi,
|
|
@@ -711,6 +763,7 @@ private fun BookSourceItemMenu(
|
|
|
var expanded by remember { mutableStateOf(false) }
|
|
var expanded by remember { mutableStateOf(false) }
|
|
|
Box {
|
|
Box {
|
|
|
SmallPlainButton(
|
|
SmallPlainButton(
|
|
|
|
|
+ modifier = Modifier.minimumInteractiveComponentSize(),
|
|
|
icon = AppIcons.MoreVert,
|
|
icon = AppIcons.MoreVert,
|
|
|
contentDescription = stringResource(R.string.menu),
|
|
contentDescription = stringResource(R.string.menu),
|
|
|
onClick = { expanded = true },
|
|
onClick = { expanded = true },
|
|
@@ -765,6 +818,7 @@ private fun SortMenuItem(
|
|
|
) = RoundDropdownMenuItem(
|
|
) = RoundDropdownMenuItem(
|
|
|
text = stringResource(textRes),
|
|
text = stringResource(textRes),
|
|
|
isSelected = state.sort == sort,
|
|
isSelected = state.sort == sort,
|
|
|
|
|
+ modifier = Modifier.semantics { this.selected = state.sort == sort },
|
|
|
onClick = { dismiss(); onIntent(BookSourceIntent.SetSort(sort)) },
|
|
onClick = { dismiss(); onIntent(BookSourceIntent.SetSort(sort)) },
|
|
|
)
|
|
)
|
|
|
|
|
|
|
@@ -848,6 +902,7 @@ private fun GroupFilterSectionTitle(text: String) {
|
|
|
color = LegadoTheme.colorScheme.onSurfaceVariant,
|
|
color = LegadoTheme.colorScheme.onSurfaceVariant,
|
|
|
modifier = Modifier
|
|
modifier = Modifier
|
|
|
.fillMaxWidth()
|
|
.fillMaxWidth()
|
|
|
|
|
+ .semantics { heading() }
|
|
|
.padding(horizontal = 4.dp, vertical = 6.dp),
|
|
.padding(horizontal = 4.dp, vertical = 6.dp),
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
@@ -864,12 +919,17 @@ private fun GroupFilterItem(
|
|
|
contentAlignment = Alignment.Center,
|
|
contentAlignment = Alignment.Center,
|
|
|
modifier = Modifier
|
|
modifier = Modifier
|
|
|
.fillMaxWidth()
|
|
.fillMaxWidth()
|
|
|
|
|
+ .heightIn(min = 48.dp)
|
|
|
.clip(shape = RoundedCornerShape(12.dp))
|
|
.clip(shape = RoundedCornerShape(12.dp))
|
|
|
.background(
|
|
.background(
|
|
|
color = if (selected) LegadoTheme.colorScheme.primaryContainer
|
|
color = if (selected) LegadoTheme.colorScheme.primaryContainer
|
|
|
else LegadoTheme.colorScheme.onSheetContent
|
|
else LegadoTheme.colorScheme.onSheetContent
|
|
|
)
|
|
)
|
|
|
- .clickable { onSelect(value) }
|
|
|
|
|
|
|
+ .selectable(
|
|
|
|
|
+ selected = selected,
|
|
|
|
|
+ role = Role.RadioButton,
|
|
|
|
|
+ onClick = { onSelect(value) },
|
|
|
|
|
+ )
|
|
|
.padding(horizontal = 12.dp, vertical = 8.dp),
|
|
.padding(horizontal = 12.dp, vertical = 8.dp),
|
|
|
) {
|
|
) {
|
|
|
AppText(
|
|
AppText(
|