Compare commits

...

23 Commits

Author SHA1 Message Date
c8d68590db Release v0.14.7 2023-10-25 12:04:09 -04:00
94448faf97 Update website links 2023-10-25 11:58:00 -04:00
28028c789c Update default user agent string 2023-10-25 11:54:41 -04:00
f8834ee764 Avoid opening blobs as webpages
Fixes #10060

(cherry picked from commit 548f7f415a)
2023-10-25 11:53:40 -04:00
7c703b17d3 Change Shikimori domain from ".me" to ".one" (#10027)
(cherry picked from commit 8f3681d79f)
2023-10-25 11:52:24 -04:00
f77ade7dda Run Netlify Build Hook after Release (#9937)
* Run Netlify Build Hook after Release

* Add if statement

* Move if statement to job level instead of step

(cherry picked from commit 9e04f14a7b)
2023-10-25 11:51:23 -04:00
91712daee8 Use consistent extension icon URLs
Better caching between versions.

(cherry picked from commit 30f845139d)
2023-10-25 11:49:33 -04:00
c615f4d458 Release v0.14.6 2023-04-16 11:00:14 -04:00
9e09a20e65 Avoid uncaught exceptions from OkHttp interceptors crashing entire app
(cherry picked from commit 26d422b0ae)
2023-04-16 10:57:40 -04:00
7115a9b9fe Update track domain shikimori.me (#9333)
shikimori.me

(cherry picked from commit 564a0980b9)
2023-04-16 10:53:01 -04:00
fd8b97fc87 Better handle overflowing content in MigrateDialog actions
Fixes #9207

(cherry picked from commit b7cd7b8b4e)
2023-04-16 10:52:53 -04:00
4dd67e4348 Save current chapter progress when navigating to adjacent chapters
Fixes #9295

(cherry picked from commit 776d36caf1)
2023-04-16 10:52:42 -04:00
10973bf3cd Fix Spanish (Latin America) being missing from in-app language selection
(cherry picked from commit 290efb0283)
2023-04-16 10:51:29 -04:00
934ed0551a Bump subsampling-scale-image-view
(cherry picked from commit e5e18c2030)
2023-04-16 10:51:16 -04:00
38428c6ebe Show proper string in manga detail screen for SourceNotInstalledException
(cherry picked from commit 14d1bcacc9)
2023-04-16 10:51:05 -04:00
bf85e147e7 Set default automatic library updates to off
(cherry picked from commit abd23b6826)
2023-04-16 10:50:55 -04:00
d2dd34c2e5 Use queued last chapter read number when performing delayed tracker update
Fixes #8876

(cherry picked from commit f7f2072621)
2023-04-16 10:50:24 -04:00
c4ab2b4675 Bump default user agent string and minimum WebView version
(cherry picked from commit c6e5f8abd9)
2023-04-16 10:49:28 -04:00
aa2ec5940f Avoid crashing in SourcePreferencesScreen if source can't be loaded
(cherry picked from commit 4efca04765)
2023-04-16 10:49:11 -04:00
79323de326 Avoid crash in DeleteLibraryMangaDialog
No clue why it ever gets a -1 index though.

(cherry picked from commit b12c7cf963)
2023-04-16 10:49:05 -04:00
08e6487a9a Fix download queue page count display bug (#9126)
When restarting a download, the page count would display as 0 until
the first page download completion, after all the existing pages were
rechecked.

To fix, calculate downloadedImages from pages instead of relying on
the downloader to reset and increment the count.

(cherry picked from commit 779df32e98)
2023-04-16 10:48:16 -04:00
4498b10a10 Fix occasional crash when opening library settings sheet
See https://stackoverflow.com/questions/47648689/sealed-classs-objects-mysteriously-becoming-null-when-referenced-by-other-compa

(cherry picked from commit c0e2eb211d)
2023-04-16 10:48:05 -04:00
6f2bb18d72 Avoid crash when loading invalid extension package
(cherry picked from commit 3d7c136320)
2023-04-16 10:47:58 -04:00
37 changed files with 136 additions and 93 deletions

View File

@ -3,7 +3,7 @@
I acknowledge that:
- I have updated:
- To the latest version of the app (stable is v0.14.5)
- To the latest version of the app (stable is v0.14.7)
- All extensions
- I have tried the troubleshooting guide: https://tachiyomi.org/help/guides/troubleshooting-problems/
- If this is an issue with an extension, that I should be opening an issue in https://github.com/tachiyomiorg/tachiyomi-extensions

View File

@ -53,7 +53,7 @@ body:
label: Tachiyomi version
description: You can find your Tachiyomi version in **More → About**.
placeholder: |
Example: "0.14.5"
Example: "0.14.7"
validations:
required: true
@ -98,7 +98,7 @@ body:
required: true
- label: I have tried the [troubleshooting guide](https://tachiyomi.org/help/guides/troubleshooting/).
required: true
- label: I have updated the app to version **[0.14.5](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**.
- label: I have updated the app to version **[0.14.7](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**.
required: true
- label: I have updated all installed extensions.
required: true

View File

@ -33,7 +33,7 @@ body:
required: true
- label: If this is an issue with an extension, I should be opening an issue in the [extensions repository](https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose).
required: true
- label: I have updated the app to version **[0.14.5](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**.
- label: I have updated the app to version **[0.14.7](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**.
required: true
- label: I will fill out all of the requested information in this form.
required: true

View File

@ -104,3 +104,13 @@ jobs:
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
update-website:
needs: [build]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/') && github.repository == 'tachiyomiorg/tachiyomi'
steps:
- name: Trigger Netlify build hook
run: curl -s -X POST -d {} "https://api.netlify.com/build_hooks/${TOKEN}"
env:
TOKEN: ${{ secrets.NETLIFY_HOOK_RELEASE }}

View File

@ -22,8 +22,8 @@ android {
defaultConfig {
applicationId = "eu.kanade.tachiyomi"
versionCode = 98
versionName = "0.14.5"
versionCode = 102
versionName = "0.14.7"
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"")

View File

@ -22,7 +22,7 @@ class LibraryPreferences(
fun landscapeColumns() = preferenceStore.getInt("pref_library_columns_landscape_key", 0)
fun libraryUpdateInterval() = preferenceStore.getInt("pref_library_update_interval_key", 24)
fun libraryUpdateInterval() = preferenceStore.getInt("pref_library_update_interval_key", 0)
fun libraryUpdateLastTimestamp() = preferenceStore.getLong("library_update_last_timestamp", 0L)
fun libraryUpdateDeviceRestriction() = preferenceStore.getStringSet("library_update_restriction", setOf(DEVICE_ONLY_ON_WIFI))

View File

@ -31,30 +31,33 @@ class DelayedTrackingUpdateJob(context: Context, workerParams: WorkerParameters)
val trackManager = Injekt.get<TrackManager>()
val delayedTrackingStore = Injekt.get<DelayedTrackingStore>()
withIOContext {
val tracks = delayedTrackingStore.getItems().mapNotNull {
val track = getTracks.awaitOne(it.trackId)
if (track == null) {
delayedTrackingStore.remove(it.trackId)
}
track
}
tracks.forEach { track ->
try {
val service = trackManager.getService(track.syncId)
if (service != null && service.isLogged) {
service.update(track.toDbTrack(), true)
insertTrack.await(track)
val results = withIOContext {
delayedTrackingStore.getItems()
.mapNotNull {
val track = getTracks.awaitOne(it.trackId)
if (track == null) {
delayedTrackingStore.remove(it.trackId)
}
track?.copy(lastChapterRead = it.lastChapterRead.toDouble())
}
.mapNotNull { track ->
try {
val service = trackManager.getService(track.syncId)
if (service != null && service.isLogged) {
logcat(LogPriority.DEBUG) { "Updating delayed track item: ${track.id}, last chapter read: ${track.lastChapterRead}" }
service.update(track.toDbTrack(), true)
insertTrack.await(track)
}
delayedTrackingStore.remove(track.id)
null
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
false
}
delayedTrackingStore.remove(track.id)
} catch (e: Exception) {
logcat(LogPriority.ERROR, e)
}
}
}
return Result.success()
return if (results.isNotEmpty()) Result.failure() else Result.success()
}
companion object {

View File

@ -64,9 +64,11 @@ fun DeleteLibraryMangaDialog(
list.forEach { state ->
val onCheck = {
val index = list.indexOf(state)
val mutableList = list.toMutableList()
mutableList[index] = state.next() as CheckboxState.State<Int>
list = mutableList.toList()
if (index != -1) {
val mutableList = list.toMutableList()
mutableList[index] = state.next() as CheckboxState.State<Int>
list = mutableList.toList()
}
}
Row(

View File

@ -62,7 +62,7 @@ fun MoreScreen(
WarningBanner(
textRes = R.string.fdroid_warning,
modifier = Modifier.clickable {
uriHandler.openUri("https://tachiyomi.org/help/faq/#how-do-i-migrate-from-the-f-droid-version")
uriHandler.openUri("https://tachiyomi.org/docs/faq/general#how-do-i-update-from-the-f-droid-builds")
},
)
}

View File

@ -118,7 +118,7 @@ object AboutScreen : Screen {
item {
TextPreferenceWidget(
title = stringResource(R.string.help_translate),
onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/help/contribution/#translation") },
onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/docs/contribute#translation") },
)
}

View File

@ -70,7 +70,7 @@ object SettingsTrackingScreen : SearchableSettings {
@Composable
override fun RowScope.AppBarAction() {
val uriHandler = LocalUriHandler.current
IconButton(onClick = { uriHandler.openUri("https://tachiyomi.org/help/guides/tracking/") }) {
IconButton(onClick = { uriHandler.openUri("https://tachiyomi.org/docs/guides/tracking") }) {
Icon(
imageVector = Icons.Outlined.HelpOutline,
contentDescription = stringResource(R.string.tracking_guide),

View File

@ -124,6 +124,12 @@ fun WebViewScreenContent(
request: WebResourceRequest?,
): Boolean {
request?.let {
// Don't attempt to open blobs as webpages
if (it.url.toString().startsWith("blob:http")) {
return false
}
// Continue with request, but with custom headers
view?.loadUrl(it.url.toString(), headers)
}
return super.shouldOverrideUrlLoading(view, request)

View File

@ -339,7 +339,6 @@ class Downloader(
?.filter { it.name!!.endsWith(".tmp") }
?.forEach { it.delete() }
download.downloadedImages = 0
download.status = Download.State.DOWNLOADING
}
// Get all the URLs to the source images, fetch pages if necessary
@ -403,7 +402,6 @@ class Downloader(
}
page.uri = file.uri
page.progress = 100
download.downloadedImages++
page.status = Page.State.READY
}
.map { page }

View File

@ -21,9 +21,8 @@ data class Download(
val totalProgress: Int
get() = pages?.sumOf(Page::progress) ?: 0
@Volatile
@Transient
var downloadedImages: Int = 0
val downloadedImages: Int
get() = pages?.count { it.status == Page.State.READY } ?: 0
@Volatile
@Transient

View File

@ -340,11 +340,11 @@ class LibraryUpdateNotifier(private val context: Context) {
}
companion object {
const val HELP_WARNING_URL = "https://tachiyomi.org/help/faq/#why-does-the-app-warn-about-large-bulk-updates-and-downloads"
const val HELP_WARNING_URL = "https://tachiyomi.org/docs/faq/library#why-am-i-warned-about-large-bulk-updates-and-downloads"
}
}
private const val NOTIF_MAX_CHAPTERS = 5
private const val NOTIF_TITLE_MAX_LEN = 45
private const val NOTIF_ICON_SIZE = 192
private const val HELP_SKIPPED_URL = "https://tachiyomi.org/help/faq/#why-does-global-update-skip-some-entries"
private const val HELP_SKIPPED_URL = "https://tachiyomi.org/docs/faq/library#why-is-global-update-skipping-entries"

View File

@ -604,4 +604,4 @@ class LibraryUpdateService(
}
private const val MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 60
private const val ERROR_LOG_HELP_URL = "https://tachiyomi.org/help/guides/troubleshooting"
private const val ERROR_LOG_HELP_URL = "https://tachiyomi.org/docs/guides/troubleshooting/"

View File

@ -138,7 +138,7 @@ internal class AppUpdateNotifier(private val context: Context) {
setContentTitle(context.getString(R.string.update_check_notification_update_available))
setContentText(context.getString(R.string.update_check_fdroid_migration_info))
setSmallIcon(R.drawable.ic_tachi)
setContentIntent(NotificationHandler.openUrl(context, "https://tachiyomi.org/help/faq/#how-do-i-migrate-from-the-f-droid-version"))
setContentIntent(NotificationHandler.openUrl(context, "https://tachiyomi.org/docs/faq/general#how-do-i-update-from-the-f-droid-builds"))
}
notificationBuilder.show(Notifications.ID_APP_UPDATE_PROMPT)
}

View File

@ -117,7 +117,7 @@ internal class ExtensionGithubApi {
hasChangelog = it.hasChangelog == 1,
sources = it.sources?.toExtensionSources() ?: emptyList(),
apkName = it.apk,
iconUrl = "${getUrlPrefix()}icon/${it.apk.replace(".apk", ".png")}",
iconUrl = "${getUrlPrefix()}icon/${it.pkg}.png",
)
}
}

View File

@ -126,8 +126,8 @@ internal object ExtensionLoader {
}
// Validate lib version
val libVersion = versionName.substringBeforeLast('.').toDouble()
if (libVersion < LIB_VERSION_MIN || libVersion > LIB_VERSION_MAX) {
val libVersion = versionName.substringBeforeLast('.').toDoubleOrNull()
if (libVersion == null || libVersion < LIB_VERSION_MIN || libVersion > LIB_VERSION_MAX) {
logcat(LogPriority.WARN) {
"Lib version is $libVersion, while only versions " +
"$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed"
@ -136,7 +136,6 @@ internal object ExtensionLoader {
}
val signatureHash = getSignatureHash(pkgInfo)
if (signatureHash == null) {
logcat(LogPriority.WARN) { "Package $pkgName isn't signed" }
return LoadResult.Error

View File

@ -384,7 +384,7 @@ class LocalSource(
companion object {
const val ID = 0L
const val HELP_URL = "https://tachiyomi.org/help/guides/local-manga/"
const val HELP_URL = "https://tachiyomi.org/docs/guides/local-source/"
private const val DEFAULT_COVER_NAME = "cover.jpg"
private val LATEST_THRESHOLD = TimeUnit.MILLISECONDS.convert(7, TimeUnit.DAYS)

View File

@ -102,7 +102,7 @@ class ExtensionDetailsScreenModel(
val extension = state.value.extension ?: return ""
if (!extension.hasReadme) {
return "https://tachiyomi.org/help/faq/#extensions"
return "https://tachiyomi.org/docs/faq/browse/extensions"
}
val pkgName = extension.pkgName.substringAfter("eu.kanade.tachiyomi.extension.")

View File

@ -61,7 +61,7 @@ class SourcePreferencesScreen(val sourceId: Long) : Screen {
Scaffold(
topBar = {
TopAppBar(
title = { Text(text = Injekt.get<SourceManager>().get(sourceId)!!.toString()) },
title = { Text(text = Injekt.get<SourceManager>().getOrStub(sourceId).toString()) },
navigationIcon = {
IconButton(onClick = navigator::pop) {
Icon(

View File

@ -2,7 +2,9 @@ package eu.kanade.tachiyomi.ui.browse.migration.search
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
@ -23,6 +25,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEachIndexed
import cafe.adriel.voyager.core.model.StateScreenModel
import eu.kanade.domain.category.interactor.SetMangaCategories
@ -111,7 +114,9 @@ internal fun MigrateDialog(
}
},
confirmButton = {
Row {
FlowRow(
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
TextButton(
onClick = {
onClickTitle()

View File

@ -31,7 +31,7 @@ fun Screen.migrateSourceTab(): TabContent {
title = stringResource(R.string.migration_help_guide),
icon = Icons.Outlined.HelpOutline,
onClick = {
uriHandler.openUri("https://tachiyomi.org/help/guides/source-migration/")
uriHandler.openUri("https://tachiyomi.org/docs/guides/source-migration")
},
),
),

View File

@ -156,7 +156,7 @@ object LibraryTab : Tab {
EmptyScreenAction(
stringResId = R.string.getting_started_guide,
icon = Icons.Outlined.HelpOutline,
onClick = { handler.openUri("https://tachiyomi.org/help/guides/getting-started") },
onClick = { handler.openUri("https://tachiyomi.org/docs/guides/getting-started") },
),
),
)

View File

@ -977,6 +977,14 @@ class MangaInfoScreenModel(
}
}
}
private val Throwable.snackbarMessage: String
get() = when (val className = this::class.simpleName) {
null -> message ?: ""
"SourceNotInstalledException" -> context.getString(R.string.loader_not_implemented_error)
"Exception", "HttpException", "IOException" -> message ?: className
else -> "$className: $message"
}
}
sealed class MangaScreenState {
@ -1055,10 +1063,3 @@ val chapterDecimalFormat = DecimalFormat(
DecimalFormatSymbols()
.apply { decimalSeparator = '.' },
)
private val Throwable.snackbarMessage: String
get() = when (val className = this::class.simpleName) {
null -> message ?: ""
"Exception", "HttpException", "IOException", "SourceNotInstalledException" -> message ?: className
else -> "$className: $message"
}

View File

@ -99,10 +99,6 @@ import uy.kohesive.injekt.injectLazy
import kotlin.math.abs
import kotlin.math.max
/**
* Activity containing the reader of Tachiyomi. This activity is mostly a container of the
* viewers, to which calls from the presenter or UI events are delegated.
*/
class ReaderActivity : BaseActivity() {
companion object {
@ -661,7 +657,7 @@ class ReaderActivity : BaseActivity() {
* Called from the presenter when a manga is ready. Used to instantiate the appropriate viewer
* and the toolbar title.
*/
fun setManga(manga: Manga) {
private fun setManga(manga: Manga) {
val prevViewer = viewer
val viewerMode = ReadingModeType.fromPreference(viewModel.getMangaReadingMode(resolveDefault = false))
@ -776,7 +772,7 @@ class ReaderActivity : BaseActivity() {
* Called from the presenter if the initial load couldn't load the pages of the chapter. In
* this case the activity is closed and a toast is shown to the user.
*/
fun setInitialChapterError(error: Throwable) {
private fun setInitialChapterError(error: Throwable) {
logcat(LogPriority.ERROR, error)
finish()
toast(error.message)

View File

@ -201,17 +201,6 @@ class ReaderViewModel(
private val incognitoMode = preferences.incognitoMode().get()
override fun onCleared() {
val currentChapters = state.value.viewerChapters
if (currentChapters != null) {
currentChapters.unref()
saveReadingProgress(currentChapters.currChapter)
chapterToDownload?.let {
downloadManager.addDownloadsToStartOfQueue(listOf(it))
}
}
}
init {
// To save state
state.map { it.viewerChapters?.currChapter }
@ -226,6 +215,17 @@ class ReaderViewModel(
.launchIn(viewModelScope)
}
override fun onCleared() {
val currentChapters = state.value.viewerChapters
if (currentChapters != null) {
currentChapters.unref()
saveReadingProgress(currentChapters.currChapter)
chapterToDownload?.let {
downloadManager.addDownloadsToStartOfQueue(listOf(it))
}
}
}
/**
* Called when the user pressed the back button and is going to leave the reader. Used to
* trigger deletion of the downloaded chapters.
@ -338,10 +338,11 @@ class ReaderViewModel(
}
/**
* Called when the user is going to load the prev/next chapter through the menu button.
* Called when the user is going to load the prev/next chapter through the toolbar buttons.
*/
private suspend fun loadAdjacent(chapter: ReaderChapter) {
val loader = loader ?: return
saveCurrentChapterReadingProgress()
logcat { "Loading adjacent ${chapter.chapter.url}" }

View File

@ -3,25 +3,22 @@ import org.gradle.api.Task
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.TaskContainerScope
private val emptyResourcesElement = "<resources>\\s*</resources>|<resources/>".toRegex()
private val valuesPrefix = "values(-(b\\+)?)?".toRegex()
fun TaskContainerScope.registerLocalesConfigTask(project: Project): TaskProvider<Task> {
return with(project) {
register("generateLocalesConfig") {
val emptyResourcesElement = "<resources>\\s*</resources>|<resources/>".toRegex()
val valuesPrefix = "values-?".toRegex()
val languages = fileTree("$projectDir/src/main/res/")
.matching {
include("**/strings.xml")
}
.filterNot {
it.readText().contains(emptyResourcesElement)
}
.matching { include("**/strings.xml") }
.filterNot { it.readText().contains(emptyResourcesElement) }
.map { it.parentFile.name }
.sorted()
.joinToString(separator = "\n") {
val language = it
.replace(valuesPrefix, "")
.replace("-r", "-")
.replace("+", "-")
.takeIf(String::isNotBlank) ?: "en"
" <locale android:name=\"$language\"/>"
}

View File

@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.network
import android.content.Context
import eu.kanade.tachiyomi.network.interceptor.CloudflareInterceptor
import eu.kanade.tachiyomi.network.interceptor.UncaughtExceptionInterceptor
import eu.kanade.tachiyomi.network.interceptor.UserAgentInterceptor
import okhttp3.Cache
import okhttp3.OkHttpClient
@ -29,6 +30,7 @@ class NetworkHelper(context: Context) {
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.callTimeout(2, TimeUnit.MINUTES)
.addInterceptor(UncaughtExceptionInterceptor())
.addInterceptor(userAgentInterceptor)
if (preferences.verboseLogging().get()) {

View File

@ -17,6 +17,6 @@ class NetworkPreferences(
}
fun defaultUserAgent(): Preference<String> {
return preferenceStore.getString("default_user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0")
return preferenceStore.getString("default_user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0")
}
}

View File

@ -0,0 +1,24 @@
package eu.kanade.tachiyomi.network.interceptor
import okhttp3.Interceptor
import okhttp3.Response
import java.io.IOException
/**
* Catches any uncaught exceptions from later in the chain and rethrows as a non-fatal
* IOException to avoid catastrophic failure.
*
* This should be the first interceptor in the client.
*
* See https://square.github.io/okhttp/4.x/okhttp/okhttp3/-interceptor/
*/
class UncaughtExceptionInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
return try {
chain.proceed(chain.request())
} catch (e: Exception) {
throw IOException(e)
}
}
}

View File

@ -12,7 +12,7 @@ import tachiyomi.core.util.system.logcat
object WebViewUtil {
const val SPOOF_PACKAGE_NAME = "org.chromium.chrome"
const val MINIMUM_WEBVIEW_VERSION = 105
const val MINIMUM_WEBVIEW_VERSION = 114
fun supportsWebView(context: Context): Boolean {
try {

View File

@ -1,7 +1,7 @@
package tachiyomi.core
object Constants {
const val URL_HELP = "https://tachiyomi.org/help/"
const val URL_HELP = "https://tachiyomi.org/docs/guides/troubleshooting/"
const val MANGA_EXTRA = "manga"

View File

@ -24,7 +24,7 @@ sealed class LibraryDisplayMode(
}
companion object {
val values = setOf(CompactGrid, ComfortableGrid, List, CoverOnlyGrid)
val values by lazy { setOf(CompactGrid, ComfortableGrid, List, CoverOnlyGrid) }
val default = CompactGrid
fun valueOf(flag: Long?): LibraryDisplayMode {

View File

@ -65,8 +65,8 @@ data class LibrarySort(
}
companion object {
val types = setOf(Type.Alphabetical, Type.LastRead, Type.LastUpdate, Type.UnreadCount, Type.TotalChapters, Type.LatestChapter, Type.ChapterFetchDate, Type.DateAdded)
val directions = setOf(Direction.Ascending, Direction.Descending)
val types by lazy { setOf(Type.Alphabetical, Type.LastRead, Type.LastUpdate, Type.UnreadCount, Type.TotalChapters, Type.LatestChapter, Type.ChapterFetchDate, Type.DateAdded) }
val directions by lazy { setOf(Direction.Ascending, Direction.Descending) }
val default = LibrarySort(Type.Alphabetical, Direction.Ascending)
fun valueOf(flag: Long): LibrarySort {

View File

@ -46,7 +46,7 @@ coil-core = { module = "io.coil-kt:coil", version.ref = "coil_version" }
coil-gif = { module = "io.coil-kt:coil-gif", version.ref = "coil_version" }
coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil_version" }
subsamplingscaleimageview = "com.github.tachiyomiorg:subsampling-scale-image-view:846abe0"
subsamplingscaleimageview = "com.github.tachiyomiorg:subsampling-scale-image-view:c8e2650"
image-decoder = "com.github.tachiyomiorg:image-decoder:7879b45"
natural-comparator = "com.github.gpanther:java-nat-sort:natural-comparator-1.1"