Compare commits

...

3 Commits

Author SHA1 Message Date
Roshan Varughese
87db3f90de
Confirmation dialog when removing privately installed extensions (#1320)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
2024-10-13 18:48:00 +06:00
Mend Renovate
0a4ad89b99
Update dependency me.zhanghai.android.libarchive:library to v1.1.3 (#1321) 2024-10-13 18:47:31 +06:00
Jack Hamilton
a72db41bf1
Added random library sort (#1317)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
2024-10-13 13:51:34 +06:00
10 changed files with 113 additions and 6 deletions

View File

@ -6,6 +6,8 @@ import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material3.FilterChip
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@ -27,6 +29,7 @@ import tachiyomi.domain.library.model.LibrarySort
import tachiyomi.domain.library.model.sort
import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.BaseSortItem
import tachiyomi.presentation.core.components.CheckboxItem
import tachiyomi.presentation.core.components.HeadingItem
import tachiyomi.presentation.core.components.SettingsChipRow
@ -178,7 +181,19 @@ private fun ColumnScope.SortPage(
MR.strings.action_sort_latest_chapter to LibrarySort.Type.LatestChapter,
MR.strings.action_sort_chapter_fetch_date to LibrarySort.Type.ChapterFetchDate,
MR.strings.action_sort_date_added to LibrarySort.Type.DateAdded,
MR.strings.action_sort_random to LibrarySort.Type.Random,
).plus(trackerSortOption).map { (titleRes, mode) ->
if (mode == LibrarySort.Type.Random) {
BaseSortItem(
label = stringResource(titleRes),
icon = Icons.Default.Refresh
.takeIf { sortingMode == LibrarySort.Type.Random },
onClick = {
screenModel.setSort(category, mode, LibrarySort.Direction.Ascending)
},
)
return@map
}
SortItem(
label = stringResource(titleRes),
sortDescending = sortDescending.takeIf { sortingMode == mode },

View File

@ -1,8 +1,15 @@
package eu.kanade.tachiyomi.ui.browse.extension
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
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.platform.LocalContext
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.presentation.browse.ExtensionScreen
@ -12,6 +19,7 @@ import eu.kanade.presentation.more.settings.screen.browse.ExtensionReposScreen
import eu.kanade.tachiyomi.extension.model.Extension
import eu.kanade.tachiyomi.ui.browse.extension.details.ExtensionDetailsScreen
import eu.kanade.tachiyomi.ui.webview.WebViewScreen
import eu.kanade.tachiyomi.util.system.isPackageInstalled
import kotlinx.collections.immutable.persistentListOf
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.stringResource
@ -21,7 +29,10 @@ fun extensionsTab(
extensionsScreenModel: ExtensionsScreenModel,
): TabContent {
val navigator = LocalNavigator.currentOrThrow
val context = LocalContext.current
val state by extensionsScreenModel.state.collectAsState()
var privateExtensionToUninstall by remember { mutableStateOf<Extension?>(null) }
return TabContent(
titleRes = MR.strings.label_extensions,
@ -45,7 +56,13 @@ fun extensionsTab(
onLongClickItem = { extension ->
when (extension) {
is Extension.Available -> extensionsScreenModel.installExtension(extension)
else -> extensionsScreenModel.uninstallExtension(extension)
else -> {
if (context.isPackageInstalled(extension.pkgName)) {
extensionsScreenModel.uninstallExtension(extension)
} else {
privateExtensionToUninstall = extension
}
}
}
},
onClickItemCancel = extensionsScreenModel::cancelInstallUpdateExtension,
@ -68,6 +85,50 @@ fun extensionsTab(
onUpdateExtension = extensionsScreenModel::updateExtension,
onRefresh = extensionsScreenModel::findAvailableExtensions,
)
privateExtensionToUninstall?.let { extension ->
ExtensionUninstallConfirmation(
extensionName = extension.name,
onClickConfirm = {
extensionsScreenModel.uninstallExtension(extension)
},
onDismissRequest = {
privateExtensionToUninstall = null
},
)
}
},
)
}
@Composable
private fun ExtensionUninstallConfirmation(
extensionName: String,
onClickConfirm: () -> Unit,
onDismissRequest: () -> Unit,
) {
AlertDialog(
title = {
Text(text = stringResource(MR.strings.ext_confirm_remove))
},
text = {
Text(text = stringResource(MR.strings.remove_private_extension_message, extensionName))
},
confirmButton = {
TextButton(
onClick = {
onClickConfirm()
onDismissRequest()
},
) {
Text(text = stringResource(MR.strings.ext_remove))
}
},
dismissButton = {
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(MR.strings.action_cancel))
}
},
onDismissRequest = onDismissRequest,
)
}

View File

@ -72,6 +72,7 @@ import tachiyomi.domain.track.model.Track
import tachiyomi.source.local.isLocal
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import kotlin.random.Random
/**
* Typealias for the library manga, using the category as keys, and list of manga as values.
@ -300,10 +301,17 @@ class LibraryScreenModel(
val item2Score = trackerScores[i2.libraryManga.id] ?: defaultTrackerScoreSortValue
item1Score.compareTo(item2Score)
}
LibrarySort.Type.Random -> {
error("Why Are We Still Here? Just To Suffer?")
}
}
}
return mapValues { (key, value) ->
if (key.sort.type == LibrarySort.Type.Random) {
return@mapValues value.shuffled(Random(libraryPreferences.randomSortSeed().get()))
}
val comparator = key.sort.comparator()
.let { if (key.sort.isAscending) it else it.reversed() }
.thenComparator(sortAlphabetically)

View File

@ -6,6 +6,7 @@ import tachiyomi.domain.category.repository.CategoryRepository
import tachiyomi.domain.library.model.LibrarySort
import tachiyomi.domain.library.model.plus
import tachiyomi.domain.library.service.LibraryPreferences
import kotlin.random.Random
class SetSortModeForCategory(
private val preferences: LibraryPreferences,
@ -15,6 +16,9 @@ class SetSortModeForCategory(
suspend fun await(categoryId: Long?, type: LibrarySort.Type, direction: LibrarySort.Direction) {
val category = categoryId?.let { categoryRepository.get(it) }
val flags = (category?.flags ?: 0) + type + direction
if (type == LibrarySort.Type.Random) {
preferences.randomSortSeed().set(Random.nextInt())
}
if (category != null && preferences.categorizedDisplaySettings().get()) {
categoryRepository.updatePartial(
CategoryUpdate(

View File

@ -30,7 +30,8 @@ data class LibrarySort(
data object LatestChapter : Type(0b00010100)
data object ChapterFetchDate : Type(0b00011000)
data object DateAdded : Type(0b00011100)
data object TrackerMean : Type(0b000100000)
data object TrackerMean : Type(0b00100000)
data object Random : Type(0b00111100)
companion object {
fun valueOf(flag: Long): Type {
@ -77,6 +78,7 @@ data class LibrarySort(
Type.ChapterFetchDate,
Type.DateAdded,
Type.TrackerMean,
Type.Random,
)
}
val directions by lazy { setOf(Direction.Ascending, Direction.Descending) }
@ -104,6 +106,7 @@ data class LibrarySort(
"CHAPTER_FETCH_DATE" -> Type.ChapterFetchDate
"DATE_ADDED" -> Type.DateAdded
"TRACKER_MEAN" -> Type.TrackerMean
"RANDOM" -> Type.Random
else -> Type.Alphabetical
}
val ascending = if (values[1] == "ASCENDING") Direction.Ascending else Direction.Descending
@ -125,6 +128,7 @@ data class LibrarySort(
Type.ChapterFetchDate -> "CHAPTER_FETCH_DATE"
Type.DateAdded -> "DATE_ADDED"
Type.TrackerMean -> "TRACKER_MEAN"
Type.Random -> "RANDOM"
}
val direction = if (direction == Direction.Ascending) "ASCENDING" else "DESCENDING"
return "$type,$direction"

View File

@ -26,6 +26,8 @@ class LibraryPreferences(
LibrarySort.Serializer::deserialize,
)
fun randomSortSeed() = preferenceStore.getInt("library_random_sort_seed", 0)
fun portraitColumns() = preferenceStore.getInt("pref_library_columns_portrait_key", 0)
fun landscapeColumns() = preferenceStore.getInt("pref_library_columns_landscape_key", 0)

View File

@ -12,7 +12,7 @@ class LibraryFlagsTest {
@Test
fun `Check the amount of flags`() {
LibraryDisplayMode.values.size shouldBe 4
LibrarySort.types.size shouldBe 9
LibrarySort.types.size shouldBe 10
LibrarySort.directions.size shouldBe 2
}

View File

@ -32,7 +32,7 @@ jsoup = "org.jsoup:jsoup:1.18.1"
disklrucache = "com.jakewharton:disklrucache:2.0.2"
unifile = "com.github.tachiyomiorg:unifile:e0def6b3dc"
libarchive = "me.zhanghai.android.libarchive:library:1.1.2"
libarchive = "me.zhanghai.android.libarchive:library:1.1.3"
sqlite-framework = { module = "androidx.sqlite:sqlite-framework", version.ref = "sqlite" }
sqlite-ktx = { module = "androidx.sqlite:sqlite-ktx", version.ref = "sqlite" }

View File

@ -69,6 +69,7 @@
<string name="action_sort_chapter_fetch_date">Chapter fetch date</string>
<string name="action_sort_date_added">Date added</string>
<string name="action_sort_tracker_score">Tracker score</string>
<string name="action_sort_random">Random</string>
<string name="action_search">Search</string>
<string name="action_search_hint">Search…</string>
<string name="action_search_settings">Search settings</string>
@ -325,10 +326,13 @@
<string name="ext_trust">Trust</string>
<string name="ext_untrusted">Untrusted</string>
<string name="ext_uninstall">Uninstall</string>
<string name="ext_remove">Remove</string>
<string name="ext_confirm_remove">Remove Extension?</string>
<string name="ext_app_info">App info</string>
<string name="untrusted_extension">Untrusted extension</string>
<string name="untrusted_extension_message">Malicious extensions can read any stored login credentials or execute arbitrary code.\n\nBy trusting this extension, you accept these risks.</string>
<string name="obsolete_extension_message">This extension is no longer available. It may not function properly and can cause issues with the app. Uninstalling it is recommended.</string>
<string name="remove_private_extension_message">Do you really want to remove \"%s\" extension?</string>
<string name="extension_api_error">Failed to fetch available extensions</string>
<string name="ext_info_version">Version</string>
<string name="ext_info_language">Language</string>

View File

@ -98,12 +98,21 @@ fun SortItem(label: String, sortDescending: Boolean?, onClick: () -> Unit) {
null -> null
}
BaseSortItem(
label = label,
icon = arrowIcon,
onClick = onClick,
)
}
@Composable
fun BaseSortItem(label: String, icon: ImageVector?, onClick: () -> Unit) {
BaseSettingsItem(
label = label,
widget = {
if (arrowIcon != null) {
if (icon != null) {
Icon(
imageVector = arrowIcon,
imageVector = icon,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
)