Merge branch 'master' into Failed-Updates-feature-added

This commit is contained in:
Programmer-0-0 2023-08-10 15:25:41 +04:00 committed by GitHub
commit 9d77b6e2b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 71 additions and 127 deletions

View file

@ -3,6 +3,7 @@ package eu.kanade.presentation.util
import android.content.Context
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.network.HttpException
import eu.kanade.tachiyomi.source.online.LicensedMangaChaptersException
import tachiyomi.data.source.NoResultsException
import tachiyomi.domain.source.model.SourceNotInstalledException
@ -13,6 +14,7 @@ val Throwable.formattedMessage: String
is NoResultsException -> return getString(R.string.no_results_found)
is SourceNotInstalledException -> return getString(R.string.loader_not_implemented_error)
is HttpException -> return "$message: ${getString(R.string.http_error_hint)}"
is LicensedMangaChaptersException -> return getString(R.string.licensed_manga_chapters_error)
}
return when (val className = this::class.simpleName) {
"Exception", "IOException" -> message ?: className

View file

@ -106,10 +106,10 @@ class BackupManager(
UniFile.fromUri(context, uri)
}
)
?: throw Exception("Couldn't create backup file")
?: throw Exception(context.getString(R.string.create_backup_file_error))
if (!file.isFile) {
throw IllegalStateException("Failed to get handle on file")
throw IllegalStateException("Failed to get handle on a backup file")
}
val byteArray = parser.encodeToByteArray(BackupSerializer, backup)

View file

@ -382,11 +382,14 @@ class ReaderActivity : BaseActivity() {
binding.pageNumber.setComposeContent {
val state by viewModel.state.collectAsState()
val showPageNumber by viewModel.readerPreferences.showPageNumber().collectAsState()
PageIndicatorText(
currentPage = state.currentPage,
totalPages = state.totalPages,
)
if (!state.menuVisible && showPageNumber) {
PageIndicatorText(
currentPage = state.currentPage,
totalPages = state.totalPages,
)
}
}
binding.dialogRoot.setComposeContent {
@ -554,10 +557,6 @@ class ReaderActivity : BaseActivity() {
bottomAnimation.applySystemAnimatorScale(this)
binding.readerMenuBottom.startAnimation(bottomAnimation)
}
if (readerPreferences.showPageNumber().get()) {
config?.setPageNumberVisibility(false)
}
} else {
if (readerPreferences.fullscreen().get()) {
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
@ -580,10 +579,6 @@ class ReaderActivity : BaseActivity() {
bottomAnimation.applySystemAnimatorScale(this)
binding.readerMenuBottom.startAnimation(bottomAnimation)
}
if (readerPreferences.showPageNumber().get()) {
config?.setPageNumberVisibility(true)
}
}
}
@ -636,9 +631,8 @@ class ReaderActivity : BaseActivity() {
private fun showReadingModeToast(mode: Int) {
try {
val strings = resources.getStringArray(R.array.viewers_selector)
readingModeToast?.cancel()
readingModeToast = toast(strings[mode])
readingModeToast = toast(ReadingModeType.fromPreference(mode).stringRes)
} catch (e: ArrayIndexOutOfBoundsException) {
logcat(LogPriority.ERROR) { "Unknown reading mode: $mode" }
}
@ -892,10 +886,6 @@ class ReaderActivity : BaseActivity() {
}
.launchIn(lifecycleScope)
readerPreferences.showPageNumber().changes()
.onEach(::setPageNumberVisibility)
.launchIn(lifecycleScope)
readerPreferences.trueColor().changes()
.onEach(::setTrueColor)
.launchIn(lifecycleScope)
@ -945,13 +935,6 @@ class ReaderActivity : BaseActivity() {
}
}
/**
* Sets the visibility of the bottom page indicator according to [visible].
*/
fun setPageNumberVisibility(visible: Boolean) {
binding.pageNumber.isVisible = visible
}
/**
* Sets the 32-bit color mode according to [enabled].
*/

View file

@ -61,7 +61,7 @@ class ReaderNavigationOverlayView(context: Context, attributeSet: AttributeSet)
override fun onDraw(canvas: Canvas) {
if (navigation == null) return
navigation?.regions?.forEach { region ->
navigation?.getRegions()?.forEach { region ->
val rect = region.rectF
// Scale rect from 1f,1f to screen width and height

View file

@ -5,14 +5,14 @@ import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import eu.kanade.tachiyomi.R
enum class OrientationType(val prefValue: Int, val flag: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int, val flagValue: Int) {
DEFAULT(0, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.label_default, R.drawable.ic_screen_rotation_24dp, 0x00000000),
FREE(1, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.rotation_free, R.drawable.ic_screen_rotation_24dp, 0x00000008),
PORTRAIT(2, ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT, R.string.rotation_portrait, R.drawable.ic_stay_current_portrait_24dp, 0x00000010),
LANDSCAPE(3, ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, R.string.rotation_landscape, R.drawable.ic_stay_current_landscape_24dp, 0x00000018),
LOCKED_PORTRAIT(4, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, R.string.rotation_force_portrait, R.drawable.ic_screen_lock_portrait_24dp, 0x00000020),
LOCKED_LANDSCAPE(5, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, R.string.rotation_force_landscape, R.drawable.ic_screen_lock_landscape_24dp, 0x00000028),
REVERSE_PORTRAIT(6, ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT, R.string.rotation_reverse_portrait, R.drawable.ic_stay_current_portrait_24dp, 0x00000030),
enum class OrientationType(val flag: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int, val flagValue: Int) {
DEFAULT(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.label_default, R.drawable.ic_screen_rotation_24dp, 0x00000000),
FREE(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.rotation_free, R.drawable.ic_screen_rotation_24dp, 0x00000008),
PORTRAIT(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT, R.string.rotation_portrait, R.drawable.ic_stay_current_portrait_24dp, 0x00000010),
LANDSCAPE(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, R.string.rotation_landscape, R.drawable.ic_stay_current_landscape_24dp, 0x00000018),
LOCKED_PORTRAIT(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, R.string.rotation_force_portrait, R.drawable.ic_screen_lock_portrait_24dp, 0x00000020),
LOCKED_LANDSCAPE(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, R.string.rotation_force_landscape, R.drawable.ic_screen_lock_landscape_24dp, 0x00000028),
REVERSE_PORTRAIT(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT, R.string.rotation_reverse_portrait, R.drawable.ic_stay_current_portrait_24dp, 0x00000030),
;
companion object {

View file

@ -10,13 +10,13 @@ import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
import eu.kanade.tachiyomi.ui.reader.viewer.pager.VerticalPagerViewer
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
enum class ReadingModeType(val prefValue: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int, val flagValue: Int) {
DEFAULT(0, R.string.label_default, R.drawable.ic_reader_default_24dp, 0x00000000),
LEFT_TO_RIGHT(1, R.string.left_to_right_viewer, R.drawable.ic_reader_ltr_24dp, 0x00000001),
RIGHT_TO_LEFT(2, R.string.right_to_left_viewer, R.drawable.ic_reader_rtl_24dp, 0x00000002),
VERTICAL(3, R.string.vertical_viewer, R.drawable.ic_reader_vertical_24dp, 0x00000003),
WEBTOON(4, R.string.webtoon_viewer, R.drawable.ic_reader_webtoon_24dp, 0x00000004),
CONTINUOUS_VERTICAL(5, R.string.vertical_plus_viewer, R.drawable.ic_reader_continuous_vertical_24dp, 0x00000005),
enum class ReadingModeType(@StringRes val stringRes: Int, @DrawableRes val iconRes: Int, val flagValue: Int) {
DEFAULT(R.string.label_default, R.drawable.ic_reader_default_24dp, 0x00000000),
LEFT_TO_RIGHT(R.string.left_to_right_viewer, R.drawable.ic_reader_ltr_24dp, 0x00000001),
RIGHT_TO_LEFT(R.string.right_to_left_viewer, R.drawable.ic_reader_rtl_24dp, 0x00000002),
VERTICAL(R.string.vertical_viewer, R.drawable.ic_reader_vertical_24dp, 0x00000003),
WEBTOON(R.string.webtoon_viewer, R.drawable.ic_reader_webtoon_24dp, 0x00000004),
CONTINUOUS_VERTICAL(R.string.vertical_plus_viewer, R.drawable.ic_reader_continuous_vertical_24dp, 0x00000005),
;
companion object {

View file

@ -32,15 +32,19 @@ abstract class ViewerNavigation {
private var constantMenuRegion: RectF = RectF(0f, 0f, 1f, 0.05f)
abstract var regions: List<Region>
var invertMode: ReaderPreferences.TappingInvertMode = ReaderPreferences.TappingInvertMode.NONE
protected abstract var regionList: List<Region>
/** Returns regions with applied inversion. */
fun getRegions(): List<Region> {
return regionList.map { it.invert(invertMode) }
}
fun getAction(pos: PointF): NavigationRegion {
val x = pos.x
val y = pos.y
val region = regions.map { it.invert(invertMode) }
.find { it.rectF.contains(x, y) }
val region = getRegions().find { it.rectF.contains(x, y) }
return when {
region != null -> region.type
constantMenuRegion.contains(x, y) -> NavigationRegion.MENU

View file

@ -14,5 +14,5 @@ import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
*/
class DisabledNavigation : ViewerNavigation() {
override var regions: List<Region> = emptyList()
override var regionList: List<Region> = emptyList()
}

View file

@ -15,7 +15,7 @@ import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
*/
class EdgeNavigation : ViewerNavigation() {
override var regions: List<Region> = listOf(
override var regionList: List<Region> = listOf(
Region(
rectF = RectF(0f, 0f, 0.33f, 1f),
type = NavigationRegion.NEXT,

View file

@ -15,7 +15,7 @@ import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
*/
class KindlishNavigation : ViewerNavigation() {
override var regions: List<Region> = listOf(
override var regionList: List<Region> = listOf(
Region(
rectF = RectF(0.33f, 0.33f, 1f, 1f),
type = NavigationRegion.NEXT,

View file

@ -15,7 +15,7 @@ import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
*/
open class LNavigation : ViewerNavigation() {
override var regions: List<Region> = listOf(
override var regionList: List<Region> = listOf(
Region(
rectF = RectF(0f, 0.33f, 0.33f, 0.66f),
type = NavigationRegion.PREV,

View file

@ -15,7 +15,7 @@ import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
*/
class RightAndLeftNavigation : ViewerNavigation() {
override var regions: List<Region> = listOf(
override var regionList: List<Region> = listOf(
Region(
rectF = RectF(0f, 0f, 0.33f, 1f),
type = NavigationRegion.LEFT,

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="viewers_selector">
<item>@string/label_default</item>
<item>@string/left_to_right_viewer</item>
<item>@string/right_to_left_viewer</item>
<item>@string/vertical_viewer</item>
<item>@string/webtoon_viewer</item>
<item>@string/vertical_plus_viewer</item>
</string-array>
<string-array name="rotation_type">
<item>@string/label_default</item>
<item>@string/rotation_free</item>
<item>@string/rotation_portrait</item>
<item>@string/rotation_landscape</item>
<item>@string/rotation_force_portrait</item>
<item>@string/rotation_force_landscape</item>
<item>@string/rotation_reverse_portrait</item>
</string-array>
</resources>

View file

@ -6,8 +6,10 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.parallel.Execution
import org.junit.jupiter.api.parallel.ExecutionMode
import tachiyomi.domain.chapter.model.Chapter
import java.time.Duration
import java.time.ZonedDateTime
import kotlin.time.Duration
import kotlin.time.Duration.Companion.hours
import kotlin.time.toJavaDuration
@Execution(ExecutionMode.CONCURRENT)
class SetFetchIntervalTest {
@ -22,49 +24,34 @@ class SetFetchIntervalTest {
@Test
fun `calculateInterval returns default of 7 days when less than 3 distinct days`() {
val chapters = mutableListOf<Chapter>()
(1..1).forEach {
val duration = Duration.ofHours(10)
val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter)
val chapters = (1..2).map {
chapterWithTime(chapter, 10.hours)
}
setFetchInterval.calculateInterval(chapters, testTime) shouldBe 7
}
@Test
fun `calculateInterval returns 7 when 5 chapters in 1 day`() {
val chapters = mutableListOf<Chapter>()
(1..5).forEach {
val duration = Duration.ofHours(10)
val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter)
val chapters = (1..5).map {
chapterWithTime(chapter, 10.hours)
}
setFetchInterval.calculateInterval(chapters, testTime) shouldBe 7
}
@Test
fun `calculateInterval returns 7 when 7 chapters in 48 hours, 2 day`() {
val chapters = mutableListOf<Chapter>()
(1..2).forEach {
val duration = Duration.ofHours(24L)
val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter)
}
(1..5).forEach {
val duration = Duration.ofHours(48L)
val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter)
val chapters = (1..2).map {
chapterWithTime(chapter, 24.hours)
} + (1..5).map {
chapterWithTime(chapter, 48.hours)
}
setFetchInterval.calculateInterval(chapters, testTime) shouldBe 7
}
@Test
fun `calculateInterval returns default of 1 day when interval less than 1`() {
val chapters = mutableListOf<Chapter>()
(1..5).forEach {
val duration = Duration.ofHours(15L * it)
val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter)
val chapters = (1..5).map {
chapterWithTime(chapter, (15 * it).hours)
}
setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1
}
@ -72,61 +59,46 @@ class SetFetchIntervalTest {
// Normal interval calculation
@Test
fun `calculateInterval returns 1 when 5 chapters in 120 hours, 5 days`() {
val chapters = mutableListOf<Chapter>()
(1..5).forEach {
val duration = Duration.ofHours(24L * it)
val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter)
val chapters = (1..5).map {
chapterWithTime(chapter, (24 * it).hours)
}
setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1
}
@Test
fun `calculateInterval returns 2 when 5 chapters in 240 hours, 10 days`() {
val chapters = mutableListOf<Chapter>()
(1..5).forEach {
val duration = Duration.ofHours(48L * it)
val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter)
val chapters = (1..5).map {
chapterWithTime(chapter, (48 * it).hours)
}
setFetchInterval.calculateInterval(chapters, testTime) shouldBe 2
}
@Test
fun `calculateInterval returns floored value when interval is decimal`() {
val chapters = mutableListOf<Chapter>()
(1..5).forEach {
val duration = Duration.ofHours(25L * it)
val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter)
val chapters = (1..5).map {
chapterWithTime(chapter, (25 * it).hours)
}
setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1
}
@Test
fun `calculateInterval returns 1 when 5 chapters in 215 hours, 5 days`() {
val chapters = mutableListOf<Chapter>()
(1..5).forEach {
val duration = Duration.ofHours(43L * it)
val newChapter = chapterAddTime(chapter, duration)
chapters.add(newChapter)
val chapters = (1..5).map {
chapterWithTime(chapter, (43 * it).hours)
}
setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1
}
@Test
fun `calculateInterval returns interval based on fetch time if upload time not available`() {
val chapters = mutableListOf<Chapter>()
(1..5).forEach {
val duration = Duration.ofHours(25L * it)
val newChapter = chapterAddTime(chapter, duration).copy(dateUpload = 0L)
chapters.add(newChapter)
val chapters = (1..5).map {
chapterWithTime(chapter, (25 * it).hours).copy(dateUpload = 0L)
}
setFetchInterval.calculateInterval(chapters, testTime) shouldBe 1
}
private fun chapterAddTime(chapter: Chapter, duration: Duration): Chapter {
val newTime = testTime.plus(duration).toEpochSecond() * 1000
private fun chapterWithTime(chapter: Chapter, duration: Duration): Chapter {
val newTime = testTime.plus(duration.toJavaDuration()).toEpochSecond() * 1000
return chapter.copy(dateFetch = newTime, dateUpload = newTime)
}
}

View file

@ -507,6 +507,7 @@
<string name="creating_backup_error">Backup failed</string>
<string name="missing_storage_permission">Storage permissions not granted</string>
<string name="empty_backup_error">No library entries to back up</string>
<string name="create_backup_file_error">Couldn\'t create a backup file</string>
<string name="restore_miui_warning">Backup/restore may not function properly if MIUI Optimization is disabled.</string>
<string name="restore_in_progress">Restore is already in progress</string>
<string name="restoring_backup">Restoring backup</string>
@ -620,6 +621,7 @@
<string name="no_results_found">No results found</string>
<!-- Do not translate "WebView" -->
<string name="http_error_hint">Check website in WebView</string>
<string name="licensed_manga_chapters_error">Licensed - No chapters to show</string>
<string name="local_source">Local source</string>
<string name="other_source">Other</string>
<string name="last_used_source">Last used</string>

View file

@ -215,7 +215,7 @@ abstract class HttpSource : CatalogueSource {
chapterListParse(response)
}
} else {
Observable.error(Exception("Licensed - No chapters to show"))
Observable.error(LicensedMangaChaptersException())
}
}
@ -404,3 +404,5 @@ abstract class HttpSource : CatalogueSource {
*/
override fun getFilterList() = FilterList()
}
class LicensedMangaChaptersException : Exception("Licensed - No chapters to show")