Merge branch 'devel' into feature/nextgen
This commit is contained in:
@@ -4,6 +4,7 @@ import android.content.Context
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.migration.Migration
|
||||
import org.koitharu.kotatsu.bookmarks.data.BookmarkEntity
|
||||
import org.koitharu.kotatsu.bookmarks.data.BookmarksDao
|
||||
import org.koitharu.kotatsu.core.db.dao.MangaDao
|
||||
@@ -65,23 +66,24 @@ abstract class MangaDatabase : RoomDatabase() {
|
||||
abstract val scrobblingDao: ScrobblingDao
|
||||
}
|
||||
|
||||
fun MangaDatabase(context: Context): MangaDatabase = Room.databaseBuilder(
|
||||
context,
|
||||
MangaDatabase::class.java,
|
||||
"kotatsu-db"
|
||||
).addMigrations(
|
||||
Migration1To2(),
|
||||
Migration2To3(),
|
||||
Migration3To4(),
|
||||
Migration4To5(),
|
||||
Migration5To6(),
|
||||
Migration6To7(),
|
||||
Migration7To8(),
|
||||
Migration8To9(),
|
||||
Migration9To10(),
|
||||
Migration10To11(),
|
||||
Migration11To12(),
|
||||
Migration12To13(),
|
||||
).addCallback(
|
||||
DatabasePrePopulateCallback(context.resources)
|
||||
).build()
|
||||
val databaseMigrations: Array<Migration>
|
||||
get() = arrayOf(
|
||||
Migration1To2(),
|
||||
Migration2To3(),
|
||||
Migration3To4(),
|
||||
Migration4To5(),
|
||||
Migration5To6(),
|
||||
Migration6To7(),
|
||||
Migration7To8(),
|
||||
Migration8To9(),
|
||||
Migration9To10(),
|
||||
Migration10To11(),
|
||||
Migration11To12(),
|
||||
Migration12To13(),
|
||||
)
|
||||
|
||||
fun MangaDatabase(context: Context): MangaDatabase = Room
|
||||
.databaseBuilder(context, MangaDatabase::class.java, "kotatsu-db")
|
||||
.addMigrations(*databaseMigrations)
|
||||
.addCallback(DatabasePrePopulateCallback(context.resources))
|
||||
.build()
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package org.koitharu.kotatsu.core.exceptions
|
||||
|
||||
class CaughtException(cause: Throwable, override val message: String?) : RuntimeException(cause)
|
||||
@@ -135,6 +135,26 @@ class ChaptersFragment :
|
||||
mode.finish()
|
||||
true
|
||||
}
|
||||
R.id.action_select_range -> {
|
||||
val controller = selectionController ?: return false
|
||||
val items = chaptersAdapter?.items ?: return false
|
||||
val ids = HashSet(controller.peekCheckedIds())
|
||||
val buffer = HashSet<Long>()
|
||||
var isAdding = false
|
||||
for (x in items) {
|
||||
if (x.chapter.id in ids) {
|
||||
isAdding = true
|
||||
if (buffer.isNotEmpty()) {
|
||||
ids.addAll(buffer)
|
||||
buffer.clear()
|
||||
}
|
||||
} else if (isAdding) {
|
||||
buffer.add(x.chapter.id)
|
||||
}
|
||||
}
|
||||
controller.addAll(ids)
|
||||
true
|
||||
}
|
||||
R.id.action_select_all -> {
|
||||
val ids = chaptersAdapter?.items?.map { it.chapter.id } ?: return false
|
||||
selectionController?.addAll(ids)
|
||||
@@ -158,14 +178,24 @@ class ChaptersFragment :
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
val selectedIds = selectionController?.peekCheckedIds() ?: return false
|
||||
val items = chaptersAdapter?.items?.filter { x -> x.chapter.id in selectedIds }.orEmpty()
|
||||
menu.findItem(R.id.action_save).isVisible = items.none { x ->
|
||||
val allItems = chaptersAdapter?.items.orEmpty()
|
||||
val items = allItems.withIndex().filter { (_, x) -> x.chapter.id in selectedIds }
|
||||
menu.findItem(R.id.action_save).isVisible = items.none { (_, x) ->
|
||||
x.chapter.source == MangaSource.LOCAL
|
||||
}
|
||||
menu.findItem(R.id.action_delete).isVisible = items.all { x ->
|
||||
menu.findItem(R.id.action_delete).isVisible = items.all { (_, x) ->
|
||||
x.chapter.source == MangaSource.LOCAL
|
||||
}
|
||||
menu.findItem(R.id.action_select_all).isVisible = items.size < allItems.size
|
||||
mode.title = items.size.toString()
|
||||
var hasGap = false
|
||||
for (i in 0 until items.size - 1) {
|
||||
if (items[i].index + 1 != items[i + 1].index) {
|
||||
hasGap = true
|
||||
break
|
||||
}
|
||||
}
|
||||
menu.findItem(R.id.action_select_range).isVisible = hasGap
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package org.koitharu.kotatsu.details.ui
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.acra.ACRA
|
||||
import org.koitharu.kotatsu.base.domain.MangaDataRepository
|
||||
import org.koitharu.kotatsu.base.domain.MangaIntent
|
||||
import org.koitharu.kotatsu.core.exceptions.MangaNotFoundException
|
||||
@@ -14,7 +13,6 @@ import org.koitharu.kotatsu.details.ui.model.ChapterListItem
|
||||
import org.koitharu.kotatsu.details.ui.model.toListItem
|
||||
import org.koitharu.kotatsu.history.domain.HistoryRepository
|
||||
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
@@ -22,7 +20,6 @@ import org.koitharu.kotatsu.parsers.util.mapToSet
|
||||
import org.koitharu.kotatsu.parsers.util.toTitleCase
|
||||
import org.koitharu.kotatsu.utils.ext.iterator
|
||||
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.utils.ext.setCurrentManga
|
||||
|
||||
class MangaDetailsDelegate(
|
||||
private val intent: MangaIntent,
|
||||
@@ -45,7 +42,6 @@ class MangaDetailsDelegate(
|
||||
suspend fun doLoad() {
|
||||
var manga = mangaDataRepository.resolveIntent(intent)
|
||||
?: throw MangaNotFoundException("Cannot find manga")
|
||||
ACRA.setCurrentManga(manga)
|
||||
mangaData.value = manga
|
||||
manga = MangaRepository(manga.source).getDetails(manga)
|
||||
// find default branch
|
||||
|
||||
@@ -433,4 +433,4 @@ class ReaderActivity :
|
||||
.putExtra(MangaIntent.KEY_ID, mangaId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import org.acra.ACRA
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.domain.MangaDataRepository
|
||||
import org.koitharu.kotatsu.base.domain.MangaIntent
|
||||
@@ -32,7 +31,6 @@ import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
||||
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.utils.ext.processLifecycleScope
|
||||
import org.koitharu.kotatsu.utils.ext.setCurrentManga
|
||||
import java.util.*
|
||||
|
||||
private const val BOUNDS_PAGE_OFFSET = 2
|
||||
@@ -262,7 +260,6 @@ class ReaderViewModel(
|
||||
private fun loadImpl() {
|
||||
loadingJob = launchLoadingJob(Dispatchers.Default) {
|
||||
var manga = dataRepository.resolveIntent(intent) ?: throw MangaNotFoundException("Cannot find manga")
|
||||
ACRA.setCurrentManga(manga)
|
||||
mangaData.value = manga
|
||||
val repo = MangaRepository(manga.source)
|
||||
manga = repo.getDetails(manga)
|
||||
|
||||
@@ -3,19 +3,15 @@ package org.koitharu.kotatsu.utils.ext
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.res.Resources
|
||||
import okio.FileNotFoundException
|
||||
import org.acra.ACRA
|
||||
import org.acra.ktx.sendWithAcra
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
||||
import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException
|
||||
import org.koitharu.kotatsu.core.exceptions.UnsupportedFileException
|
||||
import org.koitharu.kotatsu.core.exceptions.WrongPasswordException
|
||||
import org.koitharu.kotatsu.core.exceptions.*
|
||||
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
|
||||
import org.koitharu.kotatsu.parsers.exception.ContentUnavailableException
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import java.net.SocketTimeoutException
|
||||
|
||||
fun Throwable.getDisplayMessage(resources: Resources) = when (this) {
|
||||
fun Throwable.getDisplayMessage(resources: Resources): String = when (this) {
|
||||
is AuthRequiredException -> resources.getString(R.string.auth_required)
|
||||
is CloudFlareProtectedException -> resources.getString(R.string.captcha_required)
|
||||
is ActivityNotFoundException,
|
||||
@@ -23,22 +19,21 @@ fun Throwable.getDisplayMessage(resources: Resources) = when (this) {
|
||||
is UnsupportedFileException -> resources.getString(R.string.text_file_not_supported)
|
||||
is FileNotFoundException -> resources.getString(R.string.file_not_found)
|
||||
is EmptyHistoryException -> resources.getString(R.string.history_is_empty)
|
||||
is ContentUnavailableException -> message
|
||||
is ParseException -> shortMessage
|
||||
is SocketTimeoutException -> resources.getString(R.string.network_error)
|
||||
is WrongPasswordException -> resources.getString(R.string.wrong_password)
|
||||
else -> localizedMessage ?: resources.getString(R.string.error_occurred)
|
||||
}
|
||||
else -> localizedMessage
|
||||
} ?: resources.getString(R.string.error_occurred)
|
||||
|
||||
fun Throwable.isReportable(): Boolean {
|
||||
if (this !is Exception) {
|
||||
return true
|
||||
}
|
||||
return this is ParseException || this is IllegalArgumentException || this is IllegalStateException
|
||||
return this is ParseException || this is IllegalArgumentException ||
|
||||
this is IllegalStateException || this is RuntimeException
|
||||
}
|
||||
|
||||
fun Throwable.report(message: String?) {
|
||||
CaughtException(this, message).sendWithAcra()
|
||||
}
|
||||
|
||||
fun ACRA.setCurrentManga(manga: Manga?) = errorReporter.putCustomData("manga", manga?.publicUrl.toString())
|
||||
|
||||
private class CaughtException(cause: Throwable, override val message: String?) : RuntimeException(cause)
|
||||
}
|
||||
Reference in New Issue
Block a user