Turned on kt lint

This commit is contained in:
Jay 2020-03-15 22:50:20 -07:00
parent cc28ff7a77
commit da786bbc40
396 changed files with 2539 additions and 2843 deletions

View File

@ -8,7 +8,7 @@ plugins {
kotlin("android") kotlin("android")
kotlin("android.extensions") kotlin("android.extensions")
kotlin("kapt") kotlin("kapt")
//id("org.jmailen.kotlinter") version "2.3.1" id("org.jmailen.kotlinter") version "2.3.1"
id("com.github.zellius.shortcut-helper") id("com.github.zellius.shortcut-helper")
id("com.google.gms.google-services") apply false id("com.google.gms.google-services") apply false
} }
@ -114,9 +114,9 @@ dependencies {
implementation("com.google.firebase:firebase-core:17.2.3") implementation("com.google.firebase:firebase-core:17.2.3")
val lifecycle_version = "2.1.0" val lifecycleVersion = "2.1.0"
implementation("androidx.lifecycle:lifecycle-extensions:$lifecycle_version") implementation("androidx.lifecycle:lifecycle-extensions:$lifecycleVersion")
implementation("androidx.lifecycle:lifecycle-common-java8:$lifecycle_version") implementation("androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion")
// ReactiveX // ReactiveX
implementation("io.reactivex:rxandroid:1.2.1") implementation("io.reactivex:rxandroid:1.2.1")
@ -126,15 +126,15 @@ dependencies {
implementation("com.github.pwittchen:reactivenetwork:0.13.0") implementation("com.github.pwittchen:reactivenetwork:0.13.0")
// Network client // Network client
val okhttp_version = "4.3.1" val okhttpVersion = "4.3.1"
implementation("com.squareup.okhttp3:okhttp:$okhttp_version") implementation("com.squareup.okhttp3:okhttp:$okhttpVersion")
implementation("com.squareup.okhttp3:logging-interceptor:$okhttp_version") implementation("com.squareup.okhttp3:logging-interceptor:$okhttpVersion")
implementation("com.squareup.okio:okio:2.4.3") implementation("com.squareup.okio:okio:2.4.3")
// REST // REST
val retrofit_version = "2.7.1" val retrofitVersion = "2.7.1"
implementation("com.squareup.retrofit2:retrofit:$retrofit_version") implementation("com.squareup.retrofit2:retrofit:$retrofitVersion")
implementation("com.squareup.retrofit2:converter-gson:$retrofit_version") implementation("com.squareup.retrofit2:converter-gson:$retrofitVersion")
// JSON // JSON
implementation("com.google.code.gson:gson:2.8.6") implementation("com.google.code.gson:gson:2.8.6")
@ -164,18 +164,18 @@ dependencies {
implementation("io.requery:sqlite-android:3.31.0") implementation("io.requery:sqlite-android:3.31.0")
// Model View Presenter // Model View Presenter
val nucleus_version = "3.0.0" val nucleusVersion = "3.0.0"
implementation("info.android15.nucleus:nucleus:$nucleus_version") implementation("info.android15.nucleus:nucleus:$nucleusVersion")
implementation("info.android15.nucleus:nucleus-support-v7:$nucleus_version") implementation("info.android15.nucleus:nucleus-support-v7:$nucleusVersion")
// Dependency injection // Dependency injection
implementation("com.github.inorichi.injekt:injekt-core:65b0440") implementation("com.github.inorichi.injekt:injekt-core:65b0440")
// Image library // Image library
val glide_version = "4.11.0" val glideVersion = "4.11.0"
implementation("com.github.bumptech.glide:glide:$glide_version") implementation("com.github.bumptech.glide:glide:$glideVersion")
implementation("com.github.bumptech.glide:okhttp3-integration:$glide_version") implementation("com.github.bumptech.glide:okhttp3-integration:$glideVersion")
kapt("com.github.bumptech.glide:compiler:$glide_version") kapt("com.github.bumptech.glide:compiler:$glideVersion")
// Transformations // Transformations
implementation("jp.wasabeef:glide-transformations:4.1.0") implementation("jp.wasabeef:glide-transformations:4.1.0")
@ -208,28 +208,28 @@ dependencies {
implementation("com.github.inorichi:conductor-support-preference:a32c357") implementation("com.github.inorichi:conductor-support-preference:a32c357")
// RxBindings // RxBindings
val rxbindings_version = "1.0.1" val rxbindingsVersion = "1.0.1"
implementation("com.jakewharton.rxbinding:rxbinding-kotlin:$rxbindings_version") implementation("com.jakewharton.rxbinding:rxbinding-kotlin:$rxbindingsVersion")
implementation("com.jakewharton.rxbinding:rxbinding-appcompat-v7-kotlin:$rxbindings_version") implementation("com.jakewharton.rxbinding:rxbinding-appcompat-v7-kotlin:$rxbindingsVersion")
implementation("com.jakewharton.rxbinding:rxbinding-support-v4-kotlin:$rxbindings_version") implementation("com.jakewharton.rxbinding:rxbinding-support-v4-kotlin:$rxbindingsVersion")
implementation("com.jakewharton.rxbinding:rxbinding-recyclerview-v7-kotlin:$rxbindings_version") implementation("com.jakewharton.rxbinding:rxbinding-recyclerview-v7-kotlin:$rxbindingsVersion")
// Tests // Tests
testImplementation("junit:junit:4.13") testImplementation("junit:junit:4.13")
testImplementation("org.assertj:assertj-core:1.7.1") testImplementation("org.assertj:assertj-core:3.12.2")
testImplementation("org.mockito:mockito-core:1.10.19") testImplementation("org.mockito:mockito-core:1.10.19")
val robolectric_version = "3.1.4" val robolectricVersion = "3.1.4"
testImplementation("org.robolectric:robolectric:$robolectric_version") testImplementation("org.robolectric:robolectric:$robolectricVersion")
testImplementation("org.robolectric:shadows-multidex:$robolectric_version") testImplementation("org.robolectric:shadows-multidex:$robolectricVersion")
testImplementation("org.robolectric:shadows-play-services:$robolectric_version") testImplementation("org.robolectric:shadows-play-services:$robolectricVersion")
implementation(kotlin("stdlib", org.jetbrains.kotlin.config.KotlinCompilerVersion.VERSION)) implementation(kotlin("stdlib", org.jetbrains.kotlin.config.KotlinCompilerVersion.VERSION))
val coroutines_version = "1.3.3" val coroutinesVersion = "1.3.3"
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion")
//Crash reports //Crash reports
val acraVersion = "4.9.2" val acraVersion = "4.9.2"
@ -239,13 +239,13 @@ dependencies {
implementation("info.debatty:java-string-similarity:1.2.1") implementation("info.debatty:java-string-similarity:1.2.1")
} }
/*tasks.preBuild { tasks.preBuild {
dependsOn(tasks.lintKotlin) dependsOn(tasks.lintKotlin)
} }
tasks.lintKotlin { tasks.lintKotlin {
dependsOn(tasks.formatKotlin) dependsOn(tasks.formatKotlin)
}*/ }
if (getGradle().getStartParameter().getTaskRequests().toString().contains("Standard")) { if (gradle.startParameter.taskRequests.toString().contains("Standard")) {
apply(mapOf("plugin" to "com.google.gms.google-services")) apply(mapOf("plugin" to "com.google.gms.google-services"))
} }

View File

@ -52,7 +52,7 @@ open class App : Application(), LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_STOP) @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded() { fun onAppBackgrounded() {
//App in background // App in background
val preferences: PreferencesHelper by injectLazy() val preferences: PreferencesHelper by injectLazy()
if (preferences.lockAfter().getOrDefault() >= 0) { if (preferences.lockAfter().getOrDefault() >= 0) {
SecureActivityDelegate.locked = true SecureActivityDelegate.locked = true
@ -92,5 +92,4 @@ open class App : Application(), LifecycleObserver {
protected open fun setupNotificationChannels() { protected open fun setupNotificationChannels() {
Notifications.createChannels(this) Notifications.createChannels(this)
} }
} }

View File

@ -13,7 +13,11 @@ import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import uy.kohesive.injekt.api.* import uy.kohesive.injekt.api.InjektModule
import uy.kohesive.injekt.api.InjektRegistrar
import uy.kohesive.injekt.api.addSingleton
import uy.kohesive.injekt.api.addSingletonFactory
import uy.kohesive.injekt.api.get
class AppModule(val app: Application) : InjektModule { class AppModule(val app: Application) : InjektModule {
@ -52,7 +56,5 @@ class AppModule(val app: Application) : InjektModule {
GlobalScope.launch { get<DatabaseHelper>() } GlobalScope.launch { get<DatabaseHelper>() }
GlobalScope.launch { get<DownloadManager>() } GlobalScope.launch { get<DownloadManager>() }
} }
} }

View File

@ -67,5 +67,4 @@ object Migrations {
} }
return false return false
} }
}
}

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.data.backup package eu.kanade.tachiyomi.data.backup
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
object BackupConst { object BackupConst {
const val INTENT_FILTER = "SettingsBackupFragment" const val INTENT_FILTER = "SettingsBackupFragment"
@ -18,5 +17,5 @@ object BackupConst {
const val EXTRA_TIME = "$ID.$INTENT_FILTER.EXTRA_TIME" const val EXTRA_TIME = "$ID.$INTENT_FILTER.EXTRA_TIME"
const val EXTRA_ERROR_FILE_PATH = "$ID.$INTENT_FILTER.EXTRA_ERROR_FILE_PATH" const val EXTRA_ERROR_FILE_PATH = "$ID.$INTENT_FILTER.EXTRA_ERROR_FILE_PATH"
const val EXTRA_ERROR_FILE = "$ID.$INTENT_FILTER.EXTRA_ERROR_FILE" const val EXTRA_ERROR_FILE = "$ID.$INTENT_FILTER.EXTRA_ERROR_FILE"
const val EXTRA_MINI_ERROR= "$ID.$INTENT_FILTER.EXTRA_MINI_ERROR" const val EXTRA_MINI_ERROR = "$ID.$INTENT_FILTER.EXTRA_MINI_ERROR"
} }

View File

@ -5,8 +5,8 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import com.google.gson.JsonArray import com.google.gson.JsonArray
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
import eu.kanade.tachiyomi.data.database.models.Manga
/** /**
* [IntentService] used to backup [Manga] information to [JsonArray] * [IntentService] used to backup [Manga] information to [JsonArray]
@ -45,7 +45,6 @@ class BackupCreateService : IntentService(NAME) {
} }
context.startService(intent) context.startService(intent)
} }
} }
private val backupManager by lazy { BackupManager(this) } private val backupManager by lazy { BackupManager(this) }
@ -60,5 +59,4 @@ class BackupCreateService : IntentService(NAME) {
if (uri != null) if (uri != null)
backupManager.createBackup(uri, flags, false) backupManager.createBackup(uri, flags, false)
} }
} }

View File

@ -6,9 +6,9 @@ import com.evernote.android.job.JobManager
import com.evernote.android.job.JobRequest import com.evernote.android.job.JobRequest
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import java.util.concurrent.TimeUnit
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.concurrent.TimeUnit
class BackupCreatorJob : Job() { class BackupCreatorJob : Job() {

View File

@ -3,8 +3,15 @@ package eu.kanade.tachiyomi.data.backup
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import com.github.salomonbrys.kotson.* import com.github.salomonbrys.kotson.fromJson
import com.google.gson.* import com.github.salomonbrys.kotson.registerTypeAdapter
import com.github.salomonbrys.kotson.registerTypeHierarchyAdapter
import com.github.salomonbrys.kotson.set
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.hippo.unifile.UniFile import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY_MASK import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY_MASK
@ -22,22 +29,34 @@ import eu.kanade.tachiyomi.data.backup.models.Backup.HISTORY
import eu.kanade.tachiyomi.data.backup.models.Backup.MANGA import eu.kanade.tachiyomi.data.backup.models.Backup.MANGA
import eu.kanade.tachiyomi.data.backup.models.Backup.TRACK import eu.kanade.tachiyomi.data.backup.models.Backup.TRACK
import eu.kanade.tachiyomi.data.backup.models.DHistory import eu.kanade.tachiyomi.data.backup.models.DHistory
import eu.kanade.tachiyomi.data.backup.serializer.* import eu.kanade.tachiyomi.data.backup.serializer.CategoryTypeAdapter
import eu.kanade.tachiyomi.data.backup.serializer.ChapterTypeAdapter
import eu.kanade.tachiyomi.data.backup.serializer.HistoryTypeAdapter
import eu.kanade.tachiyomi.data.backup.serializer.MangaTypeAdapter
import eu.kanade.tachiyomi.data.backup.serializer.TrackTypeAdapter
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.* import eu.kanade.tachiyomi.data.database.models.CategoryImpl
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
import eu.kanade.tachiyomi.data.database.models.History
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.database.models.MangaImpl
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.database.models.TrackImpl
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
import eu.kanade.tachiyomi.util.system.sendLocalBroadcast import eu.kanade.tachiyomi.util.system.sendLocalBroadcast
import kotlin.math.max
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import rx.Observable import rx.Observable
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import kotlin.math.max
class BackupManager(val context: Context, version: Int = CURRENT_VERSION) { class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {

View File

@ -38,23 +38,22 @@ import eu.kanade.tachiyomi.util.lang.chop
import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.isServiceRunning import eu.kanade.tachiyomi.util.system.isServiceRunning
import eu.kanade.tachiyomi.util.system.notificationManager import eu.kanade.tachiyomi.util.system.notificationManager
import java.io.File
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.File
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
/** /**
* Restores backup from json file * Restores backup from json file
*/ */
class BackupRestoreService : Service() { class BackupRestoreService : Service() {
/** /**
* Wake lock that will be held until the service is destroyed. * Wake lock that will be held until the service is destroyed.
*/ */
@ -87,7 +86,6 @@ class BackupRestoreService : Service() {
*/ */
private val trackingErrors = mutableListOf<String>() private val trackingErrors = mutableListOf<String>()
/** /**
* List containing missing sources * List containing missing sources
*/ */
@ -113,7 +111,6 @@ class BackupRestoreService : Service() {
*/ */
internal val trackManager: TrackManager by injectLazy() internal val trackManager: TrackManager by injectLazy()
/** /**
* Method called when the service is created. It injects dependencies and acquire the wake lock. * Method called when the service is created. It injects dependencies and acquire the wake lock.
*/ */
@ -216,7 +213,6 @@ class BackupRestoreService : Service() {
showResultNotification(logFile.parent, logFile.name) showResultNotification(logFile.parent, logFile.name)
} }
/**Restore categories if they were backed up /**Restore categories if they were backed up
* *
*/ */
@ -246,8 +242,7 @@ class BackupRestoreService : Service() {
if (job?.isCancelled == false) { if (job?.isCancelled == false) {
showProgressNotification(restoreProgress, totalAmount, manga.title) showProgressNotification(restoreProgress, totalAmount, manga.title)
restoreProgress += 1 restoreProgress += 1
} } else {
else {
throw java.lang.Exception("Job was cancelled") throw java.lang.Exception("Job was cancelled")
} }
val dbManga = backupManager.getMangaFromDatabase(manga) val dbManga = backupManager.getMangaFromDatabase(manga)
@ -262,7 +257,7 @@ class BackupRestoreService : Service() {
} }
if (!dbMangaExists || !backupManager.restoreChaptersForManga(manga, chapters)) { if (!dbMangaExists || !backupManager.restoreChaptersForManga(manga, chapters)) {
//manga gets chapters added // manga gets chapters added
backupManager.restoreChapterFetch(source, manga, chapters) backupManager.restoreChapterFetch(source, manga, chapters)
} }
// Restore categories // Restore categories
@ -280,8 +275,7 @@ class BackupRestoreService : Service() {
val cause = e.cause val cause = e.cause
if (cause is SourceNotFoundException) { if (cause is SourceNotFoundException) {
sourcesMissing.add(cause.id) sourcesMissing.add(cause.id)
} } else if (e.message?.contains("licensed", true) == true) {
else if (e.message?.contains("licensed", true) == true) {
lincensedManga++ lincensedManga++
} }
errors.add("${manga.title} - ${cause?.message ?: e.message}") errors.add("${manga.title} - ${cause?.message ?: e.message}")
@ -303,7 +297,7 @@ class BackupRestoreService : Service() {
try { try {
service.refresh(track) service.refresh(track)
db.insertTrack(track).executeAsBlocking() db.insertTrack(track).executeAsBlocking()
}catch (e : Exception){ } catch (e: Exception) {
errors.add("${manga.title} - ${e.message}") errors.add("${manga.title} - ${e.message}")
} }
} else { } else {
@ -357,7 +351,6 @@ class BackupRestoreService : Service() {
NotificationReceiver.cancelRestorePendingBroadcast(this) NotificationReceiver.cancelRestorePendingBroadcast(this)
} }
/** /**
* Shows the notification containing the currently updating manga and the progress. * Shows the notification containing the currently updating manga and the progress.
* *
@ -473,4 +466,4 @@ class BackupRestoreService : Service() {
context.stopService(Intent(context, BackupRestoreService::class.java)) context.stopService(Intent(context, BackupRestoreService::class.java))
} }
} }
} }

View File

@ -1,7 +1,8 @@
package eu.kanade.tachiyomi.data.backup.models package eu.kanade.tachiyomi.data.backup.models
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.Date
import java.util.Locale
/** /**
* Json values * Json values
@ -20,4 +21,4 @@ object Backup {
val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date()) val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date())
return "tachiyomi_$date.json" return "tachiyomi_$date.json"
} }
} }

View File

@ -1,3 +1,3 @@
package eu.kanade.tachiyomi.data.backup.models package eu.kanade.tachiyomi.data.backup.models
data class DHistory(val url: String,val lastRead: Long) data class DHistory(val url: String, val lastRead: Long)

View File

@ -28,4 +28,4 @@ object CategoryTypeAdapter {
} }
} }
} }
} }

View File

@ -29,4 +29,4 @@ object HistoryTypeAdapter {
} }
} }
} }
} }

View File

@ -35,4 +35,4 @@ object MangaTypeAdapter {
} }
} }
} }
} }

View File

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.data.backup.serializer package eu.kanade.tachiyomi.data.backup.serializer
import android.telecom.DisconnectCause.REMOTE
import com.github.salomonbrys.kotson.typeAdapter import com.github.salomonbrys.kotson.typeAdapter
import com.google.gson.TypeAdapter import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonToken import com.google.gson.stream.JsonToken

View File

@ -9,14 +9,13 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.DiskUtil
import eu.kanade.tachiyomi.util.storage.saveTo import eu.kanade.tachiyomi.util.storage.saveTo
import java.io.File
import java.io.IOException
import okhttp3.Response import okhttp3.Response
import okio.Okio
import okio.buffer import okio.buffer
import okio.sink import okio.sink
import rx.Observable import rx.Observable
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.File
import java.io.IOException
/** /**
* Class used to create chapter cache * Class used to create chapter cache
@ -136,7 +135,6 @@ class ChapterCache(private val context: Context) {
diskCache.flush() diskCache.flush()
editor.commit() editor.commit()
editor.abortUnlessCommitted() editor.abortUnlessCommitted()
} catch (e: Exception) { } catch (e: Exception) {
// Ignore. // Ignore.
} finally { } finally {
@ -202,4 +200,3 @@ class ChapterCache(private val context: Context) {
return "${chapter.manga_id}${chapter.url}" return "${chapter.manga_id}${chapter.url}"
} }
} }

View File

@ -20,8 +20,8 @@ class CoverCache(private val context: Context) {
/** /**
* Cache directory used for cache management. * Cache directory used for cache management.
*/ */
private val cacheDir = context.getExternalFilesDir("covers") ?: private val cacheDir = context.getExternalFilesDir("covers")
File(context.filesDir, "covers").also { it.mkdirs() } ?: File(context.filesDir, "covers").also { it.mkdirs() }
/** /**
* Returns the cover from cache. * Returns the cover from cache.
@ -37,7 +37,7 @@ class CoverCache(private val context: Context) {
* Copy the given stream to this cache. * Copy the given stream to this cache.
* *
* @param thumbnailUrl url of the thumbnail. * @param thumbnailUrl url of the thumbnail.
* @param inputStream the stream to copy. * @param inputStream the stream to copy.
* @throws IOException if there's any error. * @throws IOException if there's any error.
*/ */
@Throws(IOException::class) @Throws(IOException::class)

View File

@ -29,8 +29,8 @@ import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory
/** /**
* This class provides operations to manage the database through its interfaces. * This class provides operations to manage the database through its interfaces.
*/ */
open class DatabaseHelper(context: Context) open class DatabaseHelper(context: Context) :
: MangaQueries, ChapterQueries, TrackQueries, CategoryQueries, MangaCategoryQueries, MangaQueries, ChapterQueries, TrackQueries, CategoryQueries, MangaCategoryQueries,
HistoryQueries, SearchMetadataQueries { HistoryQueries, SearchMetadataQueries {
private val configuration = SupportSQLiteOpenHelper.Configuration.builder(context) private val configuration = SupportSQLiteOpenHelper.Configuration.builder(context)
@ -52,5 +52,4 @@ open class DatabaseHelper(context: Context)
inline fun inTransaction(block: () -> Unit) = db.inTransaction(block) inline fun inTransaction(block: () -> Unit) = db.inTransaction(block)
fun lowLevel() = db.lowLevel() fun lowLevel() = db.lowLevel()
} }

View File

@ -22,4 +22,3 @@ inline fun <T> StorIOSQLite.inTransactionReturn(block: () -> T): T {
lowLevel().endTransaction() lowLevel().endTransaction()
} }
} }

View File

@ -2,10 +2,12 @@ package eu.kanade.tachiyomi.data.database
import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.sqlite.db.SupportSQLiteOpenHelper import androidx.sqlite.db.SupportSQLiteOpenHelper
import android.content.Context import eu.kanade.tachiyomi.data.database.tables.CategoryTable
import android.database.sqlite.SQLiteDatabase import eu.kanade.tachiyomi.data.database.tables.ChapterTable
import android.database.sqlite.SQLiteOpenHelper import eu.kanade.tachiyomi.data.database.tables.HistoryTable
import eu.kanade.tachiyomi.data.database.tables.* import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable
import eu.kanade.tachiyomi.data.database.tables.MangaTable
import eu.kanade.tachiyomi.data.database.tables.TrackTable
class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) { class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
@ -81,5 +83,4 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
override fun onConfigure(db: SupportSQLiteDatabase) { override fun onConfigure(db: SupportSQLiteDatabase) {
db.setForeignKeyConstraintsEnabled(true) db.setForeignKeyConstraintsEnabled(true)
} }
} }

View File

@ -5,5 +5,4 @@ import com.pushtorefresh.storio.sqlite.impl.DefaultStorIOSQLite
interface DbProvider { interface DbProvider {
val db: DefaultStorIOSQLite val db: DefaultStorIOSQLite
}
}

View File

@ -47,7 +47,6 @@ class CategoryPutResolver : DefaultPutResolver<Category>() {
val orderString = obj.mangaOrder.joinToString("/") val orderString = obj.mangaOrder.joinToString("/")
put(COL_MANGA_ORDER, orderString) put(COL_MANGA_ORDER, orderString)
} }
} }
} }

View File

@ -88,4 +88,3 @@ class ChapterDeleteResolver : DefaultDeleteResolver<Chapter>() {
.whereArgs(obj.id) .whereArgs(obj.id)
.build() .build()
} }

View File

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.data.database.mappers package eu.kanade.tachiyomi.data.database.mappers
import android.content.ContentValues import android.content.ContentValues
import android.database.Cursor import android.database.Cursor
import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping
@ -63,4 +62,4 @@ class SearchMetadataDeleteResolver : DefaultDeleteResolver<SearchMetadata>() {
.where("$COL_MANGA_ID = ?") .where("$COL_MANGA_ID = ?")
.whereArgs(obj.mangaId) .whereArgs(obj.mangaId)
.build() .build()
} }

View File

@ -54,7 +54,6 @@ class TrackPutResolver : DefaultPutResolver<Track>() {
put(COL_STATUS, obj.status) put(COL_STATUS, obj.status)
put(COL_TRACKING_URL, obj.tracking_url) put(COL_TRACKING_URL, obj.tracking_url)
put(COL_SCORE, obj.score) put(COL_SCORE, obj.score)
} }
} }

View File

@ -15,18 +15,18 @@ interface Category : Serializable {
var flags: Int var flags: Int
var mangaOrder:List<Long> var mangaOrder: List<Long>
var mangaSort:Char? var mangaSort: Char?
var isFirst:Boolean? var isFirst: Boolean?
var isLast:Boolean? var isLast: Boolean?
val nameLower: String val nameLower: String
get() = name.toLowerCase() get() = name.toLowerCase()
fun isAscending(): Boolean { fun isAscending(): Boolean {
return ((mangaSort?.minus('a') ?: 0) % 2) != 1 return ((mangaSort?.minus('a') ?: 0) % 2) != 1
} }
fun sortingMode(): Int? = when (mangaSort) { fun sortingMode(): Int? = when (mangaSort) {
@ -42,9 +42,9 @@ interface Category : Serializable {
fun sortRes(): Int = when (mangaSort) { fun sortRes(): Int = when (mangaSort) {
ALPHA_ASC, ALPHA_DSC -> R.string.title ALPHA_ASC, ALPHA_DSC -> R.string.title
UPDATED_ASC, UPDATED_DSC -> R.string.action_sort_latest_chapter UPDATED_ASC, UPDATED_DSC -> R.string.action_sort_latest_chapter
UNREAD_ASC, UNREAD_DSC -> R.string.action_filter_unread UNREAD_ASC, UNREAD_DSC -> R.string.action_filter_unread
LAST_READ_ASC, LAST_READ_DSC -> R.string.action_sort_last_read LAST_READ_ASC, LAST_READ_DSC -> R.string.action_sort_last_read
TOTAL_ASC, TOTAL_DSC -> R.string.action_sort_total TOTAL_ASC, TOTAL_DSC -> R.string.action_sort_total
else -> R.string.action_sort_drag_and_drop else -> R.string.action_sort_drag_and_drop
} }
@ -111,5 +111,4 @@ interface Category : Serializable {
isLast = true isLast = true
} }
} }
}
}

View File

@ -30,5 +30,4 @@ class CategoryImpl : Category {
override fun hashCode(): Int { override fun hashCode(): Int {
return name.hashCode() return name.hashCode()
} }
} }

View File

@ -39,5 +39,4 @@ class ChapterImpl : Chapter {
override fun hashCode(): Int { override fun hashCode(): Int {
return url.hashCode() return url.hashCode()
} }
}
}

View File

@ -35,7 +35,7 @@ interface History : Serializable {
* @param chapter chapter object * @param chapter chapter object
* @return history object * @return history object
*/ */
fun create(chapter: Chapter): History = HistoryImpl().apply { fun create(chapter: Chapter): History = HistoryImpl().apply {
this.chapter_id = chapter.id!! this.chapter_id = chapter.id!!
} }
} }

View File

@ -5,5 +5,4 @@ class LibraryManga : MangaImpl() {
var unread: Int = 0 var unread: Int = 0
var category: Int = 0 var category: Int = 0
}
}

View File

@ -3,9 +3,9 @@ package eu.kanade.tachiyomi.data.database.models
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import java.util.Locale
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.Locale
interface Manga : SManga { interface Manga : SManga {
@ -82,7 +82,7 @@ interface Manga : SManga {
tag.startsWith("chinese") || tag == "manhua" || tag.startsWith("chinese") || tag == "manhua" ||
tag.startsWith("english") || tag == "comic" tag.startsWith("english") || tag == "comic"
} == true || isComicSource(sourceName) || } == true || isComicSource(sourceName) ||
sourceName.contains("manhua", true) ) sourceName.contains("manhua", true))
ReaderActivity.LEFT_TO_RIGHT ReaderActivity.LEFT_TO_RIGHT
else 0 else 0
} }
@ -168,5 +168,4 @@ interface Manga : SManga {
this.source = source this.source = source
} }
} }
}
}

View File

@ -17,5 +17,4 @@ class MangaCategory {
return mc return mc
} }
} }
} }

View File

@ -5,6 +5,6 @@ package eu.kanade.tachiyomi.data.database.models
* *
* @param manga object containing manga * @param manga object containing manga
* @param chapter object containing chater * @param chapter object containing chater
* @param history object containing history * @param history object containing history
*/ */
data class MangaChapterHistory(val manga: Manga, val chapter: Chapter, val history: History) data class MangaChapterHistory(val manga: Manga, val chapter: Chapter, val history: History)

View File

@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.data.database.models
import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.DownloadProvider import eu.kanade.tachiyomi.data.download.DownloadProvider
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import uy.kohesive.injekt.injectLazy
import kotlin.collections.set import kotlin.collections.set
import uy.kohesive.injekt.injectLazy
open class MangaImpl : Manga { open class MangaImpl : Manga {
@ -47,9 +47,9 @@ open class MangaImpl : Manga {
title = if (currentTitle() != originalTitle()) { title = if (currentTitle() != originalTitle()) {
val customTitle = currentTitle() val customTitle = currentTitle()
val trueTitle = other.title val trueTitle = other.title
"${customTitle}${SManga.splitter}${trueTitle}" "${customTitle}${SManga.splitter}$trueTitle"
} else other.title } else other.title
val db:DownloadManager by injectLazy() val db: DownloadManager by injectLazy()
val provider = DownloadProvider(db.context) val provider = DownloadProvider(db.context)
provider.renameMangaFolder(oldTitle, title, source) provider.renameMangaFolder(oldTitle, title, source)
} }
@ -63,7 +63,6 @@ open class MangaImpl : Manga {
val manga = other as Manga val manga = other as Manga
return url == manga.url return url == manga.url
} }
override fun hashCode(): Int { override fun hashCode(): Int {
@ -71,7 +70,7 @@ open class MangaImpl : Manga {
} }
companion object { companion object {
private var lastCoverFetch:HashMap<Long, Long> = hashMapOf() private var lastCoverFetch: HashMap<Long, Long> = hashMapOf()
fun setLastCoverFetch(id: Long, time: Long) { fun setLastCoverFetch(id: Long, time: Long) {
lastCoverFetch[id] = time lastCoverFetch[id] = time
@ -79,5 +78,4 @@ open class MangaImpl : Manga {
fun getLastCoverFetch(id: Long) = lastCoverFetch[id] ?: 0 fun getLastCoverFetch(id: Long) = lastCoverFetch[id] ?: 0
} }
} }

View File

@ -18,4 +18,4 @@ data class SearchMetadata(
) { ) {
// Transient information attached to this piece of metadata, useful for caching // Transient information attached to this piece of metadata, useful for caching
var transientCache: Map<String, Any>? = null var transientCache: Map<String, Any>? = null
} }

View File

@ -37,5 +37,4 @@ interface Track : Serializable {
sync_id = serviceId sync_id = serviceId
} }
} }
} }

View File

@ -41,5 +41,4 @@ class TrackImpl : Track {
result = 31 * result + media_id result = 31 * result + media_id
return result return result
} }
} }

View File

@ -32,5 +32,4 @@ interface CategoryQueries : DbProvider {
fun deleteCategory(category: Category) = db.delete().`object`(category).prepare() fun deleteCategory(category: Category) = db.delete().`object`(category).prepare()
fun deleteCategories(categories: List<Category>) = db.delete().objects(categories).prepare() fun deleteCategories(categories: List<Category>) = db.delete().objects(categories).prepare()
}
}

View File

@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.data.database.resolvers.ChapterProgressPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.ChapterSourceOrderPutResolver import eu.kanade.tachiyomi.data.database.resolvers.ChapterSourceOrderPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaChapterGetResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaChapterGetResolver
import eu.kanade.tachiyomi.data.database.tables.ChapterTable import eu.kanade.tachiyomi.data.database.tables.ChapterTable
import java.util.* import java.util.Date
interface ChapterQueries : DbProvider { interface ChapterQueries : DbProvider {
@ -88,5 +88,4 @@ interface ChapterQueries : DbProvider {
.objects(chapters) .objects(chapters)
.withPutResolver(ChapterSourceOrderPutResolver()) .withPutResolver(ChapterSourceOrderPutResolver())
.prepare() .prepare()
}
}

View File

@ -8,7 +8,7 @@ import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
import eu.kanade.tachiyomi.data.database.resolvers.HistoryLastReadPutResolver import eu.kanade.tachiyomi.data.database.resolvers.HistoryLastReadPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaChapterHistoryGetResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaChapterHistoryGetResolver
import eu.kanade.tachiyomi.data.database.tables.HistoryTable import eu.kanade.tachiyomi.data.database.tables.HistoryTable
import java.util.* import java.util.Date
interface HistoryQueries : DbProvider { interface HistoryQueries : DbProvider {

View File

@ -28,5 +28,4 @@ interface MangaCategoryQueries : DbProvider {
insertMangasCategories(mangasCategories).executeAsBlocking() insertMangasCategories(mangasCategories).executeAsBlocking()
} }
} }
}
}

View File

@ -145,5 +145,5 @@ interface MangaQueries : DbProvider {
.prepare() .prepare()
fun getTotalChapterManga() = db.get().listOfObjects(Manga::class.java) fun getTotalChapterManga() = db.get().listOfObjects(Manga::class.java)
.withQuery(RawQuery.builder().query(getTotalChapterMangaQuery()).observesTables(MangaTable.TABLE).build()).prepare(); .withQuery(RawQuery.builder().query(getTotalChapterMangaQuery()).observesTables(MangaTable.TABLE).build()).prepare()
} }

View File

@ -83,7 +83,7 @@ fun getRecentMangasQuery(offset: Int = 0, search: String = "") = """
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID} ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID}
WHERE ${History.TABLE}.${History.COL_LAST_READ} > ? WHERE ${History.TABLE}.${History.COL_LAST_READ} > ?
AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID} AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%${search}%' AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%'
ORDER BY max_last_read.${History.COL_LAST_READ} DESC ORDER BY max_last_read.${History.COL_LAST_READ} DESC
LIMIT 25 OFFSET $offset LIMIT 25 OFFSET $offset
""" """
@ -109,7 +109,7 @@ fun getRecentMangasLimitQuery(limit: Int = 25, search: String = "") = """
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID} ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = max_last_read.${Chapter.COL_MANGA_ID}
WHERE ${History.TABLE}.${History.COL_LAST_READ} > ? WHERE ${History.TABLE}.${History.COL_LAST_READ} > ?
AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID} AND max_last_read.${History.COL_CHAPTER_ID} = ${History.TABLE}.${History.COL_CHAPTER_ID}
AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%${search}%' AND lower(${Manga.TABLE}.${Manga.COL_TITLE}) LIKE '%$search%'
ORDER BY max_last_read.${History.COL_LAST_READ} DESC ORDER BY max_last_read.${History.COL_LAST_READ} DESC
LIMIT $limit LIMIT $limit
""" """
@ -142,7 +142,7 @@ fun getLastReadMangaQuery() = """
ORDER BY max DESC ORDER BY max DESC
""" """
fun getTotalChapterMangaQuery()= """ fun getTotalChapterMangaQuery() = """
SELECT ${Manga.TABLE}.* SELECT ${Manga.TABLE}.*
FROM ${Manga.TABLE} FROM ${Manga.TABLE}
JOIN ${Chapter.TABLE} JOIN ${Chapter.TABLE}
@ -159,4 +159,4 @@ fun getCategoriesForMangaQuery() = """
JOIN ${MangaCategory.TABLE} ON ${Category.TABLE}.${Category.COL_ID} = JOIN ${MangaCategory.TABLE} ON ${Category.TABLE}.${Category.COL_ID} =
${MangaCategory.TABLE}.${MangaCategory.COL_CATEGORY_ID} ${MangaCategory.TABLE}.${MangaCategory.COL_CATEGORY_ID}
WHERE ${MangaCategory.COL_MANGA_ID} = ? WHERE ${MangaCategory.COL_MANGA_ID} = ?
""" """

View File

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.data.database.queries package eu.kanade.tachiyomi.data.database.queries
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
import com.pushtorefresh.storio.sqlite.queries.Query import com.pushtorefresh.storio.sqlite.queries.Query
import eu.kanade.tachiyomi.data.database.DbProvider import eu.kanade.tachiyomi.data.database.DbProvider
@ -42,4 +41,4 @@ interface SearchMetadataQueries : DbProvider {
.table(SearchMetadataTable.TABLE) .table(SearchMetadataTable.TABLE)
.build()) .build())
.prepare() .prepare()
} }

View File

@ -30,5 +30,4 @@ interface TrackQueries : DbProvider {
.whereArgs(manga.id, sync.id) .whereArgs(manga.id, sync.id)
.build()) .build())
.prepare() .prepare()
}
}

View File

@ -30,6 +30,4 @@ class ChapterBackupPutResolver : PutResolver<Chapter>() {
put(ChapterTable.COL_BOOKMARK, chapter.bookmark) put(ChapterTable.COL_BOOKMARK, chapter.bookmark)
put(ChapterTable.COL_LAST_PAGE_READ, chapter.last_page_read) put(ChapterTable.COL_LAST_PAGE_READ, chapter.last_page_read)
} }
} }

View File

@ -31,6 +31,4 @@ class ChapterProgressPutResolver : PutResolver<Chapter>() {
put(ChapterTable.COL_LAST_PAGE_READ, chapter.last_page_read) put(ChapterTable.COL_LAST_PAGE_READ, chapter.last_page_read)
put(ChapterTable.COL_PAGES_LEFT, chapter.pages_left) put(ChapterTable.COL_PAGES_LEFT, chapter.pages_left)
} }
} }

View File

@ -28,5 +28,4 @@ class ChapterSourceOrderPutResolver : PutResolver<Chapter>() {
fun mapToContentValues(chapter: Chapter) = ContentValues(1).apply { fun mapToContentValues(chapter: Chapter) = ContentValues(1).apply {
put(ChapterTable.COL_SOURCE_ORDER, chapter.source_order) put(ChapterTable.COL_SOURCE_ORDER, chapter.source_order)
} }
}
}

View File

@ -60,5 +60,4 @@ class HistoryLastReadPutResolver : HistoryPutResolver() {
fun mapToUpdateContentValues(history: History) = ContentValues(1).apply { fun mapToUpdateContentValues(history: History) = ContentValues(1).apply {
put(HistoryTable.COL_LAST_READ, history.last_read) put(HistoryTable.COL_LAST_READ, history.last_read)
} }
} }

View File

@ -21,5 +21,4 @@ class LibraryMangaGetResolver : DefaultGetResolver<LibraryManga>(), BaseMangaGet
return manga return manga
} }
} }

View File

@ -24,5 +24,4 @@ class MangaChapterGetResolver : DefaultGetResolver<MangaChapter>() {
return MangaChapter(manga, chapter) return MangaChapter(manga, chapter)
} }
} }

View File

@ -28,6 +28,4 @@ class MangaFavoritePutResolver : PutResolver<Manga>() {
fun mapToContentValues(manga: Manga) = ContentValues(1).apply { fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
put(MangaTable.COL_FAVORITE, manga.favorite) put(MangaTable.COL_FAVORITE, manga.favorite)
} }
} }

View File

@ -28,6 +28,4 @@ class MangaFlagsPutResolver : PutResolver<Manga>() {
fun mapToContentValues(manga: Manga) = ContentValues(1).apply { fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
put(MangaTable.COL_CHAPTER_FLAGS, manga.chapter_flags) put(MangaTable.COL_CHAPTER_FLAGS, manga.chapter_flags)
} }
} }

View File

@ -6,7 +6,6 @@ import com.pushtorefresh.storio.sqlite.operations.put.PutResolver
import com.pushtorefresh.storio.sqlite.operations.put.PutResult import com.pushtorefresh.storio.sqlite.operations.put.PutResult
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
import eu.kanade.tachiyomi.data.database.inTransactionReturn import eu.kanade.tachiyomi.data.database.inTransactionReturn
import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.tables.MangaTable import eu.kanade.tachiyomi.data.database.tables.MangaTable
@ -29,5 +28,4 @@ class MangaHideTitlePutResolver : PutResolver<Manga>() {
fun mapToContentValues(manga: Manga) = ContentValues(1).apply { fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
put(MangaTable.COL_HIDE_TITLE, manga.hide_title) put(MangaTable.COL_HIDE_TITLE, manga.hide_title)
} }
} }

View File

@ -9,7 +9,7 @@ import eu.kanade.tachiyomi.data.database.inTransactionReturn
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.tables.MangaTable import eu.kanade.tachiyomi.data.database.tables.MangaTable
class MangaInfoPutResolver(val reset:Boolean = false): PutResolver<Manga>() { class MangaInfoPutResolver(val reset: Boolean = false) : PutResolver<Manga>() {
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn { override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
val updateQuery = mapToUpdateQuery(manga) val updateQuery = mapToUpdateQuery(manga)
@ -40,6 +40,4 @@ class MangaInfoPutResolver(val reset:Boolean = false): PutResolver<Manga>() {
put(MangaTable.COL_ARTIST, manga.originalArtist()) put(MangaTable.COL_ARTIST, manga.originalArtist())
put(MangaTable.COL_DESCRIPTION, manga.originalDesc()) put(MangaTable.COL_DESCRIPTION, manga.originalDesc())
} }
}
}

View File

@ -28,6 +28,4 @@ class MangaLastUpdatedPutResolver : PutResolver<Manga>() {
fun mapToContentValues(manga: Manga) = ContentValues(1).apply { fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
put(MangaTable.COL_LAST_UPDATE, manga.last_update) put(MangaTable.COL_LAST_UPDATE, manga.last_update)
} }
} }

View File

@ -28,5 +28,4 @@ class MangaTitlePutResolver : PutResolver<Manga>() {
fun mapToContentValues(manga: Manga) = ContentValues(1).apply { fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
put(MangaTable.COL_TITLE, manga.title) put(MangaTable.COL_TITLE, manga.title)
} }
} }

View File

@ -28,5 +28,4 @@ class MangaViewerPutResolver : PutResolver<Manga>() {
fun mapToContentValues(manga: Manga) = ContentValues(1).apply { fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
put(MangaTable.COL_VIEWER, manga.viewer) put(MangaTable.COL_VIEWER, manga.viewer)
} }
} }

View File

@ -23,7 +23,6 @@ object CategoryTable {
$COL_MANGA_ORDER TEXT NOT NULL $COL_MANGA_ORDER TEXT NOT NULL
)""" )"""
val addMangaOrder: String val addMangaOrder: String
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_MANGA_ORDER TEXT" get() = "ALTER TABLE $TABLE ADD COLUMN $COL_MANGA_ORDER TEXT"
} }

View File

@ -67,5 +67,4 @@ object ChapterTable {
val pagesLeftQuery: String val pagesLeftQuery: String
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_PAGES_LEFT INTEGER DEFAULT 0" get() = "ALTER TABLE $TABLE ADD COLUMN $COL_PAGES_LEFT INTEGER DEFAULT 0"
} }

View File

@ -20,5 +20,4 @@ object MangaCategoryTable {
FOREIGN KEY($COL_MANGA_ID) REFERENCES ${MangaTable.TABLE} (${MangaTable.COL_ID}) FOREIGN KEY($COL_MANGA_ID) REFERENCES ${MangaTable.TABLE} (${MangaTable.COL_ID})
ON DELETE CASCADE ON DELETE CASCADE
)""" )"""
} }

View File

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.data.database.tables package eu.kanade.tachiyomi.data.database.tables
object SearchMetadataTable { object SearchMetadataTable {
const val TABLE = "search_metadata" const val TABLE = "search_metadata"

View File

@ -10,10 +10,10 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.DiskUtil
import java.util.concurrent.TimeUnit
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.concurrent.TimeUnit
/** /**
* Cache where we dump the downloads directory from the filesystem. This class is needed because * Cache where we dump the downloads directory from the filesystem. This class is needed because
@ -27,10 +27,10 @@ import java.util.concurrent.TimeUnit
* @param preferences the preferences of the app. * @param preferences the preferences of the app.
*/ */
class DownloadCache( class DownloadCache(
private val context: Context, private val context: Context,
private val provider: DownloadProvider, private val provider: DownloadProvider,
private val sourceManager: SourceManager, private val sourceManager: SourceManager,
private val preferences: PreferencesHelper = Injekt.get() private val preferences: PreferencesHelper = Injekt.get()
) { ) {
/** /**
@ -119,7 +119,7 @@ class DownloadCache(
onlineSources.find { provider.getSourceDirName(it) == entry.key }?.id onlineSources.find { provider.getSourceDirName(it) == entry.key }?.id
} }
val db:DatabaseHelper by injectLazy() val db: DatabaseHelper by injectLazy()
val mangas = db.getMangas().executeAsBlocking().groupBy { it.source } val mangas = db.getMangas().executeAsBlocking().groupBy { it.source }
sourceDirs.forEach { sourceValue -> sourceDirs.forEach { sourceValue ->
@ -143,8 +143,8 @@ class DownloadCache(
val trueMangaDirs = mangaDirs.mapNotNull { mangaDir -> val trueMangaDirs = mangaDirs.mapNotNull { mangaDir ->
val manga = sourceMangas.firstOrNull()?.find { DiskUtil.buildValidFilename( val manga = sourceMangas.firstOrNull()?.find { DiskUtil.buildValidFilename(
it.originalTitle()).toLowerCase() == mangaDir.key it.originalTitle()).toLowerCase() == mangaDir.key
.toLowerCase() && it.source == sourceValue.key } ?: .toLowerCase() && it.source == sourceValue.key }
sourceMangas.lastOrNull()?.find { DiskUtil.buildValidFilename( ?: sourceMangas.lastOrNull()?.find { DiskUtil.buildValidFilename(
it.originalTitle()).toLowerCase() == mangaDir.key it.originalTitle()).toLowerCase() == mangaDir.key
.toLowerCase() && it.source == sourceValue.key } .toLowerCase() && it.source == sourceValue.key }
val id = manga?.id ?: return@mapNotNull null val id = manga?.id ?: return@mapNotNull null
@ -169,8 +169,7 @@ class DownloadCache(
val files = mangaFiles[id] val files = mangaFiles[id]
if (files == null) { if (files == null) {
mangaFiles[id] = mutableSetOf(chapterDirName) mangaFiles[id] = mutableSetOf(chapterDirName)
} } else {
else {
mangaFiles[id]?.add(chapterDirName) mangaFiles[id]?.add(chapterDirName)
} }
} }
@ -216,7 +215,6 @@ class DownloadCache(
sourceDir.files = list sourceDir.files = list
}*/ }*/
/** /**
* Removes a manga that has been deleted from this cache. * Removes a manga that has been deleted from this cache.
* *
@ -230,20 +228,26 @@ class DownloadCache(
/** /**
* Class to store the files under the root downloads directory. * Class to store the files under the root downloads directory.
*/ */
private class RootDirectory(val dir: UniFile, private class RootDirectory(
var files: Map<Long, SourceDirectory> = hashMapOf()) val dir: UniFile,
var files: Map<Long, SourceDirectory> = hashMapOf()
)
/** /**
* Class to store the files under a source directory. * Class to store the files under a source directory.
*/ */
private class SourceDirectory(val dir: UniFile, private class SourceDirectory(
var files: Map<Long, MutableSet<String>> = hashMapOf()) val dir: UniFile,
var files: Map<Long, MutableSet<String>> = hashMapOf()
)
/** /**
* Class to store the files under a manga directory. * Class to store the files under a manga directory.
*/ */
private class MangaDirectory(val dir: UniFile, private class MangaDirectory(
var files: MutableSet<String> = hashSetOf()) val dir: UniFile,
var files: MutableSet<String> = hashSetOf()
)
/** /**
* Returns a new map containing only the key entries of [transform] that are not null. * Returns a new map containing only the key entries of [transform] that are not null.
@ -267,5 +271,4 @@ class DownloadCache(
} }
return destination return destination
} }
} }

View File

@ -114,7 +114,7 @@ class DownloadManager(val context: Context) {
downloader.pause() downloader.pause()
downloader.queue.clear() downloader.queue.clear()
downloader.queue.addAll(downloads) downloader.queue.addAll(downloads)
if(!wasPaused){ if (!wasPaused) {
downloader.start() downloader.start()
} }
} }
@ -221,10 +221,9 @@ class DownloadManager(val context: Context) {
} }
downloader.pause() downloader.pause()
downloader.queue.remove(chapters) downloader.queue.remove(chapters)
if(!wasPaused && downloader.queue.isNotEmpty()){ if (!wasPaused && downloader.queue.isNotEmpty()) {
downloader.start() downloader.start()
} } else if (downloader.queue.isEmpty() && DownloadService.isRunning(context)) {
else if (downloader.queue.isEmpty() && DownloadService.isRunning(context)) {
DownloadService.stop(context) DownloadService.stop(context)
} }
queue.remove(chapters) queue.remove(chapters)
@ -255,7 +254,7 @@ class DownloadManager(val context: Context) {
cleaned += readChapterDirs.size cleaned += readChapterDirs.size
cache.removeChapters(readChapters, manga) cache.removeChapters(readChapters, manga)
if (cache.getDownloadCount(manga) == 0) { if (cache.getDownloadCount(manga) == 0) {
provider.findChapterDirs(allChapters, manga, source).firstOrNull()?.parentFile?.delete()// Delete manga directory if empty provider.findChapterDirs(allChapters, manga, source).firstOrNull()?.parentFile?.delete() // Delete manga directory if empty
} }
return cleaned return cleaned
} }
@ -295,5 +294,5 @@ class DownloadManager(val context: Context) {
} }
fun addListener(listener: DownloadQueue.DownloadListener) = queue.addListener(listener) fun addListener(listener: DownloadQueue.DownloadListener) = queue.addListener(listener)
fun removeListener(listener: DownloadQueue.DownloadListener) = queue.removeListener(listener) fun removeListener(listener: DownloadQueue.DownloadListener) = queue.removeListener(listener)
} }

View File

@ -6,7 +6,6 @@ import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.download.model.DownloadQueue
import eu.kanade.tachiyomi.data.notification.NotificationHandler import eu.kanade.tachiyomi.data.notification.NotificationHandler
import eu.kanade.tachiyomi.data.notification.NotificationReceiver import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.notification.Notifications import eu.kanade.tachiyomi.data.notification.Notifications
@ -93,8 +92,7 @@ internal class DownloadNotifier(private val context: Context) {
setContentText( setContentText(
context.getString(R.string.chapter_downloading) context.getString(R.string.chapter_downloading)
) )
} } else {
else {
setContentTitle( setContentTitle(
context.getString( context.getString(
R.string.chapter_downloading R.string.chapter_downloading
@ -102,12 +100,11 @@ internal class DownloadNotifier(private val context: Context) {
) )
setContentText(null) setContentText(null)
} }
setProgress(0,0, true) setProgress(0, 0, true)
setStyle(null) setStyle(null)
} }
// Displays the progress bar on notification // Displays the progress bar on notification
notification.show() notification.show()
} }
/** /**
@ -164,7 +161,7 @@ internal class DownloadNotifier(private val context: Context) {
context.getString(R.string.action_resume), context.getString(R.string.action_resume),
NotificationReceiver.resumeDownloadsPendingBroadcast(context) NotificationReceiver.resumeDownloadsPendingBroadcast(context)
) )
//Clear action // Clear action
addAction( addAction(
R.drawable.ic_clear_grey_24dp_img, R.drawable.ic_clear_grey_24dp_img,
context.getString(R.string.action_cancel_all), context.getString(R.string.action_cancel_all),

View File

@ -136,28 +136,28 @@ class DownloadPendingDeleter(context: Context) {
* Class used to save an entry of chapters with their manga into preferences. * Class used to save an entry of chapters with their manga into preferences.
*/ */
private data class Entry( private data class Entry(
val chapters: List<ChapterEntry>, val chapters: List<ChapterEntry>,
val manga: MangaEntry val manga: MangaEntry
) )
/** /**
* Class used to save an entry for a chapter into preferences. * Class used to save an entry for a chapter into preferences.
*/ */
private data class ChapterEntry( private data class ChapterEntry(
val id: Long, val id: Long,
val url: String, val url: String,
val name: String, val name: String,
val scanlator: String? val scanlator: String?
) )
/** /**
* Class used to save an entry for a manga into preferences. * Class used to save an entry for a manga into preferences.
*/ */
private data class MangaEntry( private data class MangaEntry(
val id: Long, val id: Long,
val url: String, val url: String,
val title: String, val title: String,
val source: Long val source: Long
) )
/** /**
@ -194,5 +194,4 @@ class DownloadPendingDeleter(context: Context) {
it.name = name it.name = name
} }
} }
} }

View File

@ -37,9 +37,8 @@ class DownloadProvider(private val context: Context) {
} }
init { init {
preferences.downloadsDirectory().asObservable() preferences.downloadsDirectory().asObservable().skip(1)
.skip(1) .subscribe { downloadsDir = UniFile.fromUri(context, Uri.parse(it)) }
.subscribe { downloadsDir = UniFile.fromUri(context, Uri.parse(it)) }
} }
/** /**
@ -50,9 +49,8 @@ class DownloadProvider(private val context: Context) {
*/ */
internal fun getMangaDir(manga: Manga, source: Source): UniFile { internal fun getMangaDir(manga: Manga, source: Source): UniFile {
try { try {
return downloadsDir return downloadsDir.createDirectory(getSourceDirName(source))
.createDirectory(getSourceDirName(source)) .createDirectory(getMangaDirName(manga))
.createDirectory(getMangaDirName(manga))
} catch (e: NullPointerException) { } catch (e: NullPointerException) {
throw Exception(context.getString(R.string.invalid_download_dir)) throw Exception(context.getString(R.string.invalid_download_dir))
} }
@ -136,8 +134,6 @@ class DownloadProvider(private val context: Context) {
val sourceDir = findSourceDir(source) val sourceDir = findSourceDir(source)
val mangaDir = sourceDir?.findFile(DiskUtil.buildValidFilename(from)) val mangaDir = sourceDir?.findFile(DiskUtil.buildValidFilename(from))
mangaDir?.renameTo(to) mangaDir?.renameTo(to)
// val downloadManager:DownloadManager by injectLazy()
// downloadManager.renameCache(from, to, sourceId)
} }
/** /**
@ -147,7 +143,11 @@ class DownloadProvider(private val context: Context) {
* @param manga the manga of the chapter. * @param manga the manga of the chapter.
* @param source the source of the chapter. * @param source the source of the chapter.
*/ */
fun findUnmatchedChapterDirs(chapters: List<Chapter>, manga: Manga, source: Source): List<UniFile> { fun findUnmatchedChapterDirs(
chapters: List<Chapter>,
manga: Manga,
source: Source
): List<UniFile> {
val mangaDir = findMangaDir(manga, source) ?: return emptyList() val mangaDir = findMangaDir(manga, source) ?: return emptyList()
return mangaDir.listFiles()!!.asList().filter { return mangaDir.listFiles()!!.asList().filter {
(chapters.find { chp -> (chapters.find { chp ->
@ -170,7 +170,6 @@ class DownloadProvider(private val context: Context) {
return chapters.mapNotNull { mangaDir.findFile("${getChapterDirName(it)}_tmp") } return chapters.mapNotNull { mangaDir.findFile("${getChapterDirName(it)}_tmp") }
} }
/** /**
* Returns the download directory name for a source. * Returns the download directory name for a source.
* *
@ -213,5 +212,4 @@ class DownloadProvider(private val context: Context) {
DiskUtil.buildValidFilename(chapter.name) DiskUtil.buildValidFilename(chapter.name)
) )
} }
} }

View File

@ -221,7 +221,6 @@ class DownloadService : Service() {
.setContentTitle(getString(R.string.download_notifier_downloader_title)) .setContentTitle(getString(R.string.download_notifier_downloader_title))
.build() .build()
} }
} }
interface DownloadServiceListener { interface DownloadServiceListener {

View File

@ -15,8 +15,8 @@ import uy.kohesive.injekt.injectLazy
* @param context the application context. * @param context the application context.
*/ */
class DownloadStore( class DownloadStore(
context: Context, context: Context,
private val sourceManager: SourceManager private val sourceManager: SourceManager
) { ) {
/** /**
@ -133,5 +133,4 @@ class DownloadStore(
* @param order the order of the download in the queue. * @param order the order of the download in the queue.
*/ */
data class DownloadObject(val mangaId: Long, val chapterId: Long, val order: Int) data class DownloadObject(val mangaId: Long, val chapterId: Long, val order: Int)
} }

View File

@ -21,6 +21,7 @@ import eu.kanade.tachiyomi.util.storage.saveTo
import eu.kanade.tachiyomi.util.system.ImageUtil import eu.kanade.tachiyomi.util.system.ImageUtil
import eu.kanade.tachiyomi.util.system.launchNow import eu.kanade.tachiyomi.util.system.launchNow
import eu.kanade.tachiyomi.util.system.launchUI import eu.kanade.tachiyomi.util.system.launchUI
import java.io.File
import kotlinx.coroutines.async import kotlinx.coroutines.async
import okhttp3.Response import okhttp3.Response
import rx.Observable import rx.Observable
@ -28,7 +29,6 @@ import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers import rx.schedulers.Schedulers
import rx.subscriptions.CompositeSubscription import rx.subscriptions.CompositeSubscription
import timber.log.Timber import timber.log.Timber
import java.io.File
/** /**
* This class is the one in charge of downloading chapters. * This class is the one in charge of downloading chapters.
@ -45,10 +45,10 @@ import java.io.File
* @param sourceManager the source manager. * @param sourceManager the source manager.
*/ */
class Downloader( class Downloader(
private val context: Context, private val context: Context,
private val provider: DownloadProvider, private val provider: DownloadProvider,
private val cache: DownloadCache, private val cache: DownloadCache,
private val sourceManager: SourceManager private val sourceManager: SourceManager
) { ) {
/** /**
@ -129,12 +129,11 @@ class Downloader(
if (notifier.paused) { if (notifier.paused) {
if (queue.isEmpty()) { if (queue.isEmpty()) {
notifier.dismiss() notifier.dismiss()
} } else {
else {
notifier.paused = false notifier.paused = false
notifier.onDownloadPaused() notifier.onDownloadPaused()
} }
}else { } else {
notifier.dismiss() notifier.dismiss()
} }
} }
@ -164,7 +163,7 @@ class Downloader(
fun clearQueue(isNotification: Boolean = false) { fun clearQueue(isNotification: Boolean = false) {
destroySubscriptions() destroySubscriptions()
//Needed to update the chapter view // Needed to update the chapter view
if (isNotification) { if (isNotification) {
queue queue
.filter { it.status == Download.QUEUE } .filter { it.status == Download.QUEUE }
@ -180,7 +179,7 @@ class Downloader(
* @param isNotification value that determines if status is set (needed for view updates) * @param isNotification value that determines if status is set (needed for view updates)
*/ */
fun clearQueue(manga: Manga, isNotification: Boolean = false) { fun clearQueue(manga: Manga, isNotification: Boolean = false) {
//Needed to update the chapter view // Needed to update the chapter view
if (isNotification) { if (isNotification) {
queue queue
.filter { it.status == Download.QUEUE && it.manga.id == manga.id } .filter { it.status == Download.QUEUE && it.manga.id == manga.id }
@ -318,7 +317,6 @@ class Downloader(
notifier.onError(error.message, download.chapter.name) notifier.onError(error.message, download.chapter.name)
download download
} }
} }
/** /**
@ -448,8 +446,12 @@ class Downloader(
* @param tmpDir the directory where the download is currently stored. * @param tmpDir the directory where the download is currently stored.
* @param dirname the real (non temporary) directory name of the download. * @param dirname the real (non temporary) directory name of the download.
*/ */
private fun ensureSuccessfulDownload(download: Download, mangaDir: UniFile, private fun ensureSuccessfulDownload(
tmpDir: UniFile, dirname: String) { download: Download,
mangaDir: UniFile,
tmpDir: UniFile,
dirname: String
) {
// Ensure that the chapter folder has all the images. // Ensure that the chapter folder has all the images.
val downloadedImages = tmpDir.listFiles().orEmpty().filterNot { it.name!!.endsWith(".tmp") } val downloadedImages = tmpDir.listFiles().orEmpty().filterNot { it.name!!.endsWith(".tmp") }
@ -497,5 +499,4 @@ class Downloader(
companion object { companion object {
const val TMP_DIR_SUFFIX = "_tmp" const val TMP_DIR_SUFFIX = "_tmp"
} }
} }

View File

@ -47,4 +47,4 @@ class Download(val source: HttpSource, val manga: Manga, val chapter: Chapter) {
const val DOWNLOADED = 3 const val DOWNLOADED = 3
const val ERROR = 4 const val ERROR = 4
} }
} }

View File

@ -5,14 +5,15 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.download.DownloadStore import eu.kanade.tachiyomi.data.download.DownloadStore
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import java.util.concurrent.CopyOnWriteArrayList
import rx.Observable import rx.Observable
import rx.subjects.PublishSubject import rx.subjects.PublishSubject
import java.util.concurrent.CopyOnWriteArrayList
class DownloadQueue( class DownloadQueue(
private val store: DownloadStore, private val store: DownloadStore,
private val queue: MutableList<Download> = CopyOnWriteArrayList<Download>()) private val queue: MutableList<Download> = CopyOnWriteArrayList<Download>()
: List<Download> by queue { ) :
List<Download> by queue {
private val statusSubject = PublishSubject.create<Download>() private val statusSubject = PublishSubject.create<Download>()
@ -89,8 +90,7 @@ class DownloadQueue(
} else if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) { } else if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) {
setPagesSubject(download.pages, null) setPagesSubject(download.pages, null)
downloadListeners.forEach { it.updateDownload(download) } downloadListeners.forEach { it.updateDownload(download) }
} } else {
else {
downloadListeners.forEach { it.updateDownload(download) } downloadListeners.forEach { it.updateDownload(download) }
} }
} }
@ -111,7 +111,6 @@ class DownloadQueue(
.onBackpressureBuffer() .onBackpressureBuffer()
.filter { it == Page.READY } .filter { it == Page.READY }
.map { download } .map { download }
} else if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) { } else if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) {
setPagesSubject(download.pages, null) setPagesSubject(download.pages, null)
downloadListeners.forEach { it.updateDownload(download) } downloadListeners.forEach { it.updateDownload(download) }
@ -140,5 +139,4 @@ class DownloadQueue(
interface DownloadListener { interface DownloadListener {
fun updateDownload(download: Download) fun updateDownload(download: Download)
} }
}
}

View File

@ -5,7 +5,11 @@ import android.util.Log
import com.bumptech.glide.Priority import com.bumptech.glide.Priority
import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.data.DataFetcher import com.bumptech.glide.load.data.DataFetcher
import java.io.* import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.IOException
import java.io.InputStream
open class FileFetcher(private val file: File) : DataFetcher<InputStream> { open class FileFetcher(private val file: File) : DataFetcher<InputStream> {
@ -48,4 +52,4 @@ open class FileFetcher(private val file: File) : DataFetcher<InputStream> {
override fun getDataSource(): DataSource { override fun getDataSource(): DataSource {
return DataSource.LOCAL return DataSource.LOCAL
} }
} }

View File

@ -16,10 +16,12 @@ import java.io.InputStream
* @param manga the manga of the cover to load. * @param manga the manga of the cover to load.
* @param file the file where this cover should be. It may exists or not. * @param file the file where this cover should be. It may exists or not.
*/ */
class LibraryMangaUrlFetcher(private val networkFetcher: DataFetcher<InputStream>, class LibraryMangaUrlFetcher(
private val manga: Manga, private val networkFetcher: DataFetcher<InputStream>,
private val file: File) private val manga: Manga,
: FileFetcher(file) { private val file: File
) :
FileFetcher(file) {
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) { override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
if (!file.exists()) { if (!file.exists()) {
@ -52,7 +54,6 @@ class LibraryMangaUrlFetcher(private val networkFetcher: DataFetcher<InputStream
override fun onLoadFailed(e: Exception) { override fun onLoadFailed(e: Exception) {
callback.onLoadFailed(e) callback.onLoadFailed(e)
} }
}) })
} else { } else {
loadFromFile(callback) loadFromFile(callback)
@ -68,5 +69,4 @@ class LibraryMangaUrlFetcher(private val networkFetcher: DataFetcher<InputStream
super.cancel() super.cancel()
networkFetcher.cancel() networkFetcher.cancel()
} }
}
}

View File

@ -3,18 +3,22 @@ package eu.kanade.tachiyomi.data.glide
import android.util.LruCache import android.util.LruCache
import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher
import com.bumptech.glide.load.Options import com.bumptech.glide.load.Options
import com.bumptech.glide.load.model.* import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.load.model.Headers
import com.bumptech.glide.load.model.LazyHeaders
import com.bumptech.glide.load.model.ModelLoader
import com.bumptech.glide.load.model.ModelLoaderFactory
import com.bumptech.glide.load.model.MultiModelLoaderFactory
import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import java.io.File
import java.io.InputStream
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.File
import java.io.InputStream
/** /**
* A class for loading a cover associated with a [Manga] that can be present in our own cache. * A class for loading a cover associated with a [Manga] that can be present in our own cache.
@ -78,8 +82,12 @@ class MangaModelLoader : ModelLoader<Manga, InputStream> {
* @param width the width of the view where the resource will be loaded. * @param width the width of the view where the resource will be loaded.
* @param height the height of the view where the resource will be loaded. * @param height the height of the view where the resource will be loaded.
*/ */
override fun buildLoadData(manga: Manga, width: Int, height: Int, override fun buildLoadData(
options: Options): ModelLoader.LoadData<InputStream>? { manga: Manga,
width: Int,
height: Int,
options: Options
): ModelLoader.LoadData<InputStream>? {
// Check thumbnail is not null or empty // Check thumbnail is not null or empty
val url = manga.thumbnail_url val url = manga.thumbnail_url
if (url == null || url.isEmpty()) { if (url == null || url.isEmpty()) {
@ -142,5 +150,4 @@ class MangaModelLoader : ModelLoader<Manga, InputStream> {
value value
} }
} }
} }

View File

@ -24,4 +24,4 @@ class MangaSignature(manga: Manga, file: File) : Key {
override fun updateDiskCacheKey(md: MessageDigest) { override fun updateDiskCacheKey(md: MessageDigest) {
md.update(key.toByteArray(Key.CHARSET)) md.update(key.toByteArray(Key.CHARSET))
} }
} }

View File

@ -14,10 +14,10 @@ import java.io.InputStream
class PassthroughModelLoader : ModelLoader<InputStream, InputStream> { class PassthroughModelLoader : ModelLoader<InputStream, InputStream> {
override fun buildLoadData( override fun buildLoadData(
model: InputStream, model: InputStream,
width: Int, width: Int,
height: Int, height: Int,
options: Options options: Options
): ModelLoader.LoadData<InputStream>? { ): ModelLoader.LoadData<InputStream>? {
return ModelLoader.LoadData(ObjectKey(model), Fetcher(model)) return ModelLoader.LoadData(ObjectKey(model), Fetcher(model))
} }
@ -49,12 +49,11 @@ class PassthroughModelLoader : ModelLoader<InputStream, InputStream> {
} }
override fun loadData( override fun loadData(
priority: Priority, priority: Priority,
callback: DataFetcher.DataCallback<in InputStream> callback: DataFetcher.DataCallback<in InputStream>
) { ) {
callback.onDataReady(stream) callback.onDataReady(stream)
} }
} }
/** /**
@ -63,12 +62,11 @@ class PassthroughModelLoader : ModelLoader<InputStream, InputStream> {
class Factory : ModelLoaderFactory<InputStream, InputStream> { class Factory : ModelLoaderFactory<InputStream, InputStream> {
override fun build( override fun build(
multiFactory: MultiModelLoaderFactory multiFactory: MultiModelLoaderFactory
): ModelLoader<InputStream, InputStream> { ): ModelLoader<InputStream, InputStream> {
return PassthroughModelLoader() return PassthroughModelLoader()
} }
override fun teardown() {} override fun teardown() {}
} }
} }

View File

@ -13,9 +13,9 @@ import com.bumptech.glide.module.AppGlideModule
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import java.io.InputStream
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.InputStream
/** /**
* Class used to update Glide module settings * Class used to update Glide module settings
@ -26,8 +26,8 @@ class TachiGlideModule : AppGlideModule() {
override fun applyOptions(context: Context, builder: GlideBuilder) { override fun applyOptions(context: Context, builder: GlideBuilder) {
builder.setDiskCache(InternalCacheDiskCacheFactory(context, 50 * 1024 * 1024)) builder.setDiskCache(InternalCacheDiskCacheFactory(context, 50 * 1024 * 1024))
builder.setDefaultRequestOptions(RequestOptions().format(DecodeFormat.PREFER_RGB_565)) builder.setDefaultRequestOptions(RequestOptions().format(DecodeFormat.PREFER_RGB_565))
//val memoryCacheSizeBytes = 1024 * 1024 * 100 // 100mb // val memoryCacheSizeBytes = 1024 * 1024 * 100 // 100mb
//builder.setMemoryCache(LruResourceCache(memoryCacheSizeBytes.toLong())) // builder.setMemoryCache(LruResourceCache(memoryCacheSizeBytes.toLong()))
/* builder.setDefaultTransitionOptions( /* builder.setDefaultTransitionOptions(
Drawable::class.java, Drawable::class.java,

View File

@ -5,9 +5,9 @@ import com.evernote.android.job.JobManager
import com.evernote.android.job.JobRequest import com.evernote.android.job.JobRequest
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import java.util.concurrent.TimeUnit
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.concurrent.TimeUnit
class LibraryUpdateJob : Job() { class LibraryUpdateJob : Job() {

View File

@ -39,5 +39,4 @@ object LibraryUpdateRanker {
compareValues(mangaFirst.currentTitle(), mangaSecond.currentTitle()) compareValues(mangaFirst.currentTitle(), mangaSecond.currentTitle())
} }
} }
}
}

View File

@ -38,6 +38,10 @@ import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
import eu.kanade.tachiyomi.util.lang.chop import eu.kanade.tachiyomi.util.lang.chop
import eu.kanade.tachiyomi.util.system.notification import eu.kanade.tachiyomi.util.system.notification
import eu.kanade.tachiyomi.util.system.notificationManager import eu.kanade.tachiyomi.util.system.notificationManager
import java.util.ArrayList
import java.util.Date
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
@ -50,10 +54,6 @@ import rx.schedulers.Schedulers
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.ArrayList
import java.util.Date
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
/** /**
* This class will take care of updating the chapters of the manga from the library. It can be * This class will take care of updating the chapters of the manga from the library. It can be
@ -127,8 +127,8 @@ class LibraryUpdateService(
*/ */
enum class Target { enum class Target {
CHAPTERS, // Manga chapters CHAPTERS, // Manga chapters
DETAILS, // Manga metadata DETAILS, // Manga metadata
TRACKING // Tracking metadata TRACKING // Tracking metadata
} }
companion object { companion object {

View File

@ -10,6 +10,7 @@ import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Handler import android.os.Handler
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.BackupRestoreService import eu.kanade.tachiyomi.data.backup.BackupRestoreService
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
@ -27,12 +28,10 @@ import eu.kanade.tachiyomi.util.storage.DiskUtil
import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.notificationManager import eu.kanade.tachiyomi.util.system.notificationManager
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import java.io.File
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.File
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
/** /**
* Global [BroadcastReceiver] that runs on UI thread * Global [BroadcastReceiver] that runs on UI thread
@ -113,7 +112,6 @@ class NotificationReceiver : BroadcastReceiver() {
type = "image/*" type = "image/*"
} }
// Close Navigation Shade // Close Navigation Shade
} }
/** /**
@ -217,7 +215,6 @@ class NotificationReceiver : BroadcastReceiver() {
// Called to cancel restore // Called to cancel restore
private const val ACTION_CANCEL_RESTORE = "$ID.$NAME.CANCEL_RESTORE" private const val ACTION_CANCEL_RESTORE = "$ID.$NAME.CANCEL_RESTORE"
// Called to open chapter // Called to open chapter
private const val ACTION_OPEN_CHAPTER = "$ID.$NAME.ACTION_OPEN_CHAPTER" private const val ACTION_OPEN_CHAPTER = "$ID.$NAME.ACTION_OPEN_CHAPTER"
@ -322,8 +319,12 @@ class NotificationReceiver : BroadcastReceiver() {
* @param notificationId id of notification * @param notificationId id of notification
* @return [PendingIntent] * @return [PendingIntent]
*/ */
internal fun dismissNotification(context: Context, notificationId: Int, groupId: Int? = internal fun dismissNotification(
null) { context: Context,
notificationId: Int,
groupId: Int? =
null
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val groupKey = context.notificationManager.activeNotifications.find { val groupKey = context.notificationManager.activeNotifications.find {
it.id == notificationId it.id == notificationId
@ -350,7 +351,7 @@ class NotificationReceiver : BroadcastReceiver() {
* @return [PendingIntent] * @return [PendingIntent]
*/ */
internal fun shareImagePendingBroadcast(context: Context, path: String, notificationId: Int): PendingIntent { internal fun shareImagePendingBroadcast(context: Context, path: String, notificationId: Int): PendingIntent {
//val shareIntent = ShareStartingActivity.newIntent(context, path) // val shareIntent = ShareStartingActivity.newIntent(context, path)
val shareIntent = Intent(Intent.ACTION_SEND).apply { val shareIntent = Intent(Intent.ACTION_SEND).apply {
val uri = File(path).getUriCompat(context) val uri = File(path).getUriCompat(context)
putExtra(Intent.EXTRA_STREAM, uri) putExtra(Intent.EXTRA_STREAM, uri)
@ -358,7 +359,7 @@ class NotificationReceiver : BroadcastReceiver() {
clipData = ClipData.newRawUri(null, uri) clipData = ClipData.newRawUri(null, uri)
type = "image/*" type = "image/*"
} }
//val shareIntent2 = Intent.createChooser(shareIntent, context.getString(R.string.action_share)) // val shareIntent2 = Intent.createChooser(shareIntent, context.getString(R.string.action_share))
return PendingIntent.getActivity(context, 0, shareIntent, PendingIntent return PendingIntent.getActivity(context, 0, shareIntent, PendingIntent
.FLAG_CANCEL_CURRENT) .FLAG_CANCEL_CURRENT)
} }
@ -387,8 +388,12 @@ class NotificationReceiver : BroadcastReceiver() {
* @param manga manga of chapter * @param manga manga of chapter
* @param chapter chapter that needs to be opened * @param chapter chapter that needs to be opened
*/ */
internal fun openChapterPendingActivity(context: Context, manga: Manga, chapter: internal fun openChapterPendingActivity(
Chapter): PendingIntent { context: Context,
manga: Manga,
chapter:
Chapter
): PendingIntent {
val newIntent = ReaderActivity.newIntent(context, manga, chapter) val newIntent = ReaderActivity.newIntent(context, manga, chapter)
return PendingIntent.getActivity(context, manga.id.hashCode(), newIntent, PendingIntent return PendingIntent.getActivity(context, manga.id.hashCode(), newIntent, PendingIntent
.FLAG_UPDATE_CURRENT) .FLAG_UPDATE_CURRENT)
@ -440,15 +445,19 @@ class NotificationReceiver : BroadcastReceiver() {
return PendingIntent.getActivity(context, 0, toLaunch, 0) return PendingIntent.getActivity(context, 0, toLaunch, 0)
} }
/** /**
* Returns [PendingIntent] that marks a chapter as read and deletes it if preferred * Returns [PendingIntent] that marks a chapter as read and deletes it if preferred
* *
* @param context context of application * @param context context of application
* @param manga manga of chapter * @param manga manga of chapter
*/ */
internal fun markAsReadPendingBroadcast(context: Context, manga: Manga, chapters: internal fun markAsReadPendingBroadcast(
Array<Chapter>, groupId: Int): context: Context,
manga: Manga,
chapters:
Array<Chapter>,
groupId: Int
):
PendingIntent { PendingIntent {
val newIntent = Intent(context, NotificationReceiver::class.java).apply { val newIntent = Intent(context, NotificationReceiver::class.java).apply {
action = ACTION_MARK_AS_READ action = ACTION_MARK_AS_READ
@ -486,4 +495,4 @@ class NotificationReceiver : BroadcastReceiver() {
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
} }
} }
} }

View File

@ -38,6 +38,7 @@ object Notifications {
const val CHANNEL_NEW_CHAPTERS = "new_chapters_channel" const val CHANNEL_NEW_CHAPTERS = "new_chapters_channel"
const val ID_NEW_CHAPTERS = -301 const val ID_NEW_CHAPTERS = -301
const val GROUP_NEW_CHAPTERS = "eu.kanade.tachiyomi.NEW_CHAPTERS" const val GROUP_NEW_CHAPTERS = "eu.kanade.tachiyomi.NEW_CHAPTERS"
/** /**
* Notification channel and ids used by the library updater. * Notification channel and ids used by the library updater.
*/ */
@ -49,7 +50,6 @@ object Notifications {
const val ID_RESTORE_COMPLETE = -502 const val ID_RESTORE_COMPLETE = -502
const val ID_RESTORE_ERROR = -503 const val ID_RESTORE_ERROR = -503
/** /**
* Creates the notification channels introduced in Android Oreo. * Creates the notification channels introduced in Android Oreo.
* *
@ -58,36 +58,37 @@ object Notifications {
fun createChannels(context: Context) { fun createChannels(context: Context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
val channels = listOf( val channels = listOf(NotificationChannel(
NotificationChannel( CHANNEL_COMMON,
CHANNEL_COMMON, context.getString(R.string.channel_common),
context.getString(R.string.channel_common), NotificationManager.IMPORTANCE_LOW
NotificationManager.IMPORTANCE_LOW ), NotificationChannel(
), NotificationChannel( CHANNEL_LIBRARY,
CHANNEL_LIBRARY, context.getString(R.string.channel_library_updates),
context.getString(R.string.channel_library_updates), NotificationManager.IMPORTANCE_LOW
NotificationManager.IMPORTANCE_LOW ).apply {
).apply { setShowBadge(false)
setShowBadge(false) }, NotificationChannel(
}, NotificationChannel( CHANNEL_DOWNLOADER,
CHANNEL_DOWNLOADER, context.getString(R.string.channel_downloader),
context.getString(R.string.channel_downloader), NotificationManager.IMPORTANCE_LOW
NotificationManager.IMPORTANCE_LOW ).apply {
).apply { setShowBadge(false)
setShowBadge(false) }, NotificationChannel(
}, NotificationChannel( CHANNEL_UPDATES_TO_EXTS,
CHANNEL_UPDATES_TO_EXTS, context.getString(R.string.channel_ext_updates),
context.getString(R.string.channel_ext_updates), NotificationManager.IMPORTANCE_DEFAULT
NotificationManager.IMPORTANCE_DEFAULT ), NotificationChannel(
), NotificationChannel( CHANNEL_NEW_CHAPTERS,
CHANNEL_NEW_CHAPTERS, context.getString(R.string.channel_new_chapters),
context.getString(R.string.channel_new_chapters), NotificationManager.IMPORTANCE_DEFAULT
NotificationManager.IMPORTANCE_DEFAULT ), NotificationChannel(
), NotificationChannel(CHANNEL_RESTORE, context.getString(R.string.channel_backup_restore), CHANNEL_RESTORE,
NotificationManager.IMPORTANCE_LOW).apply { context.getString(R.string.channel_backup_restore),
setShowBadge(false) NotificationManager.IMPORTANCE_LOW
} ).apply {
) setShowBadge(false)
})
context.notificationManager.createNotificationChannels(channels) context.notificationManager.createNotificationChannels(channels)
} }
} }

View File

@ -155,11 +155,9 @@ object PreferenceKeys {
fun sourceSharedPref(sourceId: Long) = "source_$sourceId" fun sourceSharedPref(sourceId: Long) = "source_$sourceId"
fun trackUsername(syncId: Int) = "pref_mangasync_username_$syncId" fun trackUsername(syncId: Int) = "pref_mangasync_username_$syncId"
fun trackPassword(syncId: Int) = "pref_mangasync_password_$syncId" fun trackPassword(syncId: Int) = "pref_mangasync_password_$syncId"
fun trackToken(syncId: Int) = "track_token_$syncId" fun trackToken(syncId: Int) = "track_token_$syncId"
} }

View File

@ -8,13 +8,13 @@ import androidx.preference.PreferenceManager
import com.f2prateek.rx.preferences.Preference import com.f2prateek.rx.preferences.Preference
import com.f2prateek.rx.preferences.RxSharedPreferences import com.f2prateek.rx.preferences.RxSharedPreferences
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import java.io.File import java.io.File
import java.text.DateFormat import java.text.DateFormat
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
fun <T> Preference<T>.getOrDefault(): T = get() ?: defaultValue()!! fun <T> Preference<T>.getOrDefault(): T = get() ?: defaultValue()!!

View File

@ -2,10 +2,10 @@ package eu.kanade.tachiyomi.data.track
import android.content.Context import android.content.Context
import eu.kanade.tachiyomi.data.track.anilist.Anilist import eu.kanade.tachiyomi.data.track.anilist.Anilist
import eu.kanade.tachiyomi.data.track.bangumi.Bangumi
import eu.kanade.tachiyomi.data.track.kitsu.Kitsu import eu.kanade.tachiyomi.data.track.kitsu.Kitsu
import eu.kanade.tachiyomi.data.track.myanimelist.MyAnimeList import eu.kanade.tachiyomi.data.track.myanimelist.MyAnimeList
import eu.kanade.tachiyomi.data.track.shikimori.Shikimori import eu.kanade.tachiyomi.data.track.shikimori.Shikimori
import eu.kanade.tachiyomi.data.track.bangumi.Bangumi
class TrackManager(context: Context) { class TrackManager(context: Context) {
@ -32,5 +32,4 @@ class TrackManager(context: Context) {
fun getService(id: Int) = services.find { it.id == id } fun getService(id: Int) = services.find { it.id == id }
fun hasLoggedServices() = services.any { it.isLogged } fun hasLoggedServices() = services.any { it.isLogged }
} }

View File

@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.data.track
import androidx.annotation.CallSuper import androidx.annotation.CallSuper
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy

View File

@ -7,7 +7,6 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.data.track.model.TrackSearch
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -144,25 +143,24 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
track.copyPersonalFrom(remoteTrack) track.copyPersonalFrom(remoteTrack)
track.total_chapters = remoteTrack.total_chapters track.total_chapters = remoteTrack.total_chapters
return track return track
} }
override suspend fun login(username: String, password: String) = login(password) override suspend fun login(username: String, password: String) = login(password)
suspend fun login(token: String): Boolean { suspend fun login(token: String): Boolean {
val oauth = api.createOAuth(token) val oauth = api.createOAuth(token)
interceptor.setAuth(oauth) interceptor.setAuth(oauth)
return try { return try {
val currentUser = api.getCurrentUser() val currentUser = api.getCurrentUser()
scorePreference.set(currentUser.second) scorePreference.set(currentUser.second)
saveCredentials(currentUser.first.toString(), oauth.access_token) saveCredentials(currentUser.first.toString(), oauth.access_token)
true true
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e) Timber.e(e)
logout() logout()
false false
} }
} }
override fun logout() { override fun logout() {
@ -184,7 +182,6 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
} }
} }
companion object { companion object {
const val READING = 1 const val READING = 1
const val COMPLETED = 2 const val COMPLETED = 2
@ -202,6 +199,4 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
const val POINT_5 = "POINT_5" const val POINT_5 = "POINT_5"
const val POINT_3 = "POINT_3" const val POINT_3 = "POINT_3"
} }
} }

View File

@ -12,6 +12,8 @@ import com.google.gson.JsonParser
import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.network.jsonType import eu.kanade.tachiyomi.network.jsonType
import java.util.Calendar
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import okhttp3.MediaType import okhttp3.MediaType
@ -19,8 +21,6 @@ import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response import okhttp3.Response
import java.util.Calendar
import java.util.concurrent.TimeUnit
class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {

View File

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.data.track.anilist
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.Response import okhttp3.Response
class AnilistInterceptor(private val anilist: Anilist, private var token: String?) : Interceptor { class AnilistInterceptor(private val anilist: Anilist, private var token: String?) : Interceptor {
/** /**
@ -23,7 +22,7 @@ class AnilistInterceptor(private val anilist: Anilist, private var token: String
if (token.isNullOrEmpty()) { if (token.isNullOrEmpty()) {
throw Exception("Not authenticated with Anilist") throw Exception("Not authenticated with Anilist")
} }
if (oauth == null){ if (oauth == null) {
oauth = anilist.loadOAuth() oauth = anilist.loadOAuth()
} }
// Refresh access token if null or expired. // Refresh access token if null or expired.
@ -54,5 +53,4 @@ class AnilistInterceptor(private val anilist: Anilist, private var token: String
this.oauth = oauth this.oauth = oauth
anilist.saveOAuth(oauth) anilist.saveOAuth(oauth)
} }
}
}

View File

@ -5,28 +5,30 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.data.track.model.TrackSearch
import uy.kohesive.injekt.injectLazy
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
import uy.kohesive.injekt.injectLazy
data class OAuth( data class OAuth(
val access_token: String, val access_token: String,
val token_type: String, val token_type: String,
val expires: Long, val expires: Long,
val expires_in: Long) { val expires_in: Long
) {
fun isExpired() = System.currentTimeMillis() > expires fun isExpired() = System.currentTimeMillis() > expires
} }
data class ALManga( data class ALManga(
val media_id: Int, val media_id: Int,
val title_romaji: String, val title_romaji: String,
val image_url_lge: String, val image_url_lge: String,
val description: String?, val description: String?,
val type: String, val type: String,
val publishing_status: String, val publishing_status: String,
val start_date_fuzzy: Long, val start_date_fuzzy: Long,
val total_chapters: Int) { val total_chapters: Int
) {
fun toTrack() = TrackSearch.create(TrackManager.ANILIST).apply { fun toTrack() = TrackSearch.create(TrackManager.ANILIST).apply {
media_id = this@ALManga.media_id media_id = this@ALManga.media_id

View File

@ -60,12 +60,12 @@ class Bangumi(private val context: Context, id: Int) : TrackService(id) {
override suspend fun refresh(track: Track): Track { override suspend fun refresh(track: Track): Track {
val statusTrack = api.statusLibManga(track) val statusTrack = api.statusLibManga(track)
track.copyPersonalFrom(statusTrack!!) track.copyPersonalFrom(statusTrack!!)
val remoteTrack = api.findLibManga(track) val remoteTrack = api.findLibManga(track)
if(remoteTrack != null){ if (remoteTrack != null) {
track.total_chapters = remoteTrack.total_chapters track.total_chapters = remoteTrack.total_chapters
track.status = remoteTrack.status track.status = remoteTrack.status
} }
return track return track
} }
override fun getLogo() = R.drawable.tracker_bangumi override fun getLogo() = R.drawable.tracker_bangumi

View File

@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.await
import java.net.URLEncoder
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import okhttp3.CacheControl import okhttp3.CacheControl
@ -18,7 +19,6 @@ import okhttp3.FormBody
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.net.URLEncoder
class BangumiApi(private val client: OkHttpClient, interceptor: BangumiInterceptor) { class BangumiApi(private val client: OkHttpClient, interceptor: BangumiInterceptor) {
@ -26,14 +26,10 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
private val authClient = client.newBuilder().addInterceptor(interceptor).build() private val authClient = client.newBuilder().addInterceptor(interceptor).build()
suspend fun addLibManga(track: Track): Track { suspend fun addLibManga(track: Track): Track {
val body = FormBody.Builder() val body = FormBody.Builder().add("rating", track.score.toInt().toString())
.add("rating", track.score.toInt().toString()) .add("status", track.toBangumiStatus()).build()
.add("status", track.toBangumiStatus()) val request =
.build() Request.Builder().url("$apiUrl/collection/${track.media_id}/update").post(body).build()
val request = Request.Builder()
.url("$apiUrl/collection/${track.media_id}/update")
.post(body)
.build()
val response = authClient.newCall(request).await() val response = authClient.newCall(request).await()
return track return track
} }
@ -41,22 +37,17 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
suspend fun updateLibManga(track: Track): Track { suspend fun updateLibManga(track: Track): Track {
// chapter update // chapter update
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
val body = FormBody.Builder() val body =
.add("watched_eps", track.last_chapter_read.toString()) FormBody.Builder().add("watched_eps", track.last_chapter_read.toString()).build()
.build() val request =
val request = Request.Builder() Request.Builder().url("$apiUrl/subject/${track.media_id}/update/watched_eps")
.url("$apiUrl/subject/${track.media_id}/update/watched_eps") .post(body).build()
.post(body)
.build()
// read status update // read status update
val sbody = FormBody.Builder() val sbody = FormBody.Builder().add("status", track.toBangumiStatus()).build()
.add("status", track.toBangumiStatus()) val srequest =
.build() Request.Builder().url("$apiUrl/collection/${track.media_id}/update").post(sbody)
val srequest = Request.Builder() .build()
.url("$apiUrl/collection/${track.media_id}/update")
.post(sbody)
.build()
authClient.newCall(srequest).execute() authClient.newCall(srequest).execute()
authClient.newCall(request).execute() authClient.newCall(request).execute()
track track
@ -67,13 +58,8 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
val url = Uri.parse( val url = Uri.parse(
"$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}" "$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}"
).buildUpon() ).buildUpon().appendQueryParameter("max_results", "20").build()
.appendQueryParameter("max_results", "20") val request = Request.Builder().url(url.toString()).get().build()
.build()
val request = Request.Builder()
.url(url.toString())
.get()
.build()
val netResponse = authClient.newCall(request).await() val netResponse = authClient.newCall(request).await()
var responseBody = netResponse.body?.string().orEmpty() var responseBody = netResponse.body?.string().orEmpty()
@ -106,9 +92,9 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
return Track.create(TrackManager.BANGUMI).apply { return Track.create(TrackManager.BANGUMI).apply {
title = mangas["name"].asString title = mangas["name"].asString
media_id = mangas["id"].asInt media_id = mangas["id"].asInt
score = if (mangas["rating"] != null) score =
(if (mangas["rating"].isJsonObject) mangas["rating"].obj["score"].asFloat else 0f) if (mangas["rating"] != null) (if (mangas["rating"].isJsonObject) mangas["rating"].obj["score"].asFloat else 0f)
else 0f else 0f
status = Bangumi.DEFAULT_STATUS status = Bangumi.DEFAULT_STATUS
tracking_url = mangas["url"].asString tracking_url = mangas["url"].asString
} }
@ -117,10 +103,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
suspend fun findLibManga(track: Track): Track? { suspend fun findLibManga(track: Track): Track? {
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
val urlMangas = "$apiUrl/subject/${track.media_id}" val urlMangas = "$apiUrl/subject/${track.media_id}"
val requestMangas = Request.Builder() val requestMangas = Request.Builder().url(urlMangas).get().build()
.url(urlMangas)
.get()
.build()
val netResponse = authClient.newCall(requestMangas).execute() val netResponse = authClient.newCall(requestMangas).execute()
val responseBody = netResponse.body?.string().orEmpty() val responseBody = netResponse.body?.string().orEmpty()
jsonToTrack(JsonParser.parseString(responseBody).obj) jsonToTrack(JsonParser.parseString(responseBody).obj)
@ -129,11 +112,9 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
suspend fun statusLibManga(track: Track): Track? { suspend fun statusLibManga(track: Track): Track? {
val urlUserRead = "$apiUrl/collection/${track.media_id}" val urlUserRead = "$apiUrl/collection/${track.media_id}"
val requestUserRead = Request.Builder() val requestUserRead =
.url(urlUserRead) Request.Builder().url(urlUserRead).cacheControl(CacheControl.FORCE_NETWORK).get()
.cacheControl(CacheControl.FORCE_NETWORK) .build()
.get()
.build()
// todo get user readed chapter here // todo get user readed chapter here
val response = authClient.newCall(requestUserRead).await() val response = authClient.newCall(requestUserRead).await()
@ -145,10 +126,10 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
} }
suspend fun accessToken(code: String): OAuth { suspend fun accessToken(code: String): OAuth {
return withContext(Dispatchers.IO){ return withContext(Dispatchers.IO) {
val netResponse = client.newCall(accessTokenRequest(code)).execute() val netResponse = client.newCall(accessTokenRequest(code)).execute()
val responseBody = netResponse.body?.string().orEmpty() val responseBody = netResponse.body?.string().orEmpty()
if(responseBody.isEmpty()){ if (responseBody.isEmpty()) {
throw Exception("Null Response") throw Exception("Null Response")
} }
gson.fromJson(responseBody, OAuth::class.java) gson.fromJson(responseBody, OAuth::class.java)
@ -157,12 +138,8 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
private fun accessTokenRequest(code: String) = POST( private fun accessTokenRequest(code: String) = POST(
oauthUrl, oauthUrl,
body = FormBody.Builder() body = FormBody.Builder().add("grant_type", "authorization_code").add("client_id", clientId)
.add("grant_type", "authorization_code") .add("client_secret", clientSecret).add("code", code).add("redirect_uri", redirectUrl)
.add("client_id", clientId)
.add("client_secret", clientSecret)
.add("code", code)
.add("redirect_uri", redirectUrl)
.build() .build()
) )
@ -182,22 +159,15 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
return "$baseMangaUrl/$remoteId" return "$baseMangaUrl/$remoteId"
} }
fun authUrl() = fun authUrl() = Uri.parse(loginUrl).buildUpon().appendQueryParameter("client_id", clientId)
Uri.parse(loginUrl).buildUpon() .appendQueryParameter("response_type", "code")
.appendQueryParameter("client_id", clientId) .appendQueryParameter("redirect_uri", redirectUrl).build()
.appendQueryParameter("response_type", "code")
.appendQueryParameter("redirect_uri", redirectUrl)
.build()
fun refreshTokenRequest(token: String) = POST( fun refreshTokenRequest(token: String) = POST(
oauthUrl, oauthUrl,
body = FormBody.Builder() body = FormBody.Builder().add("grant_type", "refresh_token").add("client_id", clientId)
.add("grant_type", "refresh_token") .add("client_secret", clientSecret).add("refresh_token", token)
.add("client_id", clientId) .add("redirect_uri", redirectUrl).build()
.add("client_secret", clientSecret)
.add("refresh_token", token)
.add("redirect_uri", redirectUrl)
.build()
) )
} }
} }

View File

@ -59,7 +59,7 @@ class BangumiInterceptor(val bangumi: Bangumi, val gson: Gson) : Interceptor {
bangumi.saveToken(oauth) bangumi.saveToken(oauth)
} }
fun clearOauth(){ fun clearOauth() {
bangumi.saveToken(null) bangumi.saveToken(null)
} }
} }

View File

@ -1,49 +1,47 @@
package eu.kanade.tachiyomi.data.track.bangumi package eu.kanade.tachiyomi.data.track.bangumi
data class Collection( data class Collection(
val `private`: Int? = 0, val `private`: Int? = 0,
val comment: String? = "", val comment: String? = "",
val ep_status: Int? = 0, val ep_status: Int? = 0,
val lasttouch: Int? = 0, val lasttouch: Int? = 0,
val rating: Int? = 0, val rating: Int? = 0,
val status: Status? = Status(), val status: Status? = Status(),
val tag: List<String?>? = listOf(), val tag: List<String?>? = listOf(),
val user: User? = User(), val user: User? = User(),
val vol_status: Int? = 0 val vol_status: Int? = 0
) )
data class OAuth( data class OAuth(
val access_token: String, val access_token: String,
val token_type: String, val token_type: String,
val created_at: Long, val created_at: Long,
val expires_in: Long, val expires_in: Long,
val refresh_token: String?, val refresh_token: String?,
val user_id: Long? val user_id: Long?
) { ) {
// Access token refresh before expired // Access token refresh before expired
fun isExpired() = (System.currentTimeMillis() / 1000) > (created_at + expires_in - 3600) fun isExpired() = (System.currentTimeMillis() / 1000) > (created_at + expires_in - 3600)
} }
data class Status( data class Status(
val id: Int? = 0, val id: Int? = 0,
val name: String? = "", val name: String? = "",
val type: String? = "" val type: String? = ""
) )
data class User( data class User(
val avatar: Avatar? = Avatar(), val avatar: Avatar? = Avatar(),
val id: Int? = 0, val id: Int? = 0,
val nickname: String? = "", val nickname: String? = "",
val sign: String? = "", val sign: String? = "",
val url: String? = "", val url: String? = "",
val usergroup: Int? = 0, val usergroup: Int? = 0,
val username: String? = "" val username: String? = ""
) )
data class Avatar( data class Avatar(
val large: String? = "", val large: String? = "",
val medium: String? = "", val medium: String? = "",
val small: String? = "" val small: String? = ""
) )

View File

@ -7,9 +7,9 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.data.track.model.TrackSearch
import java.text.DecimalFormat
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.text.DecimalFormat
class Kitsu(private val context: Context, id: Int) : TrackService(id) { class Kitsu(private val context: Context, id: Int) : TrackService(id) {

View File

@ -42,5 +42,4 @@ class KitsuInterceptor(val kitsu: Kitsu, val gson: Gson) : Interceptor {
this.oauth = oauth this.oauth = oauth
kitsu.saveToken(oauth) kitsu.saveToken(oauth)
} }
} }

View File

@ -1,13 +1,19 @@
package eu.kanade.tachiyomi.data.track.kitsu package eu.kanade.tachiyomi.data.track.kitsu
import androidx.annotation.CallSuper import androidx.annotation.CallSuper
import com.github.salomonbrys.kotson.* import com.github.salomonbrys.kotson.byInt
import com.github.salomonbrys.kotson.byString
import com.github.salomonbrys.kotson.nullInt
import com.github.salomonbrys.kotson.nullObj
import com.github.salomonbrys.kotson.nullString
import com.github.salomonbrys.kotson.obj
import com.google.gson.JsonObject import com.google.gson.JsonObject
import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.data.track.model.TrackSearch
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.Date
import java.util.Locale
class KitsuSearchManga(obj: JsonObject) { class KitsuSearchManga(obj: JsonObject) {
val id by obj.byInt val id by obj.byInt
@ -40,7 +46,6 @@ class KitsuSearchManga(obj: JsonObject) {
} }
} }
class KitsuLibManga(obj: JsonObject, manga: JsonObject) { class KitsuLibManga(obj: JsonObject, manga: JsonObject) {
val id by manga.byInt val id by manga.byInt
private val canonicalTitle by manga["attributes"].byString private val canonicalTitle by manga["attributes"].byString
@ -77,7 +82,6 @@ class KitsuLibManga(obj: JsonObject, manga: JsonObject) {
"planned" -> Kitsu.PLAN_TO_READ "planned" -> Kitsu.PLAN_TO_READ
else -> throw Exception("Unknown status") else -> throw Exception("Unknown status")
} }
} }
fun Track.toKitsuStatus() = when (status) { fun Track.toKitsuStatus() = when (status) {

View File

@ -1,11 +1,12 @@
package eu.kanade.tachiyomi.data.track.kitsu package eu.kanade.tachiyomi.data.track.kitsu
data class OAuth( data class OAuth(
val access_token: String, val access_token: String,
val token_type: String, val token_type: String,
val created_at: Long, val created_at: Long,
val expires_in: Long, val expires_in: Long,
val refresh_token: String?) { val refresh_token: String?
) {
fun isExpired() = (System.currentTimeMillis() / 1000) > (created_at + expires_in - 3600) fun isExpired() = (System.currentTimeMillis() / 1000) > (created_at + expires_in - 3600)
} }

View File

@ -58,7 +58,5 @@ class TrackSearch : Track {
fun create(serviceId: Int): TrackSearch = TrackSearch().apply { fun create(serviceId: Int): TrackSearch = TrackSearch().apply {
sync_id = serviceId sync_id = serviceId
} }
} }
}
}

Some files were not shown because too many files have changed in this diff Show More