diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 3786f3ac7a..f782c0b7a5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -23,12 +23,12 @@ import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.registry.default.DefaultRegistrar @AcraCore( - buildConfigClass = BuildConfig::class, - excludeMatchingSharedPreferencesKeys = [".*username.*", ".*password.*", ".*token.*"] + buildConfigClass = BuildConfig::class, + excludeMatchingSharedPreferencesKeys = [".*username.*", ".*password.*", ".*token.*"] ) @AcraHttpSender( - uri = "https://tachiyomi.kanade.eu/crash_report", - httpMethod = HttpSender.Method.PUT + uri = "https://tachiyomi.kanade.eu/crash_report", + httpMethod = HttpSender.Method.PUT ) open class App : Application(), LifecycleObserver { diff --git a/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt b/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt index f9aa0a6dc3..9b480ec931 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt @@ -22,7 +22,6 @@ import uy.kohesive.injekt.api.get class AppModule(val app: Application) : InjektModule { override fun InjektRegistrar.registerInjectables() { - addSingleton(app) addSingletonFactory { PreferencesHelper(app) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt index 581b082a7a..8152be31fa 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt @@ -13,7 +13,7 @@ import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get class BackupCreatorJob(private val context: Context, workerParams: WorkerParameters) : - Worker(context, workerParams) { + Worker(context, workerParams) { override fun doWork(): Result { val preferences = Injekt.get() @@ -32,10 +32,11 @@ class BackupCreatorJob(private val context: Context, workerParams: WorkerParamet val interval = prefInterval ?: preferences.backupInterval().get() if (interval > 0) { val request = PeriodicWorkRequestBuilder( - interval.toLong(), TimeUnit.HOURS, - 10, TimeUnit.MINUTES) - .addTag(TAG) - .build() + interval.toLong(), TimeUnit.HOURS, + 10, TimeUnit.MINUTES + ) + .addTag(TAG) + .build() WorkManager.getInstance(context).enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.REPLACE, request) } else { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt index 8898b87f1d..c0f99d13bb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt @@ -85,7 +85,8 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) { private fun initParser(): Gson = when (version) { 1 -> GsonBuilder().create() - 2 -> GsonBuilder() + 2 -> + GsonBuilder() .registerTypeAdapter(MangaTypeAdapter.build()) .registerTypeHierarchyAdapter(ChapterTypeAdapter.build()) .registerTypeAdapter(CategoryTypeAdapter.build()) @@ -142,21 +143,21 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) { val numberOfBackups = numberOfBackups() val backupRegex = Regex("""tachiyomi_\d+-\d+-\d+_\d+-\d+.json""") dir.listFiles { _, filename -> backupRegex.matches(filename) } - .orEmpty() - .sortedByDescending { it.name } - .drop(numberOfBackups - 1) - .forEach { it.delete() } + .orEmpty() + .sortedByDescending { it.name } + .drop(numberOfBackups - 1) + .forEach { it.delete() } // Create new file to place backup val newFile = dir.createFile(Backup.getDefaultFilename()) - ?: throw Exception("Couldn't create backup file") + ?: throw Exception("Couldn't create backup file") newFile.openOutputStream().bufferedWriter().use { parser.toJson(root, it) } } else { val file = UniFile.fromUri(context, uri) - ?: throw Exception("Couldn't create backup file") + ?: throw Exception("Couldn't create backup file") file.openOutputStream().bufferedWriter().use { parser.toJson(root, it) } @@ -268,13 +269,13 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) { */ fun restoreMangaFetchObservable(source: Source, manga: Manga): Observable { return source.fetchMangaDetails(manga) - .map { networkManga -> - manga.copyFrom(networkManga) - manga.favorite = true - manga.initialized = true - manga.id = insertManga(manga) - manga - } + .map { networkManga -> + manga.copyFrom(networkManga) + manga.favorite = true + manga.initialized = true + manga.id = insertManga(manga) + manga + } } /** @@ -286,13 +287,13 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) { */ fun restoreChapterFetchObservable(source: Source, manga: Manga, chapters: List): Observable, List>> { return source.fetchChapterList(manga) - .map { syncChaptersWithSource(databaseHelper, it, manga, source) } - .doOnNext { pair -> - if (pair.first.isNotEmpty()) { - chapters.forEach { it.manga_id = manga.id } - insertChapters(chapters) - } + .map { syncChaptersWithSource(databaseHelper, it, manga, source) } + .doOnNext { pair -> + if (pair.first.isNotEmpty()) { + chapters.forEach { it.manga_id = manga.id } + insertChapters(chapters) } + } } /** @@ -442,8 +443,9 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) { val dbChapters = databaseHelper.getChapters(manga).executeAsBlocking() // Return if fetch is needed - if (dbChapters.isEmpty() || dbChapters.size < chapters.size) + if (dbChapters.isEmpty() || dbChapters.size < chapters.size) { return false + } for (chapter in chapters) { val pos = dbChapters.indexOf(chapter) @@ -468,7 +470,7 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) { * @return [Manga], null if not found */ internal fun getMangaFromDatabase(manga: Manga): Manga? = - databaseHelper.getManga(manga.url, manga.source).executeAsBlocking() + databaseHelper.getManga(manga.url, manga.source).executeAsBlocking() /** * Returns list containing manga from library @@ -476,7 +478,7 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) { * @return [Manga] from library */ internal fun getFavoriteManga(): List = - databaseHelper.getFavoriteMangas().executeAsBlocking() + databaseHelper.getFavoriteMangas().executeAsBlocking() /** * Inserts manga and returns id @@ -484,7 +486,7 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) { * @return id of [Manga], null if not found */ internal fun insertManga(manga: Manga): Long? = - databaseHelper.insertManga(manga).executeAsBlocking().insertedId() + databaseHelper.insertManga(manga).executeAsBlocking().insertedId() /** * Inserts list of chapters diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt index 7fb4487fee..3f5625877d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt @@ -60,7 +60,7 @@ class BackupRestoreService : Service() { * @return true if the service is running, false otherwise. */ private fun isRunning(context: Context): Boolean = - context.isServiceRunning(BackupRestoreService::class.java) + context.isServiceRunning(BackupRestoreService::class.java) /** * Starts a service to restore a backup from Json @@ -143,7 +143,8 @@ class BackupRestoreService : Service() { startForeground(Notifications.ID_RESTORE, notifier.showRestoreProgress().build()) wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, "BackupRestoreService:WakeLock") + PowerManager.PARTIAL_WAKE_LOCK, "BackupRestoreService:WakeLock" + ) wakeLock.acquire() } @@ -182,12 +183,13 @@ class BackupRestoreService : Service() { subscription?.unsubscribe() subscription = Observable.using( - { db.lowLevel().beginTransaction() }, - { getRestoreObservable(uri).doOnNext { db.lowLevel().setTransactionSuccessful() } }, - { executor.execute { db.lowLevel().endTransaction() } }) - .doAfterTerminate { stopSelf(startId) } - .subscribeOn(Schedulers.from(executor)) - .subscribe() + { db.lowLevel().beginTransaction() }, + { getRestoreObservable(uri).doOnNext { db.lowLevel().setTransactionSuccessful() } }, + { executor.execute { db.lowLevel().endTransaction() } } + ) + .doAfterTerminate { stopSelf(startId) } + .subscribeOn(Schedulers.from(executor)) + .subscribe() return START_NOT_STICKY } @@ -202,79 +204,87 @@ class BackupRestoreService : Service() { val startTime = System.currentTimeMillis() return Observable.just(Unit) - .map { - val reader = JsonReader(contentResolver.openInputStream(uri)!!.bufferedReader()) - val json = JsonParser.parseReader(reader).asJsonObject + .map { + val reader = JsonReader(contentResolver.openInputStream(uri)!!.bufferedReader()) + val json = JsonParser.parseReader(reader).asJsonObject - // Get parser version - val version = json.get(VERSION)?.asInt ?: 1 + // Get parser version + val version = json.get(VERSION)?.asInt ?: 1 - // Initialize manager - backupManager = BackupManager(this, version) + // Initialize manager + backupManager = BackupManager(this, version) - val mangasJson = json.get(MANGAS).asJsonArray + val mangasJson = json.get(MANGAS).asJsonArray - restoreAmount = mangasJson.size() + 1 // +1 for categories - restoreProgress = 0 - errors.clear() + restoreAmount = mangasJson.size() + 1 // +1 for categories + restoreProgress = 0 + errors.clear() - // Restore categories - json.get(CATEGORIES)?.let { - backupManager.restoreCategories(it.asJsonArray) - restoreProgress += 1 - showRestoreProgress(restoreProgress, restoreAmount, "Categories added") - } - - mangasJson + // Restore categories + json.get(CATEGORIES)?.let { + backupManager.restoreCategories(it.asJsonArray) + restoreProgress += 1 + showRestoreProgress(restoreProgress, restoreAmount, "Categories added") } - .flatMap { Observable.from(it) } - .concatMap { - val obj = it.asJsonObject - val manga = backupManager.parser.fromJson(obj.get(MANGA)) - val chapters = backupManager.parser.fromJson>(obj.get(CHAPTERS) - ?: JsonArray()) - val categories = backupManager.parser.fromJson>(obj.get(CATEGORIES) - ?: JsonArray()) - val history = backupManager.parser.fromJson>(obj.get(HISTORY) - ?: JsonArray()) - val tracks = backupManager.parser.fromJson>(obj.get(TRACK) - ?: JsonArray()) - val observable = getMangaRestoreObservable(manga, chapters, categories, history, tracks) - if (observable != null) { - observable - } else { - errors.add(Date() to "${manga.title} - ${getString(R.string.source_not_found)}") - restoreProgress += 1 - val content = getString(R.string.dialog_restoring_source_not_found, manga.title.chop(15)) - showRestoreProgress(restoreProgress, restoreAmount, manga.title, content) - Observable.just(manga) - } + mangasJson + } + .flatMap { Observable.from(it) } + .concatMap { + val obj = it.asJsonObject + val manga = backupManager.parser.fromJson(obj.get(MANGA)) + val chapters = backupManager.parser.fromJson>( + obj.get(CHAPTERS) + ?: JsonArray() + ) + val categories = backupManager.parser.fromJson>( + obj.get(CATEGORIES) + ?: JsonArray() + ) + val history = backupManager.parser.fromJson>( + obj.get(HISTORY) + ?: JsonArray() + ) + val tracks = backupManager.parser.fromJson>( + obj.get(TRACK) + ?: JsonArray() + ) + + val observable = getMangaRestoreObservable(manga, chapters, categories, history, tracks) + if (observable != null) { + observable + } else { + errors.add(Date() to "${manga.title} - ${getString(R.string.source_not_found)}") + restoreProgress += 1 + val content = getString(R.string.dialog_restoring_source_not_found, manga.title.chop(15)) + showRestoreProgress(restoreProgress, restoreAmount, manga.title, content) + Observable.just(manga) } - .toList() - .doOnNext { - val endTime = System.currentTimeMillis() - val time = endTime - startTime - val logFile = writeErrorLog() - val completeIntent = Intent(BackupConst.INTENT_FILTER).apply { - putExtra(BackupConst.EXTRA_TIME, time) - putExtra(BackupConst.EXTRA_ERRORS, errors.size) - putExtra(BackupConst.EXTRA_ERROR_FILE_PATH, logFile.parent) - putExtra(BackupConst.EXTRA_ERROR_FILE, logFile.name) - putExtra(BackupConst.ACTION, BackupConst.ACTION_RESTORE_COMPLETED) - } - sendLocalBroadcast(completeIntent) + } + .toList() + .doOnNext { + val endTime = System.currentTimeMillis() + val time = endTime - startTime + val logFile = writeErrorLog() + val completeIntent = Intent(BackupConst.INTENT_FILTER).apply { + putExtra(BackupConst.EXTRA_TIME, time) + putExtra(BackupConst.EXTRA_ERRORS, errors.size) + putExtra(BackupConst.EXTRA_ERROR_FILE_PATH, logFile.parent) + putExtra(BackupConst.EXTRA_ERROR_FILE, logFile.name) + putExtra(BackupConst.ACTION, BackupConst.ACTION_RESTORE_COMPLETED) } - .doOnError { error -> - Timber.e(error) - writeErrorLog() - val errorIntent = Intent(BackupConst.INTENT_FILTER).apply { - putExtra(BackupConst.ACTION, BackupConst.ACTION_RESTORE_ERROR) - putExtra(BackupConst.EXTRA_ERROR_MESSAGE, error.message) - } - sendLocalBroadcast(errorIntent) + sendLocalBroadcast(completeIntent) + } + .doOnError { error -> + Timber.e(error) + writeErrorLog() + val errorIntent = Intent(BackupConst.INTENT_FILTER).apply { + putExtra(BackupConst.ACTION, BackupConst.ACTION_RESTORE_ERROR) + putExtra(BackupConst.EXTRA_ERROR_MESSAGE, error.message) } - .onErrorReturn { emptyList() } + sendLocalBroadcast(errorIntent) + } + .onErrorReturn { emptyList() } } /** @@ -347,28 +357,28 @@ class BackupRestoreService : Service() { tracks: List ): Observable { return backupManager.restoreMangaFetchObservable(source, manga) - .onErrorReturn { - errors.add(Date() to "${manga.title} - ${it.message}") - manga - } - .filter { it.id != null } - .flatMap { - chapterFetchObservable(source, it, chapters) - // Convert to the manga that contains new chapters. - .map { manga } - } - .doOnNext { - restoreExtraForManga(it, categories, history, tracks) - } - .flatMap { - trackingFetchObservable(it, tracks) - // Convert to the manga that contains new chapters. - .map { manga } - } - .doOnCompleted { - restoreProgress += 1 - showRestoreProgress(restoreProgress, restoreAmount, manga.title) - } + .onErrorReturn { + errors.add(Date() to "${manga.title} - ${it.message}") + manga + } + .filter { it.id != null } + .flatMap { + chapterFetchObservable(source, it, chapters) + // Convert to the manga that contains new chapters. + .map { manga } + } + .doOnNext { + restoreExtraForManga(it, categories, history, tracks) + } + .flatMap { + trackingFetchObservable(it, tracks) + // Convert to the manga that contains new chapters. + .map { manga } + } + .doOnCompleted { + restoreProgress += 1 + showRestoreProgress(restoreProgress, restoreAmount, manga.title) + } } private fun mangaNoFetchObservable( @@ -379,28 +389,27 @@ class BackupRestoreService : Service() { history: List, tracks: List ): Observable { - return Observable.just(backupManga) - .flatMap { manga -> - if (!backupManager.restoreChaptersForManga(manga, chapters)) { - chapterFetchObservable(source, manga, chapters) - .map { manga } - } else { - Observable.just(manga) - } - } - .doOnNext { - restoreExtraForManga(it, categories, history, tracks) - } - .flatMap { manga -> - trackingFetchObservable(manga, tracks) - // Convert to the manga that contains new chapters. - .map { manga } - } - .doOnCompleted { - restoreProgress += 1 - showRestoreProgress(restoreProgress, restoreAmount, backupManga.title) + .flatMap { manga -> + if (!backupManager.restoreChaptersForManga(manga, chapters)) { + chapterFetchObservable(source, manga, chapters) + .map { manga } + } else { + Observable.just(manga) } + } + .doOnNext { + restoreExtraForManga(it, categories, history, tracks) + } + .flatMap { manga -> + trackingFetchObservable(manga, tracks) + // Convert to the manga that contains new chapters. + .map { manga } + } + .doOnCompleted { + restoreProgress += 1 + showRestoreProgress(restoreProgress, restoreAmount, backupManga.title) + } } private fun restoreExtraForManga(manga: Manga, categories: List, history: List, tracks: List) { @@ -423,11 +432,11 @@ class BackupRestoreService : Service() { */ private fun chapterFetchObservable(source: Source, manga: Manga, chapters: List): Observable, List>> { return backupManager.restoreChapterFetchObservable(source, manga, chapters) - // If there's any error, return empty update and continue. - .onErrorReturn { - errors.add(Date() to "${manga.title} - ${it.message}") - Pair(emptyList(), emptyList()) - } + // If there's any error, return empty update and continue. + .onErrorReturn { + errors.add(Date() to "${manga.title} - ${it.message}") + Pair(emptyList(), emptyList()) + } } /** @@ -438,20 +447,20 @@ class BackupRestoreService : Service() { */ private fun trackingFetchObservable(manga: Manga, tracks: List): Observable { return Observable.from(tracks) - .concatMap { track -> - val service = trackManager.getService(track.sync_id) - if (service != null && service.isLogged) { - service.refresh(track) - .doOnNext { db.insertTrack(it).executeAsBlocking() } - .onErrorReturn { - errors.add(Date() to "${manga.title} - ${it.message}") - track - } - } else { - errors.add(Date() to "${manga.title} - ${service?.name} not logged in") - Observable.empty() - } + .concatMap { track -> + val service = trackManager.getService(track.sync_id) + if (service != null && service.isLogged) { + service.refresh(track) + .doOnNext { db.insertTrack(it).executeAsBlocking() } + .onErrorReturn { + errors.add(Date() to "${manga.title} - ${it.message}") + track + } + } else { + errors.add(Date() to "${manga.title} - ${service?.name} not logged in") + Observable.empty() } + } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt index 52b246f331..bb63a82256 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt @@ -46,10 +46,12 @@ class ChapterCache(private val context: Context) { private val gson: Gson by injectLazy() /** Cache class used for cache management. */ - private val diskCache = DiskLruCache.open(File(context.cacheDir, PARAMETER_CACHE_DIRECTORY), - PARAMETER_APP_VERSION, - PARAMETER_VALUE_COUNT, - PARAMETER_CACHE_SIZE) + private val diskCache = DiskLruCache.open( + File(context.cacheDir, PARAMETER_CACHE_DIRECTORY), + PARAMETER_APP_VERSION, + PARAMETER_VALUE_COUNT, + PARAMETER_CACHE_SIZE + ) /** * Returns directory of cache. @@ -77,8 +79,9 @@ class ChapterCache(private val context: Context) { */ fun removeFileFromCache(file: String): Boolean { // Make sure we don't delete the journal file (keeps track of cache). - if (file == "journal" || file.startsWith("journal.")) + if (file == "journal" || file.startsWith("journal.")) { return false + } return try { // Remove the extension from the file to get the key of the cache diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.kt index 2fa227146a..a2bfab8a2b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.kt @@ -21,7 +21,7 @@ class CoverCache(private val context: Context) { * Cache directory used for cache management. */ 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. @@ -56,8 +56,9 @@ class CoverCache(private val context: Context) { */ fun deleteFromCache(thumbnailUrl: String?): Boolean { // Check if url is empty. - if (thumbnailUrl.isNullOrEmpty()) + if (thumbnailUrl.isNullOrEmpty()) { return false + } // Remove file. val file = getCoverFile(thumbnailUrl) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt index dc12f00950..a2e4c2626e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt @@ -30,19 +30,19 @@ open class DatabaseHelper(context: Context) : MangaQueries, ChapterQueries, TrackQueries, CategoryQueries, MangaCategoryQueries, HistoryQueries { private val configuration = SupportSQLiteOpenHelper.Configuration.builder(context) - .name(DbOpenCallback.DATABASE_NAME) - .callback(DbOpenCallback()) - .build() + .name(DbOpenCallback.DATABASE_NAME) + .callback(DbOpenCallback()) + .build() override val db = DefaultStorIOSQLite.builder() - .sqliteOpenHelper(RequerySQLiteOpenHelperFactory().create(configuration)) - .addTypeMapping(Manga::class.java, MangaTypeMapping()) - .addTypeMapping(Chapter::class.java, ChapterTypeMapping()) - .addTypeMapping(Track::class.java, TrackTypeMapping()) - .addTypeMapping(Category::class.java, CategoryTypeMapping()) - .addTypeMapping(MangaCategory::class.java, MangaCategoryTypeMapping()) - .addTypeMapping(History::class.java, HistoryTypeMapping()) - .build() + .sqliteOpenHelper(RequerySQLiteOpenHelperFactory().create(configuration)) + .addTypeMapping(Manga::class.java, MangaTypeMapping()) + .addTypeMapping(Chapter::class.java, ChapterTypeMapping()) + .addTypeMapping(Track::class.java, TrackTypeMapping()) + .addTypeMapping(Category::class.java, CategoryTypeMapping()) + .addTypeMapping(MangaCategory::class.java, MangaCategoryTypeMapping()) + .addTypeMapping(History::class.java, HistoryTypeMapping()) + .build() inline fun inTransaction(block: () -> Unit) = db.inTransaction(block) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt index 949275a9a1..d7c887b1bd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt @@ -44,8 +44,10 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) { db.execSQL(ChapterTable.sourceOrderUpdateQuery) // Fix kissmanga covers after supporting cloudflare - db.execSQL("""UPDATE mangas SET thumbnail_url = - REPLACE(thumbnail_url, '93.174.95.110', 'kissmanga.com') WHERE source = 4""") + db.execSQL( + """UPDATE mangas SET thumbnail_url = + REPLACE(thumbnail_url, '93.174.95.110', 'kissmanga.com') WHERE source = 4""" + ) } if (oldVersion < 3) { // Initialize history tables diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/CategoryTypeMapping.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/CategoryTypeMapping.kt index 0069934be1..4cf2d1eea6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/CategoryTypeMapping.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/CategoryTypeMapping.kt @@ -18,22 +18,22 @@ import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_ORDER import eu.kanade.tachiyomi.data.database.tables.CategoryTable.TABLE class CategoryTypeMapping : SQLiteTypeMapping( - CategoryPutResolver(), - CategoryGetResolver(), - CategoryDeleteResolver() + CategoryPutResolver(), + CategoryGetResolver(), + CategoryDeleteResolver() ) class CategoryPutResolver : DefaultPutResolver() { override fun mapToInsertQuery(obj: Category) = InsertQuery.builder() - .table(TABLE) - .build() + .table(TABLE) + .build() override fun mapToUpdateQuery(obj: Category) = UpdateQuery.builder() - .table(TABLE) - .where("$COL_ID = ?") - .whereArgs(obj.id) - .build() + .table(TABLE) + .where("$COL_ID = ?") + .whereArgs(obj.id) + .build() override fun mapToContentValues(obj: Category) = ContentValues(4).apply { put(COL_ID, obj.id) @@ -56,8 +56,8 @@ class CategoryGetResolver : DefaultGetResolver() { class CategoryDeleteResolver : DefaultDeleteResolver() { override fun mapToDeleteQuery(obj: Category) = DeleteQuery.builder() - .table(TABLE) - .where("$COL_ID = ?") - .whereArgs(obj.id) - .build() + .table(TABLE) + .where("$COL_ID = ?") + .whereArgs(obj.id) + .build() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/ChapterTypeMapping.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/ChapterTypeMapping.kt index a610f8969b..9d5810e012 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/ChapterTypeMapping.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/ChapterTypeMapping.kt @@ -26,22 +26,22 @@ import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_URL import eu.kanade.tachiyomi.data.database.tables.ChapterTable.TABLE class ChapterTypeMapping : SQLiteTypeMapping( - ChapterPutResolver(), - ChapterGetResolver(), - ChapterDeleteResolver() + ChapterPutResolver(), + ChapterGetResolver(), + ChapterDeleteResolver() ) class ChapterPutResolver : DefaultPutResolver() { override fun mapToInsertQuery(obj: Chapter) = InsertQuery.builder() - .table(TABLE) - .build() + .table(TABLE) + .build() override fun mapToUpdateQuery(obj: Chapter) = UpdateQuery.builder() - .table(TABLE) - .where("$COL_ID = ?") - .whereArgs(obj.id) - .build() + .table(TABLE) + .where("$COL_ID = ?") + .whereArgs(obj.id) + .build() override fun mapToContentValues(obj: Chapter) = ContentValues(11).apply { put(COL_ID, obj.id) @@ -80,8 +80,8 @@ class ChapterGetResolver : DefaultGetResolver() { class ChapterDeleteResolver : DefaultDeleteResolver() { override fun mapToDeleteQuery(obj: Chapter) = DeleteQuery.builder() - .table(TABLE) - .where("$COL_ID = ?") - .whereArgs(obj.id) - .build() + .table(TABLE) + .where("$COL_ID = ?") + .whereArgs(obj.id) + .build() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/HistoryTypeMapping.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/HistoryTypeMapping.kt index fdd96f69ad..e3da101695 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/HistoryTypeMapping.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/HistoryTypeMapping.kt @@ -18,22 +18,22 @@ import eu.kanade.tachiyomi.data.database.tables.HistoryTable.COL_TIME_READ import eu.kanade.tachiyomi.data.database.tables.HistoryTable.TABLE class HistoryTypeMapping : SQLiteTypeMapping( - HistoryPutResolver(), - HistoryGetResolver(), - HistoryDeleteResolver() + HistoryPutResolver(), + HistoryGetResolver(), + HistoryDeleteResolver() ) open class HistoryPutResolver : DefaultPutResolver() { override fun mapToInsertQuery(obj: History) = InsertQuery.builder() - .table(TABLE) - .build() + .table(TABLE) + .build() override fun mapToUpdateQuery(obj: History) = UpdateQuery.builder() - .table(TABLE) - .where("$COL_ID = ?") - .whereArgs(obj.id) - .build() + .table(TABLE) + .where("$COL_ID = ?") + .whereArgs(obj.id) + .build() override fun mapToContentValues(obj: History) = ContentValues(4).apply { put(COL_ID, obj.id) @@ -56,8 +56,8 @@ class HistoryGetResolver : DefaultGetResolver() { class HistoryDeleteResolver : DefaultDeleteResolver() { override fun mapToDeleteQuery(obj: History) = DeleteQuery.builder() - .table(TABLE) - .where("$COL_ID = ?") - .whereArgs(obj.id) - .build() + .table(TABLE) + .where("$COL_ID = ?") + .whereArgs(obj.id) + .build() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaCategoryTypeMapping.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaCategoryTypeMapping.kt index 99cfdd47cc..24fff124cd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaCategoryTypeMapping.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaCategoryTypeMapping.kt @@ -16,22 +16,22 @@ import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable.COL_MANGA_ID import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable.TABLE class MangaCategoryTypeMapping : SQLiteTypeMapping( - MangaCategoryPutResolver(), - MangaCategoryGetResolver(), - MangaCategoryDeleteResolver() + MangaCategoryPutResolver(), + MangaCategoryGetResolver(), + MangaCategoryDeleteResolver() ) class MangaCategoryPutResolver : DefaultPutResolver() { override fun mapToInsertQuery(obj: MangaCategory) = InsertQuery.builder() - .table(TABLE) - .build() + .table(TABLE) + .build() override fun mapToUpdateQuery(obj: MangaCategory) = UpdateQuery.builder() - .table(TABLE) - .where("$COL_ID = ?") - .whereArgs(obj.id) - .build() + .table(TABLE) + .where("$COL_ID = ?") + .whereArgs(obj.id) + .build() override fun mapToContentValues(obj: MangaCategory) = ContentValues(3).apply { put(COL_ID, obj.id) @@ -52,8 +52,8 @@ class MangaCategoryGetResolver : DefaultGetResolver() { class MangaCategoryDeleteResolver : DefaultDeleteResolver() { override fun mapToDeleteQuery(obj: MangaCategory) = DeleteQuery.builder() - .table(TABLE) - .where("$COL_ID = ?") - .whereArgs(obj.id) - .build() + .table(TABLE) + .where("$COL_ID = ?") + .whereArgs(obj.id) + .build() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaTypeMapping.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaTypeMapping.kt index 9ad72908fe..001a83c00c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaTypeMapping.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaTypeMapping.kt @@ -29,22 +29,22 @@ import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_VIEWER import eu.kanade.tachiyomi.data.database.tables.MangaTable.TABLE class MangaTypeMapping : SQLiteTypeMapping( - MangaPutResolver(), - MangaGetResolver(), - MangaDeleteResolver() + MangaPutResolver(), + MangaGetResolver(), + MangaDeleteResolver() ) class MangaPutResolver : DefaultPutResolver() { override fun mapToInsertQuery(obj: Manga) = InsertQuery.builder() - .table(TABLE) - .build() + .table(TABLE) + .build() override fun mapToUpdateQuery(obj: Manga) = UpdateQuery.builder() - .table(TABLE) - .where("$COL_ID = ?") - .whereArgs(obj.id) - .build() + .table(TABLE) + .where("$COL_ID = ?") + .whereArgs(obj.id) + .build() override fun mapToContentValues(obj: Manga) = ContentValues(15).apply { put(COL_ID, obj.id) @@ -95,8 +95,8 @@ open class MangaGetResolver : DefaultGetResolver(), BaseMangaGetResolver class MangaDeleteResolver : DefaultDeleteResolver() { override fun mapToDeleteQuery(obj: Manga) = DeleteQuery.builder() - .table(TABLE) - .where("$COL_ID = ?") - .whereArgs(obj.id) - .build() + .table(TABLE) + .where("$COL_ID = ?") + .whereArgs(obj.id) + .build() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/TrackTypeMapping.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/TrackTypeMapping.kt index ea04f88df0..94de567ad5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/TrackTypeMapping.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/TrackTypeMapping.kt @@ -27,22 +27,22 @@ import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_TRACKING_URL import eu.kanade.tachiyomi.data.database.tables.TrackTable.TABLE class TrackTypeMapping : SQLiteTypeMapping( - TrackPutResolver(), - TrackGetResolver(), - TrackDeleteResolver() + TrackPutResolver(), + TrackGetResolver(), + TrackDeleteResolver() ) class TrackPutResolver : DefaultPutResolver() { override fun mapToInsertQuery(obj: Track) = InsertQuery.builder() - .table(TABLE) - .build() + .table(TABLE) + .build() override fun mapToUpdateQuery(obj: Track) = UpdateQuery.builder() - .table(TABLE) - .where("$COL_ID = ?") - .whereArgs(obj.id) - .build() + .table(TABLE) + .where("$COL_ID = ?") + .whereArgs(obj.id) + .build() override fun mapToContentValues(obj: Track) = ContentValues(10).apply { put(COL_ID, obj.id) @@ -83,8 +83,8 @@ class TrackGetResolver : DefaultGetResolver() { class TrackDeleteResolver : DefaultDeleteResolver() { override fun mapToDeleteQuery(obj: Track) = DeleteQuery.builder() - .table(TABLE) - .where("$COL_ID = ?") - .whereArgs(obj.id) - .build() + .table(TABLE) + .where("$COL_ID = ?") + .whereArgs(obj.id) + .build() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/CategoryQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/CategoryQueries.kt index d677d880d3..bf769b1545 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/CategoryQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/CategoryQueries.kt @@ -10,20 +10,24 @@ import eu.kanade.tachiyomi.data.database.tables.CategoryTable interface CategoryQueries : DbProvider { fun getCategories() = db.get() - .listOfObjects(Category::class.java) - .withQuery(Query.builder() - .table(CategoryTable.TABLE) - .orderBy(CategoryTable.COL_ORDER) - .build()) - .prepare() + .listOfObjects(Category::class.java) + .withQuery( + Query.builder() + .table(CategoryTable.TABLE) + .orderBy(CategoryTable.COL_ORDER) + .build() + ) + .prepare() fun getCategoriesForManga(manga: Manga) = db.get() - .listOfObjects(Category::class.java) - .withQuery(RawQuery.builder() - .query(getCategoriesForMangaQuery()) - .args(manga.id) - .build()) - .prepare() + .listOfObjects(Category::class.java) + .withQuery( + RawQuery.builder() + .query(getCategoriesForMangaQuery()) + .args(manga.id) + .build() + ) + .prepare() fun insertCategory(category: Category) = db.put().`object`(category).prepare() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt index b9313e0f2e..77f7b3de29 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt @@ -16,50 +16,60 @@ import java.util.Date interface ChapterQueries : DbProvider { fun getChapters(manga: Manga) = db.get() - .listOfObjects(Chapter::class.java) - .withQuery(Query.builder() - .table(ChapterTable.TABLE) - .where("${ChapterTable.COL_MANGA_ID} = ?") - .whereArgs(manga.id) - .build()) - .prepare() + .listOfObjects(Chapter::class.java) + .withQuery( + Query.builder() + .table(ChapterTable.TABLE) + .where("${ChapterTable.COL_MANGA_ID} = ?") + .whereArgs(manga.id) + .build() + ) + .prepare() fun getRecentChapters(date: Date) = db.get() - .listOfObjects(MangaChapter::class.java) - .withQuery(RawQuery.builder() - .query(getRecentsQuery()) - .args(date.time) - .observesTables(ChapterTable.TABLE) - .build()) - .withGetResolver(MangaChapterGetResolver.INSTANCE) - .prepare() + .listOfObjects(MangaChapter::class.java) + .withQuery( + RawQuery.builder() + .query(getRecentsQuery()) + .args(date.time) + .observesTables(ChapterTable.TABLE) + .build() + ) + .withGetResolver(MangaChapterGetResolver.INSTANCE) + .prepare() fun getChapter(id: Long) = db.get() - .`object`(Chapter::class.java) - .withQuery(Query.builder() - .table(ChapterTable.TABLE) - .where("${ChapterTable.COL_ID} = ?") - .whereArgs(id) - .build()) - .prepare() + .`object`(Chapter::class.java) + .withQuery( + Query.builder() + .table(ChapterTable.TABLE) + .where("${ChapterTable.COL_ID} = ?") + .whereArgs(id) + .build() + ) + .prepare() fun getChapter(url: String) = db.get() - .`object`(Chapter::class.java) - .withQuery(Query.builder() - .table(ChapterTable.TABLE) - .where("${ChapterTable.COL_URL} = ?") - .whereArgs(url) - .build()) - .prepare() + .`object`(Chapter::class.java) + .withQuery( + Query.builder() + .table(ChapterTable.TABLE) + .where("${ChapterTable.COL_URL} = ?") + .whereArgs(url) + .build() + ) + .prepare() fun getChapter(url: String, mangaId: Long) = db.get() - .`object`(Chapter::class.java) - .withQuery(Query.builder() - .table(ChapterTable.TABLE) - .where("${ChapterTable.COL_URL} = ? AND ${ChapterTable.COL_MANGA_ID} = ?") - .whereArgs(url, mangaId) - .build()) - .prepare() + .`object`(Chapter::class.java) + .withQuery( + Query.builder() + .table(ChapterTable.TABLE) + .where("${ChapterTable.COL_URL} = ? AND ${ChapterTable.COL_MANGA_ID} = ?") + .whereArgs(url, mangaId) + .build() + ) + .prepare() fun insertChapter(chapter: Chapter) = db.put().`object`(chapter).prepare() @@ -70,22 +80,22 @@ interface ChapterQueries : DbProvider { fun deleteChapters(chapters: List) = db.delete().objects(chapters).prepare() fun updateChaptersBackup(chapters: List) = db.put() - .objects(chapters) - .withPutResolver(ChapterBackupPutResolver()) - .prepare() + .objects(chapters) + .withPutResolver(ChapterBackupPutResolver()) + .prepare() fun updateChapterProgress(chapter: Chapter) = db.put() - .`object`(chapter) - .withPutResolver(ChapterProgressPutResolver()) - .prepare() + .`object`(chapter) + .withPutResolver(ChapterProgressPutResolver()) + .prepare() fun updateChaptersProgress(chapters: List) = db.put() - .objects(chapters) - .withPutResolver(ChapterProgressPutResolver()) - .prepare() + .objects(chapters) + .withPutResolver(ChapterProgressPutResolver()) + .prepare() fun fixChaptersSourceOrder(chapters: List) = db.put() - .objects(chapters) - .withPutResolver(ChapterSourceOrderPutResolver()) - .prepare() + .objects(chapters) + .withPutResolver(ChapterSourceOrderPutResolver()) + .prepare() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt index ef870cfdb7..fa4072dd9b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt @@ -23,32 +23,38 @@ interface HistoryQueries : DbProvider { * @param date recent date range */ fun getRecentManga(date: Date) = db.get() - .listOfObjects(MangaChapterHistory::class.java) - .withQuery(RawQuery.builder() - .query(getRecentMangasQuery()) - .args(date.time) - .observesTables(HistoryTable.TABLE) - .build()) - .withGetResolver(MangaChapterHistoryGetResolver.INSTANCE) - .prepare() + .listOfObjects(MangaChapterHistory::class.java) + .withQuery( + RawQuery.builder() + .query(getRecentMangasQuery()) + .args(date.time) + .observesTables(HistoryTable.TABLE) + .build() + ) + .withGetResolver(MangaChapterHistoryGetResolver.INSTANCE) + .prepare() fun getHistoryByMangaId(mangaId: Long) = db.get() - .listOfObjects(History::class.java) - .withQuery(RawQuery.builder() - .query(getHistoryByMangaId()) - .args(mangaId) - .observesTables(HistoryTable.TABLE) - .build()) - .prepare() + .listOfObjects(History::class.java) + .withQuery( + RawQuery.builder() + .query(getHistoryByMangaId()) + .args(mangaId) + .observesTables(HistoryTable.TABLE) + .build() + ) + .prepare() fun getHistoryByChapterUrl(chapterUrl: String) = db.get() - .`object`(History::class.java) - .withQuery(RawQuery.builder() - .query(getHistoryByChapterUrl()) - .args(chapterUrl) - .observesTables(HistoryTable.TABLE) - .build()) - .prepare() + .`object`(History::class.java) + .withQuery( + RawQuery.builder() + .query(getHistoryByChapterUrl()) + .args(chapterUrl) + .observesTables(HistoryTable.TABLE) + .build() + ) + .prepare() /** * Updates the history last read. @@ -56,9 +62,9 @@ interface HistoryQueries : DbProvider { * @param history history object */ fun updateHistoryLastRead(history: History) = db.put() - .`object`(history) - .withPutResolver(HistoryLastReadPutResolver()) - .prepare() + .`object`(history) + .withPutResolver(HistoryLastReadPutResolver()) + .prepare() /** * Updates the history last read. @@ -66,21 +72,25 @@ interface HistoryQueries : DbProvider { * @param historyList history object list */ fun updateHistoryLastRead(historyList: List) = db.put() - .objects(historyList) - .withPutResolver(HistoryLastReadPutResolver()) - .prepare() + .objects(historyList) + .withPutResolver(HistoryLastReadPutResolver()) + .prepare() fun deleteHistory() = db.delete() - .byQuery(DeleteQuery.builder() - .table(HistoryTable.TABLE) - .build()) - .prepare() + .byQuery( + DeleteQuery.builder() + .table(HistoryTable.TABLE) + .build() + ) + .prepare() fun deleteHistoryNoLastRead() = db.delete() - .byQuery(DeleteQuery.builder() - .table(HistoryTable.TABLE) - .where("${HistoryTable.COL_LAST_READ} = ?") - .whereArgs(0) - .build()) - .prepare() + .byQuery( + DeleteQuery.builder() + .table(HistoryTable.TABLE) + .where("${HistoryTable.COL_LAST_READ} = ?") + .whereArgs(0) + .build() + ) + .prepare() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaCategoryQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaCategoryQueries.kt index 926339d0c8..9330f4923a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaCategoryQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaCategoryQueries.kt @@ -15,12 +15,14 @@ interface MangaCategoryQueries : DbProvider { fun insertMangasCategories(mangasCategories: List) = db.put().objects(mangasCategories).prepare() fun deleteOldMangasCategories(mangas: List) = db.delete() - .byQuery(DeleteQuery.builder() - .table(MangaCategoryTable.TABLE) - .where("${MangaCategoryTable.COL_MANGA_ID} IN (${Queries.placeholders(mangas.size)})") - .whereArgs(*mangas.map { it.id }.toTypedArray()) - .build()) - .prepare() + .byQuery( + DeleteQuery.builder() + .table(MangaCategoryTable.TABLE) + .where("${MangaCategoryTable.COL_MANGA_ID} IN (${Queries.placeholders(mangas.size)})") + .whereArgs(*mangas.map { it.id }.toTypedArray()) + .build() + ) + .prepare() fun setMangaCategories(mangasCategories: List, mangas: List) { db.inTransaction { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt index b9161f0ccc..a4c9630c3c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt @@ -20,117 +20,137 @@ import eu.kanade.tachiyomi.data.database.tables.MangaTable interface MangaQueries : DbProvider { fun getMangas() = db.get() - .listOfObjects(Manga::class.java) - .withQuery(Query.builder() - .table(MangaTable.TABLE) - .build()) - .prepare() + .listOfObjects(Manga::class.java) + .withQuery( + Query.builder() + .table(MangaTable.TABLE) + .build() + ) + .prepare() fun getLibraryMangas() = db.get() - .listOfObjects(LibraryManga::class.java) - .withQuery(RawQuery.builder() - .query(libraryQuery) - .observesTables(MangaTable.TABLE, ChapterTable.TABLE, MangaCategoryTable.TABLE, CategoryTable.TABLE) - .build()) - .withGetResolver(LibraryMangaGetResolver.INSTANCE) - .prepare() + .listOfObjects(LibraryManga::class.java) + .withQuery( + RawQuery.builder() + .query(libraryQuery) + .observesTables(MangaTable.TABLE, ChapterTable.TABLE, MangaCategoryTable.TABLE, CategoryTable.TABLE) + .build() + ) + .withGetResolver(LibraryMangaGetResolver.INSTANCE) + .prepare() fun getFavoriteMangas() = db.get() - .listOfObjects(Manga::class.java) - .withQuery(Query.builder() - .table(MangaTable.TABLE) - .where("${MangaTable.COL_FAVORITE} = ?") - .whereArgs(1) - .orderBy(MangaTable.COL_TITLE) - .build()) - .prepare() + .listOfObjects(Manga::class.java) + .withQuery( + Query.builder() + .table(MangaTable.TABLE) + .where("${MangaTable.COL_FAVORITE} = ?") + .whereArgs(1) + .orderBy(MangaTable.COL_TITLE) + .build() + ) + .prepare() fun getManga(url: String, sourceId: Long) = db.get() - .`object`(Manga::class.java) - .withQuery(Query.builder() - .table(MangaTable.TABLE) - .where("${MangaTable.COL_URL} = ? AND ${MangaTable.COL_SOURCE} = ?") - .whereArgs(url, sourceId) - .build()) - .prepare() + .`object`(Manga::class.java) + .withQuery( + Query.builder() + .table(MangaTable.TABLE) + .where("${MangaTable.COL_URL} = ? AND ${MangaTable.COL_SOURCE} = ?") + .whereArgs(url, sourceId) + .build() + ) + .prepare() fun getManga(id: Long) = db.get() - .`object`(Manga::class.java) - .withQuery(Query.builder() - .table(MangaTable.TABLE) - .where("${MangaTable.COL_ID} = ?") - .whereArgs(id) - .build()) - .prepare() + .`object`(Manga::class.java) + .withQuery( + Query.builder() + .table(MangaTable.TABLE) + .where("${MangaTable.COL_ID} = ?") + .whereArgs(id) + .build() + ) + .prepare() fun insertManga(manga: Manga) = db.put().`object`(manga).prepare() fun insertMangas(mangas: List) = db.put().objects(mangas).prepare() fun updateFlags(manga: Manga) = db.put() - .`object`(manga) - .withPutResolver(MangaFlagsPutResolver()) - .prepare() + .`object`(manga) + .withPutResolver(MangaFlagsPutResolver()) + .prepare() fun updateLastUpdated(manga: Manga) = db.put() - .`object`(manga) - .withPutResolver(MangaLastUpdatedPutResolver()) - .prepare() + .`object`(manga) + .withPutResolver(MangaLastUpdatedPutResolver()) + .prepare() fun updateMangaFavorite(manga: Manga) = db.put() - .`object`(manga) - .withPutResolver(MangaFavoritePutResolver()) - .prepare() + .`object`(manga) + .withPutResolver(MangaFavoritePutResolver()) + .prepare() fun updateMangaViewer(manga: Manga) = db.put() - .`object`(manga) - .withPutResolver(MangaViewerPutResolver()) - .prepare() + .`object`(manga) + .withPutResolver(MangaViewerPutResolver()) + .prepare() fun updateMangaTitle(manga: Manga) = db.put() - .`object`(manga) - .withPutResolver(MangaTitlePutResolver()) - .prepare() + .`object`(manga) + .withPutResolver(MangaTitlePutResolver()) + .prepare() fun deleteManga(manga: Manga) = db.delete().`object`(manga).prepare() fun deleteMangas(mangas: List) = db.delete().objects(mangas).prepare() fun deleteMangasNotInLibrary() = db.delete() - .byQuery(DeleteQuery.builder() - .table(MangaTable.TABLE) - .where("${MangaTable.COL_FAVORITE} = ?") - .whereArgs(0) - .build()) - .prepare() + .byQuery( + DeleteQuery.builder() + .table(MangaTable.TABLE) + .where("${MangaTable.COL_FAVORITE} = ?") + .whereArgs(0) + .build() + ) + .prepare() fun deleteMangas() = db.delete() - .byQuery(DeleteQuery.builder() - .table(MangaTable.TABLE) - .build()) - .prepare() + .byQuery( + DeleteQuery.builder() + .table(MangaTable.TABLE) + .build() + ) + .prepare() fun getLastReadManga() = db.get() - .listOfObjects(Manga::class.java) - .withQuery(RawQuery.builder() - .query(getLastReadMangaQuery()) - .observesTables(MangaTable.TABLE) - .build()) - .prepare() + .listOfObjects(Manga::class.java) + .withQuery( + RawQuery.builder() + .query(getLastReadMangaQuery()) + .observesTables(MangaTable.TABLE) + .build() + ) + .prepare() fun getTotalChapterManga() = db.get() - .listOfObjects(Manga::class.java) - .withQuery(RawQuery.builder() - .query(getTotalChapterMangaQuery()) - .observesTables(MangaTable.TABLE) - .build()) - .prepare() + .listOfObjects(Manga::class.java) + .withQuery( + RawQuery.builder() + .query(getTotalChapterMangaQuery()) + .observesTables(MangaTable.TABLE) + .build() + ) + .prepare() fun getLatestChapterManga() = db.get() - .listOfObjects(Manga::class.java) - .withQuery(RawQuery.builder() - .query(getLatestChapterMangaQuery()) - .observesTables(MangaTable.TABLE) - .build()) - .prepare() + .listOfObjects(Manga::class.java) + .withQuery( + RawQuery.builder() + .query(getLatestChapterMangaQuery()) + .observesTables(MangaTable.TABLE) + .build() + ) + .prepare() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt index a57d2ed050..b24c9beb02 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt @@ -9,7 +9,8 @@ import eu.kanade.tachiyomi.data.database.tables.MangaTable as Manga /** * Query to get the manga from the library, with their categories and unread count. */ -val libraryQuery = """ +val libraryQuery = + """ SELECT M.*, COALESCE(MC.${MangaCategory.COL_CATEGORY_ID}, 0) AS ${Manga.COL_CATEGORY} FROM ( SELECT ${Manga.TABLE}.*, COALESCE(C.unread, 0) AS ${Manga.COL_UNREAD} @@ -33,7 +34,8 @@ val libraryQuery = """ /** * Query to get the recent chapters of manga from the library up to a date. */ -fun getRecentsQuery() = """ +fun getRecentsQuery() = + """ SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, * FROM ${Manga.TABLE} JOIN ${Chapter.TABLE} ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} WHERE ${Manga.COL_FAVORITE} = 1 AND ${Chapter.COL_DATE_UPLOAD} > ? @@ -47,7 +49,8 @@ fun getRecentsQuery() = """ * and are read after the given time period * @return return limit is 25 */ -fun getRecentMangasQuery() = """ +fun getRecentMangasQuery() = + """ SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.* FROM ${Manga.TABLE} JOIN ${Chapter.TABLE} @@ -65,7 +68,8 @@ fun getRecentMangasQuery() = """ LIMIT 25 """ -fun getHistoryByMangaId() = """ +fun getHistoryByMangaId() = + """ SELECT ${History.TABLE}.* FROM ${History.TABLE} JOIN ${Chapter.TABLE} @@ -73,7 +77,8 @@ fun getHistoryByMangaId() = """ WHERE ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = ? AND ${History.TABLE}.${History.COL_CHAPTER_ID} = ${Chapter.TABLE}.${Chapter.COL_ID} """ -fun getHistoryByChapterUrl() = """ +fun getHistoryByChapterUrl() = + """ SELECT ${History.TABLE}.* FROM ${History.TABLE} JOIN ${Chapter.TABLE} @@ -81,7 +86,8 @@ fun getHistoryByChapterUrl() = """ WHERE ${Chapter.TABLE}.${Chapter.COL_URL} = ? AND ${History.TABLE}.${History.COL_CHAPTER_ID} = ${Chapter.TABLE}.${Chapter.COL_ID} """ -fun getLastReadMangaQuery() = """ +fun getLastReadMangaQuery() = + """ SELECT ${Manga.TABLE}.*, MAX(${History.TABLE}.${History.COL_LAST_READ}) AS max FROM ${Manga.TABLE} JOIN ${Chapter.TABLE} @@ -93,7 +99,8 @@ fun getLastReadMangaQuery() = """ ORDER BY max DESC """ -fun getTotalChapterMangaQuery() = """ +fun getTotalChapterMangaQuery() = + """ SELECT ${Manga.TABLE}.* FROM ${Manga.TABLE} JOIN ${Chapter.TABLE} @@ -102,7 +109,8 @@ fun getTotalChapterMangaQuery() = """ ORDER by COUNT(*) """ -fun getLatestChapterMangaQuery() = """ +fun getLatestChapterMangaQuery() = + """ SELECT ${Manga.TABLE}.*, MAX(${Chapter.TABLE}.${Chapter.COL_DATE_UPLOAD}) AS max FROM ${Manga.TABLE} JOIN ${Chapter.TABLE} @@ -114,7 +122,8 @@ fun getLatestChapterMangaQuery() = """ /** * Query to get the categories for a manga. */ -fun getCategoriesForMangaQuery() = """ +fun getCategoriesForMangaQuery() = + """ SELECT ${Category.TABLE}.* FROM ${Category.TABLE} JOIN ${MangaCategory.TABLE} ON ${Category.TABLE}.${Category.COL_ID} = ${MangaCategory.TABLE}.${MangaCategory.COL_CATEGORY_ID} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/TrackQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/TrackQueries.kt index fee55dbd54..7311fe40de 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/TrackQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/TrackQueries.kt @@ -11,23 +11,27 @@ import eu.kanade.tachiyomi.data.track.TrackService interface TrackQueries : DbProvider { fun getTracks(manga: Manga) = db.get() - .listOfObjects(Track::class.java) - .withQuery(Query.builder() - .table(TrackTable.TABLE) - .where("${TrackTable.COL_MANGA_ID} = ?") - .whereArgs(manga.id) - .build()) - .prepare() + .listOfObjects(Track::class.java) + .withQuery( + Query.builder() + .table(TrackTable.TABLE) + .where("${TrackTable.COL_MANGA_ID} = ?") + .whereArgs(manga.id) + .build() + ) + .prepare() fun insertTrack(track: Track) = db.put().`object`(track).prepare() fun insertTracks(tracks: List) = db.put().objects(tracks).prepare() fun deleteTrackForManga(manga: Manga, sync: TrackService) = db.delete() - .byQuery(DeleteQuery.builder() - .table(TrackTable.TABLE) - .where("${TrackTable.COL_MANGA_ID} = ? AND ${TrackTable.COL_SYNC_ID} = ?") - .whereArgs(manga.id, sync.id) - .build()) - .prepare() + .byQuery( + DeleteQuery.builder() + .table(TrackTable.TABLE) + .where("${TrackTable.COL_MANGA_ID} = ? AND ${TrackTable.COL_SYNC_ID} = ?") + .whereArgs(manga.id, sync.id) + .build() + ) + .prepare() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterBackupPutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterBackupPutResolver.kt index d42758beae..20008e0748 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterBackupPutResolver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterBackupPutResolver.kt @@ -20,10 +20,10 @@ class ChapterBackupPutResolver : PutResolver() { } fun mapToUpdateQuery(chapter: Chapter) = UpdateQuery.builder() - .table(ChapterTable.TABLE) - .where("${ChapterTable.COL_URL} = ?") - .whereArgs(chapter.url) - .build() + .table(ChapterTable.TABLE) + .where("${ChapterTable.COL_URL} = ?") + .whereArgs(chapter.url) + .build() fun mapToContentValues(chapter: Chapter) = ContentValues(3).apply { put(ChapterTable.COL_READ, chapter.read) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterProgressPutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterProgressPutResolver.kt index d646d50c35..b2800551f8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterProgressPutResolver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterProgressPutResolver.kt @@ -20,10 +20,10 @@ class ChapterProgressPutResolver : PutResolver() { } fun mapToUpdateQuery(chapter: Chapter) = UpdateQuery.builder() - .table(ChapterTable.TABLE) - .where("${ChapterTable.COL_ID} = ?") - .whereArgs(chapter.id) - .build() + .table(ChapterTable.TABLE) + .where("${ChapterTable.COL_ID} = ?") + .whereArgs(chapter.id) + .build() fun mapToContentValues(chapter: Chapter) = ContentValues(3).apply { put(ChapterTable.COL_READ, chapter.read) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterSourceOrderPutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterSourceOrderPutResolver.kt index 40c7a7df79..fa0f3514c8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterSourceOrderPutResolver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterSourceOrderPutResolver.kt @@ -20,10 +20,10 @@ class ChapterSourceOrderPutResolver : PutResolver() { } fun mapToUpdateQuery(chapter: Chapter) = UpdateQuery.builder() - .table(ChapterTable.TABLE) - .where("${ChapterTable.COL_URL} = ? AND ${ChapterTable.COL_MANGA_ID} = ?") - .whereArgs(chapter.url, chapter.manga_id) - .build() + .table(ChapterTable.TABLE) + .where("${ChapterTable.COL_URL} = ? AND ${ChapterTable.COL_MANGA_ID} = ?") + .whereArgs(chapter.url, chapter.manga_id) + .build() fun mapToContentValues(chapter: Chapter) = ContentValues(1).apply { put(ChapterTable.COL_SOURCE_ORDER, chapter.source_order) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/HistoryLastReadPutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/HistoryLastReadPutResolver.kt index 3834b710b8..32f73c0097 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/HistoryLastReadPutResolver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/HistoryLastReadPutResolver.kt @@ -19,11 +19,13 @@ class HistoryLastReadPutResolver : HistoryPutResolver() { override fun performPut(@NonNull db: StorIOSQLite, @NonNull history: History): PutResult = db.inTransactionReturn { val updateQuery = mapToUpdateQuery(history) - val cursor = db.lowLevel().query(Query.builder() + val cursor = db.lowLevel().query( + Query.builder() .table(updateQuery.table()) .where(updateQuery.where()) .whereArgs(updateQuery.whereArgs()) - .build()) + .build() + ) val putResult: PutResult @@ -46,10 +48,10 @@ class HistoryLastReadPutResolver : HistoryPutResolver() { * @param obj history object */ override fun mapToUpdateQuery(obj: History) = UpdateQuery.builder() - .table(HistoryTable.TABLE) - .where("${HistoryTable.COL_CHAPTER_ID} = ?") - .whereArgs(obj.chapter_id) - .build() + .table(HistoryTable.TABLE) + .where("${HistoryTable.COL_CHAPTER_ID} = ?") + .whereArgs(obj.chapter_id) + .build() /** * Create content query diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFavoritePutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFavoritePutResolver.kt index a2d23f5051..5c948a2c8e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFavoritePutResolver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFavoritePutResolver.kt @@ -20,10 +20,10 @@ class MangaFavoritePutResolver : PutResolver() { } fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder() - .table(MangaTable.TABLE) - .where("${MangaTable.COL_ID} = ?") - .whereArgs(manga.id) - .build() + .table(MangaTable.TABLE) + .where("${MangaTable.COL_ID} = ?") + .whereArgs(manga.id) + .build() fun mapToContentValues(manga: Manga) = ContentValues(1).apply { put(MangaTable.COL_FAVORITE, manga.favorite) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFlagsPutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFlagsPutResolver.kt index 4ed0a07288..0a30da7dab 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFlagsPutResolver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFlagsPutResolver.kt @@ -20,10 +20,10 @@ class MangaFlagsPutResolver : PutResolver() { } fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder() - .table(MangaTable.TABLE) - .where("${MangaTable.COL_ID} = ?") - .whereArgs(manga.id) - .build() + .table(MangaTable.TABLE) + .where("${MangaTable.COL_ID} = ?") + .whereArgs(manga.id) + .build() fun mapToContentValues(manga: Manga) = ContentValues(1).apply { put(MangaTable.COL_CHAPTER_FLAGS, manga.chapter_flags) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaLastUpdatedPutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaLastUpdatedPutResolver.kt index b1e5e78165..6b33ed2554 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaLastUpdatedPutResolver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaLastUpdatedPutResolver.kt @@ -20,10 +20,10 @@ class MangaLastUpdatedPutResolver : PutResolver() { } fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder() - .table(MangaTable.TABLE) - .where("${MangaTable.COL_ID} = ?") - .whereArgs(manga.id) - .build() + .table(MangaTable.TABLE) + .where("${MangaTable.COL_ID} = ?") + .whereArgs(manga.id) + .build() fun mapToContentValues(manga: Manga) = ContentValues(1).apply { put(MangaTable.COL_LAST_UPDATE, manga.last_update) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaTitlePutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaTitlePutResolver.kt index 0ffb18ffd1..cb29c26d95 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaTitlePutResolver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaTitlePutResolver.kt @@ -20,10 +20,10 @@ class MangaTitlePutResolver : PutResolver() { } fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder() - .table(MangaTable.TABLE) - .where("${MangaTable.COL_ID} = ?") - .whereArgs(manga.id) - .build() + .table(MangaTable.TABLE) + .where("${MangaTable.COL_ID} = ?") + .whereArgs(manga.id) + .build() fun mapToContentValues(manga: Manga) = ContentValues(1).apply { put(MangaTable.COL_TITLE, manga.title) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaViewerPutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaViewerPutResolver.kt index a6b7c9b195..13005d24c2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaViewerPutResolver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaViewerPutResolver.kt @@ -20,10 +20,10 @@ class MangaViewerPutResolver : PutResolver() { } fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder() - .table(MangaTable.TABLE) - .where("${MangaTable.COL_ID} = ?") - .whereArgs(manga.id) - .build() + .table(MangaTable.TABLE) + .where("${MangaTable.COL_ID} = ?") + .whereArgs(manga.id) + .build() fun mapToContentValues(manga: Manga) = ContentValues(1).apply { put(MangaTable.COL_VIEWER, manga.viewer) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/CategoryTable.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/CategoryTable.kt index 297c2a8e08..76ffd7187e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/CategoryTable.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/CategoryTable.kt @@ -13,7 +13,8 @@ object CategoryTable { const val COL_FLAGS = "flags" val createTableQuery: String - get() = """CREATE TABLE $TABLE( + get() = + """CREATE TABLE $TABLE( $COL_ID INTEGER NOT NULL PRIMARY KEY, $COL_NAME TEXT NOT NULL, $COL_ORDER INTEGER NOT NULL, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/ChapterTable.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/ChapterTable.kt index afd54675a9..67047cc004 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/ChapterTable.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/ChapterTable.kt @@ -29,7 +29,8 @@ object ChapterTable { const val COL_SOURCE_ORDER = "source_order" val createTableQuery: String - get() = """CREATE TABLE $TABLE( + get() = + """CREATE TABLE $TABLE( $COL_ID INTEGER NOT NULL PRIMARY KEY, $COL_MANGA_ID INTEGER NOT NULL, $COL_URL TEXT NOT NULL, @@ -51,7 +52,7 @@ object ChapterTable { val createUnreadChaptersIndexQuery: String get() = "CREATE INDEX ${TABLE}_unread_by_manga_index ON $TABLE($COL_MANGA_ID, $COL_READ) " + - "WHERE $COL_READ = 0" + "WHERE $COL_READ = 0" val sourceOrderUpdateQuery: String get() = "ALTER TABLE $TABLE ADD COLUMN $COL_SOURCE_ORDER INTEGER DEFAULT 0" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/HistoryTable.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/HistoryTable.kt index d552b8fbd2..9d19544a49 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/HistoryTable.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/HistoryTable.kt @@ -31,7 +31,8 @@ object HistoryTable { * query to create history table */ val createTableQuery: String - get() = """CREATE TABLE $TABLE( + get() = + """CREATE TABLE $TABLE( $COL_ID INTEGER NOT NULL PRIMARY KEY, $COL_CHAPTER_ID INTEGER NOT NULL UNIQUE, $COL_LAST_READ LONG, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaCategoryTable.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaCategoryTable.kt index d0d34bbb78..578a85bbc9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaCategoryTable.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaCategoryTable.kt @@ -11,7 +11,8 @@ object MangaCategoryTable { const val COL_CATEGORY_ID = "category_id" val createTableQuery: String - get() = """CREATE TABLE $TABLE( + get() = + """CREATE TABLE $TABLE( $COL_ID INTEGER NOT NULL PRIMARY KEY, $COL_MANGA_ID INTEGER NOT NULL, $COL_CATEGORY_ID INTEGER NOT NULL, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaTable.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaTable.kt index 2b1ff7458d..cbea44d654 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaTable.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaTable.kt @@ -39,7 +39,8 @@ object MangaTable { const val COL_CATEGORY = "category" val createTableQuery: String - get() = """CREATE TABLE $TABLE( + get() = + """CREATE TABLE $TABLE( $COL_ID INTEGER NOT NULL PRIMARY KEY, $COL_SOURCE INTEGER NOT NULL, $COL_URL TEXT NOT NULL, @@ -62,5 +63,5 @@ object MangaTable { val createLibraryIndexQuery: String get() = "CREATE INDEX library_${COL_FAVORITE}_index ON $TABLE($COL_FAVORITE) " + - "WHERE $COL_FAVORITE = 1" + "WHERE $COL_FAVORITE = 1" } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt index fc30bafa6c..c8dff441a4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt @@ -31,7 +31,8 @@ object TrackTable { const val COL_FINISH_DATE = "finish_date" val createTableQuery: String - get() = """CREATE TABLE $TABLE( + get() = + """CREATE TABLE $TABLE( $COL_ID INTEGER NOT NULL PRIMARY KEY, $COL_MANGA_ID INTEGER NOT NULL, $COL_SYNC_ID INTEGER NOT NULL, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt index 6082cfdb9b..85ded01f8c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt @@ -100,8 +100,8 @@ class DownloadCache( val mangaDir = sourceDir.files[provider.getMangaDirName(manga)] if (mangaDir != null) { return mangaDir.files - .filter { !it.endsWith(Downloader.TMP_DIR_SUFFIX) } - .size + .filter { !it.endsWith(Downloader.TMP_DIR_SUFFIX) } + .size } } return 0 @@ -125,26 +125,26 @@ class DownloadCache( val onlineSources = sourceManager.getOnlineSources() val sourceDirs = rootDir.dir.listFiles() - .orEmpty() - .associate { it.name to SourceDirectory(it) } - .mapNotNullKeys { entry -> - onlineSources.find { provider.getSourceDirName(it) == entry.key }?.id - } + .orEmpty() + .associate { it.name to SourceDirectory(it) } + .mapNotNullKeys { entry -> + onlineSources.find { provider.getSourceDirName(it) == entry.key }?.id + } rootDir.files = sourceDirs sourceDirs.values.forEach { sourceDir -> val mangaDirs = sourceDir.dir.listFiles() - .orEmpty() - .associateNotNullKeys { it.name to MangaDirectory(it) } + .orEmpty() + .associateNotNullKeys { it.name to MangaDirectory(it) } sourceDir.files = mangaDirs mangaDirs.values.forEach { mangaDir -> val chapterDirs = mangaDir.dir.listFiles() - .orEmpty() - .mapNotNull { it.name } - .toHashSet() + .orEmpty() + .mapNotNull { it.name } + .toHashSet() mangaDir.files = chapterDirs } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt index d01d227fed..4593671ef4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt @@ -148,16 +148,16 @@ class DownloadManager(private val context: Context) { private fun buildPageList(chapterDir: UniFile?): Observable> { return Observable.fromCallable { val files = chapterDir?.listFiles().orEmpty() - .filter { "image" in it.type.orEmpty() } + .filter { "image" in it.type.orEmpty() } if (files.isEmpty()) { throw Exception("Page list is empty") } files.sortedBy { it.name } - .mapIndexed { i, file -> - Page(i, uri = file.uri).apply { status = Page.READY } - } + .mapIndexed { i, file -> + Page(i, uri = file.uri).apply { status = Page.READY } + } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt index 274c10959f..9a57144222 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt @@ -87,13 +87,15 @@ internal class DownloadNotifier(private val context: Context) { setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context)) isDownloading = true // Pause action - addAction(R.drawable.ic_pause_24dp, - context.getString(R.string.action_pause), - NotificationReceiver.pauseDownloadsPendingBroadcast(context)) + addAction( + R.drawable.ic_pause_24dp, + context.getString(R.string.action_pause), + NotificationReceiver.pauseDownloadsPendingBroadcast(context) + ) } val downloadingProgressText = context.getString(R.string.chapter_downloading_progress) - .format(download.downloadedImages, download.pages!!.size) + .format(download.downloadedImages, download.pages!!.size) if (preferences.hideNotificationContent()) { setContentTitle(downloadingProgressText) @@ -126,13 +128,17 @@ internal class DownloadNotifier(private val context: Context) { // Open download manager when clicked setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context)) // Resume action - addAction(R.drawable.ic_play_arrow_24dp, - context.getString(R.string.action_resume), - NotificationReceiver.resumeDownloadsPendingBroadcast(context)) + addAction( + R.drawable.ic_play_arrow_24dp, + context.getString(R.string.action_resume), + NotificationReceiver.resumeDownloadsPendingBroadcast(context) + ) // Clear action - addAction(R.drawable.ic_close_24dp, - context.getString(R.string.action_cancel_all), - NotificationReceiver.clearDownloadsPendingBroadcast(context)) + addAction( + R.drawable.ic_close_24dp, + context.getString(R.string.action_cancel_all), + NotificationReceiver.clearDownloadsPendingBroadcast(context) + ) } // Show notification. @@ -173,8 +179,10 @@ internal class DownloadNotifier(private val context: Context) { fun onError(error: String? = null, chapter: String? = null) { // Create notification with(notificationBuilder) { - setContentTitle(chapter - ?: context.getString(R.string.download_notifier_downloader_title)) + setContentTitle( + chapter + ?: context.getString(R.string.download_notifier_downloader_title) + ) setContentText(error ?: context.getString(R.string.download_notifier_unknown_error)) setSmallIcon(android.R.drawable.stat_sys_warning) clearActions() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt index 1d5f04ea75..3bf7a73008 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt @@ -52,8 +52,8 @@ class DownloadProvider(private val context: Context) { internal fun getMangaDir(manga: Manga, source: Source): UniFile { try { return downloadsDir - .createDirectory(getSourceDirName(source)) - .createDirectory(getMangaDirName(manga)) + .createDirectory(getSourceDirName(source)) + .createDirectory(getMangaDirName(manga)) } catch (e: NullPointerException) { throw Exception(context.getString(R.string.invalid_download_dir)) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadService.kt index 58b1acb394..332ac1ea8e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadService.kt @@ -123,14 +123,17 @@ class DownloadService : Service() { */ private fun listenNetworkChanges() { subscriptions += ReactiveNetwork.observeNetworkConnectivity(applicationContext) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ state -> + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { state -> onNetworkStateChanged(state) - }, { + }, + { toast(R.string.download_queue_error) stopSelf() - }) + } + ) } /** @@ -162,10 +165,11 @@ class DownloadService : Service() { */ private fun listenDownloaderState() { subscriptions += downloadManager.runningRelay.subscribe { running -> - if (running) + if (running) { wakeLock.acquireIfNeeded() - else + } else { wakeLock.releaseIfNeeded() + } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadStore.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadStore.kt index f5a6712636..de9b48630a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadStore.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadStore.kt @@ -77,9 +77,9 @@ class DownloadStore( */ fun restore(): List { val objs = preferences.all - .mapNotNull { it.value as? String } - .mapNotNull { deserialize(it) } - .sortedBy { it.order } + .mapNotNull { it.value as? String } + .mapNotNull { deserialize(it) } + .sortedBy { it.order } val downloads = mutableListOf() if (objs.isNotEmpty()) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt index a8ed2cb82a..3a8d47d25d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt @@ -100,11 +100,13 @@ class Downloader( * @return true if the downloader is started, false otherwise. */ fun start(): Boolean { - if (isRunning || queue.isEmpty()) + if (isRunning || queue.isEmpty()) { return false + } - if (!subscriptions.hasSubscriptions()) + if (!subscriptions.hasSubscriptions()) { initializeSubscriptions() + } val pending = queue.filter { it.status != Download.DOWNLOADED } pending.forEach { if (it.status != Download.QUEUE) it.status = Download.QUEUE } @@ -119,8 +121,8 @@ class Downloader( fun stop(reason: String? = null) { destroySubscriptions() queue - .filter { it.status == Download.DOWNLOADING } - .forEach { it.status = Download.ERROR } + .filter { it.status == Download.DOWNLOADING } + .forEach { it.status = Download.ERROR } if (reason != null) { notifier.onWarning(reason) @@ -140,8 +142,8 @@ class Downloader( fun pause() { destroySubscriptions() queue - .filter { it.status == Download.DOWNLOADING } - .forEach { it.status = Download.QUEUE } + .filter { it.status == Download.DOWNLOADING } + .forEach { it.status = Download.QUEUE } notifier.paused = true } @@ -156,8 +158,8 @@ class Downloader( // Needed to update the chapter view if (isNotification) { queue - .filter { it.status == Download.QUEUE } - .forEach { it.status = Download.NOT_DOWNLOADED } + .filter { it.status == Download.QUEUE } + .forEach { it.status = Download.NOT_DOWNLOADED } } queue.clear() notifier.dismiss() @@ -174,16 +176,19 @@ class Downloader( subscriptions.clear() subscriptions += downloadsRelay.concatMapIterable { it } - .concatMap { downloadChapter(it).subscribeOn(Schedulers.io()) } - .onBackpressureBuffer() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ + .concatMap { downloadChapter(it).subscribeOn(Schedulers.io()) } + .onBackpressureBuffer() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { completeDownload(it) - }, { error -> + }, + { error -> DownloadService.stop(context) Timber.e(error) notifier.onError(error.message) - }) + } + ) } /** @@ -212,20 +217,20 @@ class Downloader( val mangaDir = provider.findMangaDir(manga, source) chapters - // Avoid downloading chapters with the same name. - .distinctBy { it.name } - // Filter out those already downloaded. - .filter { mangaDir?.findFile(provider.getChapterDirName(it)) == null } - // Add chapters to queue from the start. - .sortedByDescending { it.source_order } + // Avoid downloading chapters with the same name. + .distinctBy { it.name } + // Filter out those already downloaded. + .filter { mangaDir?.findFile(provider.getChapterDirName(it)) == null } + // Add chapters to queue from the start. + .sortedByDescending { it.source_order } } // Runs in main thread (synchronization needed). val chaptersToQueue = chaptersWithoutDir.await() - // Filter out those already enqueued. - .filter { chapter -> queue.none { it.chapter.id == chapter.id } } - // Create a download for each one. - .map { Download(source, manga, it) } + // Filter out those already enqueued. + .filter { chapter -> queue.none { it.chapter.id == chapter.id } } + // Create a download for each one. + .map { Download(source, manga, it) } if (chaptersToQueue.isNotEmpty()) { queue.addAll(chaptersToQueue) @@ -255,43 +260,43 @@ class Downloader( val pageListObservable = if (download.pages == null) { // Pull page list from network and add them to download object download.source.fetchPageList(download.chapter) - .doOnNext { pages -> - if (pages.isEmpty()) { - throw Exception("Page list is empty") - } - download.pages = pages + .doOnNext { pages -> + if (pages.isEmpty()) { + throw Exception("Page list is empty") } + download.pages = pages + } } else { // Or if the page list already exists, start from the file Observable.just(download.pages!!) } pageListObservable - .doOnNext { _ -> - // Delete all temporary (unfinished) files - tmpDir.listFiles() - ?.filter { it.name!!.endsWith(".tmp") } - ?.forEach { it.delete() } + .doOnNext { _ -> + // Delete all temporary (unfinished) files + tmpDir.listFiles() + ?.filter { it.name!!.endsWith(".tmp") } + ?.forEach { it.delete() } - download.downloadedImages = 0 - download.status = Download.DOWNLOADING - } - // Get all the URLs to the source images, fetch pages if necessary - .flatMap { download.source.fetchAllImageUrlsFromPageList(it) } - // Start downloading images, consider we can have downloaded images already - .concatMap { page -> getOrDownloadImage(page, download, tmpDir) } - // Do when page is downloaded. - .doOnNext { notifier.onProgressChange(download) } - .toList() - .map { download } - // Do after download completes - .doOnNext { ensureSuccessfulDownload(download, mangaDir, tmpDir, chapterDirname) } - // If the page list threw, it will resume here - .onErrorReturn { error -> - download.status = Download.ERROR - notifier.onError(error.message, download.chapter.name) - download - } + download.downloadedImages = 0 + download.status = Download.DOWNLOADING + } + // Get all the URLs to the source images, fetch pages if necessary + .flatMap { download.source.fetchAllImageUrlsFromPageList(it) } + // Start downloading images, consider we can have downloaded images already + .concatMap { page -> getOrDownloadImage(page, download, tmpDir) } + // Do when page is downloaded. + .doOnNext { notifier.onProgressChange(download) } + .toList() + .map { download } + // Do after download completes + .doOnNext { ensureSuccessfulDownload(download, mangaDir, tmpDir, chapterDirname) } + // If the page list threw, it will resume here + .onErrorReturn { error -> + download.status = Download.ERROR + notifier.onError(error.message, download.chapter.name) + download + } } /** @@ -304,8 +309,9 @@ class Downloader( */ private fun getOrDownloadImage(page: Page, download: Download, tmpDir: UniFile): Observable { // If the image URL is empty, do nothing - if (page.imageUrl == null) + if (page.imageUrl == null) { return Observable.just(page) + } val filename = String.format("%03d", page.number) val tmpFile = tmpDir.findFile("$filename.tmp") @@ -317,26 +323,27 @@ class Downloader( val imageFile = tmpDir.listFiles()!!.find { it.name!!.startsWith("$filename.") } // If the image is already downloaded, do nothing. Otherwise download from network - val pageObservable = if (imageFile != null) + val pageObservable = if (imageFile != null) { Observable.just(imageFile) - else + } else { downloadImage(page, download.source, tmpDir, filename) + } return pageObservable - // When the image is ready, set image path, progress (just in case) and status - .doOnNext { file -> - page.uri = file.uri - page.progress = 100 - download.downloadedImages++ - page.status = Page.READY - } - .map { page } - // Mark this page as error and allow to download the remaining - .onErrorReturn { - page.progress = 0 - page.status = Page.ERROR - page - } + // When the image is ready, set image path, progress (just in case) and status + .doOnNext { file -> + page.uri = file.uri + page.progress = 100 + download.downloadedImages++ + page.status = Page.READY + } + .map { page } + // Mark this page as error and allow to download the remaining + .onErrorReturn { + page.progress = 0 + page.status = Page.ERROR + page + } } /** @@ -351,21 +358,21 @@ class Downloader( page.status = Page.DOWNLOAD_IMAGE page.progress = 0 return source.fetchImage(page) - .map { response -> - val file = tmpDir.createFile("$filename.tmp") - try { - response.body!!.source().saveTo(file.openOutputStream()) - val extension = getImageExtension(response, file) - file.renameTo("$filename.$extension") - } catch (e: Exception) { - response.close() - file.delete() - throw e - } - file + .map { response -> + val file = tmpDir.createFile("$filename.tmp") + try { + response.body!!.source().saveTo(file.openOutputStream()) + val extension = getImageExtension(response, file) + file.renameTo("$filename.$extension") + } catch (e: Exception) { + response.close() + file.delete() + throw e } - // Retry 3 times, waiting 2, 4 and 8 seconds between attempts. - .retryWhen(RetryWithDelay(3, { (2 shl it - 1) * 1000 }, Schedulers.trampoline())) + file + } + // Retry 3 times, waiting 2, 4 and 8 seconds between attempts. + .retryWhen(RetryWithDelay(3, { (2 shl it - 1) * 1000 }, Schedulers.trampoline())) } /** @@ -378,10 +385,10 @@ class Downloader( private fun getImageExtension(response: Response, file: UniFile): String { // Read content type if available. val mime = response.body?.contentType()?.let { ct -> "${ct.type}/${ct.subtype}" } - // Else guess from the uri. - ?: context.contentResolver.getType(file.uri) - // Else read magic numbers. - ?: ImageUtil.findImageType { file.openInputStream() }?.mime + // Else guess from the uri. + ?: context.contentResolver.getType(file.uri) + // Else read magic numbers. + ?: ImageUtil.findImageType { file.openInputStream() }?.mime return MimeTypeMap.getSingleton().getExtensionFromMimeType(mime) ?: "jpg" } @@ -400,7 +407,6 @@ class Downloader( tmpDir: UniFile, dirname: String ) { - // Ensure that the chapter folder has all the images. val downloadedImages = tmpDir.listFiles().orEmpty().filterNot { it.name!!.endsWith(".tmp") } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/model/DownloadQueue.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/model/DownloadQueue.kt index a6aa931f72..79dde6a6ed 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/model/DownloadQueue.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/model/DownloadQueue.kt @@ -70,13 +70,13 @@ class DownloadQueue( } fun getActiveDownloads(): Observable = - Observable.from(this).filter { download -> download.status == Download.DOWNLOADING } + Observable.from(this).filter { download -> download.status == Download.DOWNLOADING } fun getStatusObservable(): Observable = statusSubject.onBackpressureBuffer() fun getUpdatedObservable(): Observable> = updatedRelay.onBackpressureBuffer() - .startWith(Unit) - .map { this } + .startWith(Unit) + .map { this } private fun setPagesFor(download: Download) { if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) { @@ -86,21 +86,21 @@ class DownloadQueue( fun getProgressObservable(): Observable { return statusSubject.onBackpressureBuffer() - .startWith(getActiveDownloads()) - .flatMap { download -> - if (download.status == Download.DOWNLOADING) { - val pageStatusSubject = PublishSubject.create() - setPagesSubject(download.pages, pageStatusSubject) - return@flatMap pageStatusSubject - .onBackpressureBuffer() - .filter { it == Page.READY } - .map { download } - } else if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) { - setPagesSubject(download.pages, null) - } - Observable.just(download) + .startWith(getActiveDownloads()) + .flatMap { download -> + if (download.status == Download.DOWNLOADING) { + val pageStatusSubject = PublishSubject.create() + setPagesSubject(download.pages, pageStatusSubject) + return@flatMap pageStatusSubject + .onBackpressureBuffer() + .filter { it == Page.READY } + .map { download } + } else if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) { + setPagesSubject(download.pages, null) } - .filter { it.status == Download.DOWNLOADING } + Observable.just(download) + } + .filter { it.status == Download.DOWNLOADING } } private fun setPagesSubject(pages: List?, subject: PublishSubject?) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/glide/LibraryMangaUrlFetcher.kt b/app/src/main/java/eu/kanade/tachiyomi/data/glide/LibraryMangaUrlFetcher.kt index c61e3fc922..79c81af4f2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/glide/LibraryMangaUrlFetcher.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/glide/LibraryMangaUrlFetcher.kt @@ -25,36 +25,39 @@ class LibraryMangaUrlFetcher( override fun loadData(priority: Priority, callback: DataFetcher.DataCallback) { if (!file.exists()) { - networkFetcher.loadData(priority, object : DataFetcher.DataCallback { - override fun onDataReady(data: InputStream?) { - if (data != null) { - val tmpFile = File(file.path + ".tmp") - try { - // Retrieve destination stream, create parent folders if needed. - val output = try { - tmpFile.outputStream() - } catch (e: FileNotFoundException) { - tmpFile.parentFile.mkdirs() - tmpFile.outputStream() - } + networkFetcher.loadData( + priority, + object : DataFetcher.DataCallback { + override fun onDataReady(data: InputStream?) { + if (data != null) { + val tmpFile = File(file.path + ".tmp") + try { + // Retrieve destination stream, create parent folders if needed. + val output = try { + tmpFile.outputStream() + } catch (e: FileNotFoundException) { + tmpFile.parentFile.mkdirs() + tmpFile.outputStream() + } - // Copy the file and rename to the original. - data.use { output.use { data.copyTo(output) } } - tmpFile.renameTo(file) - loadFromFile(callback) - } catch (e: Exception) { - tmpFile.delete() - callback.onLoadFailed(e) + // Copy the file and rename to the original. + data.use { output.use { data.copyTo(output) } } + tmpFile.renameTo(file) + loadFromFile(callback) + } catch (e: Exception) { + tmpFile.delete() + callback.onLoadFailed(e) + } + } else { + callback.onLoadFailed(Exception("Null data")) } - } else { - callback.onLoadFailed(Exception("Null data")) + } + + override fun onLoadFailed(e: Exception) { + callback.onLoadFailed(e) } } - - override fun onLoadFailed(e: Exception) { - callback.onLoadFailed(e) - } - }) + ) } else { loadFromFile(callback) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/glide/TachiGlideModule.kt b/app/src/main/java/eu/kanade/tachiyomi/data/glide/TachiGlideModule.kt index 40d57b6fdd..9e83370f53 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/glide/TachiGlideModule.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/glide/TachiGlideModule.kt @@ -27,8 +27,10 @@ class TachiGlideModule : AppGlideModule() { override fun applyOptions(context: Context, builder: GlideBuilder) { builder.setDiskCache(InternalCacheDiskCacheFactory(context, 50 * 1024 * 1024)) builder.setDefaultRequestOptions(RequestOptions().format(DecodeFormat.PREFER_RGB_565)) - builder.setDefaultTransitionOptions(Drawable::class.java, - DrawableTransitionOptions.withCrossFade()) + builder.setDefaultTransitionOptions( + Drawable::class.java, + DrawableTransitionOptions.withCrossFade() + ) } override fun registerComponents(context: Context, glide: Glide, registry: Registry) { @@ -36,7 +38,10 @@ class TachiGlideModule : AppGlideModule() { registry.replace(GlideUrl::class.java, InputStream::class.java, networkFactory) registry.append(MangaThumbnail::class.java, InputStream::class.java, MangaThumbnailModelLoader.Factory()) - registry.append(InputStream::class.java, InputStream::class.java, PassthroughModelLoader - .Factory()) + registry.append( + InputStream::class.java, InputStream::class.java, + PassthroughModelLoader + .Factory() + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt index 12c0f15785..2f4230edf6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt @@ -14,7 +14,7 @@ import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get class LibraryUpdateJob(private val context: Context, workerParams: WorkerParameters) : - Worker(context, workerParams) { + Worker(context, workerParams) { override fun doWork(): Result { LibraryUpdateService.start(context) @@ -30,22 +30,24 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet if (interval > 0) { val restrictions = preferences.libraryUpdateRestriction()!! val acRestriction = "ac" in restrictions - val wifiRestriction = if ("wifi" in restrictions) + val wifiRestriction = if ("wifi" in restrictions) { NetworkType.UNMETERED - else + } else { NetworkType.CONNECTED + } val constraints = Constraints.Builder() - .setRequiredNetworkType(wifiRestriction) - .setRequiresCharging(acRestriction) - .build() + .setRequiredNetworkType(wifiRestriction) + .setRequiresCharging(acRestriction) + .build() val request = PeriodicWorkRequestBuilder( - interval.toLong(), TimeUnit.HOURS, - 10, TimeUnit.MINUTES) - .addTag(TAG) - .setConstraints(constraints) - .build() + interval.toLong(), TimeUnit.HOURS, + 10, TimeUnit.MINUTES + ) + .addTag(TAG) + .setConstraints(constraints) + .build() WorkManager.getInstance(context).enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.REPLACE, request) } else { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateRanker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateRanker.kt index b392e006ac..651a391ee4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateRanker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateRanker.kt @@ -8,8 +8,9 @@ import eu.kanade.tachiyomi.data.database.models.Manga object LibraryUpdateRanker { val rankingScheme = listOf( - (this::lexicographicRanking)(), - (this::latestFirstRanking)()) + (this::lexicographicRanking)(), + (this::latestFirstRanking)() + ) /** * Provides a total ordering over all the Mangas. @@ -22,7 +23,7 @@ object LibraryUpdateRanker { */ fun latestFirstRanking(): Comparator { return Comparator { mangaFirst: Manga, - mangaSecond: Manga -> + mangaSecond: Manga -> compareValues(mangaSecond.last_update, mangaFirst.last_update) } } @@ -35,7 +36,7 @@ object LibraryUpdateRanker { */ fun lexicographicRanking(): Comparator { return Comparator { mangaFirst: Manga, - mangaSecond: Manga -> + mangaSecond: Manga -> compareValues(mangaFirst.title, mangaSecond.title) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt index a5a70f8e3b..5d33d56db3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt @@ -184,7 +184,8 @@ class LibraryUpdateService( super.onCreate() startForeground(Notifications.ID_LIBRARY_PROGRESS, progressNotificationBuilder.build()) wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, "LibraryUpdateService:WakeLock") + PowerManager.PARTIAL_WAKE_LOCK, "LibraryUpdateService:WakeLock" + ) wakeLock.acquire() } @@ -218,33 +219,37 @@ class LibraryUpdateService( override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { if (intent == null) return START_NOT_STICKY val target = intent.getSerializableExtra(KEY_TARGET) as? Target - ?: return START_NOT_STICKY + ?: return START_NOT_STICKY // Unsubscribe from any previous subscription if needed. subscription?.unsubscribe() // Update favorite manga. Destroy service when completed or in case of an error. subscription = Observable - .defer { - val selectedScheme = preferences.libraryUpdatePrioritization().get() - val mangaList = getMangaToUpdate(intent, target) - .sortedWith(rankingScheme[selectedScheme]) + .defer { + val selectedScheme = preferences.libraryUpdatePrioritization().get() + val mangaList = getMangaToUpdate(intent, target) + .sortedWith(rankingScheme[selectedScheme]) - // Update either chapter list or manga details. - when (target) { - Target.CHAPTERS -> updateChapterList(mangaList) - Target.DETAILS -> updateDetails(mangaList) - Target.TRACKING -> updateTrackings(mangaList) - } + // Update either chapter list or manga details. + when (target) { + Target.CHAPTERS -> updateChapterList(mangaList) + Target.DETAILS -> updateDetails(mangaList) + Target.TRACKING -> updateTrackings(mangaList) } - .subscribeOn(Schedulers.io()) - .subscribe({ - }, { + } + .subscribeOn(Schedulers.io()) + .subscribe( + { + }, + { Timber.e(it) stopSelf(startId) - }, { + }, + { stopSelf(startId) - }) + } + ) return START_REDELIVER_INTENT } @@ -259,16 +264,17 @@ class LibraryUpdateService( fun getMangaToUpdate(intent: Intent, target: Target): List { val categoryId = intent.getIntExtra(KEY_CATEGORY, -1) - var listToUpdate = if (categoryId != -1) + var listToUpdate = if (categoryId != -1) { db.getLibraryMangas().executeAsBlocking().filter { it.category == categoryId } - else { + } else { val categoriesToUpdate = preferences.libraryUpdateCategories().get().map(String::toInt) - if (categoriesToUpdate.isNotEmpty()) + if (categoriesToUpdate.isNotEmpty()) { db.getLibraryMangas().executeAsBlocking() - .filter { it.category in categoriesToUpdate } - .distinctBy { it.id } - else + .filter { it.category in categoriesToUpdate } + .distinctBy { it.id } + } else { db.getLibraryMangas().executeAsBlocking().distinctBy { it.id } + } } if (target == Target.CHAPTERS && preferences.updateOnlyNonCompleted()) { listToUpdate = listToUpdate.filter { it.status != SManga.COMPLETED } @@ -302,55 +308,57 @@ class LibraryUpdateService( // Emit each manga and update it sequentially. return Observable.from(mangaToUpdate) - // Notify manga that will update. - .doOnNext { showProgressNotification(it, count.andIncrement, mangaToUpdate.size) } - // Update the chapters of the manga. - .concatMap { manga -> - updateManga(manga) - // If there's any error, return empty update and continue. - .onErrorReturn { - failedUpdates.add(manga) - Pair(emptyList(), emptyList()) - } - // Filter out mangas without new chapters (or failed). - .filter { pair -> pair.first.isNotEmpty() } - .doOnNext { - if (downloadNew && (categoriesToDownload.isEmpty() || - manga.category in categoriesToDownload)) { - - downloadChapters(manga, it.first) - hasDownloads = true - } - } - // Convert to the manga that contains new chapters. - .map { - Pair( - manga, - (it.first.sortedByDescending { ch -> ch.source_order }.toTypedArray()) - ) - } - } - // Add manga with new chapters to the list. - .doOnNext { manga -> - // Add to the list - newUpdates.add(manga) - } - // Notify result of the overall update. - .doOnCompleted { - if (newUpdates.isNotEmpty()) { - showUpdateNotifications(newUpdates) - if (downloadNew && hasDownloads) { - DownloadService.start(this) + // Notify manga that will update. + .doOnNext { showProgressNotification(it, count.andIncrement, mangaToUpdate.size) } + // Update the chapters of the manga. + .concatMap { manga -> + updateManga(manga) + // If there's any error, return empty update and continue. + .onErrorReturn { + failedUpdates.add(manga) + Pair(emptyList(), emptyList()) + } + // Filter out mangas without new chapters (or failed). + .filter { pair -> pair.first.isNotEmpty() } + .doOnNext { + if (downloadNew && ( + categoriesToDownload.isEmpty() || + manga.category in categoriesToDownload + ) + ) { + downloadChapters(manga, it.first) + hasDownloads = true } } - - if (failedUpdates.isNotEmpty()) { - Timber.e("Failed updating: ${failedUpdates.map { it.title }}") + // Convert to the manga that contains new chapters. + .map { + Pair( + manga, + (it.first.sortedByDescending { ch -> ch.source_order }.toTypedArray()) + ) + } + } + // Add manga with new chapters to the list. + .doOnNext { manga -> + // Add to the list + newUpdates.add(manga) + } + // Notify result of the overall update. + .doOnCompleted { + if (newUpdates.isNotEmpty()) { + showUpdateNotifications(newUpdates) + if (downloadNew && hasDownloads) { + DownloadService.start(this) } - - cancelProgressNotification() } - .map { manga -> manga.first } + + if (failedUpdates.isNotEmpty()) { + Timber.e("Failed updating: ${failedUpdates.map { it.title }}") + } + + cancelProgressNotification() + } + .map { manga -> manga.first } } fun downloadChapters(manga: Manga, chapters: List) { @@ -373,7 +381,7 @@ class LibraryUpdateService( fun updateManga(manga: Manga): Observable, List>> { val source = sourceManager.get(manga.source) as? HttpSource ?: return Observable.empty() return source.fetchChapterList(manga) - .map { syncChaptersWithSource(db, it, manga, source) } + .map { syncChaptersWithSource(db, it, manga, source) } } /** @@ -389,24 +397,24 @@ class LibraryUpdateService( // Emit each manga and update it sequentially. return Observable.from(mangaToUpdate) - // Notify manga that will update. - .doOnNext { showProgressNotification(it, count.andIncrement, mangaToUpdate.size) } - // Update the details of the manga. - .concatMap { manga -> - val source = sourceManager.get(manga.source) as? HttpSource - ?: return@concatMap Observable.empty() + // Notify manga that will update. + .doOnNext { showProgressNotification(it, count.andIncrement, mangaToUpdate.size) } + // Update the details of the manga. + .concatMap { manga -> + val source = sourceManager.get(manga.source) as? HttpSource + ?: return@concatMap Observable.empty() - source.fetchMangaDetails(manga) - .map { networkManga -> - manga.copyFrom(networkManga) - db.insertManga(manga).executeAsBlocking() - manga - } - .onErrorReturn { manga } - } - .doOnCompleted { - cancelProgressNotification() - } + source.fetchMangaDetails(manga) + .map { networkManga -> + manga.copyFrom(networkManga) + db.insertManga(manga).executeAsBlocking() + manga + } + .onErrorReturn { manga } + } + .doOnCompleted { + cancelProgressNotification() + } } /** @@ -421,28 +429,28 @@ class LibraryUpdateService( // Emit each manga and update it sequentially. return Observable.from(mangaToUpdate) - // Notify manga that will update. - .doOnNext { showProgressNotification(it, count++, mangaToUpdate.size) } - // Update the tracking details. - .concatMap { manga -> - val tracks = db.getTracks(manga).executeAsBlocking() + // Notify manga that will update. + .doOnNext { showProgressNotification(it, count++, mangaToUpdate.size) } + // Update the tracking details. + .concatMap { manga -> + val tracks = db.getTracks(manga).executeAsBlocking() - Observable.from(tracks) - .concatMap { track -> - val service = trackManager.getService(track.sync_id) - if (service != null && service in loggedServices) { - service.refresh(track) - .doOnNext { db.insertTrack(it).executeAsBlocking() } - .onErrorReturn { track } - } else { - Observable.empty() - } - } - .map { manga } - } - .doOnCompleted { - cancelProgressNotification() - } + Observable.from(tracks) + .concatMap { track -> + val service = trackManager.getService(track.sync_id) + if (service != null && service in loggedServices) { + service.refresh(track) + .doOnNext { db.insertTrack(it).executeAsBlocking() } + .onErrorReturn { track } + } else { + Observable.empty() + } + } + .map { manga } + } + .doOnCompleted { + cancelProgressNotification() + } } /** @@ -453,15 +461,19 @@ class LibraryUpdateService( * @param total the total progress. */ private fun showProgressNotification(manga: Manga, current: Int, total: Int) { - val title = if (preferences.hideNotificationContent()) + val title = if (preferences.hideNotificationContent()) { getString(R.string.notification_check_updates) - else + } else { manga.title + } - notificationManager.notify(Notifications.ID_LIBRARY_PROGRESS, progressNotificationBuilder + notificationManager.notify( + Notifications.ID_LIBRARY_PROGRESS, + progressNotificationBuilder .setContentTitle(title) .setProgress(total, current, false) - .build()) + .build() + ) } /** @@ -476,31 +488,38 @@ class LibraryUpdateService( NotificationManagerCompat.from(this).apply { // Parent group notification - notify(Notifications.ID_NEW_CHAPTERS, notification(Notifications.CHANNEL_NEW_CHAPTERS) { - setContentTitle(getString(R.string.notification_new_chapters)) - if (updates.size == 1 && !preferences.hideNotificationContent()) { - setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN)) - } else { - setContentText(resources.getQuantityString(R.plurals.notification_new_chapters_summary, updates.size, updates.size)) + notify( + Notifications.ID_NEW_CHAPTERS, + notification(Notifications.CHANNEL_NEW_CHAPTERS) { + setContentTitle(getString(R.string.notification_new_chapters)) + if (updates.size == 1 && !preferences.hideNotificationContent()) { + setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN)) + } else { + setContentText(resources.getQuantityString(R.plurals.notification_new_chapters_summary, updates.size, updates.size)) - if (!preferences.hideNotificationContent()) { - setStyle(NotificationCompat.BigTextStyle().bigText(updates.joinToString("\n") { - it.first.title.chop(NOTIF_TITLE_MAX_LEN) - })) + if (!preferences.hideNotificationContent()) { + setStyle( + NotificationCompat.BigTextStyle().bigText( + updates.joinToString("\n") { + it.first.title.chop(NOTIF_TITLE_MAX_LEN) + } + ) + ) + } } + + setSmallIcon(R.drawable.ic_tachi) + setLargeIcon(notificationBitmap) + + setGroup(Notifications.GROUP_NEW_CHAPTERS) + setGroupAlertBehavior(GROUP_ALERT_SUMMARY) + setGroupSummary(true) + priority = NotificationCompat.PRIORITY_HIGH + + setContentIntent(getNotificationIntent()) + setAutoCancel(true) } - - setSmallIcon(R.drawable.ic_tachi) - setLargeIcon(notificationBitmap) - - setGroup(Notifications.GROUP_NEW_CHAPTERS) - setGroupAlertBehavior(GROUP_ALERT_SUMMARY) - setGroupSummary(true) - priority = NotificationCompat.PRIORITY_HIGH - - setContentIntent(getNotificationIntent()) - setAutoCancel(true) - }) + ) // Per-manga notification if (!preferences.hideNotificationContent()) { @@ -536,13 +555,21 @@ class LibraryUpdateService( setAutoCancel(true) // Mark chapters as read action - addAction(R.drawable.ic_glasses_black_24dp, getString(R.string.action_mark_as_read), - NotificationReceiver.markAsReadPendingBroadcast(this@LibraryUpdateService, - manga, chapters, Notifications.ID_NEW_CHAPTERS)) + addAction( + R.drawable.ic_glasses_black_24dp, getString(R.string.action_mark_as_read), + NotificationReceiver.markAsReadPendingBroadcast( + this@LibraryUpdateService, + manga, chapters, Notifications.ID_NEW_CHAPTERS + ) + ) // View chapters action - addAction(R.drawable.ic_book_24dp, getString(R.string.action_view_chapters), - NotificationReceiver.openChapterPendingActivity(this@LibraryUpdateService, - manga, Notifications.ID_NEW_CHAPTERS)) + addAction( + R.drawable.ic_book_24dp, getString(R.string.action_view_chapters), + NotificationReceiver.openChapterPendingActivity( + this@LibraryUpdateService, + manga, Notifications.ID_NEW_CHAPTERS + ) + ) } } @@ -556,28 +583,31 @@ class LibraryUpdateService( private fun getMangaIcon(manga: Manga): Bitmap? { return try { Glide.with(this) - .asBitmap() - .load(manga.toMangaThumbnail()) - .dontTransform() - .centerCrop() - .circleCrop() - .override(NOTIF_ICON_SIZE, NOTIF_ICON_SIZE) - .submit() - .get() + .asBitmap() + .load(manga.toMangaThumbnail()) + .dontTransform() + .centerCrop() + .circleCrop() + .override(NOTIF_ICON_SIZE, NOTIF_ICON_SIZE) + .submit() + .get() } catch (e: Exception) { null } } private fun getNewChaptersDescription(chapters: Array): String { - val formatter = DecimalFormat("#.###", DecimalFormatSymbols() - .apply { decimalSeparator = '.' }) + val formatter = DecimalFormat( + "#.###", + DecimalFormatSymbols() + .apply { decimalSeparator = '.' } + ) val displayableChapterNumbers = chapters - .filter { it.isRecognizedNumber } - .sortedBy { it.chapter_number } - .map { formatter.format(it.chapter_number) } - .toSet() + .filter { it.isRecognizedNumber } + .sortedBy { it.chapter_number } + .map { formatter.format(it.chapter_number) } + .toSet() return when (displayableChapterNumbers.size) { // No sensible chapter numbers to show (i.e. no chapters have parsed chapter number) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt index 0fbbdf4a26..40333ee2c3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt @@ -54,22 +54,35 @@ class NotificationReceiver : BroadcastReceiver() { // Clear the download queue ACTION_CLEAR_DOWNLOADS -> downloadManager.clearQueue(true) // Launch share activity and dismiss notification - ACTION_SHARE_IMAGE -> shareImage(context, intent.getStringExtra(EXTRA_FILE_LOCATION), - intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)) + ACTION_SHARE_IMAGE -> + shareImage( + context, intent.getStringExtra(EXTRA_FILE_LOCATION), + intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1) + ) // Delete image from path and dismiss notification - ACTION_DELETE_IMAGE -> deleteImage(context, intent.getStringExtra(EXTRA_FILE_LOCATION), - intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)) + ACTION_DELETE_IMAGE -> + deleteImage( + context, intent.getStringExtra(EXTRA_FILE_LOCATION), + intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1) + ) // Share backup file - ACTION_SHARE_BACKUP -> shareBackup(context, intent.getParcelableExtra(EXTRA_URI), - intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)) - ACTION_CANCEL_RESTORE -> cancelRestore(context, - intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)) + ACTION_SHARE_BACKUP -> + shareBackup( + context, intent.getParcelableExtra(EXTRA_URI), + intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1) + ) + ACTION_CANCEL_RESTORE -> cancelRestore( + context, + intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1) + ) // Cancel library update and dismiss notification ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context, Notifications.ID_LIBRARY_PROGRESS) // Open reader activity ACTION_OPEN_CHAPTER -> { - openChapter(context, intent.getLongExtra(EXTRA_MANGA_ID, -1), - intent.getLongExtra(EXTRA_CHAPTER_ID, -1)) + openChapter( + context, intent.getLongExtra(EXTRA_MANGA_ID, -1), + intent.getLongExtra(EXTRA_CHAPTER_ID, -1) + ) } // Mark updated manga chapters as read ACTION_MARK_AS_READ -> { @@ -208,19 +221,19 @@ class NotificationReceiver : BroadcastReceiver() { launchIO { chapterUrls.mapNotNull { db.getChapter(it, mangaId).executeAsBlocking() } - .forEach { - it.read = true - db.updateChapterProgress(it).executeAsBlocking() - if (preferences.removeAfterMarkedAsRead()) { - val manga = db.getManga(mangaId).executeAsBlocking() - if (manga != null) { - val source = sourceManager.get(manga.source) - if (source != null) { - downloadManager.deleteChapters(listOf(it), manga, source) - } + .forEach { + it.read = true + db.updateChapterProgress(it).executeAsBlocking() + if (preferences.removeAfterMarkedAsRead()) { + val manga = db.getManga(mangaId).executeAsBlocking() + if (manga != null) { + val source = sourceManager.get(manga.source) + if (source != null) { + downloadManager.deleteChapters(listOf(it), manga, source) } } } + } } } @@ -427,11 +440,11 @@ class NotificationReceiver : BroadcastReceiver() { */ internal fun openChapterPendingActivity(context: Context, manga: Manga, groupId: Int): PendingIntent { val newIntent = - Intent(context, MainActivity::class.java).setAction(MainActivity.SHORTCUT_MANGA) - .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - .putExtra(MangaController.MANGA_EXTRA, manga.id) - .putExtra("notificationId", manga.id.hashCode()) - .putExtra("groupId", groupId) + Intent(context, MainActivity::class.java).setAction(MainActivity.SHORTCUT_MANGA) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + .putExtra(MangaController.MANGA_EXTRA, manga.id) + .putExtra("notificationId", manga.id.hashCode()) + .putExtra("groupId", groupId) return PendingIntent.getActivity(context, manga.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt index fa45ac4bcb..c006ce9513 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt @@ -61,24 +61,36 @@ object Notifications { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return val channels = listOf( - NotificationChannel(CHANNEL_COMMON, context.getString(R.string.channel_common), - NotificationManager.IMPORTANCE_LOW), - NotificationChannel(CHANNEL_LIBRARY, context.getString(R.string.channel_library), - NotificationManager.IMPORTANCE_LOW).apply { - setShowBadge(false) - }, - NotificationChannel(CHANNEL_DOWNLOADER, context.getString(R.string.channel_downloader), - NotificationManager.IMPORTANCE_LOW).apply { - setShowBadge(false) - }, - NotificationChannel(CHANNEL_NEW_CHAPTERS, context.getString(R.string.channel_new_chapters), - NotificationManager.IMPORTANCE_DEFAULT), - NotificationChannel(CHANNEL_UPDATES_TO_EXTS, context.getString(R.string.channel_ext_updates), - NotificationManager.IMPORTANCE_DEFAULT), - NotificationChannel(CHANNEL_BACKUP_RESTORE, context.getString(R.string.channel_backup_restore), - NotificationManager.IMPORTANCE_HIGH).apply { - setShowBadge(false) - } + NotificationChannel( + CHANNEL_COMMON, context.getString(R.string.channel_common), + NotificationManager.IMPORTANCE_LOW + ), + NotificationChannel( + CHANNEL_LIBRARY, context.getString(R.string.channel_library), + NotificationManager.IMPORTANCE_LOW + ).apply { + setShowBadge(false) + }, + NotificationChannel( + CHANNEL_DOWNLOADER, context.getString(R.string.channel_downloader), + NotificationManager.IMPORTANCE_LOW + ).apply { + setShowBadge(false) + }, + NotificationChannel( + CHANNEL_NEW_CHAPTERS, context.getString(R.string.channel_new_chapters), + NotificationManager.IMPORTANCE_DEFAULT + ), + NotificationChannel( + CHANNEL_UPDATES_TO_EXTS, context.getString(R.string.channel_ext_updates), + NotificationManager.IMPORTANCE_DEFAULT + ), + NotificationChannel( + CHANNEL_BACKUP_RESTORE, context.getString(R.string.channel_backup_restore), + NotificationManager.IMPORTANCE_HIGH + ).apply { + setShowBadge(false) + } ) context.notificationManager.createNotificationChannels(channels) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index 3bd69b4b5d..2fca7fde6b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -45,12 +45,20 @@ class PreferencesHelper(val context: Context) { private val flowPrefs = FlowSharedPreferences(prefs) private val defaultDownloadsDir = Uri.fromFile( - File(Environment.getExternalStorageDirectory().absolutePath + File.separator + - context.getString(R.string.app_name), "downloads")) + File( + Environment.getExternalStorageDirectory().absolutePath + File.separator + + context.getString(R.string.app_name), + "downloads" + ) + ) private val defaultBackupDir = Uri.fromFile( - File(Environment.getExternalStorageDirectory().absolutePath + File.separator + - context.getString(R.string.app_name), "backup")) + File( + Environment.getExternalStorageDirectory().absolutePath + File.separator + + context.getString(R.string.app_name), + "backup" + ) + ) fun startScreen() = prefs.getInt(Keys.startScreen, 1) @@ -148,9 +156,9 @@ class PreferencesHelper(val context: Context) { fun setTrackCredentials(sync: TrackService, username: String, password: String) { prefs.edit() - .putString(Keys.trackUsername(sync.id), username) - .putString(Keys.trackPassword(sync.id), password) - .apply() + .putString(Keys.trackUsername(sync.id), username) + .putString(Keys.trackPassword(sync.id), password) + .apply() } fun trackToken(sync: TrackService) = flowPrefs.getString(Keys.trackToken(sync.id), "") diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt index 3fd39018d2..8c2c54da85 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt @@ -63,7 +63,7 @@ abstract class TrackService(val id: Int) { open val isLogged: Boolean get() = getUsername().isNotEmpty() && - getPassword().isNotEmpty() + getPassword().isNotEmpty() fun getUsername() = preferences.trackUsername(this)!! diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt index bba0ea0aaf..0ad37fa03a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt @@ -150,18 +150,18 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) { override fun bind(track: Track): Observable { return api.findLibManga(track, getUsername().toInt()) - .flatMap { remoteTrack -> - if (remoteTrack != null) { - track.copyPersonalFrom(remoteTrack) - track.library_id = remoteTrack.library_id - update(track) - } else { - // Set default fields if it's not found in the list - track.score = DEFAULT_SCORE.toFloat() - track.status = DEFAULT_STATUS - add(track) - } + .flatMap { remoteTrack -> + if (remoteTrack != null) { + track.copyPersonalFrom(remoteTrack) + track.library_id = remoteTrack.library_id + update(track) + } else { + // Set default fields if it's not found in the list + track.score = DEFAULT_SCORE.toFloat() + track.status = DEFAULT_STATUS + add(track) } + } } override fun search(query: String): Observable> { @@ -170,11 +170,11 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) { override fun refresh(track: Track): Observable { return api.getLibManga(track, getUsername().toInt()) - .map { remoteTrack -> - track.copyPersonalFrom(remoteTrack) - track.total_chapters = remoteTrack.total_chapters - track - } + .map { remoteTrack -> + track.copyPersonalFrom(remoteTrack) + track.total_chapters = remoteTrack.total_chapters + track + } } override fun login(username: String, password: String) = login(password) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt index 321daa7b75..201d84be6c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt @@ -25,7 +25,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { private val authClient = client.newBuilder().addInterceptor(interceptor).build() fun addLibManga(track: Track): Observable { - val query = """ + val query = + """ |mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) { |SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status) { | id @@ -34,35 +35,36 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { |} |""".trimMargin() val variables = jsonObject( - "mangaId" to track.media_id, - "progress" to track.last_chapter_read, - "status" to track.toAnilistStatus() + "mangaId" to track.media_id, + "progress" to track.last_chapter_read, + "status" to track.toAnilistStatus() ) val payload = jsonObject( - "query" to query, - "variables" to variables + "query" to query, + "variables" to variables ) val body = payload.toString().toRequestBody(jsonMime) val request = Request.Builder() - .url(apiUrl) - .post(body) - .build() + .url(apiUrl) + .post(body) + .build() return authClient.newCall(request) - .asObservableSuccess() - .map { netResponse -> - val responseBody = netResponse.body?.string().orEmpty() - netResponse.close() - if (responseBody.isEmpty()) { - throw Exception("Null Response") - } - val response = JsonParser.parseString(responseBody).obj - track.library_id = response["data"]["SaveMediaListEntry"]["id"].asLong - track + .asObservableSuccess() + .map { netResponse -> + val responseBody = netResponse.body?.string().orEmpty() + netResponse.close() + if (responseBody.isEmpty()) { + throw Exception("Null Response") } + val response = JsonParser.parseString(responseBody).obj + track.library_id = response["data"]["SaveMediaListEntry"]["id"].asLong + track + } } fun updateLibManga(track: Track): Observable { - val query = """ + val query = + """ |mutation UpdateManga(${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}score: Int) { |SaveMediaListEntry (id: ${'$'}listId, progress: ${'$'}progress, status: ${'$'}status, scoreRaw: ${'$'}score) { |id @@ -72,29 +74,30 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { |} |""".trimMargin() val variables = jsonObject( - "listId" to track.library_id, - "progress" to track.last_chapter_read, - "status" to track.toAnilistStatus(), - "score" to track.score.toInt() + "listId" to track.library_id, + "progress" to track.last_chapter_read, + "status" to track.toAnilistStatus(), + "score" to track.score.toInt() ) val payload = jsonObject( - "query" to query, - "variables" to variables + "query" to query, + "variables" to variables ) val body = payload.toString().toRequestBody(jsonMime) val request = Request.Builder() - .url(apiUrl) - .post(body) - .build() + .url(apiUrl) + .post(body) + .build() return authClient.newCall(request) - .asObservableSuccess() - .map { - track - } + .asObservableSuccess() + .map { + track + } } fun search(search: String): Observable> { - val query = """ + val query = + """ |query Search(${'$'}query: String) { |Page (perPage: 50) { |media(search: ${'$'}query, type: MANGA, format_not_in: [NOVEL]) { @@ -119,35 +122,36 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { |} |""".trimMargin() val variables = jsonObject( - "query" to search + "query" to search ) val payload = jsonObject( - "query" to query, - "variables" to variables + "query" to query, + "variables" to variables ) val body = payload.toString().toRequestBody(jsonMime) val request = Request.Builder() - .url(apiUrl) - .post(body) - .build() + .url(apiUrl) + .post(body) + .build() return authClient.newCall(request) - .asObservableSuccess() - .map { netResponse -> - val responseBody = netResponse.body?.string().orEmpty() - if (responseBody.isEmpty()) { - throw Exception("Null Response") - } - val response = JsonParser.parseString(responseBody).obj - val data = response["data"]!!.obj - val page = data["Page"].obj - val media = page["media"].array - val entries = media.map { jsonToALManga(it.obj) } - entries.map { it.toTrack() } + .asObservableSuccess() + .map { netResponse -> + val responseBody = netResponse.body?.string().orEmpty() + if (responseBody.isEmpty()) { + throw Exception("Null Response") } + val response = JsonParser.parseString(responseBody).obj + val data = response["data"]!!.obj + val page = data["Page"].obj + val media = page["media"].array + val entries = media.map { jsonToALManga(it.obj) } + entries.map { it.toTrack() } + } } fun findLibManga(track: Track, userid: Int): Observable { - val query = """ + val query = + """ |query (${'$'}id: Int!, ${'$'}manga_id: Int!) { |Page { |mediaList(userId: ${'$'}id, type: MANGA, mediaId: ${'$'}manga_id) { @@ -178,37 +182,37 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { |} |""".trimMargin() val variables = jsonObject( - "id" to userid, - "manga_id" to track.media_id + "id" to userid, + "manga_id" to track.media_id ) val payload = jsonObject( - "query" to query, - "variables" to variables + "query" to query, + "variables" to variables ) val body = payload.toString().toRequestBody(jsonMime) val request = Request.Builder() - .url(apiUrl) - .post(body) - .build() + .url(apiUrl) + .post(body) + .build() return authClient.newCall(request) - .asObservableSuccess() - .map { netResponse -> - val responseBody = netResponse.body?.string().orEmpty() - if (responseBody.isEmpty()) { - throw Exception("Null Response") - } - val response = JsonParser.parseString(responseBody).obj - val data = response["data"]!!.obj - val page = data["Page"].obj - val media = page["mediaList"].array - val entries = media.map { jsonToALUserManga(it.obj) } - entries.firstOrNull()?.toTrack() + .asObservableSuccess() + .map { netResponse -> + val responseBody = netResponse.body?.string().orEmpty() + if (responseBody.isEmpty()) { + throw Exception("Null Response") } + val response = JsonParser.parseString(responseBody).obj + val data = response["data"]!!.obj + val page = data["Page"].obj + val media = page["mediaList"].array + val entries = media.map { jsonToALUserManga(it.obj) } + entries.firstOrNull()?.toTrack() + } } fun getLibManga(track: Track, userid: Int): Observable { return findLibManga(track, userid) - .map { it ?: throw Exception("Could not find manga") } + .map { it ?: throw Exception("Could not find manga") } } fun createOAuth(token: String): OAuth { @@ -216,7 +220,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { } fun getCurrentUser(): Observable> { - val query = """ + val query = + """ |query User { |Viewer { |id @@ -227,41 +232,48 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { |} |""".trimMargin() val payload = jsonObject( - "query" to query + "query" to query ) val body = payload.toString().toRequestBody(jsonMime) val request = Request.Builder() - .url(apiUrl) - .post(body) - .build() + .url(apiUrl) + .post(body) + .build() return authClient.newCall(request) - .asObservableSuccess() - .map { netResponse -> - val responseBody = netResponse.body?.string().orEmpty() - if (responseBody.isEmpty()) { - throw Exception("Null Response") - } - val response = JsonParser.parseString(responseBody).obj - val data = response["data"]!!.obj - val viewer = data["Viewer"].obj - Pair(viewer["id"].asInt, viewer["mediaListOptions"]["scoreFormat"].asString) + .asObservableSuccess() + .map { netResponse -> + val responseBody = netResponse.body?.string().orEmpty() + if (responseBody.isEmpty()) { + throw Exception("Null Response") } + val response = JsonParser.parseString(responseBody).obj + val data = response["data"]!!.obj + val viewer = data["Viewer"].obj + Pair(viewer["id"].asInt, viewer["mediaListOptions"]["scoreFormat"].asString) + } } private fun jsonToALManga(struct: JsonObject): ALManga { val date = try { val date = Calendar.getInstance() - date.set(struct["startDate"]["year"].nullInt ?: 0, (struct["startDate"]["month"].nullInt - ?: 0) - 1, - struct["startDate"]["day"].nullInt ?: 0) + date.set( + struct["startDate"]["year"].nullInt ?: 0, + ( + struct["startDate"]["month"].nullInt + ?: 0 + ) - 1, + struct["startDate"]["day"].nullInt ?: 0 + ) date.timeInMillis } catch (_: Exception) { 0L } - return ALManga(struct["id"].asInt, struct["title"]["romaji"].asString, struct["coverImage"]["large"].asString, - struct["description"].nullString.orEmpty(), struct["type"].asString, struct["status"].asString, - date, struct["chapters"].nullInt ?: 0) + return ALManga( + struct["id"].asInt, struct["title"]["romaji"].asString, struct["coverImage"]["large"].asString, + struct["description"].nullString.orEmpty(), struct["type"].asString, struct["status"].asString, + date, struct["chapters"].nullInt ?: 0 + ) } private fun jsonToALUserManga(struct: JsonObject): ALUserManga { @@ -280,8 +292,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { } fun authUrl() = Uri.parse("${baseUrl}oauth/authorize").buildUpon() - .appendQueryParameter("client_id", clientId) - .appendQueryParameter("response_type", "token") - .build() + .appendQueryParameter("client_id", clientId) + .appendQueryParameter("response_type", "token") + .build() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistInterceptor.kt index 4fd13dae1e..07ac60111b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistInterceptor.kt @@ -38,8 +38,8 @@ class AnilistInterceptor(val anilist: Anilist, private var token: String?) : Int // Add the authorization header to the original request. val authRequest = originalRequest.newBuilder() - .addHeader("Authorization", "Bearer ${oauth!!.access_token}") - .build() + .addHeader("Authorization", "Bearer ${oauth!!.access_token}") + .build() return chain.proceed(authRequest) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt index bb042f6454..99f1db5817 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt @@ -39,23 +39,23 @@ class Bangumi(private val context: Context, id: Int) : TrackService(id) { override fun bind(track: Track): Observable { return api.statusLibManga(track) - .flatMap { - api.findLibManga(track).flatMap { remoteTrack -> - if (remoteTrack != null && it != null) { - track.copyPersonalFrom(remoteTrack) - track.library_id = remoteTrack.library_id - track.status = remoteTrack.status - track.last_chapter_read = remoteTrack.last_chapter_read - refresh(track) - } else { - // Set default fields if it's not found in the list - track.score = DEFAULT_SCORE.toFloat() - track.status = DEFAULT_STATUS - add(track) - update(track) - } + .flatMap { + api.findLibManga(track).flatMap { remoteTrack -> + if (remoteTrack != null && it != null) { + track.copyPersonalFrom(remoteTrack) + track.library_id = remoteTrack.library_id + track.status = remoteTrack.status + track.last_chapter_read = remoteTrack.last_chapter_read + refresh(track) + } else { + // Set default fields if it's not found in the list + track.score = DEFAULT_SCORE.toFloat() + track.status = DEFAULT_STATUS + add(track) + update(track) } } + } } override fun search(query: String): Observable> { @@ -64,17 +64,17 @@ class Bangumi(private val context: Context, id: Int) : TrackService(id) { override fun refresh(track: Track): Observable { return api.statusLibManga(track) - .flatMap { - track.copyPersonalFrom(it!!) - api.findLibManga(track) - .map { remoteTrack -> - if (remoteTrack != null) { - track.total_chapters = remoteTrack.total_chapters - track.status = remoteTrack.status - } - track - } - } + .flatMap { + track.copyPersonalFrom(it!!) + api.findLibManga(track) + .map { remoteTrack -> + if (remoteTrack != null) { + track.total_chapters = remoteTrack.total_chapters + track.status = remoteTrack.status + } + track + } + } } override fun getLogo() = R.drawable.ic_tracker_bangumi diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt index 8095744648..a5c44106b7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt @@ -26,73 +26,74 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept fun addLibManga(track: Track): Observable { val body = FormBody.Builder() - .add("rating", track.score.toInt().toString()) - .add("status", track.toBangumiStatus()) - .build() + .add("rating", track.score.toInt().toString()) + .add("status", track.toBangumiStatus()) + .build() val request = Request.Builder() - .url("$apiUrl/collection/${track.media_id}/update") - .post(body) - .build() + .url("$apiUrl/collection/${track.media_id}/update") + .post(body) + .build() return authClient.newCall(request) - .asObservableSuccess() - .map { - track - } + .asObservableSuccess() + .map { + track + } } fun updateLibManga(track: Track): Observable { // chapter update val body = FormBody.Builder() - .add("watched_eps", track.last_chapter_read.toString()) - .build() + .add("watched_eps", track.last_chapter_read.toString()) + .build() val request = Request.Builder() - .url("$apiUrl/subject/${track.media_id}/update/watched_eps") - .post(body) - .build() + .url("$apiUrl/subject/${track.media_id}/update/watched_eps") + .post(body) + .build() // read status update val sbody = FormBody.Builder() - .add("status", track.toBangumiStatus()) - .build() + .add("status", track.toBangumiStatus()) + .build() val srequest = Request.Builder() - .url("$apiUrl/collection/${track.media_id}/update") - .post(sbody) - .build() + .url("$apiUrl/collection/${track.media_id}/update") + .post(sbody) + .build() return authClient.newCall(srequest) - .asObservableSuccess() - .map { - track - }.flatMap { - authClient.newCall(request) - .asObservableSuccess() - .map { - track - } - } + .asObservableSuccess() + .map { + track + }.flatMap { + authClient.newCall(request) + .asObservableSuccess() + .map { + track + } + } } fun search(search: String): Observable> { val url = Uri.parse( - "$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}").buildUpon() - .appendQueryParameter("max_results", "20") - .build() + "$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}" + ).buildUpon() + .appendQueryParameter("max_results", "20") + .build() val request = Request.Builder() - .url(url.toString()) - .get() - .build() + .url(url.toString()) + .get() + .build() return authClient.newCall(request) - .asObservableSuccess() - .map { netResponse -> - var responseBody = netResponse.body?.string().orEmpty() - if (responseBody.isEmpty()) { - throw Exception("Null Response") - } - if (responseBody.contains("\"code\":404")) { - responseBody = "{\"results\":0,\"list\":[]}" - } - val response = JsonParser.parseString(responseBody).obj["list"]?.array - response?.filter { it.obj["type"].asInt == 1 }?.map { jsonToSearch(it.obj) } + .asObservableSuccess() + .map { netResponse -> + var responseBody = netResponse.body?.string().orEmpty() + if (responseBody.isEmpty()) { + throw Exception("Null Response") } + if (responseBody.contains("\"code\":404")) { + responseBody = "{\"results\":0,\"list\":[]}" + } + val response = JsonParser.parseString(responseBody).obj["list"]?.array + response?.filter { it.obj["type"].asInt == 1 }?.map { jsonToSearch(it.obj) } + } } private fun jsonToSearch(obj: JsonObject): TrackSearch { @@ -109,9 +110,15 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept return Track.create(TrackManager.BANGUMI).apply { title = mangas["name"].asString media_id = mangas["id"].asInt - score = if (mangas["rating"] != null) - (if (mangas["rating"].isJsonObject) mangas["rating"].obj["score"].asFloat else 0f) - else 0f + score = if (mangas["rating"] != null) { + if (mangas["rating"].isJsonObject) { + mangas["rating"].obj["score"].asFloat + } else { + 0f + } + } else { + 0f + } status = Bangumi.DEFAULT_STATUS tracking_url = mangas["url"].asString } @@ -120,37 +127,37 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept fun findLibManga(track: Track): Observable { val urlMangas = "$apiUrl/subject/${track.media_id}" val requestMangas = Request.Builder() - .url(urlMangas) - .get() - .build() + .url(urlMangas) + .get() + .build() return authClient.newCall(requestMangas) - .asObservableSuccess() - .map { netResponse -> - // get comic info - val responseBody = netResponse.body?.string().orEmpty() - jsonToTrack(JsonParser.parseString(responseBody).obj) - } + .asObservableSuccess() + .map { netResponse -> + // get comic info + val responseBody = netResponse.body?.string().orEmpty() + jsonToTrack(JsonParser.parseString(responseBody).obj) + } } fun statusLibManga(track: Track): Observable { val urlUserRead = "$apiUrl/collection/${track.media_id}" val requestUserRead = Request.Builder() - .url(urlUserRead) - .cacheControl(CacheControl.FORCE_NETWORK) - .get() - .build() + .url(urlUserRead) + .cacheControl(CacheControl.FORCE_NETWORK) + .get() + .build() // todo get user readed chapter here return authClient.newCall(requestUserRead) - .asObservableSuccess() - .map { netResponse -> - val resp = netResponse.body?.string() - val coll = gson.fromJson(resp, Collection::class.java) - track.status = coll.status?.id!! - track.last_chapter_read = coll.ep_status!! - track - } + .asObservableSuccess() + .map { netResponse -> + val resp = netResponse.body?.string() + val coll = gson.fromJson(resp, Collection::class.java) + track.status = coll.status?.id!! + track.last_chapter_read = coll.ep_status!! + track + } } fun accessToken(code: String): Observable { @@ -163,14 +170,15 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept } } - private fun accessTokenRequest(code: String) = POST(oauthUrl, - body = FormBody.Builder() - .add("grant_type", "authorization_code") - .add("client_id", clientId) - .add("client_secret", clientSecret) - .add("code", code) - .add("redirect_uri", redirectUrl) - .build() + private fun accessTokenRequest(code: String) = POST( + oauthUrl, + body = FormBody.Builder() + .add("grant_type", "authorization_code") + .add("client_id", clientId) + .add("client_secret", clientSecret) + .add("code", code) + .add("redirect_uri", redirectUrl) + .build() ) companion object { @@ -190,19 +198,21 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept } fun authUrl() = - Uri.parse(loginUrl).buildUpon() - .appendQueryParameter("client_id", clientId) - .appendQueryParameter("response_type", "code") - .appendQueryParameter("redirect_uri", redirectUrl) - .build() + Uri.parse(loginUrl).buildUpon() + .appendQueryParameter("client_id", clientId) + .appendQueryParameter("response_type", "code") + .appendQueryParameter("redirect_uri", redirectUrl) + .build() - fun refreshTokenRequest(token: String) = POST(oauthUrl, - body = FormBody.Builder() - .add("grant_type", "refresh_token") - .add("client_id", clientId) - .add("client_secret", clientSecret) - .add("refresh_token", token) - .add("redirect_uri", redirectUrl) - .build()) + fun refreshTokenRequest(token: String) = POST( + oauthUrl, + body = FormBody.Builder() + .add("grant_type", "refresh_token") + .add("client_id", clientId) + .add("client_secret", clientSecret) + .add("refresh_token", token) + .add("redirect_uri", redirectUrl) + .build() + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiInterceptor.kt index add168201e..2ffa9ad0e1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiInterceptor.kt @@ -36,25 +36,28 @@ class BangumiInterceptor(val bangumi: Bangumi, val gson: Gson) : Interceptor { } val authRequest = if (originalRequest.method == "GET") originalRequest.newBuilder() - .header("User-Agent", "Tachiyomi") - .url(originalRequest.url.newBuilder() - .addQueryParameter("access_token", currAuth.access_token).build()) - .build() else originalRequest.newBuilder() - .post(addTocken(currAuth.access_token, originalRequest.body as FormBody)) - .header("User-Agent", "Tachiyomi") - .build() + .header("User-Agent", "Tachiyomi") + .url( + originalRequest.url.newBuilder() + .addQueryParameter("access_token", currAuth.access_token).build() + ) + .build() else originalRequest.newBuilder() + .post(addTocken(currAuth.access_token, originalRequest.body as FormBody)) + .header("User-Agent", "Tachiyomi") + .build() return chain.proceed(authRequest) } fun newAuth(oauth: OAuth?) { this.oauth = if (oauth == null) null else OAuth( - oauth.access_token, - oauth.token_type, - System.currentTimeMillis() / 1000, - oauth.expires_in, - oauth.refresh_token, - this.oauth?.user_id) + oauth.access_token, + oauth.token_type, + System.currentTimeMillis() / 1000, + oauth.expires_in, + oauth.refresh_token, + this.oauth?.user_id + ) bangumi.saveToken(oauth) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt index 593f0fd526..8b5ef74f1f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt @@ -78,17 +78,17 @@ class Kitsu(private val context: Context, id: Int) : TrackService(id) { override fun bind(track: Track): Observable { return api.findLibManga(track, getUserId()) - .flatMap { remoteTrack -> - if (remoteTrack != null) { - track.copyPersonalFrom(remoteTrack) - track.media_id = remoteTrack.media_id - update(track) - } else { - track.score = DEFAULT_SCORE - track.status = DEFAULT_STATUS - add(track) - } + .flatMap { remoteTrack -> + if (remoteTrack != null) { + track.copyPersonalFrom(remoteTrack) + track.media_id = remoteTrack.media_id + update(track) + } else { + track.score = DEFAULT_SCORE + track.status = DEFAULT_STATUS + add(track) } + } } override fun search(query: String): Observable> { @@ -97,20 +97,20 @@ class Kitsu(private val context: Context, id: Int) : TrackService(id) { override fun refresh(track: Track): Observable { return api.getLibManga(track) - .map { remoteTrack -> - track.copyPersonalFrom(remoteTrack) - track.total_chapters = remoteTrack.total_chapters - track - } + .map { remoteTrack -> + track.copyPersonalFrom(remoteTrack) + track.total_chapters = remoteTrack.total_chapters + track + } } override fun login(username: String, password: String): Completable { return api.login(username, password) - .doOnNext { interceptor.newAuth(it) } - .flatMap { api.getCurrentUser() } - .doOnNext { userId -> saveCredentials(username, userId) } - .doOnError { logout() } - .toCompletable() + .doOnNext { interceptor.newAuth(it) } + .flatMap { api.getCurrentUser() } + .doOnNext { userId -> saveCredentials(username, userId) } + .doOnError { logout() } + .toCompletable() } override fun logout() { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt index 20ca7136c6..63e55c65da 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt @@ -33,59 +33,59 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) private val authClient = client.newBuilder().addInterceptor(interceptor).build() private val rest = Retrofit.Builder() - .baseUrl(baseUrl) - .client(authClient) - .addConverterFactory(GsonConverterFactory.create(GsonBuilder().serializeNulls().create())) - .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) - .build() - .create(Rest::class.java) + .baseUrl(baseUrl) + .client(authClient) + .addConverterFactory(GsonConverterFactory.create(GsonBuilder().serializeNulls().create())) + .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) + .build() + .create(Rest::class.java) private val searchRest = Retrofit.Builder() - .baseUrl(algoliaKeyUrl) - .client(authClient) - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) - .build() - .create(SearchKeyRest::class.java) + .baseUrl(algoliaKeyUrl) + .client(authClient) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) + .build() + .create(SearchKeyRest::class.java) private val algoliaRest = Retrofit.Builder() - .baseUrl(algoliaUrl) - .client(client) - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) - .build() - .create(AgoliaSearchRest::class.java) + .baseUrl(algoliaUrl) + .client(client) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) + .build() + .create(AgoliaSearchRest::class.java) fun addLibManga(track: Track, userId: String): Observable { return Observable.defer { // @formatter:off val data = jsonObject( - "type" to "libraryEntries", - "attributes" to jsonObject( - "status" to track.toKitsuStatus(), - "progress" to track.last_chapter_read + "type" to "libraryEntries", + "attributes" to jsonObject( + "status" to track.toKitsuStatus(), + "progress" to track.last_chapter_read + ), + "relationships" to jsonObject( + "user" to jsonObject( + "data" to jsonObject( + "id" to userId, + "type" to "users" + ) ), - "relationships" to jsonObject( - "user" to jsonObject( - "data" to jsonObject( - "id" to userId, - "type" to "users" - ) - ), - "media" to jsonObject( - "data" to jsonObject( - "id" to track.media_id, - "type" to "manga" - ) - ) + "media" to jsonObject( + "data" to jsonObject( + "id" to track.media_id, + "type" to "manga" + ) ) + ) ) rest.addLibManga(jsonObject("data" to data)) - .map { json -> - track.media_id = json["data"]["id"].int - track - } + .map { json -> + track.media_id = json["data"]["id"].int + track + } } } @@ -93,77 +93,77 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) return Observable.defer { // @formatter:off val data = jsonObject( - "type" to "libraryEntries", - "id" to track.media_id, - "attributes" to jsonObject( - "status" to track.toKitsuStatus(), - "progress" to track.last_chapter_read, - "ratingTwenty" to track.toKitsuScore() - ) + "type" to "libraryEntries", + "id" to track.media_id, + "attributes" to jsonObject( + "status" to track.toKitsuStatus(), + "progress" to track.last_chapter_read, + "ratingTwenty" to track.toKitsuScore() + ) ) // @formatter:on rest.updateLibManga(track.media_id, jsonObject("data" to data)) - .map { track } + .map { track } } } fun search(query: String): Observable> { return searchRest - .getKey().map { json -> - json["media"].asJsonObject["key"].string - }.flatMap { key -> - algoliaSearch(key, query) - } + .getKey().map { json -> + json["media"].asJsonObject["key"].string + }.flatMap { key -> + algoliaSearch(key, query) + } } private fun algoliaSearch(key: String, query: String): Observable> { val jsonObject = jsonObject("params" to "query=$query$algoliaFilter") return algoliaRest - .getSearchQuery(algoliaAppId, key, jsonObject) - .map { json -> - val data = json["hits"].array - data.map { KitsuSearchManga(it.obj) } - .filter { it.subType != "novel" } - .map { it.toTrack() } - } + .getSearchQuery(algoliaAppId, key, jsonObject) + .map { json -> + val data = json["hits"].array + data.map { KitsuSearchManga(it.obj) } + .filter { it.subType != "novel" } + .map { it.toTrack() } + } } fun findLibManga(track: Track, userId: String): Observable { return rest.findLibManga(track.media_id, userId) - .map { json -> - val data = json["data"].array - if (data.size() > 0) { - val manga = json["included"].array[0].obj - KitsuLibManga(data[0].obj, manga).toTrack() - } else { - null - } + .map { json -> + val data = json["data"].array + if (data.size() > 0) { + val manga = json["included"].array[0].obj + KitsuLibManga(data[0].obj, manga).toTrack() + } else { + null } + } } fun getLibManga(track: Track): Observable { return rest.getLibManga(track.media_id) - .map { json -> - val data = json["data"].array - if (data.size() > 0) { - val manga = json["included"].array[0].obj - KitsuLibManga(data[0].obj, manga).toTrack() - } else { - throw Exception("Could not find manga") - } + .map { json -> + val data = json["data"].array + if (data.size() > 0) { + val manga = json["included"].array[0].obj + KitsuLibManga(data[0].obj, manga).toTrack() + } else { + throw Exception("Could not find manga") } + } } fun login(username: String, password: String): Observable { return Retrofit.Builder() - .baseUrl(loginUrl) - .client(client) - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) - .build() - .create(LoginRest::class.java) - .requestAccessToken(username, password) + .baseUrl(loginUrl) + .client(client) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) + .build() + .create(LoginRest::class.java) + .requestAccessToken(username, password) } fun getCurrentUser(): Observable { @@ -242,12 +242,14 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) return baseMangaUrl + remoteId } - fun refreshTokenRequest(token: String) = POST("${loginUrl}oauth/token", - body = FormBody.Builder() - .add("grant_type", "refresh_token") - .add("client_id", clientId) - .add("client_secret", clientSecret) - .add("refresh_token", token) - .build()) + fun refreshTokenRequest(token: String) = POST( + "${loginUrl}oauth/token", + body = FormBody.Builder() + .add("grant_type", "refresh_token") + .add("client_id", clientId) + .add("client_secret", clientSecret) + .add("refresh_token", token) + .build() + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuInterceptor.kt index 1f1d4e8f2a..0e4dc070cb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuInterceptor.kt @@ -30,10 +30,10 @@ class KitsuInterceptor(val kitsu: Kitsu, val gson: Gson) : Interceptor { // Add the authorization header to the original request. val authRequest = originalRequest.newBuilder() - .addHeader("Authorization", "Bearer ${oauth!!.access_token}") - .header("Accept", "application/vnd.api+json") - .header("Content-Type", "application/vnd.api+json") - .build() + .addHeader("Authorization", "Bearer ${oauth!!.access_token}") + .header("Accept", "application/vnd.api+json") + .header("Content-Type", "application/vnd.api+json") + .build() return chain.proceed(authRequest) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt index 48a959b454..a87bb61cef 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt @@ -74,17 +74,17 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) { override fun bind(track: Track): Observable { return api.findLibManga(track) - .flatMap { remoteTrack -> - if (remoteTrack != null) { - track.copyPersonalFrom(remoteTrack) - update(track) - } else { - // Set default fields if it's not found in the list - track.score = DEFAULT_SCORE.toFloat() - track.status = DEFAULT_STATUS - add(track) - } + .flatMap { remoteTrack -> + if (remoteTrack != null) { + track.copyPersonalFrom(remoteTrack) + update(track) + } else { + // Set default fields if it's not found in the list + track.score = DEFAULT_SCORE.toFloat() + track.status = DEFAULT_STATUS + add(track) } + } } override fun search(query: String): Observable> { @@ -93,21 +93,21 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) { override fun refresh(track: Track): Observable { return api.getLibManga(track) - .map { remoteTrack -> - track.copyPersonalFrom(remoteTrack) - track.total_chapters = remoteTrack.total_chapters - track - } + .map { remoteTrack -> + track.copyPersonalFrom(remoteTrack) + track.total_chapters = remoteTrack.total_chapters + track + } } override fun login(username: String, password: String): Completable { logout() return Observable.fromCallable { api.login(username, password) } - .doOnNext { csrf -> saveCSRF(csrf) } - .doOnNext { saveCredentials(username, password) } - .doOnError { logout() } - .toCompletable() + .doOnNext { csrf -> saveCSRF(csrf) } + .doOnNext { saveCredentials(username, password) } + .doOnError { logout() } + .toCompletable() } fun refreshLogin() { @@ -141,8 +141,8 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) { val isAuthorized: Boolean get() = super.isLogged && - getCSRF().isNotEmpty() && - checkCookies() + getCSRF().isNotEmpty() && + checkCookies() fun getCSRF(): String = preferences.trackToken(this).get() @@ -152,8 +152,9 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) { var ckCount = 0 val url = BASE_URL.toHttpUrlOrNull()!! for (ck in networkService.cookieManager.get(url)) { - if (ck.name == USER_SESSION_COOKIE || ck.name == LOGGED_IN_COOKIE) + if (ck.name == USER_SESSION_COOKIE || ck.name == LOGGED_IN_COOKIE) { ckCount++ + } } return ckCount == 2 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt index 53256c5873..974dc978f0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt @@ -39,43 +39,45 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI return if (query.startsWith(PREFIX_MY)) { val realQuery = query.removePrefix(PREFIX_MY) getList() - .flatMap { Observable.from(it) } - .filter { it.title.contains(realQuery, true) } - .toList() + .flatMap { Observable.from(it) } + .filter { it.title.contains(realQuery, true) } + .toList() } else { client.newCall(GET(searchUrl(query))) - .asObservable() - .flatMap { response -> - Observable.from(Jsoup.parse(response.consumeBody()) - .select("div.js-categories-seasonal.js-block-list.list") - .select("table").select("tbody") - .select("tr").drop(1)) + .asObservable() + .flatMap { response -> + Observable.from( + Jsoup.parse(response.consumeBody()) + .select("div.js-categories-seasonal.js-block-list.list") + .select("table").select("tbody") + .select("tr").drop(1) + ) + } + .filter { row -> + row.select(TD)[2].text() != "Novel" + } + .map { row -> + TrackSearch.create(TrackManager.MYANIMELIST).apply { + title = row.searchTitle() + media_id = row.searchMediaId() + total_chapters = row.searchTotalChapters() + summary = row.searchSummary() + cover_url = row.searchCoverUrl() + tracking_url = mangaUrl(media_id) + publishing_status = row.searchPublishingStatus() + publishing_type = row.searchPublishingType() + start_date = row.searchStartDate() } - .filter { row -> - row.select(TD)[2].text() != "Novel" - } - .map { row -> - TrackSearch.create(TrackManager.MYANIMELIST).apply { - title = row.searchTitle() - media_id = row.searchMediaId() - total_chapters = row.searchTotalChapters() - summary = row.searchSummary() - cover_url = row.searchCoverUrl() - tracking_url = mangaUrl(media_id) - publishing_status = row.searchPublishingStatus() - publishing_type = row.searchPublishingType() - start_date = row.searchStartDate() - } - } - .toList() + } + .toList() } } fun addLibManga(track: Track): Observable { return Observable.defer { authClient.newCall(POST(url = addUrl(), body = mangaPostPayload(track))) - .asObservableSuccess() - .map { track } + .asObservableSuccess() + .map { track } } } @@ -95,40 +97,40 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI // Update remote authClient.newCall(POST(url = editPageUrl(track.media_id), body = mangaEditPostBody(editData))) - .asObservableSuccess() - .map { - track - } + .asObservableSuccess() + .map { + track + } } } fun findLibManga(track: Track): Observable { return authClient.newCall(GET(url = editPageUrl(track.media_id))) - .asObservable() - .map { response -> - var libTrack: Track? = null - response.use { - if (it.priorResponse?.isRedirect != true) { - val trackForm = Jsoup.parse(it.consumeBody()) + .asObservable() + .map { response -> + var libTrack: Track? = null + response.use { + if (it.priorResponse?.isRedirect != true) { + val trackForm = Jsoup.parse(it.consumeBody()) - libTrack = Track.create(TrackManager.MYANIMELIST).apply { - last_chapter_read = trackForm.select("#add_manga_num_read_chapters").`val`().toInt() - total_chapters = trackForm.select("#totalChap").text().toInt() - status = trackForm.select("#add_manga_status > option[selected]").`val`().toInt() - score = trackForm.select("#add_manga_score > option[selected]").`val`().toFloatOrNull() - ?: 0f - started_reading_date = trackForm.searchDatePicker("#add_manga_start_date") - finished_reading_date = trackForm.searchDatePicker("#add_manga_finish_date") - } + libTrack = Track.create(TrackManager.MYANIMELIST).apply { + last_chapter_read = trackForm.select("#add_manga_num_read_chapters").`val`().toInt() + total_chapters = trackForm.select("#totalChap").text().toInt() + status = trackForm.select("#add_manga_status > option[selected]").`val`().toInt() + score = trackForm.select("#add_manga_score > option[selected]").`val`().toFloatOrNull() + ?: 0f + started_reading_date = trackForm.searchDatePicker("#add_manga_start_date") + finished_reading_date = trackForm.searchDatePicker("#add_manga_finish_date") } } - libTrack } + libTrack + } } fun getLibManga(track: Track): Observable { return findLibManga(track) - .map { it ?: throw Exception("Could not find manga") } + .map { it ?: throw Exception("Could not find manga") } } fun login(username: String, password: String): String { @@ -143,8 +145,8 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI val response = client.newCall(GET(loginUrl())).execute() return Jsoup.parse(response.consumeBody()) - .select("meta[name=csrf_token]") - .attr("content") + .select("meta[name=csrf_token]") + .attr("content") } private fun login(username: String, password: String, csrf: String) { @@ -157,45 +159,45 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI private fun getList(): Observable> { return getListUrl() - .flatMap { url -> - getListXml(url) + .flatMap { url -> + getListXml(url) + } + .flatMap { doc -> + Observable.from(doc.select("manga")) + } + .map { + TrackSearch.create(TrackManager.MYANIMELIST).apply { + title = it.selectText("manga_title")!! + media_id = it.selectInt("manga_mangadb_id") + last_chapter_read = it.selectInt("my_read_chapters") + status = getStatus(it.selectText("my_status")!!) + score = it.selectInt("my_score").toFloat() + total_chapters = it.selectInt("manga_chapters") + tracking_url = mangaUrl(media_id) + started_reading_date = it.searchDateXml("my_start_date") + finished_reading_date = it.searchDateXml("my_finish_date") } - .flatMap { doc -> - Observable.from(doc.select("manga")) - } - .map { - TrackSearch.create(TrackManager.MYANIMELIST).apply { - title = it.selectText("manga_title")!! - media_id = it.selectInt("manga_mangadb_id") - last_chapter_read = it.selectInt("my_read_chapters") - status = getStatus(it.selectText("my_status")!!) - score = it.selectInt("my_score").toFloat() - total_chapters = it.selectInt("manga_chapters") - tracking_url = mangaUrl(media_id) - started_reading_date = it.searchDateXml("my_start_date") - finished_reading_date = it.searchDateXml("my_finish_date") - } - } - .toList() + } + .toList() } private fun getListUrl(): Observable { return authClient.newCall(POST(url = exportListUrl(), body = exportPostBody())) - .asObservable() - .map { response -> - baseUrl + Jsoup.parse(response.consumeBody()) - .select("div.goodresult") - .select("a") - .attr("href") - } + .asObservable() + .map { response -> + baseUrl + Jsoup.parse(response.consumeBody()) + .select("div.goodresult") + .select("a") + .attr("href") + } } private fun getListXml(url: String): Observable { return authClient.newCall(GET(url)) - .asObservable() - .map { response -> - Jsoup.parse(response.consumeXmlBody(), "", Parser.xmlParser()) - } + .asObservable() + .map { response -> + Jsoup.parse(response.consumeXmlBody(), "", Parser.xmlParser()) + } } private fun Response.consumeBody(): String? { @@ -222,28 +224,28 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI val tables = page.select("form#main-form table") return MyAnimeListEditData( - entry_id = tables[0].select("input[name=entry_id]").`val`(), // Always 0 - manga_id = tables[0].select("#manga_id").`val`(), - status = tables[0].select("#add_manga_status > option[selected]").`val`(), - num_read_volumes = tables[0].select("#add_manga_num_read_volumes").`val`(), - last_completed_vol = tables[0].select("input[name=last_completed_vol]").`val`(), // Always empty - num_read_chapters = tables[0].select("#add_manga_num_read_chapters").`val`(), - score = tables[0].select("#add_manga_score > option[selected]").`val`(), - start_date_month = tables[0].select("#add_manga_start_date_month > option[selected]").`val`(), - start_date_day = tables[0].select("#add_manga_start_date_day > option[selected]").`val`(), - start_date_year = tables[0].select("#add_manga_start_date_year > option[selected]").`val`(), - finish_date_month = tables[0].select("#add_manga_finish_date_month > option[selected]").`val`(), - finish_date_day = tables[0].select("#add_manga_finish_date_day > option[selected]").`val`(), - finish_date_year = tables[0].select("#add_manga_finish_date_year > option[selected]").`val`(), - tags = tables[1].select("#add_manga_tags").`val`(), - priority = tables[1].select("#add_manga_priority > option[selected]").`val`(), - storage_type = tables[1].select("#add_manga_storage_type > option[selected]").`val`(), - num_retail_volumes = tables[1].select("#add_manga_num_retail_volumes").`val`(), - num_read_times = tables[1].select("#add_manga_num_read_times").`val`(), - reread_value = tables[1].select("#add_manga_reread_value > option[selected]").`val`(), - comments = tables[1].select("#add_manga_comments").`val`(), - is_asked_to_discuss = tables[1].select("#add_manga_is_asked_to_discuss > option[selected]").`val`(), - sns_post_type = tables[1].select("#add_manga_sns_post_type > option[selected]").`val`() + entry_id = tables[0].select("input[name=entry_id]").`val`(), // Always 0 + manga_id = tables[0].select("#manga_id").`val`(), + status = tables[0].select("#add_manga_status > option[selected]").`val`(), + num_read_volumes = tables[0].select("#add_manga_num_read_volumes").`val`(), + last_completed_vol = tables[0].select("input[name=last_completed_vol]").`val`(), // Always empty + num_read_chapters = tables[0].select("#add_manga_num_read_chapters").`val`(), + score = tables[0].select("#add_manga_score > option[selected]").`val`(), + start_date_month = tables[0].select("#add_manga_start_date_month > option[selected]").`val`(), + start_date_day = tables[0].select("#add_manga_start_date_day > option[selected]").`val`(), + start_date_year = tables[0].select("#add_manga_start_date_year > option[selected]").`val`(), + finish_date_month = tables[0].select("#add_manga_finish_date_month > option[selected]").`val`(), + finish_date_day = tables[0].select("#add_manga_finish_date_day > option[selected]").`val`(), + finish_date_year = tables[0].select("#add_manga_finish_date_year > option[selected]").`val`(), + tags = tables[1].select("#add_manga_tags").`val`(), + priority = tables[1].select("#add_manga_priority > option[selected]").`val`(), + storage_type = tables[1].select("#add_manga_storage_type > option[selected]").`val`(), + num_retail_volumes = tables[1].select("#add_manga_num_retail_volumes").`val`(), + num_read_times = tables[1].select("#add_manga_num_read_times").`val`(), + reread_value = tables[1].select("#add_manga_reread_value > option[selected]").`val`(), + comments = tables[1].select("#add_manga_comments").`val`(), + is_asked_to_discuss = tables[1].select("#add_manga_is_asked_to_discuss > option[selected]").`val`(), + sns_post_type = tables[1].select("#add_manga_sns_post_type > option[selected]").`val`() ) } @@ -259,98 +261,99 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI private fun mangaUrl(remoteId: Int) = baseMangaUrl + remoteId private fun loginUrl() = Uri.parse(baseUrl).buildUpon() - .appendPath("login.php") - .toString() + .appendPath("login.php") + .toString() private fun searchUrl(query: String): String { val col = "c[]" return Uri.parse(baseUrl).buildUpon() - .appendPath("manga.php") - .appendQueryParameter("q", query) - .appendQueryParameter(col, "a") - .appendQueryParameter(col, "b") - .appendQueryParameter(col, "c") - .appendQueryParameter(col, "d") - .appendQueryParameter(col, "e") - .appendQueryParameter(col, "g") - .toString() + .appendPath("manga.php") + .appendQueryParameter("q", query) + .appendQueryParameter(col, "a") + .appendQueryParameter(col, "b") + .appendQueryParameter(col, "c") + .appendQueryParameter(col, "d") + .appendQueryParameter(col, "e") + .appendQueryParameter(col, "g") + .toString() } private fun exportListUrl() = Uri.parse(baseUrl).buildUpon() - .appendPath("panel.php") - .appendQueryParameter("go", "export") - .toString() + .appendPath("panel.php") + .appendQueryParameter("go", "export") + .toString() private fun editPageUrl(mediaId: Int) = Uri.parse(baseModifyListUrl).buildUpon() - .appendPath(mediaId.toString()) - .appendPath("edit") - .toString() + .appendPath(mediaId.toString()) + .appendPath("edit") + .toString() private fun addUrl() = Uri.parse(baseModifyListUrl).buildUpon() - .appendPath("add.json") - .toString() + .appendPath("add.json") + .toString() private fun loginPostBody(username: String, password: String, csrf: String): RequestBody { return FormBody.Builder() - .add("user_name", username) - .add("password", password) - .add("cookie", "1") - .add("sublogin", "Login") - .add("submit", "1") - .add(CSRF, csrf) - .build() + .add("user_name", username) + .add("password", password) + .add("cookie", "1") + .add("sublogin", "Login") + .add("submit", "1") + .add(CSRF, csrf) + .build() } private fun exportPostBody(): RequestBody { return FormBody.Builder() - .add("type", "2") - .add("subexport", "Export My List") - .build() + .add("type", "2") + .add("subexport", "Export My List") + .build() } private fun mangaPostPayload(track: Track): RequestBody { val body = JSONObject() - .put("manga_id", track.media_id) - .put("status", track.status) - .put("score", track.score) - .put("num_read_chapters", track.last_chapter_read) + .put("manga_id", track.media_id) + .put("status", track.status) + .put("score", track.score) + .put("num_read_chapters", track.last_chapter_read) return body.toString().toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull()) } private fun mangaEditPostBody(track: MyAnimeListEditData): RequestBody { return FormBody.Builder() - .add("entry_id", track.entry_id) - .add("manga_id", track.manga_id) - .add("add_manga[status]", track.status) - .add("add_manga[num_read_volumes]", track.num_read_volumes) - .add("last_completed_vol", track.last_completed_vol) - .add("add_manga[num_read_chapters]", track.num_read_chapters) - .add("add_manga[score]", track.score) - .add("add_manga[start_date][month]", track.start_date_month) - .add("add_manga[start_date][day]", track.start_date_day) - .add("add_manga[start_date][year]", track.start_date_year) - .add("add_manga[finish_date][month]", track.finish_date_month) - .add("add_manga[finish_date][day]", track.finish_date_day) - .add("add_manga[finish_date][year]", track.finish_date_year) - .add("add_manga[tags]", track.tags) - .add("add_manga[priority]", track.priority) - .add("add_manga[storage_type]", track.storage_type) - .add("add_manga[num_retail_volumes]", track.num_retail_volumes) - .add("add_manga[num_read_times]", track.num_read_chapters) - .add("add_manga[reread_value]", track.reread_value) - .add("add_manga[comments]", track.comments) - .add("add_manga[is_asked_to_discuss]", track.is_asked_to_discuss) - .add("add_manga[sns_post_type]", track.sns_post_type) - .add("submitIt", track.submitIt) - .build() + .add("entry_id", track.entry_id) + .add("manga_id", track.manga_id) + .add("add_manga[status]", track.status) + .add("add_manga[num_read_volumes]", track.num_read_volumes) + .add("last_completed_vol", track.last_completed_vol) + .add("add_manga[num_read_chapters]", track.num_read_chapters) + .add("add_manga[score]", track.score) + .add("add_manga[start_date][month]", track.start_date_month) + .add("add_manga[start_date][day]", track.start_date_day) + .add("add_manga[start_date][year]", track.start_date_year) + .add("add_manga[finish_date][month]", track.finish_date_month) + .add("add_manga[finish_date][day]", track.finish_date_day) + .add("add_manga[finish_date][year]", track.finish_date_year) + .add("add_manga[tags]", track.tags) + .add("add_manga[priority]", track.priority) + .add("add_manga[storage_type]", track.storage_type) + .add("add_manga[num_retail_volumes]", track.num_retail_volumes) + .add("add_manga[num_read_times]", track.num_read_chapters) + .add("add_manga[reread_value]", track.reread_value) + .add("add_manga[comments]", track.comments) + .add("add_manga[is_asked_to_discuss]", track.is_asked_to_discuss) + .add("add_manga[sns_post_type]", track.sns_post_type) + .add("submitIt", track.submitIt) + .build() } private fun Element.searchDateXml(field: String): Long { val text = selectText(field, "0000-00-00")!! // MAL sets the data to 0000-00-00 when date is invalid or missing - if (text == "0000-00-00") + if (text == "0000-00-00") { return 0L + } return SimpleDateFormat("yyyy-MM-dd", Locale.US).parse(text)?.time ?: 0L } @@ -359,8 +362,9 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI val month = select(id + "_month > option[selected]").`val`().toIntOrNull() val day = select(id + "_day > option[selected]").`val`().toIntOrNull() val year = select(id + "_year > option[selected]").`val`().toIntOrNull() - if (year == null || month == null || day == null) + if (year == null || month == null || day == null) { return 0L + } return GregorianCalendar(year, month - 1, day).timeInMillis } @@ -370,18 +374,18 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI private fun Element.searchTotalChapters() = if (select(TD)[4].text() == "-") 0 else select(TD)[4].text().toInt() private fun Element.searchCoverUrl() = select("img") - .attr("data-src") - .split("\\?")[0] - .replace("/r/50x70/", "/") + .attr("data-src") + .split("\\?")[0] + .replace("/r/50x70/", "/") private fun Element.searchMediaId() = select("div.picSurround") - .select("a").attr("id") - .replace("sarea", "") - .toInt() + .select("a").attr("id") + .replace("sarea", "") + .toInt() private fun Element.searchSummary() = select("div.pt4") - .first() - .ownText()!! + .first() + .ownText()!! private fun Element.searchPublishingStatus() = if (select(TD).last().text() == "-") "Publishing" else "Finished" @@ -472,8 +476,9 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI fun copyPersonalFrom(track: Track) { num_read_chapters = track.last_chapter_read.toString() val numScore = track.score.toInt() - if (numScore in 1..9) + if (numScore in 1..9) { score = numScore.toString() + } status = track.status.toString() if (track.started_reading_date == 0L) { start_date_month = "" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt index 46801fb83c..a39f8f6edb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt @@ -53,7 +53,7 @@ class MyAnimeListInterceptor(private val myanimelist: MyAnimeList) : Interceptor private fun updateJsonBody(requestBody: RequestBody): RequestBody { val jsonString = bodyToString(requestBody) val newBody = JSONObject(jsonString) - .put(MyAnimeListApi.CSRF, myanimelist.getCSRF()) + .put(MyAnimeListApi.CSRF, myanimelist.getCSRF()) return newBody.toString().toRequestBody(requestBody.contentType()) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt index 3469e84035..397559b114 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt @@ -51,18 +51,18 @@ class Shikimori(private val context: Context, id: Int) : TrackService(id) { override fun bind(track: Track): Observable { return api.findLibManga(track, getUsername()) - .flatMap { remoteTrack -> - if (remoteTrack != null) { - track.copyPersonalFrom(remoteTrack) - track.library_id = remoteTrack.library_id - update(track) - } else { - // Set default fields if it's not found in the list - track.score = DEFAULT_SCORE.toFloat() - track.status = DEFAULT_STATUS - add(track) - } + .flatMap { remoteTrack -> + if (remoteTrack != null) { + track.copyPersonalFrom(remoteTrack) + track.library_id = remoteTrack.library_id + update(track) + } else { + // Set default fields if it's not found in the list + track.score = DEFAULT_SCORE.toFloat() + track.status = DEFAULT_STATUS + add(track) } + } } override fun search(query: String): Observable> { @@ -71,13 +71,13 @@ class Shikimori(private val context: Context, id: Int) : TrackService(id) { override fun refresh(track: Track): Observable { return api.findLibManga(track, getUsername()) - .map { remoteTrack -> - if (remoteTrack != null) { - track.copyPersonalFrom(remoteTrack) - track.total_chapters = remoteTrack.total_chapters - } - track + .map { remoteTrack -> + if (remoteTrack != null) { + track.copyPersonalFrom(remoteTrack) + track.total_chapters = remoteTrack.total_chapters } + track + } } override fun getLogo() = R.drawable.ic_tracker_shikimori diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt index a56d063477..069786a0a5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt @@ -30,49 +30,49 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter fun addLibManga(track: Track, user_id: String): Observable { val payload = jsonObject( - "user_rate" to jsonObject( - "user_id" to user_id, - "target_id" to track.media_id, - "target_type" to "Manga", - "chapters" to track.last_chapter_read, - "score" to track.score.toInt(), - "status" to track.toShikimoriStatus() - ) + "user_rate" to jsonObject( + "user_id" to user_id, + "target_id" to track.media_id, + "target_type" to "Manga", + "chapters" to track.last_chapter_read, + "score" to track.score.toInt(), + "status" to track.toShikimoriStatus() + ) ) val body = payload.toString().toRequestBody(jsonime) val request = Request.Builder() - .url("$apiUrl/v2/user_rates") - .post(body) - .build() + .url("$apiUrl/v2/user_rates") + .post(body) + .build() return authClient.newCall(request) - .asObservableSuccess() - .map { - track - } + .asObservableSuccess() + .map { + track + } } fun updateLibManga(track: Track, user_id: String): Observable = addLibManga(track, user_id) fun search(search: String): Observable> { val url = Uri.parse("$apiUrl/mangas").buildUpon() - .appendQueryParameter("order", "popularity") - .appendQueryParameter("search", search) - .appendQueryParameter("limit", "20") - .build() + .appendQueryParameter("order", "popularity") + .appendQueryParameter("search", search) + .appendQueryParameter("limit", "20") + .build() val request = Request.Builder() - .url(url.toString()) - .get() - .build() + .url(url.toString()) + .get() + .build() return authClient.newCall(request) - .asObservableSuccess() - .map { netResponse -> - val responseBody = netResponse.body?.string().orEmpty() - if (responseBody.isEmpty()) { - throw Exception("Null Response") - } - val response = JsonParser.parseString(responseBody).array - response.map { jsonToSearch(it.obj) } + .asObservableSuccess() + .map { netResponse -> + val responseBody = netResponse.body?.string().orEmpty() + if (responseBody.isEmpty()) { + throw Exception("Null Response") } + val response = JsonParser.parseString(responseBody).array + response.map { jsonToSearch(it.obj) } + } } private fun jsonToSearch(obj: JsonObject): TrackSearch { @@ -103,45 +103,45 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter fun findLibManga(track: Track, user_id: String): Observable { val url = Uri.parse("$apiUrl/v2/user_rates").buildUpon() - .appendQueryParameter("user_id", user_id) - .appendQueryParameter("target_id", track.media_id.toString()) - .appendQueryParameter("target_type", "Manga") - .build() + .appendQueryParameter("user_id", user_id) + .appendQueryParameter("target_id", track.media_id.toString()) + .appendQueryParameter("target_type", "Manga") + .build() val request = Request.Builder() - .url(url.toString()) - .get() - .build() + .url(url.toString()) + .get() + .build() val urlMangas = Uri.parse("$apiUrl/mangas").buildUpon() - .appendPath(track.media_id.toString()) - .build() + .appendPath(track.media_id.toString()) + .build() val requestMangas = Request.Builder() - .url(urlMangas.toString()) - .get() - .build() + .url(urlMangas.toString()) + .get() + .build() return authClient.newCall(requestMangas) - .asObservableSuccess() - .map { netResponse -> - val responseBody = netResponse.body?.string().orEmpty() - JsonParser.parseString(responseBody).obj - }.flatMap { mangas -> - authClient.newCall(request) - .asObservableSuccess() - .map { netResponse -> - val responseBody = netResponse.body?.string().orEmpty() - if (responseBody.isEmpty()) { - throw Exception("Null Response") - } - val response = JsonParser.parseString(responseBody).array - if (response.size() > 1) { - throw Exception("Too much mangas in response") - } - val entry = response.map { - jsonToTrack(it.obj, mangas) - } - entry.firstOrNull() - } - } + .asObservableSuccess() + .map { netResponse -> + val responseBody = netResponse.body?.string().orEmpty() + JsonParser.parseString(responseBody).obj + }.flatMap { mangas -> + authClient.newCall(request) + .asObservableSuccess() + .map { netResponse -> + val responseBody = netResponse.body?.string().orEmpty() + if (responseBody.isEmpty()) { + throw Exception("Null Response") + } + val response = JsonParser.parseString(responseBody).array + if (response.size() > 1) { + throw Exception("Too much mangas in response") + } + val entry = response.map { + jsonToTrack(it.obj, mangas) + } + entry.firstOrNull() + } + } } fun getCurrentUser(): Int { @@ -159,14 +159,15 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter } } - private fun accessTokenRequest(code: String) = POST(oauthUrl, - body = FormBody.Builder() - .add("grant_type", "authorization_code") - .add("client_id", clientId) - .add("client_secret", clientSecret) - .add("code", code) - .add("redirect_uri", redirectUrl) - .build() + private fun accessTokenRequest(code: String) = POST( + oauthUrl, + body = FormBody.Builder() + .add("grant_type", "authorization_code") + .add("client_id", clientId) + .add("client_secret", clientSecret) + .add("code", code) + .add("redirect_uri", redirectUrl) + .build() ) companion object { @@ -186,18 +187,20 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter } fun authUrl() = - Uri.parse(loginUrl).buildUpon() - .appendQueryParameter("client_id", clientId) - .appendQueryParameter("redirect_uri", redirectUrl) - .appendQueryParameter("response_type", "code") - .build() + Uri.parse(loginUrl).buildUpon() + .appendQueryParameter("client_id", clientId) + .appendQueryParameter("redirect_uri", redirectUrl) + .appendQueryParameter("response_type", "code") + .build() - fun refreshTokenRequest(token: String) = POST(oauthUrl, - body = FormBody.Builder() - .add("grant_type", "refresh_token") - .add("client_id", clientId) - .add("client_secret", clientSecret) - .add("refresh_token", token) - .build()) + fun refreshTokenRequest(token: String) = POST( + oauthUrl, + body = FormBody.Builder() + .add("grant_type", "refresh_token") + .add("client_id", clientId) + .add("client_secret", clientSecret) + .add("refresh_token", token) + .build() + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriInterceptor.kt index 6e10b4de3d..0a2688d70f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriInterceptor.kt @@ -29,9 +29,9 @@ class ShikimoriInterceptor(val shikimori: Shikimori, val gson: Gson) : Intercept } // Add the authorization header to the original request. val authRequest = originalRequest.newBuilder() - .addHeader("Authorization", "Bearer ${oauth!!.access_token}") - .header("User-Agent", "Tachiyomi") - .build() + .addHeader("Authorization", "Bearer ${oauth!!.access_token}") + .header("User-Agent", "Tachiyomi") + .build() return chain.proceed(authRequest) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdaterJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdaterJob.kt index bbd093a9ec..f786afc101 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdaterJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdaterJob.kt @@ -18,7 +18,7 @@ import java.util.concurrent.TimeUnit import kotlinx.coroutines.runBlocking class UpdaterJob(private val context: Context, workerParams: WorkerParameters) : - Worker(context, workerParams) { + Worker(context, workerParams) { override fun doWork(): Result { return runBlocking { @@ -37,9 +37,11 @@ class UpdaterJob(private val context: Context, workerParams: WorkerParameters) : setContentText(context.getString(R.string.update_check_notification_update_available)) setSmallIcon(android.R.drawable.stat_sys_download_done) // Download action - addAction(android.R.drawable.stat_sys_download_done, - context.getString(R.string.action_download), - PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)) + addAction( + android.R.drawable.stat_sys_download_done, + context.getString(R.string.action_download), + PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + ) } } Result.success() @@ -59,15 +61,16 @@ class UpdaterJob(private val context: Context, workerParams: WorkerParameters) : fun setupTask(context: Context) { val constraints = Constraints.Builder() - .setRequiredNetworkType(NetworkType.CONNECTED) - .build() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() val request = PeriodicWorkRequestBuilder( - 3, TimeUnit.DAYS, - 3, TimeUnit.HOURS) - .addTag(TAG) - .setConstraints(constraints) - .build() + 3, TimeUnit.DAYS, + 3, TimeUnit.HOURS + ) + .addTag(TAG) + .setConstraints(constraints) + .build() WorkManager.getInstance(context).enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.REPLACE, request) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdaterNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdaterNotifier.kt index 8f878df9be..440b40067d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdaterNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdaterNotifier.kt @@ -69,13 +69,17 @@ internal class UpdaterNotifier(private val context: Context) { setProgress(0, 0, false) // Install action setContentIntent(NotificationHandler.installApkPendingActivity(context, uri)) - addAction(R.drawable.ic_system_update_alt_white_24dp, - context.getString(R.string.action_install), - NotificationHandler.installApkPendingActivity(context, uri)) + addAction( + R.drawable.ic_system_update_alt_white_24dp, + context.getString(R.string.action_install), + NotificationHandler.installApkPendingActivity(context, uri) + ) // Cancel action - addAction(R.drawable.ic_close_24dp, - context.getString(R.string.action_cancel), - NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER)) + addAction( + R.drawable.ic_close_24dp, + context.getString(R.string.action_cancel), + NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER) + ) } notificationBuilder.show() } @@ -92,13 +96,17 @@ internal class UpdaterNotifier(private val context: Context) { setOnlyAlertOnce(false) setProgress(0, 0, false) // Retry action - addAction(R.drawable.ic_refresh_24dp, - context.getString(R.string.action_retry), - UpdaterService.downloadApkPendingService(context, url)) + addAction( + R.drawable.ic_refresh_24dp, + context.getString(R.string.action_retry), + UpdaterService.downloadApkPendingService(context, url) + ) // Cancel action - addAction(R.drawable.ic_close_24dp, - context.getString(R.string.action_cancel), - NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER)) + addAction( + R.drawable.ic_close_24dp, + context.getString(R.string.action_cancel), + NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER) + ) } notificationBuilder.show(Notifications.ID_UPDATER) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/devrepo/DevRepoUpdateChecker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/devrepo/DevRepoUpdateChecker.kt index 37b7726922..88084a234a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/devrepo/DevRepoUpdateChecker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/devrepo/DevRepoUpdateChecker.kt @@ -16,8 +16,8 @@ class DevRepoUpdateChecker : UpdateChecker() { private val client: OkHttpClient by lazy { Injekt.get().client.newBuilder() - .followRedirects(false) - .build() + .followRedirects(false) + .build() } private val versionRegex: Regex by lazy { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/github/GithubService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/github/GithubService.kt index 5c6b5ac09b..88a9eb37cb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/github/GithubService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/github/GithubService.kt @@ -15,10 +15,10 @@ interface GithubService { companion object { fun create(): GithubService { val restAdapter = Retrofit.Builder() - .baseUrl("https://api.github.com") - .addConverterFactory(GsonConverterFactory.create()) - .client(Injekt.get().client) - .build() + .baseUrl("https://api.github.com") + .addConverterFactory(GsonConverterFactory.create()) + .client(Injekt.get().client) + .build() return restAdapter.create(GithubService::class.java) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt index d7dcfcb439..96ef8b3176 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt @@ -119,16 +119,16 @@ class ExtensionManager( val extensions = ExtensionLoader.loadExtensions(context) installedExtensions = extensions - .filterIsInstance() - .map { it.extension } + .filterIsInstance() + .map { it.extension } installedExtensions - .flatMap { it.sources } - // overwrite is needed until the bundled sources are removed - .forEach { sourceManager.registerSource(it, true) } + .flatMap { it.sources } + // overwrite is needed until the bundled sources are removed + .forEach { sourceManager.registerSource(it, true) } untrustedExtensions = extensions - .filterIsInstance() - .map { it.extension } + .filterIsInstance() + .map { it.extension } } /** @@ -223,7 +223,7 @@ class ExtensionManager( */ fun updateExtension(extension: Extension.Installed): Observable { val availableExt = availableExtensions.find { it.pkgName == extension.pkgName } - ?: return Observable.empty() + ?: return Observable.empty() return installExtension(availableExt) } @@ -266,15 +266,15 @@ class ExtensionManager( val ctx = context launchNow { nowTrustedExtensions - .map { extension -> - async { ExtensionLoader.loadExtensionFromPkgName(ctx, extension.pkgName) } - } - .map { it.await() } - .forEach { result -> - if (result is LoadResult.Success) { - registerNewExtension(result.extension) - } + .map { extension -> + async { ExtensionLoader.loadExtensionFromPkgName(ctx, extension.pkgName) } + } + .map { it.await() } + .forEach { result -> + if (result is LoadResult.Success) { + registerNewExtension(result.extension) } + } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionUpdateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionUpdateJob.kt index 29c2b36644..d9d2ed398a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionUpdateJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionUpdateJob.kt @@ -40,7 +40,8 @@ class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParam private fun createUpdateNotification(names: List) { NotificationManagerCompat.from(context).apply { - notify(Notifications.ID_UPDATES_TO_EXTS, + notify( + Notifications.ID_UPDATES_TO_EXTS, context.notification(Notifications.CHANNEL_UPDATES_TO_EXTS) { setContentTitle( context.resources.getQuantityString( @@ -55,7 +56,8 @@ class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParam setSmallIcon(R.drawable.ic_extension_24dp) setContentIntent(NotificationReceiver.openExtensionsPendingActivity(context)) setAutoCancel(true) - }) + } + ) } } @@ -72,7 +74,8 @@ class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParam val request = PeriodicWorkRequestBuilder( 12, TimeUnit.HOURS, - 1, TimeUnit.HOURS) + 1, TimeUnit.HOURS + ) .addTag(TAG) .setConstraints(constraints) .build() diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt index 2ad7de9a55..98b0928b56 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt @@ -70,22 +70,22 @@ internal class ExtensionGithubApi { val json = gson.fromJson(text) return json - .filter { element -> - val versionName = element["version"].string - val libVersion = versionName.substringBeforeLast('.').toDouble() - libVersion >= ExtensionLoader.LIB_VERSION_MIN && libVersion <= ExtensionLoader.LIB_VERSION_MAX - } - .map { element -> - val name = element["name"].string.substringAfter("Tachiyomi: ") - val pkgName = element["pkg"].string - val apkName = element["apk"].string - val versionName = element["version"].string - val versionCode = element["code"].int - val lang = element["lang"].string - val icon = "$REPO_URL/icon/${apkName.replace(".apk", ".png")}" + .filter { element -> + val versionName = element["version"].string + val libVersion = versionName.substringBeforeLast('.').toDouble() + libVersion >= ExtensionLoader.LIB_VERSION_MIN && libVersion <= ExtensionLoader.LIB_VERSION_MAX + } + .map { element -> + val name = element["name"].string.substringAfter("Tachiyomi: ") + val pkgName = element["pkg"].string + val apkName = element["apk"].string + val versionName = element["version"].string + val versionCode = element["code"].int + val lang = element["lang"].string + val icon = "$REPO_URL/icon/${apkName.replace(".apk", ".png")}" - Extension.Available(name, pkgName, versionName, versionCode, lang, apkName, icon) - } + Extension.Available(name, pkgName, versionName, versionCode, lang, apkName, icon) + } } fun getApkUrl(extension: Extension.Available): String { diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallActivity.kt index db2f726ea2..1623a5d7d6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallActivity.kt @@ -18,9 +18,9 @@ class ExtensionInstallActivity : Activity() { super.onCreate(savedInstanceState) val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE) - .setDataAndType(intent.data, intent.type) - .putExtra(Intent.EXTRA_RETURN_RESULT, true) - .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + .setDataAndType(intent.data, intent.type) + .putExtra(Intent.EXTRA_RETURN_RESULT, true) + .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) try { startActivityForResult(installIntent, INSTALL_REQUEST_CODE) diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt index 0cffad2d4f..cdef6e4368 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt @@ -19,7 +19,7 @@ import kotlinx.coroutines.async * @param listener The listener that should be notified of extension installation events. */ internal class ExtensionInstallReceiver(private val listener: Listener) : - BroadcastReceiver() { + BroadcastReceiver() { /** * Registers this broadcast receiver @@ -93,7 +93,7 @@ internal class ExtensionInstallReceiver(private val listener: Listener) : */ private suspend fun getExtensionFromIntent(context: Context, intent: Intent?): LoadResult { val pkgName = getPackageNameFromIntent(intent) - ?: return LoadResult.Error("Package name not found") + ?: return LoadResult.Error("Package name not found") return GlobalScope.async(Dispatchers.Default, CoroutineStart.DEFAULT) { ExtensionLoader.loadExtensionFromPkgName(context, pkgName) }.await() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstaller.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstaller.kt index d86e20d675..a0fca50918 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstaller.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstaller.kt @@ -65,26 +65,26 @@ internal class ExtensionInstaller(private val context: Context) { val downloadUri = Uri.parse(url) val request = DownloadManager.Request(downloadUri) - .setTitle(extension.name) - .setMimeType(APK_MIME) - .setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, downloadUri.lastPathSegment) - .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) + .setTitle(extension.name) + .setMimeType(APK_MIME) + .setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, downloadUri.lastPathSegment) + .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) val id = downloadManager.enqueue(request) activeDownloads[pkgName] = id downloadsRelay.filter { it.first == id } - .map { it.second } - // Poll download status - .mergeWith(pollStatus(id)) - // Force an error if the download takes more than 3 minutes - .mergeWith(Observable.timer(3, TimeUnit.MINUTES).map { InstallStep.Error }) - // Stop when the application is installed or errors - .takeUntil { it.isCompleted() } - // Always notify on main thread - .observeOn(AndroidSchedulers.mainThread()) - // Always remove the download when unsubscribed - .doOnUnsubscribe { deleteDownload(pkgName) } + .map { it.second } + // Poll download status + .mergeWith(pollStatus(id)) + // Force an error if the download takes more than 3 minutes + .mergeWith(Observable.timer(3, TimeUnit.MINUTES).map { InstallStep.Error }) + // Stop when the application is installed or errors + .takeUntil { it.isCompleted() } + // Always notify on main thread + .observeOn(AndroidSchedulers.mainThread()) + // Always remove the download when unsubscribed + .doOnUnsubscribe { deleteDownload(pkgName) } } /** @@ -97,25 +97,25 @@ internal class ExtensionInstaller(private val context: Context) { val query = DownloadManager.Query().setFilterById(id) return Observable.interval(0, 1, TimeUnit.SECONDS) - // Get the current download status - .map { - downloadManager.query(query).use { cursor -> - cursor.moveToFirst() - cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) - } + // Get the current download status + .map { + downloadManager.query(query).use { cursor -> + cursor.moveToFirst() + cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) } - // Ignore duplicate results - .distinctUntilChanged() - // Stop polling when the download fails or finishes - .takeUntil { it == DownloadManager.STATUS_SUCCESSFUL || it == DownloadManager.STATUS_FAILED } - // Map to our model - .flatMap { status -> - when (status) { - DownloadManager.STATUS_PENDING -> Observable.just(InstallStep.Pending) - DownloadManager.STATUS_RUNNING -> Observable.just(InstallStep.Downloading) - else -> Observable.empty() - } + } + // Ignore duplicate results + .distinctUntilChanged() + // Stop polling when the download fails or finishes + .takeUntil { it == DownloadManager.STATUS_SUCCESSFUL || it == DownloadManager.STATUS_FAILED } + // Map to our model + .flatMap { status -> + when (status) { + DownloadManager.STATUS_PENDING -> Observable.just(InstallStep.Pending) + DownloadManager.STATUS_RUNNING -> Observable.just(InstallStep.Downloading) + else -> Observable.empty() } + } } /** @@ -125,9 +125,9 @@ internal class ExtensionInstaller(private val context: Context) { */ fun installApk(downloadId: Long, uri: Uri) { val intent = Intent(context, ExtensionInstallActivity::class.java) - .setDataAndType(uri, APK_MIME) - .putExtra(EXTRA_DOWNLOAD_ID, downloadId) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION) + .setDataAndType(uri, APK_MIME) + .putExtra(EXTRA_DOWNLOAD_ID, downloadId) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION) context.startActivity(intent) } @@ -140,7 +140,7 @@ internal class ExtensionInstaller(private val context: Context) { fun uninstallApk(pkgName: String) { val packageUri = Uri.parse("package:$pkgName") val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) context.startActivity(intent) } @@ -227,7 +227,7 @@ internal class ExtensionInstaller(private val context: Context) { downloadManager.query(query).use { cursor -> if (cursor.moveToFirst()) { val localUri = cursor.getString( - cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI) + cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI) ).removePrefix(FILE_SCHEME) installApk(id, File(localUri).getUriCompat(context)) diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt index 6987624902..0ff9b6e61b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt @@ -35,9 +35,9 @@ internal object ExtensionLoader { * List of the trusted signatures. */ var trustedSignatures = mutableSetOf() + - Injekt.get().trustedSignatures().get() + - // inorichi's key - "7ce04da7773d41b489f4693a366c36bcd0a11fc39b547168553c285bd7348e23" + Injekt.get().trustedSignatures().get() + + // inorichi's key + "7ce04da7773d41b489f4693a366c36bcd0a11fc39b547168553c285bd7348e23" /** * Return a list of all the installed extensions initialized concurrently. @@ -107,8 +107,10 @@ internal object ExtensionLoader { // Validate lib version val libVersion = versionName.substringBeforeLast('.').toDouble() if (libVersion < LIB_VERSION_MIN || libVersion > LIB_VERSION_MAX) { - val exception = Exception("Lib version is $libVersion, while only versions " + - "$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed") + val exception = Exception( + "Lib version is $libVersion, while only versions " + + "$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed" + ) Timber.w(exception) return LoadResult.Error(exception) } @@ -126,29 +128,30 @@ internal object ExtensionLoader { val classLoader = PathClassLoader(appInfo.sourceDir, null, context.classLoader) val sources = appInfo.metaData.getString(METADATA_SOURCE_CLASS)!! - .split(";") - .map { - val sourceClass = it.trim() - if (sourceClass.startsWith(".")) - pkgInfo.packageName + sourceClass - else - sourceClass + .split(";") + .map { + val sourceClass = it.trim() + if (sourceClass.startsWith(".")) { + pkgInfo.packageName + sourceClass + } else { + sourceClass } - .flatMap { - try { - when (val obj = Class.forName(it, false, classLoader).newInstance()) { - is Source -> listOf(obj) - is SourceFactory -> obj.createSources() - else -> throw Exception("Unknown source class type! ${obj.javaClass}") - } - } catch (e: Throwable) { - Timber.e(e, "Extension load error: $extName.") - return LoadResult.Error(e) + } + .flatMap { + try { + when (val obj = Class.forName(it, false, classLoader).newInstance()) { + is Source -> listOf(obj) + is SourceFactory -> obj.createSources() + else -> throw Exception("Unknown source class type! ${obj.javaClass}") } + } catch (e: Throwable) { + Timber.e(e, "Extension load error: $extName.") + return LoadResult.Error(e) } + } val langs = sources.filterIsInstance() - .map { it.lang } - .toSet() + .map { it.lang } + .toSet() val lang = when (langs.size) { 0 -> "" diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/AndroidCookieJar.kt b/app/src/main/java/eu/kanade/tachiyomi/network/AndroidCookieJar.kt index 18023ba4a5..c93b217ee0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/network/AndroidCookieJar.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/network/AndroidCookieJar.kt @@ -44,9 +44,9 @@ class AndroidCookieJar : CookieJar { } cookies.split(";") - .map { it.substringBefore("=") } - .filterNames() - .onEach { manager.setCookie(urlString, "$it=;Max-Age=$maxAge") } + .map { it.substringBefore("=") } + .filterNames() + .onEach { manager.setCookie(urlString, "$it=;Max-Age=$maxAge") } } fun removeAll() { diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/CloudflareInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/network/CloudflareInterceptor.kt index eabaa087a7..fcfaacd710 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/network/CloudflareInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/network/CloudflareInterceptor.kt @@ -54,7 +54,7 @@ class CloudflareInterceptor(private val context: Context) : Interceptor { response.close() networkHelper.cookieManager.remove(originalRequest.url, COOKIE_NAMES, 0) val oldCookie = networkHelper.cookieManager.get(originalRequest.url) - .firstOrNull { it.name == "cf_clearance" } + .firstOrNull { it.name == "cf_clearance" } resolveWithWebView(originalRequest, oldCookie) return chain.proceed(originalRequest) @@ -87,14 +87,14 @@ class CloudflareInterceptor(private val context: Context) : Interceptor { // Avoid set empty User-Agent, Chromium WebView will reset to default if empty webview.settings.userAgentString = request.header("User-Agent") - ?: HttpSource.DEFAULT_USERAGENT + ?: HttpSource.DEFAULT_USERAGENT webview.webViewClient = object : WebViewClientCompat() { override fun onPageFinished(view: WebView, url: String) { fun isCloudFlareBypassed(): Boolean { return networkHelper.cookieManager.get(origRequestUrl.toHttpUrl()) - .firstOrNull { it.name == "cf_clearance" } - .let { it != null && it != oldCookie } + .firstOrNull { it.name == "cf_clearance" } + .let { it != null && it != oldCookie } } if (isCloudFlareBypassed()) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt index fb4c6d486a..6ec7ae9553 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt @@ -14,12 +14,12 @@ class NetworkHelper(context: Context) { val cookieManager = AndroidCookieJar() val client = OkHttpClient.Builder() - .cookieJar(cookieManager) - .cache(Cache(cacheDir, cacheSize)) - .build() + .cookieJar(cookieManager) + .cache(Cache(cacheDir, cacheSize)) + .build() val cloudflareClient = client.newBuilder() - .addInterceptor(UserAgentInterceptor()) - .addInterceptor(CloudflareInterceptor(context)) - .build() + .addInterceptor(UserAgentInterceptor()) + .addInterceptor(CloudflareInterceptor(context)) + .build() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt index aa752801b3..8d86629cf5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt @@ -92,14 +92,14 @@ fun Call.asObservableSuccess(): Observable { fun OkHttpClient.newCallWithProgress(request: Request, listener: ProgressListener): Call { val progressClient = newBuilder() - .cache(null) - .addNetworkInterceptor { chain -> - val originalResponse = chain.proceed(chain.request()) - originalResponse.newBuilder() - .body(ProgressResponseBody(originalResponse.body!!, listener)) - .build() - } - .build() + .cache(null) + .addNetworkInterceptor { chain -> + val originalResponse = chain.proceed(chain.request()) + originalResponse.newBuilder() + .body(ProgressResponseBody(originalResponse.body!!, listener)) + .build() + } + .build() return progressClient.newCall(request) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/Requests.kt b/app/src/main/java/eu/kanade/tachiyomi/network/Requests.kt index 63ecff109c..8fc2b9a6ff 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/network/Requests.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/network/Requests.kt @@ -17,10 +17,10 @@ fun GET( cache: CacheControl = DEFAULT_CACHE_CONTROL ): Request { return Request.Builder() - .url(url) - .headers(headers) - .cacheControl(cache) - .build() + .url(url) + .headers(headers) + .cacheControl(cache) + .build() } fun POST( @@ -30,9 +30,9 @@ fun POST( cache: CacheControl = DEFAULT_CACHE_CONTROL ): Request { return Request.Builder() - .url(url) - .post(body) - .headers(headers) - .cacheControl(cache) - .build() + .url(url) + .post(body) + .headers(headers) + .cacheControl(cache) + .build() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/UserAgentInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/network/UserAgentInterceptor.kt index 52d37a77aa..a5aa3e4f51 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/network/UserAgentInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/network/UserAgentInterceptor.kt @@ -10,10 +10,10 @@ class UserAgentInterceptor : Interceptor { return if (originalRequest.header("User-Agent").isNullOrEmpty()) { val newRequest = originalRequest - .newBuilder() - .removeHeader("User-Agent") - .addHeader("User-Agent", HttpSource.DEFAULT_USERAGENT) - .build() + .newBuilder() + .removeHeader("User-Agent") + .addHeader("User-Agent", HttpSource.DEFAULT_USERAGENT) + .build() chain.proceed(newRequest) } else { chain.proceed(originalRequest) diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt index 573806e6af..c153d6c6a8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt @@ -76,23 +76,25 @@ class LocalSource(private val context: Context) : CatalogueSource { val time = if (filters === LATEST_FILTERS) System.currentTimeMillis() - LATEST_THRESHOLD else 0L var mangaDirs = baseDirs.mapNotNull { it.listFiles()?.toList() } - .flatten() - .filter { it.isDirectory && if (time == 0L) it.name.contains(query, ignoreCase = true) else it.lastModified() >= time } - .distinctBy { it.name } + .flatten() + .filter { it.isDirectory && if (time == 0L) it.name.contains(query, ignoreCase = true) else it.lastModified() >= time } + .distinctBy { it.name } val state = ((if (filters.isEmpty()) POPULAR_FILTERS else filters)[0] as OrderBy).state when (state?.index) { 0 -> { - mangaDirs = if (state.ascending) + mangaDirs = if (state.ascending) { mangaDirs.sortedBy { it.name.toLowerCase(Locale.ENGLISH) } - else + } else { mangaDirs.sortedByDescending { it.name.toLowerCase(Locale.ENGLISH) } + } } 1 -> { - mangaDirs = if (state.ascending) + mangaDirs = if (state.ascending) { mangaDirs.sortedBy(File::lastModified) - else + } else { mangaDirs.sortedByDescending(File::lastModified) + } } } @@ -131,47 +133,49 @@ class LocalSource(private val context: Context) : CatalogueSource { override fun fetchMangaDetails(manga: SManga): Observable { getBaseDirectories(context) - .mapNotNull { File(it, manga.url).listFiles()?.toList() } - .flatten() - .firstOrNull { it.extension == "json" } - ?.apply { - val json = Gson().fromJson(Scanner(this).useDelimiter("\\Z").next(), JsonObject::class.java) - manga.title = json["title"]?.asString ?: manga.title - manga.author = json["author"]?.asString ?: manga.author - manga.artist = json["artist"]?.asString ?: manga.artist - manga.description = json["description"]?.asString ?: manga.description - manga.genre = json["genre"]?.asJsonArray?.joinToString(", ") { it.asString } - ?: manga.genre - manga.status = json["status"]?.asInt ?: manga.status - } + .mapNotNull { File(it, manga.url).listFiles()?.toList() } + .flatten() + .firstOrNull { it.extension == "json" } + ?.apply { + val json = Gson().fromJson(Scanner(this).useDelimiter("\\Z").next(), JsonObject::class.java) + manga.title = json["title"]?.asString ?: manga.title + manga.author = json["author"]?.asString ?: manga.author + manga.artist = json["artist"]?.asString ?: manga.artist + manga.description = json["description"]?.asString ?: manga.description + manga.genre = json["genre"]?.asJsonArray?.joinToString(", ") { it.asString } + ?: manga.genre + manga.status = json["status"]?.asInt ?: manga.status + } return Observable.just(manga) } override fun fetchChapterList(manga: SManga): Observable> { val chapters = getBaseDirectories(context) - .asSequence() - .mapNotNull { File(it, manga.url).listFiles()?.toList() } - .flatten() - .filter { it.isDirectory || isSupportedFile(it.extension) } - .map { chapterFile -> - SChapter.create().apply { - url = "${manga.url}/${chapterFile.name}" - val chapName = if (chapterFile.isDirectory) { - chapterFile.name - } else { - chapterFile.nameWithoutExtension - } - val chapNameCut = chapName.replace(manga.title, "", true).trim(' ', '-', '_') - name = if (chapNameCut.isEmpty()) chapName else chapNameCut - date_upload = chapterFile.lastModified() - ChapterRecognition.parseChapterNumber(this, manga) + .asSequence() + .mapNotNull { File(it, manga.url).listFiles()?.toList() } + .flatten() + .filter { it.isDirectory || isSupportedFile(it.extension) } + .map { chapterFile -> + SChapter.create().apply { + url = "${manga.url}/${chapterFile.name}" + val chapName = if (chapterFile.isDirectory) { + chapterFile.name + } else { + chapterFile.nameWithoutExtension } + val chapNameCut = chapName.replace(manga.title, "", true).trim(' ', '-', '_') + name = if (chapNameCut.isEmpty()) chapName else chapNameCut + date_upload = chapterFile.lastModified() + ChapterRecognition.parseChapterNumber(this, manga) } - .sortedWith(Comparator { c1, c2 -> + } + .sortedWith( + Comparator { c1, c2 -> val c = c2.chapter_number.compareTo(c1.chapter_number) if (c == 0) c2.name.compareToCaseInsensitiveNaturalOrder(c1.name) else c - }) - .toList() + } + ) + .toList() return Observable.just(chapters) } @@ -215,16 +219,16 @@ class LocalSource(private val context: Context) : CatalogueSource { return when (val format = getFormat(chapter)) { is Format.Directory -> { val entry = format.file.listFiles() - .sortedWith(Comparator { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) }) - .find { !it.isDirectory && ImageUtil.isImage(it.name) { FileInputStream(it) } } + .sortedWith(Comparator { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) }) + .find { !it.isDirectory && ImageUtil.isImage(it.name) { FileInputStream(it) } } entry?.let { updateCover(context, manga, it.inputStream()) } } is Format.Zip -> { ZipFile(format.file).use { zip -> val entry = zip.entries().toList() - .sortedWith(Comparator { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) }) - .find { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } } + .sortedWith(Comparator { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) }) + .find { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } } entry?.let { updateCover(context, manga, zip.getInputStream(it)) } } @@ -232,8 +236,8 @@ class LocalSource(private val context: Context) : CatalogueSource { is Format.Rar -> { Archive(format.file).use { archive -> val entry = archive.fileHeaders - .sortedWith(Comparator { f1, f2 -> f1.fileNameString.compareToCaseInsensitiveNaturalOrder(f2.fileNameString) }) - .find { !it.isDirectory && ImageUtil.isImage(it.fileNameString) { archive.getInputStream(it) } } + .sortedWith(Comparator { f1, f2 -> f1.fileNameString.compareToCaseInsensitiveNaturalOrder(f2.fileNameString) }) + .find { !it.isDirectory && ImageUtil.isImage(it.fileNameString) { archive.getInputStream(it) } } entry?.let { updateCover(context, manga, archive.getInputStream(it)) } } @@ -241,8 +245,8 @@ class LocalSource(private val context: Context) : CatalogueSource { is Format.Epub -> { EpubFile(format.file).use { epub -> val entry = epub.getImagesFromPages() - .firstOrNull() - ?.let { epub.getEntry(it) } + .firstOrNull() + ?.let { epub.getEntry(it) } entry?.let { updateCover(context, manga, epub.getInputStream(it)) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt b/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt index 25abe55ee3..f8586ea246 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt @@ -46,7 +46,7 @@ open class SourceManager(private val context: Context) { } private fun createInternalSources(): List = listOf( - LocalSource(context) + LocalSource(context) ) private inner class StubSource(override val id: Long) : Source { diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt b/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt index f7a88ea9bf..63911e10b3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt @@ -23,25 +23,31 @@ interface SManga : Serializable { var initialized: Boolean fun copyFrom(other: SManga) { - if (other.author != null) + if (other.author != null) { author = other.author + } - if (other.artist != null) + if (other.artist != null) { artist = other.artist + } - if (other.description != null) + if (other.description != null) { description = other.description + } - if (other.genre != null) + if (other.genre != null) { genre = other.genre + } - if (other.thumbnail_url != null) + if (other.thumbnail_url != null) { thumbnail_url = other.thumbnail_url + } status = other.status - if (!initialized) + if (!initialized) { initialized = other.initialized + } } companion object { diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt index 9e5e752ee1..02ff3b8771 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt @@ -90,10 +90,10 @@ abstract class HttpSource : CatalogueSource { */ override fun fetchPopularManga(page: Int): Observable { return client.newCall(popularMangaRequest(page)) - .asObservableSuccess() - .map { response -> - popularMangaParse(response) - } + .asObservableSuccess() + .map { response -> + popularMangaParse(response) + } } /** @@ -120,10 +120,10 @@ abstract class HttpSource : CatalogueSource { */ override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { return client.newCall(searchMangaRequest(page, query, filters)) - .asObservableSuccess() - .map { response -> - searchMangaParse(response) - } + .asObservableSuccess() + .map { response -> + searchMangaParse(response) + } } /** @@ -149,10 +149,10 @@ abstract class HttpSource : CatalogueSource { */ override fun fetchLatestUpdates(page: Int): Observable { return client.newCall(latestUpdatesRequest(page)) - .asObservableSuccess() - .map { response -> - latestUpdatesParse(response) - } + .asObservableSuccess() + .map { response -> + latestUpdatesParse(response) + } } /** @@ -177,10 +177,10 @@ abstract class HttpSource : CatalogueSource { */ override fun fetchMangaDetails(manga: SManga): Observable { return client.newCall(mangaDetailsRequest(manga)) - .asObservableSuccess() - .map { response -> - mangaDetailsParse(response).apply { initialized = true } - } + .asObservableSuccess() + .map { response -> + mangaDetailsParse(response).apply { initialized = true } + } } /** @@ -209,10 +209,10 @@ abstract class HttpSource : CatalogueSource { override fun fetchChapterList(manga: SManga): Observable> { return if (manga.status != SManga.LICENSED) { client.newCall(chapterListRequest(manga)) - .asObservableSuccess() - .map { response -> - chapterListParse(response) - } + .asObservableSuccess() + .map { response -> + chapterListParse(response) + } } else { Observable.error(Exception("Licensed - No chapters to show")) } @@ -242,10 +242,10 @@ abstract class HttpSource : CatalogueSource { */ override fun fetchPageList(chapter: SChapter): Observable> { return client.newCall(pageListRequest(chapter)) - .asObservableSuccess() - .map { response -> - pageListParse(response) - } + .asObservableSuccess() + .map { response -> + pageListParse(response) + } } /** @@ -273,8 +273,8 @@ abstract class HttpSource : CatalogueSource { */ open fun fetchImageUrl(page: Page): Observable { return client.newCall(imageUrlRequest(page)) - .asObservableSuccess() - .map { imageUrlParse(it) } + .asObservableSuccess() + .map { imageUrlParse(it) } } /** @@ -301,7 +301,7 @@ abstract class HttpSource : CatalogueSource { */ fun fetchImage(page: Page): Observable { return client.newCallWithProgress(imageRequest(page), page) - .asObservableSuccess() + .asObservableSuccess() } /** @@ -343,10 +343,12 @@ abstract class HttpSource : CatalogueSource { return try { val uri = URI(orig) var out = uri.path - if (uri.query != null) + if (uri.query != null) { out += "?" + uri.query - if (uri.fragment != null) + } + if (uri.fragment != null) { out += "#" + uri.fragment + } out } catch (e: URISyntaxException) { orig diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSourceFetcher.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSourceFetcher.kt index 7247878ff6..7b3ea4bdec 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSourceFetcher.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSourceFetcher.kt @@ -6,20 +6,20 @@ import rx.Observable fun HttpSource.getImageUrl(page: Page): Observable { page.status = Page.LOAD_PAGE return fetchImageUrl(page) - .doOnError { page.status = Page.ERROR } - .onErrorReturn { null } - .doOnNext { page.imageUrl = it } - .map { page } + .doOnError { page.status = Page.ERROR } + .onErrorReturn { null } + .doOnNext { page.imageUrl = it } + .map { page } } fun HttpSource.fetchAllImageUrlsFromPageList(pages: List): Observable { return Observable.from(pages) - .filter { !it.imageUrl.isNullOrEmpty() } - .mergeWith(fetchRemainingImageUrlsFromPageList(pages)) + .filter { !it.imageUrl.isNullOrEmpty() } + .mergeWith(fetchRemainingImageUrlsFromPageList(pages)) } fun HttpSource.fetchRemainingImageUrlsFromPageList(pages: List): Observable { return Observable.from(pages) - .filter { it.imageUrl.isNullOrEmpty() } - .concatMap { getImageUrl(it) } + .filter { it.imageUrl.isNullOrEmpty() } + .concatMap { getImageUrl(it) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt index 07a8b7049e..11c86bf184 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt @@ -59,17 +59,19 @@ abstract class BaseActivity : AppCompatActivity() { } override fun onCreate(savedInstanceState: Bundle?) { - setTheme(when (preferences.themeMode().get()) { - Values.THEME_MODE_SYSTEM -> { - if (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) { - darkTheme - } else { - lightTheme + setTheme( + when (preferences.themeMode().get()) { + Values.THEME_MODE_SYSTEM -> { + if (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) { + darkTheme + } else { + lightTheme + } } + Values.THEME_MODE_DARK -> darkTheme + else -> lightTheme } - Values.THEME_MODE_DARK -> darkTheme - else -> lightTheme - }) + ) super.onCreate(savedInstanceState) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/BaseController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/BaseController.kt index c0922d646e..48e7aa8a3d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/BaseController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/BaseController.kt @@ -15,8 +15,9 @@ import kotlinx.android.extensions.LayoutContainer import kotlinx.android.synthetic.clearFindViewByIdCache import timber.log.Timber -abstract class BaseController(bundle: Bundle? = null) : RestoreViewOnCreateController(bundle), - LayoutContainer { +abstract class BaseController(bundle: Bundle? = null) : + RestoreViewOnCreateController(bundle), + LayoutContainer { lateinit var binding: VB diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/ConductorExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/ConductorExtensions.kt index 79a6ce86a6..ef42399129 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/ConductorExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/ConductorExtensions.kt @@ -30,6 +30,6 @@ fun Controller.requestPermissionsSafe(permissions: Array, requestCode: I fun Controller.withFadeTransaction(): RouterTransaction { return RouterTransaction.with(this) - .pushChangeHandler(FadeChangeHandler()) - .popChangeHandler(FadeChangeHandler()) + .pushChangeHandler(FadeChangeHandler()) + .popChangeHandler(FadeChangeHandler()) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/DialogController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/DialogController.kt index 4388fa8d1d..9fecbecda4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/DialogController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/DialogController.kt @@ -87,10 +87,12 @@ abstract class DialogController : RestoreViewOnCreateController { */ fun showDialog(router: Router, tag: String?) { dismissed = false - router.pushController(RouterTransaction.with(this) + router.pushController( + RouterTransaction.with(this) .pushChangeHandler(SimpleSwapChangeHandler(false)) .popChangeHandler(SimpleSwapChangeHandler(false)) - .tag(tag)) + .tag(tag) + ) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/RxController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/RxController.kt index dd470e79ae..2c3d7e9b3c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/RxController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/RxController.kt @@ -44,12 +44,10 @@ abstract class RxController(bundle: Bundle? = null) : BaseCont } fun Observable.subscribeUntilDetach(): Subscription { - return subscribe().also { untilDetachSubscriptions.add(it) } } fun Observable.subscribeUntilDetach(onNext: (T) -> Unit): Subscription { - return subscribe(onNext).also { untilDetachSubscriptions.add(it) } } @@ -57,7 +55,6 @@ abstract class RxController(bundle: Bundle? = null) : BaseCont onNext: (T) -> Unit, onError: (Throwable) -> Unit ): Subscription { - return subscribe(onNext, onError).also { untilDetachSubscriptions.add(it) } } @@ -66,17 +63,14 @@ abstract class RxController(bundle: Bundle? = null) : BaseCont onError: (Throwable) -> Unit, onCompleted: () -> Unit ): Subscription { - return subscribe(onNext, onError, onCompleted).also { untilDetachSubscriptions.add(it) } } fun Observable.subscribeUntilDestroy(): Subscription { - return subscribe().also { untilDestroySubscriptions.add(it) } } fun Observable.subscribeUntilDestroy(onNext: (T) -> Unit): Subscription { - return subscribe(onNext).also { untilDestroySubscriptions.add(it) } } @@ -84,7 +78,6 @@ abstract class RxController(bundle: Bundle? = null) : BaseCont onNext: (T) -> Unit, onError: (Throwable) -> Unit ): Subscription { - return subscribe(onNext, onError).also { untilDestroySubscriptions.add(it) } } @@ -93,7 +86,6 @@ abstract class RxController(bundle: Bundle? = null) : BaseCont onError: (Throwable) -> Unit, onCompleted: () -> Unit ): Subscription { - return subscribe(onNext, onError, onCompleted).also { untilDestroySubscriptions.add(it) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt index fe095d4632..c8eb46e5b2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt @@ -59,11 +59,11 @@ open class BasePresenter : RxPresenter() { override fun call(observable: Observable): Observable> { return observable - .materialize() - .filter { notification -> !notification.isOnCompleted } - .flatMap { notification -> - view.take(1).filter { it != null }.map { Delivery(it, notification) } - } + .materialize() + .filter { notification -> !notification.isOnCompleted } + .flatMap { notification -> + view.take(1).filter { it != null }.map { Delivery(it, notification) } + } } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt index dbfeca2cc9..ef48469b3e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt @@ -8,7 +8,7 @@ import eu.davidea.flexibleadapter.FlexibleAdapter * @param controller The containing controller. */ class CategoryAdapter(controller: CategoryController) : - FlexibleAdapter(null, controller, true) { + FlexibleAdapter(null, controller, true) { /** * Listener called when an item of the list is released. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryController.kt index ba4d68a880..55d5448cae 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryController.kt @@ -25,14 +25,15 @@ import reactivecircus.flowbinding.android.view.clicks /** * Controller to manage the categories for the users' library. */ -class CategoryController : NucleusController(), - ActionMode.Callback, - FlexibleAdapter.OnItemClickListener, - FlexibleAdapter.OnItemLongClickListener, - CategoryAdapter.OnItemReleaseListener, - CategoryCreateDialog.Listener, - CategoryRenameDialog.Listener, - UndoHelper.OnActionListener { +class CategoryController : + NucleusController(), + ActionMode.Callback, + FlexibleAdapter.OnItemClickListener, + FlexibleAdapter.OnItemLongClickListener, + CategoryAdapter.OnItemReleaseListener, + CategoryCreateDialog.Listener, + CategoryRenameDialog.Listener, + UndoHelper.OnActionListener { /** * Object used to show ActionMode toolbar. @@ -176,8 +177,10 @@ class CategoryController : NucleusController { undoHelper = UndoHelper(adapter, this) - undoHelper?.start(adapter.selectedPositions, view!!, - R.string.snack_categories_deleted, R.string.action_undo, 3000) + undoHelper?.start( + adapter.selectedPositions, view!!, + R.string.snack_categories_deleted, R.string.action_undo, 3000 + ) mode.finish() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryCreateDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryCreateDialog.kt index e723f0d6c2..bdaa51ad14 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryCreateDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryCreateDialog.kt @@ -31,17 +31,17 @@ class CategoryCreateDialog(bundle: Bundle? = null) : DialogController(bundle) */ override fun onCreateDialog(savedViewState: Bundle?): Dialog { return MaterialDialog(activity!!) - .title(R.string.action_add_category) - .negativeButton(android.R.string.cancel) - .input( - hint = resources?.getString(R.string.name), - prefill = currentName - ) { _, input -> - currentName = input.toString() - } - .positiveButton(android.R.string.ok) { - (targetController as? Listener)?.createCategory(currentName) - } + .title(R.string.action_add_category) + .negativeButton(android.R.string.cancel) + .input( + hint = resources?.getString(R.string.name), + prefill = currentName + ) { _, input -> + currentName = input.toString() + } + .positiveButton(android.R.string.ok) { + (targetController as? Listener)?.createCategory(currentName) + } } interface Listener { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryItem.kt index 250a871b2d..cdcde2a8ba 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryItem.kt @@ -49,7 +49,6 @@ class CategoryItem(val category: Category) : AbstractFlexibleItem? ) { - holder.bind(category) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt index fb2d4b0aa8..4c4409f569 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt @@ -30,10 +30,10 @@ class CategoryPresenter( super.onCreate(savedState) db.getCategories().asRxObservable() - .doOnNext { categories = it } - .map { it.map(::CategoryItem) } - .observeOn(AndroidSchedulers.mainThread()) - .subscribeLatestCache(CategoryController::setCategories) + .doOnNext { categories = it } + .map { it.map(::CategoryItem) } + .observeOn(AndroidSchedulers.mainThread()) + .subscribeLatestCache(CategoryController::setCategories) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryRenameDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryRenameDialog.kt index 693408ec04..ac1073b654 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryRenameDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryRenameDialog.kt @@ -36,15 +36,15 @@ class CategoryRenameDialog(bundle: Bundle? = null) : DialogController(bundle) */ override fun onCreateDialog(savedViewState: Bundle?): Dialog { return MaterialDialog(activity!!) - .title(R.string.action_rename_category) - .negativeButton(android.R.string.cancel) - .input( - hint = resources?.getString(R.string.name), - prefill = currentName - ) { _, input -> - currentName = input.toString() - } - .positiveButton(android.R.string.ok) { onPositive() } + .title(R.string.action_rename_category) + .negativeButton(android.R.string.cancel) + .input( + hint = resources?.getString(R.string.name), + prefill = currentName + ) { _, input -> + currentName = input.toString() + } + .positiveButton(android.R.string.ok) { onPositive() } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadController.kt index ac8cbf0b22..eb869f70b7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadController.kt @@ -23,7 +23,8 @@ import rx.android.schedulers.AndroidSchedulers * Controller that shows the currently active downloads. * Uses R.layout.fragment_download_queue. */ -class DownloadController : NucleusController(), +class DownloadController : + NucleusController(), DownloadAdapter.DownloadItemListener { /** @@ -75,16 +76,16 @@ class DownloadController : NucleusController x + y } - } - // Keep only the latest emission to avoid backpressure. - .onBackpressureLatest() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { progress -> - // Update the view only if the progress has changed. - if (download.totalProgress != progress) { - download.totalProgress = progress - onUpdateProgress(download) - } + // Get the sum of percentages for all the pages. + .flatMap { + Observable.from(download.pages) + .map(Page::progress) + .reduce { x, y -> x + y } + } + // Keep only the latest emission to avoid backpressure. + .onBackpressureLatest() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { progress -> + // Update the view only if the progress has changed. + if (download.totalProgress != progress) { + download.totalProgress = progress + onUpdateProgress(download) } + } // Avoid leaking subscriptions progressSubscriptions.remove(download)?.unsubscribe() @@ -279,10 +281,11 @@ class DownloadController : NucleusController() { super.onCreate(savedState) downloadQueue.getUpdatedObservable() - .observeOn(AndroidSchedulers.mainThread()) - .map { it.map(::DownloadItem) } - .subscribeLatestCache(DownloadController::onNextDownloads) { _, error -> - Timber.e(error) - } + .observeOn(AndroidSchedulers.mainThread()) + .map { it.map(::DownloadItem) } + .subscribeLatestCache(DownloadController::onNextDownloads) { _, error -> + Timber.e(error) + } } fun getDownloadStatusObservable(): Observable { return downloadQueue.getStatusObservable() - .startWith(downloadQueue.getActiveDownloads()) + .startWith(downloadQueue.getActiveDownloads()) } fun getDownloadProgressObservable(): Observable { return downloadQueue.getProgressObservable() - .onBackpressureBuffer() + .onBackpressureBuffer() } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionAdapter.kt index 09a439ff56..1ace42adc2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionAdapter.kt @@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.util.system.getResourceColor * @param controller instance of [ExtensionController]. */ class ExtensionAdapter(val controller: ExtensionController) : - FlexibleAdapter>(null, controller, true) { + FlexibleAdapter>(null, controller, true) { val cardBackground = controller.activity!!.getResourceColor(R.attr.colorSurface) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionController.kt index d1f8f3c7a9..71d56a04f5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionController.kt @@ -32,11 +32,12 @@ import uy.kohesive.injekt.api.get /** * Controller to manage the catalogues available in the app. */ -open class ExtensionController : NucleusController(), - ExtensionAdapter.OnButtonClickListener, - FlexibleAdapter.OnItemClickListener, - FlexibleAdapter.OnItemLongClickListener, - ExtensionTrustDialog.Listener { +open class ExtensionController : + NucleusController(), + ExtensionAdapter.OnButtonClickListener, + FlexibleAdapter.OnItemClickListener, + FlexibleAdapter.OnItemLongClickListener, + ExtensionTrustDialog.Listener { private val preferences: PreferencesHelper = Injekt.get() @@ -92,9 +93,11 @@ open class ExtensionController : NucleusController expandActionViewFromInteraction = true R.id.action_settings -> { - router.pushController((RouterTransaction.with(ExtensionFilterController())) + router.pushController( + (RouterTransaction.with(ExtensionFilterController())) .popChangeHandler(SettingsExtensionsFadeChangeHandler()) - .pushChangeHandler(FadeChangeHandler())) + .pushChangeHandler(FadeChangeHandler()) + ) } R.id.action_auto_check -> { item.isChecked = !item.isChecked @@ -184,7 +187,7 @@ open class ExtensionController : NucleusController) { @@ -196,9 +199,10 @@ open class ExtensionController : NucleusController(bundle), - PreferenceManager.OnDisplayPreferenceDialogListener, - DialogPreference.TargetFragment { + NucleusController(bundle), + PreferenceManager.OnDisplayPreferenceDialogListener, + DialogPreference.TargetFragment { private var lastOpenPreferencePosition: Int? = null private var preferenceScreen: PreferenceScreen? = null - constructor(pkgName: String) : this(Bundle().apply { - putString(PKGNAME_KEY, pkgName) - }) + constructor(pkgName: String) : this( + Bundle().apply { + putString(PKGNAME_KEY, pkgName) + } + ) override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View { val themedInflater = inflater.cloneInContext(getPreferenceThemeContext()) @@ -136,8 +138,9 @@ class ExtensionDetailsController(bundle: Bundle? = null) : val dataStore = SharedPreferencesDataStore(/*if (source is HttpSource) { source.preferences } else {*/ - context.getSharedPreferences("source_${source.id}", Context.MODE_PRIVATE) - /*}*/) + context.getSharedPreferences("source_${source.id}", Context.MODE_PRIVATE) + /*}*/ + ) if (source is ConfigurableSource) { if (multiSource) { @@ -178,14 +181,19 @@ class ExtensionDetailsController(bundle: Bundle? = null) : } val f = when (preference) { - is EditTextPreference -> EditTextPreferenceDialogController + is EditTextPreference -> + EditTextPreferenceDialogController .newInstance(preference.getKey()) - is ListPreference -> ListPreferenceDialogController + is ListPreference -> + ListPreferenceDialogController .newInstance(preference.getKey()) - is MultiSelectListPreference -> MultiSelectListPreferenceDialogController + is MultiSelectListPreference -> + MultiSelectListPreferenceDialogController .newInstance(preference.getKey()) - else -> throw IllegalArgumentException("Tried to display dialog for unknown " + - "preference type. Did you forget to override onDisplayPreferenceDialog()?") + else -> throw IllegalArgumentException( + "Tried to display dialog for unknown " + + "preference type. Did you forget to override onDisplayPreferenceDialog()?" + ) } f.targetController = this f.showDialog(router) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionDetailsPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionDetailsPresenter.kt index 93b79d4670..51e58c34b7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionDetailsPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionDetailsPresenter.kt @@ -22,14 +22,14 @@ class ExtensionDetailsPresenter( private fun bindToUninstalledExtension() { extensionManager.getInstalledExtensionsObservable() - .skip(1) - .filter { extensions -> extensions.none { it.pkgName == pkgName } } - .map { Unit } - .take(1) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeFirst({ view, _ -> - view.onExtensionUninstalled() - }) + .skip(1) + .filter { extensions -> extensions.none { it.pkgName == pkgName } } + .map { Unit } + .take(1) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeFirst({ view, _ -> + view.onExtensionUninstalled() + }) } fun uninstallExtension() { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionDividerItemDecoration.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionDividerItemDecoration.kt index 8d8662c4ab..6bef0da268 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionDividerItemDecoration.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionDividerItemDecoration.kt @@ -23,7 +23,8 @@ class ExtensionDividerItemDecoration(context: Context) : RecyclerView.ItemDecora val child = parent.getChildAt(i) val holder = parent.getChildViewHolder(child) if (holder is ExtensionHolder && - parent.getChildViewHolder(parent.getChildAt(i + 1)) is ExtensionHolder) { + parent.getChildViewHolder(parent.getChildAt(i + 1)) is ExtensionHolder + ) { val params = child.layoutParams as RecyclerView.LayoutParams val top = child.bottom + params.bottomMargin val bottom = top + divider.intrinsicHeight diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionFilterController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionFilterController.kt index 511dde50d4..6a4c8f904d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionFilterController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionFilterController.kt @@ -19,13 +19,13 @@ class ExtensionFilterController : SettingsController() { val activeLangs = preferences.enabledLanguages().get() val availableLangs = - Injekt.get().availableExtensions.groupBy { - it.lang - }.keys.minus("all").partition { - it in activeLangs - }.let { - it.first + it.second - } + Injekt.get().availableExtensions.groupBy { + it.lang + }.keys.minus("all").partition { + it in activeLangs + }.let { + it.first + it.second + } availableLangs.forEach { switchPreference { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionGroupHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionGroupHolder.kt index 61faf00e13..cd98f0941e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionGroupHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionGroupHolder.kt @@ -7,7 +7,7 @@ import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder import kotlinx.android.synthetic.main.extension_card_header.title class ExtensionGroupHolder(view: View, adapter: FlexibleAdapter<*>) : - BaseFlexibleViewHolder(view, adapter) { + BaseFlexibleViewHolder(view, adapter) { @SuppressLint("SetTextI18n") fun bind(item: ExtensionGroupItem) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionGroupItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionGroupItem.kt index 154df68112..3da04552e5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionGroupItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionGroupItem.kt @@ -38,7 +38,6 @@ data class ExtensionGroupItem(val name: String, val size: Int, val showSize: Boo position: Int, payloads: List? ) { - holder.bind(this) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionHolder.kt index 53f2b5b7ce..10b16b42c9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionHolder.kt @@ -18,8 +18,8 @@ import kotlinx.android.synthetic.main.extension_card_item.lang import kotlinx.android.synthetic.main.extension_card_item.version class ExtensionHolder(view: View, override val adapter: ExtensionAdapter) : - BaseFlexibleViewHolder(view, adapter), - SlicedHolder { + BaseFlexibleViewHolder(view, adapter), + SlicedHolder { override val slice = Slice(card).apply { setColor(adapter.cardBackground) @@ -50,8 +50,8 @@ class ExtensionHolder(view: View, override val adapter: ExtensionAdapter) : GlideApp.with(itemView.context).clear(image) if (extension is Extension.Available) { GlideApp.with(itemView.context) - .load(extension.iconUrl) - .into(image) + .load(extension.iconUrl) + .into(image) } else { extension.getApplicationIcon(itemView.context)?.let { image.setImageDrawable(it) } } @@ -69,13 +69,15 @@ class ExtensionHolder(view: View, override val adapter: ExtensionAdapter) : val installStep = item.installStep if (installStep != null) { - setText(when (installStep) { - InstallStep.Pending -> R.string.ext_pending - InstallStep.Downloading -> R.string.ext_downloading - InstallStep.Installing -> R.string.ext_installing - InstallStep.Installed -> R.string.ext_installed - InstallStep.Error -> R.string.action_retry - }) + setText( + when (installStep) { + InstallStep.Pending -> R.string.ext_pending + InstallStep.Downloading -> R.string.ext_downloading + InstallStep.Installing -> R.string.ext_installing + InstallStep.Installed -> R.string.ext_installed + InstallStep.Error -> R.string.action_retry + } + ) if (installStep != InstallStep.Error) { isEnabled = false isClickable = false diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionItem.kt index 3c3b63ad59..017918b9a8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionItem.kt @@ -21,7 +21,7 @@ data class ExtensionItem( val header: ExtensionGroupItem? = null, val installStep: InstallStep? = null ) : - AbstractSectionableItem(header) { + AbstractSectionableItem(header) { /** * Returns the layout resource of this item. @@ -46,7 +46,6 @@ data class ExtensionItem( position: Int, payloads: List? ) { - if (payloads == null || payloads.isEmpty()) { holder.bind(this) } else { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionPresenter.kt index 528d3b3e03..ae77e52a74 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionPresenter.kt @@ -17,7 +17,7 @@ import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get private typealias ExtensionTuple = - Triple, List, List> + Triple, List, List> /** * Presenter of [ExtensionController]. @@ -42,13 +42,13 @@ open class ExtensionPresenter( val installedObservable = extensionManager.getInstalledExtensionsObservable() val untrustedObservable = extensionManager.getUntrustedExtensionsObservable() val availableObservable = extensionManager.getAvailableExtensionsObservable() - .startWith(emptyList()) + .startWith(emptyList()) return Observable.combineLatest(installedObservable, untrustedObservable, availableObservable) { installed, untrusted, available -> Triple(installed, untrusted, available) } - .debounce(100, TimeUnit.MILLISECONDS) - .map(::toItems) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeLatestCache({ view, _ -> view.setExtensions(extensions) }) + .debounce(100, TimeUnit.MILLISECONDS) + .map(::toItems) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeLatestCache({ view, _ -> view.setExtensions(extensions) }) } @Synchronized @@ -64,13 +64,13 @@ open class ExtensionPresenter( val installedSorted = installed.filter { !it.hasUpdate }.sortedWith(compareBy({ !it.isObsolete }, { it.pkgName })) val untrustedSorted = untrusted.sortedBy { it.pkgName } val availableSorted = available - // Filter out already installed extensions and disabled languages - .filter { avail -> - installed.none { it.pkgName == avail.pkgName } && - untrusted.none { it.pkgName == avail.pkgName } && - (avail.lang in activeLangs || avail.lang == "all") - } - .sortedBy { it.pkgName } + // Filter out already installed extensions and disabled languages + .filter { avail -> + installed.none { it.pkgName == avail.pkgName } && + untrusted.none { it.pkgName == avail.pkgName } && + (avail.lang in activeLangs || avail.lang == "all") + } + .sortedBy { it.pkgName } if (updatesSorted.isNotEmpty()) { val header = ExtensionGroupItem(context.getString(R.string.ext_updates_pending), updatesSorted.size, true) @@ -89,16 +89,16 @@ open class ExtensionPresenter( } if (availableSorted.isNotEmpty()) { val availableGroupedByLang = availableSorted - .groupBy { LocaleHelper.getSourceDisplayName(it.lang, context) } - .toSortedMap() + .groupBy { LocaleHelper.getSourceDisplayName(it.lang, context) } + .toSortedMap() availableGroupedByLang - .forEach { - val header = ExtensionGroupItem(it.key, it.value.size) - items += it.value.map { extension -> - ExtensionItem(extension, header, currentDownloads[extension.pkgName]) - } + .forEach { + val header = ExtensionGroupItem(it.key, it.value.size) + items += it.value.map { extension -> + ExtensionItem(extension, header, currentDownloads[extension.pkgName]) } + } } this.extensions = items @@ -131,13 +131,13 @@ open class ExtensionPresenter( private fun Observable.subscribeToInstallUpdate(extension: Extension) { this.doOnNext { currentDownloads[extension.pkgName] = it } - .doOnUnsubscribe { currentDownloads.remove(extension.pkgName) } - .map { state -> updateInstallStep(extension, state) } - .subscribeWithView({ view, item -> - if (item != null) { - view.downloadUpdate(item) - } - }) + .doOnUnsubscribe { currentDownloads.remove(extension.pkgName) } + .map { state -> updateInstallStep(extension, state) } + .subscribeWithView({ view, item -> + if (item != null) { + view.downloadUpdate(item) + } + }) } fun uninstallExtension(pkgName: String) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionTrustDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionTrustDialog.kt index 5b63b46fae..458a60f4b1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionTrustDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionTrustDialog.kt @@ -10,23 +10,25 @@ import eu.kanade.tachiyomi.ui.base.controller.DialogController class ExtensionTrustDialog(bundle: Bundle? = null) : DialogController(bundle) where T : Controller, T : ExtensionTrustDialog.Listener { - constructor(target: T, signatureHash: String, pkgName: String) : this(Bundle().apply { - putString(SIGNATURE_KEY, signatureHash) - putString(PKGNAME_KEY, pkgName) - }) { + constructor(target: T, signatureHash: String, pkgName: String) : this( + Bundle().apply { + putString(SIGNATURE_KEY, signatureHash) + putString(PKGNAME_KEY, pkgName) + } + ) { targetController = target } override fun onCreateDialog(savedViewState: Bundle?): Dialog { return MaterialDialog(activity!!) - .title(R.string.untrusted_extension) - .message(R.string.untrusted_extension_message) - .positiveButton(R.string.ext_trust) { - (targetController as? Listener)?.trustSignature(args.getString(SIGNATURE_KEY)!!) - } - .negativeButton(R.string.ext_uninstall) { - (targetController as? Listener)?.uninstallExtension(args.getString(PKGNAME_KEY)!!) - } + .title(R.string.untrusted_extension) + .message(R.string.untrusted_extension_message) + .positiveButton(R.string.ext_trust) { + (targetController as? Listener)?.trustSignature(args.getString(SIGNATURE_KEY)!!) + } + .negativeButton(R.string.ext_uninstall) { + (targetController as? Listener)?.uninstallExtension(args.getString(PKGNAME_KEY)!!) + } } private companion object { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/ChangeMangaCategoriesDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/ChangeMangaCategoriesDialog.kt index a848749716..5d267927f7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/ChangeMangaCategoriesDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/ChangeMangaCategoriesDialog.kt @@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.ui.base.controller.DialogController class ChangeMangaCategoriesDialog(bundle: Bundle? = null) : - DialogController(bundle) where T : Controller, T : ChangeMangaCategoriesDialog.Listener { + DialogController(bundle) where T : Controller, T : ChangeMangaCategoriesDialog.Listener { private var mangas = emptyList() @@ -33,17 +33,17 @@ class ChangeMangaCategoriesDialog(bundle: Bundle? = null) : override fun onCreateDialog(savedViewState: Bundle?): Dialog { return MaterialDialog(activity!!) - .title(R.string.action_move_category) - .listItemsMultiChoice( - items = categories.map { it.name }, - initialSelection = preselected.toIntArray(), - allowEmptySelection = true - ) { _, selections, _ -> - val newCategories = selections.map { categories[it] } - (targetController as? Listener)?.updateCategoriesForMangas(mangas, newCategories) - } - .positiveButton(android.R.string.ok) - .negativeButton(android.R.string.cancel) + .title(R.string.action_move_category) + .listItemsMultiChoice( + items = categories.map { it.name }, + initialSelection = preselected.toIntArray(), + allowEmptySelection = true + ) { _, selections, _ -> + val newCategories = selections.map { categories[it] } + (targetController as? Listener)?.updateCategoriesForMangas(mangas, newCategories) + } + .positiveButton(android.R.string.ok) + .negativeButton(android.R.string.cancel) } interface Listener { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/DeleteLibraryMangasDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/DeleteLibraryMangasDialog.kt index 4c6eda1355..969f19f578 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/DeleteLibraryMangasDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/DeleteLibraryMangasDialog.kt @@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.widget.DialogCheckboxView class DeleteLibraryMangasDialog(bundle: Bundle? = null) : - DialogController(bundle) where T : Controller, T : DeleteLibraryMangasDialog.Listener { + DialogController(bundle) where T : Controller, T : DeleteLibraryMangasDialog.Listener { private var mangas = emptyList() @@ -27,16 +27,16 @@ class DeleteLibraryMangasDialog(bundle: Bundle? = null) : } return MaterialDialog(activity!!) - .title(R.string.action_remove) - .customView( - view = view, - horizontalPadding = true - ) - .positiveButton(android.R.string.ok) { - val deleteChapters = view.isChecked() - (targetController as? Listener)?.deleteMangasFromLibrary(mangas, deleteChapters) - } - .negativeButton(android.R.string.cancel) + .title(R.string.action_remove) + .customView( + view = view, + horizontalPadding = true + ) + .positiveButton(android.R.string.ok) { + val deleteChapters = view.isChecked() + (targetController as? Listener)?.deleteMangasFromLibrary(mangas, deleteChapters) + } + .negativeButton(android.R.string.cancel) } interface Listener { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt index fbcad7254a..5b6e0c787f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt @@ -9,7 +9,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga * @param view the fragment containing this adapter. */ class LibraryCategoryAdapter(view: LibraryCategoryView) : - FlexibleAdapter(null, view, true) { + FlexibleAdapter(null, view, true) { /** * The list of manga in this category. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt index 172dea2657..2254a0ffce 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt @@ -33,9 +33,9 @@ import uy.kohesive.injekt.injectLazy * Fragment containing the library manga for a certain category. */ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - FrameLayout(context, attrs), - FlexibleAdapter.OnItemClickListener, - FlexibleAdapter.OnItemLongClickListener { + FrameLayout(context, attrs), + FlexibleAdapter.OnItemClickListener, + FlexibleAdapter.OnItemLongClickListener { private val scope = CoroutineScope(Job() + Dispatchers.Main) @@ -122,24 +122,24 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att } subscriptions += controller.searchRelay - .doOnNext { adapter.setFilter(it) } - .skip(1) - .subscribe { adapter.performFilter() } + .doOnNext { adapter.setFilter(it) } + .skip(1) + .subscribe { adapter.performFilter() } subscriptions += controller.libraryMangaRelay - .subscribe { onNextLibraryManga(it) } + .subscribe { onNextLibraryManga(it) } subscriptions += controller.selectionRelay - .subscribe { onSelectionChanged(it) } + .subscribe { onSelectionChanged(it) } subscriptions += controller.selectAllRelay - .filter { it == category.id } - .subscribe { - adapter.currentItems.forEach { item -> - controller.setSelection(item.manga, true) - } - controller.invalidateActionMode() + .filter { it == category.id } + .subscribe { + adapter.currentItems.forEach { item -> + controller.setSelection(item.manga, true) } + controller.invalidateActionMode() + } subscriptions += controller.selectInverseRelay .filter { it == category.id } @@ -255,10 +255,12 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att controller.createActionModeIfNeeded() when { lastClickPosition == -1 -> setSelection(position) - lastClickPosition > position -> for (i in position until lastClickPosition) - setSelection(i) - lastClickPosition < position -> for (i in lastClickPosition + 1..position) - setSelection(i) + lastClickPosition > position -> + for (i in position until lastClickPosition) + setSelection(i) + lastClickPosition < position -> + for (i in lastClickPosition + 1..position) + setSelection(i) else -> setSelection(position) } lastClickPosition = position diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index 3350a44542..f68e15b793 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -51,11 +51,11 @@ class LibraryController( bundle: Bundle? = null, private val preferences: PreferencesHelper = Injekt.get() ) : NucleusController(bundle), - RootController, - TabbedController, - ActionMode.Callback, - ChangeMangaCategoriesDialog.Listener, - DeleteLibraryMangasDialog.Listener { + RootController, + TabbedController, + ActionMode.Callback, + ChangeMangaCategoriesDialog.Listener, + DeleteLibraryMangasDialog.Listener { /** * Position of the active category. @@ -155,10 +155,10 @@ class LibraryController( .launchIn(scope) getColumnsPreferenceForCurrentOrientation().asObservable() - .doOnNext { mangaPerRow = it } - .skip(1) - // Set again the adapter to recalculate the covers height - .subscribeUntilDestroy { reattachAdapter() } + .doOnNext { mangaPerRow = it } + .skip(1) + // Set again the adapter to recalculate the covers height + .subscribeUntilDestroy { reattachAdapter() } if (selectedMangas.isNotEmpty()) { createActionModeIfNeeded() @@ -230,10 +230,11 @@ class LibraryController( } // Get the current active category. - val activeCat = if (adapter.categories.isNotEmpty()) + val activeCat = if (adapter.categories.isNotEmpty()) { binding.libraryPager.currentItem - else + } else { activeCategory + } // Set the categories adapter.categories = categories @@ -260,10 +261,11 @@ class LibraryController( * @return the preference. */ private fun getColumnsPreferenceForCurrentOrientation(): Preference { - return if (resources?.configuration?.orientation == Configuration.ORIENTATION_PORTRAIT) + return if (resources?.configuration?.orientation == Configuration.ORIENTATION_PORTRAIT) { preferences.portraitColumns() - else + } else { preferences.landscapeColumns() + } } /** @@ -306,8 +308,8 @@ class LibraryController( if (actionMode == null) { actionMode = (activity as AppCompatActivity).startSupportActionMode(this) binding.actionToolbar.show( - actionMode!!, - R.menu.library_selection + actionMode!!, + R.menu.library_selection ) { onActionItemClicked(actionMode!!, it!!) } } } @@ -479,11 +481,11 @@ class LibraryController( // Get indexes of the common categories to preselect. val commonCategoriesIndexes = presenter.getCommonCategories(mangas) - .map { categories.indexOf(it) } - .toTypedArray() + .map { categories.indexOf(it) } + .toTypedArray() ChangeMangaCategoriesDialog(this, mangas, categories, commonCategoriesIndexes) - .showDialog(router) + .showDialog(router) } private fun showDeleteMangaDialog() { @@ -510,8 +512,13 @@ class LibraryController( if (manga.favorite) { val intent = Intent(Intent.ACTION_GET_CONTENT) intent.type = "image/*" - startActivityForResult(Intent.createChooser(intent, - resources?.getString(R.string.file_select_cover)), REQUEST_IMAGE_OPEN) + startActivityForResult( + Intent.createChooser( + intent, + resources?.getString(R.string.file_select_cover) + ), + REQUEST_IMAGE_OPEN + ) } else { activity?.toast(R.string.notification_first_add_to_library) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt index 8a2c159899..5c1bf711a0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt @@ -53,9 +53,9 @@ class LibraryGridHolder( // Update the cover. GlideApp.with(view.context).clear(thumbnail) GlideApp.with(view.context) - .load(item.manga.toMangaThumbnail()) - .diskCacheStrategy(DiskCacheStrategy.RESOURCE) - .centerCrop() - .into(thumbnail) + .load(item.manga.toMangaThumbnail()) + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .centerCrop() + .into(thumbnail) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt index 9c22457f3c..cd3a5bbd8e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt @@ -20,17 +20,18 @@ import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference) : - AbstractFlexibleItem(), IFilterable { + AbstractFlexibleItem(), IFilterable { private val sourceManager: SourceManager = Injekt.get() var downloadCount = -1 override fun getLayoutRes(): Int { - return if (libraryAsList.get()) + return if (libraryAsList.get()) { R.layout.source_list_item - else + } else { R.layout.source_grid_item + } } override fun createViewHolder(view: View, adapter: FlexibleAdapter>): LibraryHolder { @@ -40,7 +41,8 @@ class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference val coverHeight = parent.itemWidth / 3 * 4 card.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, coverHeight) gradient.layoutParams = FrameLayout.LayoutParams( - MATCH_PARENT, coverHeight / 2, Gravity.BOTTOM) + MATCH_PARENT, coverHeight / 2, Gravity.BOTTOM + ) } LibraryGridHolder(view, adapter) } else { @@ -65,25 +67,26 @@ class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference */ override fun filter(constraint: String): Boolean { return manga.title.contains(constraint, true) || - (manga.author?.contains(constraint, true) ?: false) || - (manga.artist?.contains(constraint, true) ?: false) || - sourceManager.getOrStub(manga.source).name.contains(constraint, true) || - if (constraint.contains(",")) { - constraint.split(",").all { containsGenre(it.trim(), manga.getGenres()) } - } else { - containsGenre(constraint, manga.getGenres()) - } + (manga.author?.contains(constraint, true) ?: false) || + (manga.artist?.contains(constraint, true) ?: false) || + sourceManager.getOrStub(manga.source).name.contains(constraint, true) || + if (constraint.contains(",")) { + constraint.split(",").all { containsGenre(it.trim(), manga.getGenres()) } + } else { + containsGenre(constraint, manga.getGenres()) + } } private fun containsGenre(tag: String, genres: List?): Boolean { - return if (tag.startsWith("-")) + return if (tag.startsWith("-")) { genres?.find { it.trim().toLowerCase() == tag.substringAfter("-").toLowerCase() } == null - else + } else { genres?.find { it.trim().toLowerCase() == tag.toLowerCase() } != null + } } override fun equals(other: Any?): Boolean { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt index 201c965662..9fcb3a3464 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt @@ -60,11 +60,11 @@ class LibraryListHolder( // Update the cover. GlideApp.with(itemView.context).clear(thumbnail) GlideApp.with(itemView.context) - .load(item.manga.toMangaThumbnail()) - .diskCacheStrategy(DiskCacheStrategy.RESOURCE) - .centerCrop() - .circleCrop() - .dontAnimate() - .into(thumbnail) + .load(item.manga.toMangaThumbnail()) + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .centerCrop() + .circleCrop() + .dontAnimate() + .into(thumbnail) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index e08404a996..410dbb8599 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -88,19 +88,19 @@ class LibraryPresenter( fun subscribeLibrary() { if (librarySubscription.isNullOrUnsubscribed()) { librarySubscription = getLibraryObservable() - .combineLatest(downloadTriggerRelay.observeOn(Schedulers.io())) { lib, _ -> - lib.apply { setDownloadCount(mangaMap) } - } - .combineLatest(filterTriggerRelay.observeOn(Schedulers.io())) { lib, _ -> - lib.copy(mangaMap = applyFilters(lib.mangaMap)) - } - .combineLatest(sortTriggerRelay.observeOn(Schedulers.io())) { lib, _ -> - lib.copy(mangaMap = applySort(lib.mangaMap)) - } - .observeOn(AndroidSchedulers.mainThread()) - .subscribeLatestCache({ view, (categories, mangaMap) -> - view.onNextLibraryUpdate(categories, mangaMap) - }) + .combineLatest(downloadTriggerRelay.observeOn(Schedulers.io())) { lib, _ -> + lib.apply { setDownloadCount(mangaMap) } + } + .combineLatest(filterTriggerRelay.observeOn(Schedulers.io())) { lib, _ -> + lib.copy(mangaMap = applyFilters(lib.mangaMap)) + } + .combineLatest(sortTriggerRelay.observeOn(Schedulers.io())) { lib, _ -> + lib.copy(mangaMap = applySort(lib.mangaMap)) + } + .observeOn(AndroidSchedulers.mainThread()) + .subscribeLatestCache({ view, (categories, mangaMap) -> + view.onNextLibraryUpdate(categories, mangaMap) + }) } } @@ -205,19 +205,20 @@ class LibraryPresenter( } LibrarySort.LATEST_CHAPTER -> { val manga1latestChapter = latestChapterManga[i1.manga.id!!] - ?: latestChapterManga.size + ?: latestChapterManga.size val manga2latestChapter = latestChapterManga[i2.manga.id!!] - ?: latestChapterManga.size + ?: latestChapterManga.size manga1latestChapter.compareTo(manga2latestChapter) } else -> throw Exception("Unknown sorting mode") } } - val comparator = if (preferences.librarySortingAscending().get()) + val comparator = if (preferences.librarySortingAscending().get()) { Comparator(sortFn) - else + } else { Collections.reverseOrder(sortFn) + } return map.mapValues { entry -> entry.value.sortedWith(comparator) } } @@ -229,10 +230,11 @@ class LibraryPresenter( */ private fun getLibraryObservable(): Observable { return Observable.combineLatest(getCategoriesObservable(), getLibraryMangasObservable()) { dbCategories, libraryManga -> - val categories = if (libraryManga.containsKey(0)) + val categories = if (libraryManga.containsKey(0)) { arrayListOf(Category.createDefault()) + dbCategories - else + } else { dbCategories + } this.categories = categories Library(categories, libraryManga) @@ -257,9 +259,9 @@ class LibraryPresenter( private fun getLibraryMangasObservable(): Observable { val libraryAsList = preferences.libraryAsList() return db.getLibraryMangas().asRxObservable() - .map { list -> - list.map { LibraryItem(it, libraryAsList) }.groupBy { it.manga.category } - } + .map { list -> + list.map { LibraryItem(it, libraryAsList) }.groupBy { it.manga.category } + } } /** @@ -299,8 +301,8 @@ class LibraryPresenter( fun getCommonCategories(mangas: List): Collection { if (mangas.isEmpty()) return emptyList() return mangas.toSet() - .map { db.getCategoriesForManga(it).executeAsBlocking() } - .reduce { set1: Iterable, set2 -> set1.intersect(set2).toMutableList() } + .map { db.getCategoriesForManga(it).executeAsBlocking() } + .reduce { set1: Iterable, set2 -> set1.intersect(set2).toMutableList() } } /** @@ -315,9 +317,9 @@ class LibraryPresenter( mangaToDelete.forEach { it.favorite = false } Observable.fromCallable { db.insertMangas(mangaToDelete).executeAsBlocking() } - .onErrorResumeNext { Observable.empty() } - .subscribeOn(Schedulers.io()) - .subscribe() + .onErrorResumeNext { Observable.empty() } + .subscribeOn(Schedulers.io()) + .subscribe() Observable.fromCallable { mangaToDelete.forEach { manga -> @@ -330,8 +332,8 @@ class LibraryPresenter( } } } - .subscribeOn(Schedulers.io()) - .subscribe() + .subscribeOn(Schedulers.io()) + .subscribe() } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt index a2ec5eb1e8..5616af920f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt @@ -129,8 +129,11 @@ class LibrarySettingsSheet( override fun initModels() { val sorting = preferences.librarySortingMode().get() - val order = if (preferences.librarySortingAscending().get()) - Item.MultiSort.SORT_ASC else Item.MultiSort.SORT_DESC + val order = if (preferences.librarySortingAscending().get()) { + Item.MultiSort.SORT_ASC + } else { + Item.MultiSort.SORT_DESC + } alphabetically.state = if (sorting == LibrarySort.ALPHA) order else Item.MultiSort.SORT_NONE diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index 596c6107e6..9bb9112011 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -29,7 +29,7 @@ import eu.kanade.tachiyomi.ui.more.MoreController import eu.kanade.tachiyomi.ui.recent.history.HistoryController import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController import eu.kanade.tachiyomi.ui.source.SourceController -import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchController +import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchController import eu.kanade.tachiyomi.util.lang.launchUI import eu.kanade.tachiyomi.util.system.WebViewUtil import eu.kanade.tachiyomi.util.system.toast diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/ViewHeightAnimator.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/ViewHeightAnimator.kt index 3e4a2704b6..1b12429e34 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/ViewHeightAnimator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/ViewHeightAnimator.kt @@ -30,23 +30,23 @@ class ViewHeightAnimator(val view: View) { init { view.viewTreeObserver.addOnGlobalLayoutListener( - object : ViewTreeObserver.OnGlobalLayoutListener { - override fun onGlobalLayout() { - if (view.height > 0) { - view.viewTreeObserver.removeOnGlobalLayoutListener(this) + object : ViewTreeObserver.OnGlobalLayoutListener { + override fun onGlobalLayout() { + if (view.height > 0) { + view.viewTreeObserver.removeOnGlobalLayoutListener(this) - // Save the tabs default height. - height = view.height + // Save the tabs default height. + height = view.height - // Now that we know the height, set the initial height. - if (isLastStateShown) { - setHeight(height) - } else { - setHeight(0) - } + // Now that we know the height, set the initial height. + if (isLastStateShown) { + setHeight(height) + } else { + setHeight(0) } } } + } ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt index 22371a6919..f49fe7ba13 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt @@ -35,10 +35,12 @@ import uy.kohesive.injekt.api.get class MangaController : RxController, TabbedController { - constructor(manga: Manga?, fromSource: Boolean = false) : super(Bundle().apply { - putLong(MANGA_EXTRA, manga?.id ?: 0) - putBoolean(FROM_SOURCE_EXTRA, fromSource) - }) { + constructor(manga: Manga?, fromSource: Boolean = false) : super( + Bundle().apply { + putLong(MANGA_EXTRA, manga?.id ?: 0) + putBoolean(FROM_SOURCE_EXTRA, fromSource) + } + ) { this.manga = manga if (manga != null) { source = Injekt.get().getOrStub(manga.source) @@ -46,7 +48,8 @@ class MangaController : RxController, TabbedController { } constructor(mangaId: Long) : this( - Injekt.get().getManga(mangaId).executeAsBlocking()) + Injekt.get().getManga(mangaId).executeAsBlocking() + ) @Suppress("unused") constructor(bundle: Bundle) : this(bundle.getLong(MANGA_EXTRA)) @@ -87,8 +90,9 @@ class MangaController : RxController, TabbedController { binding.mangaPager.offscreenPageLimit = 3 binding.mangaPager.adapter = adapter - if (!fromSource) + if (!fromSource) { binding.mangaPager.currentItem = CHAPTERS_CONTROLLER + } } override fun onDestroyView(view: View) { @@ -130,9 +134,11 @@ class MangaController : RxController, TabbedController { private fun setTrackingIconInternal(visible: Boolean) { val tab = activity?.tabs?.getTabAt(TRACK_CONTROLLER) ?: return - val drawable = if (visible) + val drawable = if (visible) { VectorDrawableCompat.create(resources!!, R.drawable.ic_done_white_18dp, null) - else null + } else { + null + } tab.icon = drawable } @@ -142,10 +148,11 @@ class MangaController : RxController, TabbedController { private val tabCount = if (Injekt.get().hasLoggedServices()) 3 else 2 private val tabTitles = listOf( - R.string.manga_detail_tab, - R.string.manga_chapters_tab, - R.string.manga_tracking_tab) - .map { resources!!.getString(it) } + R.string.manga_detail_tab, + R.string.manga_chapters_tab, + R.string.manga_tracking_tab + ) + .map { resources!!.getString(it) } override fun getCount(): Int { return tabCount diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterItem.kt index 38693aa297..649cab7530 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterItem.kt @@ -10,8 +10,9 @@ import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.download.model.Download -class ChapterItem(val chapter: Chapter, val manga: Manga) : AbstractFlexibleItem(), - Chapter by chapter { +class ChapterItem(val chapter: Chapter, val manga: Manga) : + AbstractFlexibleItem(), + Chapter by chapter { private var _status: Int = 0 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt index ad32a11c3e..dd0fa66d84 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt @@ -26,8 +26,11 @@ class ChaptersAdapter( val bookmarkedColor = context.getResourceColor(R.attr.colorAccent) - val decimalFormat = DecimalFormat("#.###", DecimalFormatSymbols() - .apply { decimalSeparator = '.' }) + val decimalFormat = DecimalFormat( + "#.###", + DecimalFormatSymbols() + .apply { decimalSeparator = '.' } + ) val dateFormat: DateFormat = preferences.dateFormat().getOrDefault() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt index 323f7cfd14..290e731ee4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt @@ -39,12 +39,13 @@ import reactivecircus.flowbinding.android.view.clicks import reactivecircus.flowbinding.swiperefreshlayout.refreshes import timber.log.Timber -class ChaptersController : NucleusController(), - ActionMode.Callback, - FlexibleAdapter.OnItemClickListener, - FlexibleAdapter.OnItemLongClickListener, - DownloadCustomChaptersDialog.Listener, - DeleteChaptersDialog.Listener { +class ChaptersController : + NucleusController(), + ActionMode.Callback, + FlexibleAdapter.OnItemClickListener, + FlexibleAdapter.OnItemLongClickListener, + DownloadCustomChaptersDialog.Listener, + DeleteChaptersDialog.Listener { /** * Adapter containing a list of chapters. @@ -168,11 +169,13 @@ class ChaptersController : NucleusController setSelection(position) - lastClickPosition > position -> for (i in position until lastClickPosition) - setSelection(i) - lastClickPosition < position -> for (i in lastClickPosition + 1..position) - setSelection(i) + lastClickPosition > position -> + for (i in position until lastClickPosition) + setSelection(i) + lastClickPosition < position -> + for (i in lastClickPosition + 1..position) + setSelection(i) else -> setSelection(position) } lastClickPosition = position @@ -364,8 +369,8 @@ class ChaptersController : NucleusController> - by lazy { PublishRelay.create>() } + by lazy { PublishRelay.create>() } /** * Whether the chapter list has been requested to the source. @@ -66,12 +66,13 @@ class ChaptersPresenter( // Prepare the relay. chaptersRelay.flatMap { applyChapterFilters(it) } - .observeOn(AndroidSchedulers.mainThread()) - .subscribeLatestCache(ChaptersController::onNextChapters) { _, error -> Timber.e(error) } + .observeOn(AndroidSchedulers.mainThread()) + .subscribeLatestCache(ChaptersController::onNextChapters) { _, error -> Timber.e(error) } // Add the subscription that retrieves the chapters from the database, keeps subscribed to // changes, and sends the list of chapters to the relay. - add(db.getChapters(manga).asRxObservable() + add( + db.getChapters(manga).asRxObservable() .map { chapters -> // Convert every chapter to a model. chapters.map { it.toModel() } @@ -86,18 +87,19 @@ class ChaptersPresenter( // Listen for download status changes observeDownloads() } - .subscribe { chaptersRelay.call(it) }) + .subscribe { chaptersRelay.call(it) } + ) } private fun observeDownloads() { observeDownloadsSubscription?.let { remove(it) } observeDownloadsSubscription = downloadManager.queue.getStatusObservable() - .observeOn(AndroidSchedulers.mainThread()) - .filter { download -> download.manga.id == manga.id } - .doOnNext { onDownloadStatusChange(it) } - .subscribeLatestCache(ChaptersController::onChapterStatusChange) { _, error -> - Timber.e(error) - } + .observeOn(AndroidSchedulers.mainThread()) + .filter { download -> download.manga.id == manga.id } + .doOnNext { onDownloadStatusChange(it) } + .subscribeLatestCache(ChaptersController::onChapterStatusChange) { _, error -> + Timber.e(error) + } } /** @@ -138,12 +140,15 @@ class ChaptersPresenter( if (!fetchChaptersSubscription.isNullOrUnsubscribed()) return fetchChaptersSubscription = Observable.defer { source.fetchChapterList(manga) } - .subscribeOn(Schedulers.io()) - .map { syncChaptersWithSource(db, it, manga, source) } - .observeOn(AndroidSchedulers.mainThread()) - .subscribeFirst({ view, _ -> + .subscribeOn(Schedulers.io()) + .map { syncChaptersWithSource(db, it, manga, source) } + .observeOn(AndroidSchedulers.mainThread()) + .subscribeFirst( + { view, _ -> view.onFetchChaptersDone() - }, ChaptersController::onFetchChaptersError) + }, + ChaptersController::onFetchChaptersError + ) } /** @@ -200,8 +205,9 @@ class ChaptersPresenter( } // Force UI update if downloaded filter active and download finished. - if (onlyDownloaded() && download.status == Download.DOWNLOADED) + if (onlyDownloaded() && download.status == Download.DOWNLOADED) { refreshChapters() + } } /** @@ -218,16 +224,16 @@ class ChaptersPresenter( */ fun markChaptersRead(selectedChapters: List, read: Boolean) { Observable.from(selectedChapters) - .doOnNext { chapter -> - chapter.read = read - if (!read) { - chapter.last_page_read = 0 - } + .doOnNext { chapter -> + chapter.read = read + if (!read) { + chapter.last_page_read = 0 } - .toList() - .flatMap { db.updateChaptersProgress(it).asRxObservable() } - .subscribeOn(Schedulers.io()) - .subscribe() + } + .toList() + .flatMap { db.updateChaptersProgress(it).asRxObservable() } + .subscribeOn(Schedulers.io()) + .subscribe() } /** @@ -244,13 +250,13 @@ class ChaptersPresenter( */ fun bookmarkChapters(selectedChapters: List, bookmarked: Boolean) { Observable.from(selectedChapters) - .doOnNext { chapter -> - chapter.bookmark = bookmarked - } - .toList() - .flatMap { db.updateChaptersProgress(it).asRxObservable() } - .subscribeOn(Schedulers.io()) - .subscribe() + .doOnNext { chapter -> + chapter.bookmark = bookmarked + } + .toList() + .flatMap { db.updateChaptersProgress(it).asRxObservable() } + .subscribeOn(Schedulers.io()) + .subscribe() } /** @@ -259,13 +265,16 @@ class ChaptersPresenter( */ fun deleteChapters(chapters: List) { Observable.just(chapters) - .doOnNext { deleteChaptersInternal(chapters) } - .doOnNext { if (onlyDownloaded()) refreshChapters() } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeFirst({ view, _ -> + .doOnNext { deleteChaptersInternal(chapters) } + .doOnNext { if (onlyDownloaded()) refreshChapters() } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeFirst( + { view, _ -> view.onChaptersDeleted(chapters) - }, ChaptersController::onChaptersDeletedError) + }, + ChaptersController::onChaptersDeletedError + ) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/DeleteChaptersDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/DeleteChaptersDialog.kt index c2ef933c40..5c0f95271f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/DeleteChaptersDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/DeleteChaptersDialog.kt @@ -16,11 +16,11 @@ class DeleteChaptersDialog(bundle: Bundle? = null) : DialogController(bundle) override fun onCreateDialog(savedViewState: Bundle?): Dialog { return MaterialDialog(activity!!) - .message(R.string.confirm_delete_chapters) - .positiveButton(android.R.string.ok) { - (targetController as? Listener)?.deleteChapters() - } - .negativeButton(android.R.string.cancel) + .message(R.string.confirm_delete_chapters) + .positiveButton(android.R.string.ok) { + (targetController as? Listener)?.deleteChapters() + } + .negativeButton(android.R.string.cancel) } interface Listener { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/DownloadCustomChaptersDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/DownloadCustomChaptersDialog.kt index 74cc94a9fb..37b00d3a31 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/DownloadCustomChaptersDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/DownloadCustomChaptersDialog.kt @@ -24,10 +24,12 @@ class DownloadCustomChaptersDialog : DialogController * Initialize dialog. * @param maxChapters maximal number of chapters that user can download. */ - constructor(target: T, maxChapters: Int) : super(Bundle().apply { - // Add maximum number of chapters to download value to bundle. - putInt(KEY_ITEM_MAX, maxChapters) - }) { + constructor(target: T, maxChapters: Int) : super( + Bundle().apply { + // Add maximum number of chapters to download value to bundle. + putInt(KEY_ITEM_MAX, maxChapters) + } + ) { targetController = target this.maxChapters = maxChapters } @@ -57,12 +59,12 @@ class DownloadCustomChaptersDialog : DialogController // Build dialog. // when positive dialog is pressed call custom listener. return MaterialDialog(activity) - .title(R.string.custom_download) - .customView(view = view, scrollable = true) - .positiveButton(android.R.string.ok) { - (targetController as? Listener)?.downloadCustomChapters(view.amount) - } - .negativeButton(android.R.string.cancel) + .title(R.string.custom_download) + .customView(view = view, scrollable = true) + .positiveButton(android.R.string.ok) { + (targetController as? Listener)?.downloadCustomChapters(view.amount) + } + .negativeButton(android.R.string.cancel) } interface Listener { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt index f50c5218e3..9565dbd841 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt @@ -31,7 +31,7 @@ import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.recent.history.HistoryController import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController import eu.kanade.tachiyomi.ui.source.browse.BrowseSourceController -import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchController +import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchController import eu.kanade.tachiyomi.ui.webview.WebViewActivity import eu.kanade.tachiyomi.util.lang.truncateCenter import eu.kanade.tachiyomi.util.system.toast @@ -217,12 +217,14 @@ class MangaInfoController(private val fromSource: Boolean = false) : } // Update status TextView. - binding.mangaStatus.setText(when (manga.status) { - SManga.ONGOING -> R.string.ongoing - SManga.COMPLETED -> R.string.completed - SManga.LICENSED -> R.string.licensed - else -> R.string.unknown - }) + binding.mangaStatus.setText( + when (manga.status) { + SManga.ONGOING -> R.string.ongoing + SManga.COMPLETED -> R.string.completed + SManga.LICENSED -> R.string.licensed + else -> R.string.unknown + } + ) // Set the favorite drawable to the correct one. setFavoriteButtonState(manga.favorite) @@ -233,16 +235,16 @@ class MangaInfoController(private val fromSource: Boolean = false) : val mangaThumbnail = manga.toMangaThumbnail() GlideApp.with(view.context) - .load(mangaThumbnail) - .diskCacheStrategy(DiskCacheStrategy.RESOURCE) - .centerCrop() - .into(binding.mangaCover) + .load(mangaThumbnail) + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .centerCrop() + .into(binding.mangaCover) GlideApp.with(view.context) - .load(mangaThumbnail) - .diskCacheStrategy(DiskCacheStrategy.RESOURCE) - .centerCrop() - .into(binding.backdrop) + .load(mangaThumbnail) + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .centerCrop() + .into(binding.backdrop) } // Manga info section @@ -291,23 +293,26 @@ class MangaInfoController(private val fromSource: Boolean = false) : val isExpanded = binding.mangaInfoToggle.text == context.getString(R.string.manga_info_collapse) binding.mangaInfoToggle.text = - if (isExpanded) + if (isExpanded) { context.getString(R.string.manga_info_expand) - else + } else { context.getString(R.string.manga_info_collapse) + } with(binding.mangaSummary) { maxLines = - if (isExpanded) + if (isExpanded) { 3 - else + } else { Int.MAX_VALUE + } ellipsize = - if (isExpanded) + if (isExpanded) { TextUtils.TruncateAt.END - else + } else { null + } } binding.mangaGenresTagsCompact.visibleIf { isExpanded } @@ -447,7 +452,7 @@ class MangaInfoController(private val fromSource: Boolean = false) : }.toTypedArray() ChangeMangaCategoriesDialog(this, listOf(manga), categories, preselected) - .showDialog(router) + .showDialog(router) } } } @@ -463,7 +468,7 @@ class MangaInfoController(private val fromSource: Boolean = false) : }.toTypedArray() ChangeMangaCategoriesDialog(this, listOf(manga), categories, preselected) - .showDialog(router) + .showDialog(router) } override fun updateCategoriesForMangas(mangas: List, categories: List) { @@ -492,8 +497,10 @@ class MangaInfoController(private val fromSource: Boolean = false) : val clipboard = activity.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager clipboard.setPrimaryClip(ClipData.newPlainText(label, content)) - activity.toast(view.context.getString(R.string.copied_to_clipboard, content.truncateCenter(20)), - Toast.LENGTH_SHORT) + activity.toast( + view.context.getString(R.string.copied_to_clipboard, content.truncateCenter(20)), + Toast.LENGTH_SHORT + ) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt index cb048f7d7d..9113b6ea1f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt @@ -48,8 +48,8 @@ class MangaInfoPresenter( // Update favorite status mangaFavoriteRelay.observeOn(AndroidSchedulers.mainThread()) - .subscribe { setFavorite(it) } - .apply { add(this) } + .subscribe { setFavorite(it) } + .apply { add(this) } } /** @@ -58,7 +58,7 @@ class MangaInfoPresenter( fun sendMangaToView() { viewMangaSubscription?.let { remove(it) } viewMangaSubscription = Observable.just(manga) - .subscribeLatestCache({ view, manga -> view.onNextManga(manga, source) }) + .subscribeLatestCache({ view, manga -> view.onNextManga(manga, source) }) } /** @@ -67,18 +67,21 @@ class MangaInfoPresenter( fun fetchMangaFromSource() { if (!fetchMangaSubscription.isNullOrUnsubscribed()) return fetchMangaSubscription = Observable.defer { source.fetchMangaDetails(manga) } - .map { networkManga -> - manga.copyFrom(networkManga) - manga.initialized = true - db.insertManga(manga).executeAsBlocking() - manga - } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnNext { sendMangaToView() } - .subscribeFirst({ view, _ -> + .map { networkManga -> + manga.copyFrom(networkManga) + manga.initialized = true + db.insertManga(manga).executeAsBlocking() + manga + } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext { sendMangaToView() } + .subscribeFirst( + { view, _ -> view.onFetchMangaDone() - }, MangaInfoController::onFetchMangaError) + }, + MangaInfoController::onFetchMangaError + ) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/SetTrackChaptersDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/SetTrackChaptersDialog.kt index 41b758d465..311bab8625 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/SetTrackChaptersDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/SetTrackChaptersDialog.kt @@ -19,9 +19,11 @@ class SetTrackChaptersDialog : DialogController private val item: TrackItem - constructor(target: T, item: TrackItem) : super(Bundle().apply { - putSerializable(KEY_ITEM_TRACK, item.track) - }) { + constructor(target: T, item: TrackItem) : super( + Bundle().apply { + putSerializable(KEY_ITEM_TRACK, item.track) + } + ) { targetController = target this.item = item } @@ -37,17 +39,17 @@ class SetTrackChaptersDialog : DialogController val item = item val dialog = MaterialDialog(activity!!) - .title(R.string.chapters) - .customView(R.layout.track_chapters_dialog, dialogWrapContent = false) - .positiveButton(android.R.string.ok) { dialog -> - val view = dialog.getCustomView() - // Remove focus to update selected number - val np: NumberPicker = view.findViewById(R.id.chapters_picker) - np.clearFocus() + .title(R.string.chapters) + .customView(R.layout.track_chapters_dialog, dialogWrapContent = false) + .positiveButton(android.R.string.ok) { dialog -> + val view = dialog.getCustomView() + // Remove focus to update selected number + val np: NumberPicker = view.findViewById(R.id.chapters_picker) + np.clearFocus() - (targetController as? Listener)?.setChaptersRead(item, np.value) - } - .negativeButton(android.R.string.cancel) + (targetController as? Listener)?.setChaptersRead(item, np.value) + } + .negativeButton(android.R.string.cancel) val view = dialog.getCustomView() val np: NumberPicker = view.findViewById(R.id.chapters_picker) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/SetTrackReadingDatesDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/SetTrackReadingDatesDialog.kt index 4f458b009d..00aed713b2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/SetTrackReadingDatesDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/SetTrackReadingDatesDialog.kt @@ -20,9 +20,11 @@ class SetTrackReadingDatesDialog : DialogController private val dateToUpdate: ReadingDate - constructor(target: T, dateToUpdate: ReadingDate, item: TrackItem) : super(Bundle().apply { - putSerializable(SetTrackReadingDatesDialog.KEY_ITEM_TRACK, item.track) - }) { + constructor(target: T, dateToUpdate: ReadingDate, item: TrackItem) : super( + Bundle().apply { + putSerializable(SetTrackReadingDatesDialog.KEY_ITEM_TRACK, item.track) + } + ) { targetController = target this.item = item this.dateToUpdate = dateToUpdate @@ -40,16 +42,18 @@ class SetTrackReadingDatesDialog : DialogController val listener = (targetController as? Listener) return MaterialDialog(activity!!) - .title(when (dateToUpdate) { + .title( + when (dateToUpdate) { ReadingDate.Start -> R.string.track_started_reading_date ReadingDate.Finish -> R.string.track_finished_reading_date - }) - .datePicker(currentDate = getCurrentDate()) { _, date -> - listener?.setReadingDate(item, dateToUpdate, date.timeInMillis) - } - .neutralButton(R.string.action_remove) { - listener?.setReadingDate(item, dateToUpdate, 0L) } + ) + .datePicker(currentDate = getCurrentDate()) { _, date -> + listener?.setReadingDate(item, dateToUpdate, date.timeInMillis) + } + .neutralButton(R.string.action_remove) { + listener?.setReadingDate(item, dateToUpdate, 0L) + } } private fun getCurrentDate(): Calendar { @@ -60,8 +64,9 @@ class SetTrackReadingDatesDialog : DialogController ReadingDate.Start -> it.started_reading_date ReadingDate.Finish -> it.finished_reading_date } - if (date != 0L) + if (date != 0L) { timeInMillis = date + } } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/SetTrackScoreDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/SetTrackScoreDialog.kt index 50fcfe500d..266b49f9fe 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/SetTrackScoreDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/SetTrackScoreDialog.kt @@ -19,9 +19,11 @@ class SetTrackScoreDialog : DialogController private val item: TrackItem - constructor(target: T, item: TrackItem) : super(Bundle().apply { - putSerializable(KEY_ITEM_TRACK, item.track) - }) { + constructor(target: T, item: TrackItem) : super( + Bundle().apply { + putSerializable(KEY_ITEM_TRACK, item.track) + } + ) { targetController = target this.item = item } @@ -37,17 +39,17 @@ class SetTrackScoreDialog : DialogController val item = item val dialog = MaterialDialog(activity!!) - .title(R.string.score) - .customView(R.layout.track_score_dialog, dialogWrapContent = false) - .positiveButton(android.R.string.ok) { dialog -> - val view = dialog.getCustomView() - // Remove focus to update selected number - val np: NumberPicker = view.findViewById(R.id.score_picker) - np.clearFocus() + .title(R.string.score) + .customView(R.layout.track_score_dialog, dialogWrapContent = false) + .positiveButton(android.R.string.ok) { dialog -> + val view = dialog.getCustomView() + // Remove focus to update selected number + val np: NumberPicker = view.findViewById(R.id.score_picker) + np.clearFocus() - (targetController as? Listener)?.setScore(item, np.value) - } - .negativeButton(android.R.string.cancel) + (targetController as? Listener)?.setScore(item, np.value) + } + .negativeButton(android.R.string.cancel) val view = dialog.getCustomView() val np: NumberPicker = view.findViewById(R.id.score_picker) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/SetTrackStatusDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/SetTrackStatusDialog.kt index 4738e6c6ec..a7116362e7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/SetTrackStatusDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/SetTrackStatusDialog.kt @@ -17,9 +17,11 @@ class SetTrackStatusDialog : DialogController private val item: TrackItem - constructor(target: T, item: TrackItem) : super(Bundle().apply { - putSerializable(KEY_ITEM_TRACK, item.track) - }) { + constructor(target: T, item: TrackItem) : super( + Bundle().apply { + putSerializable(KEY_ITEM_TRACK, item.track) + } + ) { targetController = target this.item = item } @@ -38,16 +40,16 @@ class SetTrackStatusDialog : DialogController val selectedIndex = statusList.indexOf(item.track?.status) return MaterialDialog(activity!!) - .title(R.string.status) - .negativeButton(android.R.string.cancel) - .listItemsSingleChoice( - items = statusString, - initialSelection = selectedIndex, - waitForPositiveButton = false - ) { dialog, position, _ -> - (targetController as? Listener)?.setStatus(item, position) - dialog.dismiss() - } + .title(R.string.status) + .negativeButton(android.R.string.cancel) + .listItemsSingleChoice( + items = statusString, + initialSelection = selectedIndex, + waitForPositiveButton = false + ) { dialog, position, _ -> + (targetController as? Listener)?.setStatus(item, position) + dialog.dismiss() + } } interface Listener { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackController.kt index 287f77335b..d7e0824c66 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackController.kt @@ -17,12 +17,13 @@ import kotlinx.coroutines.flow.onEach import reactivecircus.flowbinding.swiperefreshlayout.refreshes import timber.log.Timber -class TrackController : NucleusController(), - TrackAdapter.OnClickListener, - SetTrackStatusDialog.Listener, - SetTrackChaptersDialog.Listener, - SetTrackScoreDialog.Listener, - SetTrackReadingDatesDialog.Listener { +class TrackController : + NucleusController(), + TrackAdapter.OnClickListener, + SetTrackStatusDialog.Listener, + SetTrackChaptersDialog.Listener, + SetTrackScoreDialog.Listener, + SetTrackReadingDatesDialog.Listener { private var adapter: TrackAdapter? = null diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackHolder.kt index 71dc0b8ceb..7f76b7af5a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackHolder.kt @@ -56,15 +56,15 @@ class TrackHolder(view: View, adapter: TrackAdapter) : BaseViewHolder(view) { if (track != null) { track_title.text = track.title track_chapters.text = "${track.last_chapter_read}/" + - if (track.total_chapters > 0) track.total_chapters else "-" + if (track.total_chapters > 0) track.total_chapters else "-" track_status.text = item.service.getStatus(track.status) track_score.text = if (track.score == 0f) "-" else item.service.displayScore(track) if (item.service.supportsReadingDates) { track_start_date.text = - if (track.started_reading_date != 0L) dateFormat.format(track.started_reading_date) else "-" + if (track.started_reading_date != 0L) dateFormat.format(track.started_reading_date) else "-" track_finish_date.text = - if (track.finished_reading_date != 0L) dateFormat.format(track.finished_reading_date) else "-" + if (track.finished_reading_date != 0L) dateFormat.format(track.finished_reading_date) else "-" } else { bottom_divider.gone() vert_divider_3.gone() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackPresenter.kt index 3d5f94c780..31794cb9e1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackPresenter.kt @@ -43,52 +43,60 @@ class TrackPresenter( fun fetchTrackings() { trackSubscription?.let { remove(it) } trackSubscription = db.getTracks(manga) - .asRxObservable() - .map { tracks -> - loggedServices.map { service -> - TrackItem(tracks.find { it.sync_id == service.id }, service) - } + .asRxObservable() + .map { tracks -> + loggedServices.map { service -> + TrackItem(tracks.find { it.sync_id == service.id }, service) } - .observeOn(AndroidSchedulers.mainThread()) - .doOnNext { trackList = it } - .subscribeLatestCache(TrackController::onNextTrackings) + } + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext { trackList = it } + .subscribeLatestCache(TrackController::onNextTrackings) } fun refresh() { refreshSubscription?.let { remove(it) } refreshSubscription = Observable.from(trackList) - .filter { it.track != null } - .concatMap { item -> - item.service.refresh(item.track!!) - .flatMap { db.insertTrack(it).asRxObservable() } - .map { item } - .onErrorReturn { item } - } - .toList() - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeFirst({ view, _ -> view.onRefreshDone() }, - TrackController::onRefreshError) + .filter { it.track != null } + .concatMap { item -> + item.service.refresh(item.track!!) + .flatMap { db.insertTrack(it).asRxObservable() } + .map { item } + .onErrorReturn { item } + } + .toList() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeFirst( + { view, _ -> view.onRefreshDone() }, + TrackController::onRefreshError + ) } fun search(query: String, service: TrackService) { searchSubscription?.let { remove(it) } searchSubscription = service.search(query) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeLatestCache(TrackController::onSearchResults, - TrackController::onSearchResultsError) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeLatestCache( + TrackController::onSearchResults, + TrackController::onSearchResultsError + ) } fun registerTracking(item: Track?, service: TrackService) { if (item != null) { item.manga_id = manga.id!! - add(service.bind(item) + add( + service.bind(item) .flatMap { db.insertTrack(item).asRxObservable() } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ }, - { error -> context.toast(error.message) })) + .subscribe( + { }, + { error -> context.toast(error.message) } + ) + ) } else { unregisterTracking(service) } @@ -100,16 +108,18 @@ class TrackPresenter( private fun updateRemote(track: Track, service: TrackService) { service.update(track) - .flatMap { db.insertTrack(track).asRxObservable() } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeFirst({ view, _ -> view.onRefreshDone() }, - { view, error -> - view.onRefreshError(error) + .flatMap { db.insertTrack(track).asRxObservable() } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeFirst( + { view, _ -> view.onRefreshDone() }, + { view, error -> + view.onRefreshError(error) - // Restart on error to set old values - fetchTrackings() - }) + // Restart on error to set old values + fetchTrackings() + } + ) } fun setStatus(item: TrackItem, index: Int) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchAdapter.kt index 9d523efeee..99c381a9bb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchAdapter.kt @@ -56,10 +56,10 @@ class TrackSearchAdapter(context: Context) : GlideApp.with(view.context).clear(view.track_search_cover) if (!track.cover_url.isEmpty()) { GlideApp.with(view.context) - .load(track.cover_url) - .diskCacheStrategy(DiskCacheStrategy.RESOURCE) - .centerCrop() - .into(view.track_search_cover) + .load(track.cover_url) + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .centerCrop() + .into(view.track_search_cover) } if (track.publishing_status.isBlank()) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchDialog.kt index 53ee623aa3..6a9f8ad8e7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchDialog.kt @@ -40,9 +40,11 @@ class TrackSearchDialog : DialogController { private val trackController get() = targetController as TrackController - constructor(target: TrackController, service: TrackService) : super(Bundle().apply { - putInt(KEY_SERVICE, service.id) - }) { + constructor(target: TrackController, service: TrackService) : super( + Bundle().apply { + putInt(KEY_SERVICE, service.id) + } + ) { targetController = target this.service = service } @@ -54,10 +56,10 @@ class TrackSearchDialog : DialogController { override fun onCreateDialog(savedViewState: Bundle?): Dialog { val dialog = MaterialDialog(activity!!) - .customView(R.layout.track_search_dialog) - .positiveButton(android.R.string.ok) { onPositiveButtonClick() } - .negativeButton(android.R.string.cancel) - .neutralButton(R.string.action_remove) { onRemoveButtonClick() } + .customView(R.layout.track_search_dialog) + .positiveButton(android.R.string.ok) { onPositiveButtonClick() } + .negativeButton(android.R.string.cancel) + .neutralButton(R.string.action_remove) { onRemoveButtonClick() } dialogView = dialog.view onViewCreated(dialog.view, savedViewState) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MangaAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MangaAdapter.kt index a2860c2e58..5cf41f0cd6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MangaAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MangaAdapter.kt @@ -4,7 +4,7 @@ import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.items.IFlexible class MangaAdapter(controller: MigrationController) : - FlexibleAdapter>(null, controller) { + FlexibleAdapter>(null, controller) { private var items: List>? = null diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MangaHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MangaHolder.kt index 69c608a12f..b42d42561a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MangaHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MangaHolder.kt @@ -27,11 +27,11 @@ class MangaHolder( // Update the cover. GlideApp.with(itemView.context).clear(thumbnail) GlideApp.with(itemView.context) - .load(item.manga.toMangaThumbnail()) - .diskCacheStrategy(DiskCacheStrategy.RESOURCE) - .centerCrop() - .circleCrop() - .dontAnimate() - .into(thumbnail) + .load(item.manga.toMangaThumbnail()) + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .centerCrop() + .circleCrop() + .dontAnimate() + .into(thumbnail) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MangaItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MangaItem.kt index 9f9146017b..04c951beaf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MangaItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MangaItem.kt @@ -24,7 +24,6 @@ class MangaItem(val manga: Manga) : AbstractFlexibleItem() { position: Int, payloads: List? ) { - holder.bind(this) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationController.kt index 635d1335e6..bfd3530433 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationController.kt @@ -11,9 +11,10 @@ import eu.kanade.tachiyomi.databinding.MigrationControllerBinding import eu.kanade.tachiyomi.ui.base.controller.NucleusController import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction -class MigrationController : NucleusController(), - FlexibleAdapter.OnItemClickListener, - SourceAdapter.OnSelectClickListener { +class MigrationController : + NucleusController(), + FlexibleAdapter.OnItemClickListener, + SourceAdapter.OnSelectClickListener { private var adapter: FlexibleAdapter>? = null diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationPresenter.kt index db037ef838..77e5b9392a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MigrationPresenter.kt @@ -31,18 +31,19 @@ class MigrationPresenter( super.onCreate(savedState) db.getFavoriteMangas() - .asRxObservable() - .observeOn(AndroidSchedulers.mainThread()) - .doOnNext { state = state.copy(sourcesWithManga = findSourcesWithManga(it)) } - .combineLatest(stateRelay.map { it.selectedSource } - .distinctUntilChanged() - ) { library, source -> library to source } - .filter { (_, source) -> source != null } - .observeOn(Schedulers.io()) - .map { (library, source) -> libraryToMigrationItem(library, source!!.id) } - .observeOn(AndroidSchedulers.mainThread()) - .doOnNext { state = state.copy(mangaForSource = it) } - .subscribe() + .asRxObservable() + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext { state = state.copy(sourcesWithManga = findSourcesWithManga(it)) } + .combineLatest( + stateRelay.map { it.selectedSource } + .distinctUntilChanged() + ) { library, source -> library to source } + .filter { (_, source) -> source != null } + .observeOn(Schedulers.io()) + .map { (library, source) -> libraryToMigrationItem(library, source!!.id) } + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext { state = state.copy(mangaForSource = it) } + .subscribe() // Render the view when any field changes stateRelay.subscribeLatestCache(MigrationController::render) @@ -59,8 +60,8 @@ class MigrationPresenter( private fun findSourcesWithManga(library: List): List { val header = SelectionHeader() return library.map { it.source }.toSet() - .mapNotNull { if (it != LocalSource.ID) sourceManager.getOrStub(it) else null } - .map { SourceItem(it, header) } + .mapNotNull { if (it != LocalSource.ID) sourceManager.getOrStub(it) else null } + .map { SourceItem(it, header) } } private fun libraryToMigrationItem(library: List, sourceId: Long): List { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SearchController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SearchController.kt index 5a18f74280..6a9fdda735 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SearchController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SearchController.kt @@ -8,8 +8,8 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.ui.base.controller.DialogController -import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchController -import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchPresenter +import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchController +import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchPresenter import eu.kanade.tachiyomi.util.view.gone import eu.kanade.tachiyomi.util.view.visible import uy.kohesive.injekt.injectLazy @@ -81,22 +81,22 @@ class SearchController( val preselected = MigrationFlags.getEnabledFlagsPositions(prefValue) return MaterialDialog(activity!!) - .message(R.string.migration_dialog_what_to_include) - .listItemsMultiChoice( - items = MigrationFlags.titles.map { resources?.getString(it) as CharSequence }, - initialSelection = preselected.toIntArray() - ) { _, positions, _ -> - // Save current settings for the next time - val newValue = MigrationFlags.getFlagsFromPositions(positions.toTypedArray()) - preferences.migrateFlags().set(newValue) - } - .positiveButton(R.string.migrate) { - (targetController as? SearchController)?.migrateManga() - } - .negativeButton(R.string.copy) { - (targetController as? SearchController)?.copyManga() - } - .neutralButton(android.R.string.cancel) + .message(R.string.migration_dialog_what_to_include) + .listItemsMultiChoice( + items = MigrationFlags.titles.map { resources?.getString(it) as CharSequence }, + initialSelection = preselected.toIntArray() + ) { _, positions, _ -> + // Save current settings for the next time + val newValue = MigrationFlags.getFlagsFromPositions(positions.toTypedArray()) + preferences.migrateFlags().set(newValue) + } + .positiveButton(R.string.migrate) { + (targetController as? SearchController)?.migrateManga() + } + .negativeButton(R.string.copy) { + (targetController as? SearchController)?.copyManga() + } + .neutralButton(android.R.string.cancel) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SearchPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SearchPresenter.kt index b4b32ee531..4563a25596 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SearchPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SearchPresenter.kt @@ -8,9 +8,9 @@ import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga -import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchCardItem -import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchItem -import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchPresenter +import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchCardItem +import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchItem +import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchPresenter import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import rx.Observable import rx.android.schedulers.AndroidSchedulers @@ -32,7 +32,7 @@ class SearchPresenter( override fun getEnabledSources(): List { // Put the source of the selected manga at the top return super.getEnabledSources() - .sortedByDescending { it.id == manga.source } + .sortedByDescending { it.id == manga.source } } override fun createCatalogueSearchItem(source: CatalogueSource, results: List?): GlobalSearchItem { @@ -53,13 +53,13 @@ class SearchPresenter( replacingMangaRelay.call(true) Observable.defer { source.fetchChapterList(manga) } - .onErrorReturn { emptyList() } - .doOnNext { migrateMangaInternal(source, it, prevManga, manga, replace) } - .onErrorReturn { emptyList() } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnUnsubscribe { replacingMangaRelay.call(false) } - .subscribe() + .onErrorReturn { emptyList() } + .doOnNext { migrateMangaInternal(source, it, prevManga, manga, replace) } + .onErrorReturn { emptyList() } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnUnsubscribe { replacingMangaRelay.call(false) } + .subscribe() } private fun migrateMangaInternal( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SourceAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SourceAdapter.kt index 22af8dd0f5..64a3ba412a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SourceAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SourceAdapter.kt @@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.util.system.getResourceColor * @param controller instance of [MigrationController]. */ class SourceAdapter(val controller: MigrationController) : - FlexibleAdapter>(null, controller, true) { + FlexibleAdapter>(null, controller, true) { val cardBackground = controller.activity!!.getResourceColor(R.attr.colorSurface) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SourceHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SourceHolder.kt index 1a053e9541..129841194c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SourceHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SourceHolder.kt @@ -15,8 +15,8 @@ import kotlinx.android.synthetic.main.source_main_controller_card_item.source_la import kotlinx.android.synthetic.main.source_main_controller_card_item.title class SourceHolder(view: View, override val adapter: SourceAdapter) : - BaseFlexibleViewHolder(view, adapter), - SlicedHolder { + BaseFlexibleViewHolder(view, adapter), + SlicedHolder { override val slice = Slice(card).apply { setColor(adapter.cardBackground) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SourceItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SourceItem.kt index a1088d11f0..0e24f06337 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SourceItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SourceItem.kt @@ -15,7 +15,7 @@ import eu.kanade.tachiyomi.source.Source * @param header The header for this item. */ data class SourceItem(val source: Source, val header: SelectionHeader? = null) : - AbstractSectionableItem(header) { + AbstractSectionableItem(header) { /** * Returns the layout resource of this item. @@ -40,7 +40,6 @@ data class SourceItem(val source: Source, val header: SelectionHeader? = null) : position: Int, payloads: List? ) { - holder.bind(this) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/more/AboutController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/more/AboutController.kt index 90987e7937..4a5faa941e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/more/AboutController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/more/AboutController.kt @@ -50,10 +50,11 @@ class AboutController : SettingsController() { preference { titleRes = R.string.version - summary = if (BuildConfig.DEBUG) + summary = if (BuildConfig.DEBUG) { "Preview r${BuildConfig.COMMIT_COUNT} (${BuildConfig.COMMIT_SHA})" - else + } else { "Stable ${BuildConfig.VERSION_NAME}" + } } preference { titleRes = R.string.build_time @@ -157,24 +158,26 @@ class AboutController : SettingsController() { class NewUpdateDialogController(bundle: Bundle? = null) : DialogController(bundle) { - constructor(body: String, url: String) : this(Bundle().apply { - putString(BODY_KEY, body) - putString(URL_KEY, url) - }) + constructor(body: String, url: String) : this( + Bundle().apply { + putString(BODY_KEY, body) + putString(URL_KEY, url) + } + ) override fun onCreateDialog(savedViewState: Bundle?): Dialog { return MaterialDialog(activity!!) - .title(res = R.string.update_check_notification_update_available) - .message(text = args.getString(BODY_KEY) ?: "") - .positiveButton(R.string.update_check_confirm) { - val appContext = applicationContext - if (appContext != null) { - // Start download - val url = args.getString(URL_KEY) ?: "" - UpdaterService.downloadUpdate(appContext, url) - } + .title(res = R.string.update_check_notification_update_available) + .message(text = args.getString(BODY_KEY) ?: "") + .positiveButton(R.string.update_check_confirm) { + val appContext = applicationContext + if (appContext != null) { + // Start download + val url = args.getString(URL_KEY) ?: "" + UpdaterService.downloadUpdate(appContext, url) } - .negativeButton(R.string.update_check_ignore) + } + .negativeButton(R.string.update_check_ignore) } private companion object { @@ -190,7 +193,8 @@ class AboutController : SettingsController() { val buildTime = inputDf.parse(BuildConfig.BUILD_TIME) val outputDf = DateFormat.getDateTimeInstance( - DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault()) + DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault() + ) outputDf.timeZone = TimeZone.getDefault() buildTime.toDateTimestampString(dateFormat) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ChapterLoadStrategy.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ChapterLoadStrategy.kt index e25abc0140..b07c803f23 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ChapterLoadStrategy.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ChapterLoadStrategy.kt @@ -26,7 +26,8 @@ class ChapterLoadByNumber { // If there is only one chapter for this number, use it chaptersForNumber.size == 1 -> chaptersForNumber.first() // Prefer a chapter of the same scanlator as the selected - else -> chaptersForNumber.find { it.scanlator == selectedChapter.scanlator } + else -> + chaptersForNumber.find { it.scanlator == selectedChapter.scanlator } ?: chaptersForNumber.first() } chapters.add(preferredChapter) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/PageIndicatorTextView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/PageIndicatorTextView.kt index 06c4b76111..d3f4db747c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/PageIndicatorTextView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/PageIndicatorTextView.kt @@ -47,8 +47,8 @@ class PageIndicatorTextView( // A span object with text outlining properties val spanOutline = OutlineSpan( - strokeColor = strokeColor, - strokeWidth = 4f + strokeColor = strokeColor, + strokeWidth = 4f ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 0b89b122e1..ebfd55d593 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -127,10 +127,12 @@ class ReaderActivity : BaseRxActivity() * Called when the activity is created. Initializes the presenter and configuration. */ override fun onCreate(savedInstanceState: Bundle?) { - setTheme(when (preferences.readerTheme().get()) { - 0 -> R.style.Theme_Reader_Light - else -> R.style.Theme_Reader - }) + setTheme( + when (preferences.readerTheme().get()) { + 0 -> R.style.Theme_Reader_Light + else -> R.style.Theme_Reader + } + ) super.onCreate(savedInstanceState) binding = ReaderActivityBinding.inflate(layoutInflater) @@ -275,10 +277,11 @@ class ReaderActivity : BaseRxActivity() ViewCompat.setOnApplyWindowInsetsListener(binding.readerMenu) { _, insets -> if (!window.isDefaultBar()) { binding.readerMenu.setPadding( - insets.systemWindowInsetLeft, - insets.systemWindowInsetTop, - insets.systemWindowInsetRight, - insets.systemWindowInsetBottom) + insets.systemWindowInsetLeft, + insets.systemWindowInsetTop, + insets.systemWindowInsetRight, + insets.systemWindowInsetBottom + ) } insets } @@ -293,18 +296,20 @@ class ReaderActivity : BaseRxActivity() }) binding.leftChapter.setOnClickListener { if (viewer != null) { - if (viewer is R2LPagerViewer) + if (viewer is R2LPagerViewer) { loadNextChapter() - else + } else { loadPreviousChapter() + } } } binding.rightChapter.setOnClickListener { if (viewer != null) { - if (viewer is R2LPagerViewer) + if (viewer is R2LPagerViewer) { loadPreviousChapter() - else + } else { loadNextChapter() + } } } @@ -590,11 +595,13 @@ class ReaderActivity : BaseRxActivity() * depending on the [result]. */ fun onSetAsCoverResult(result: ReaderPresenter.SetAsCoverResult) { - toast(when (result) { - Success -> R.string.cover_updated - AddToLibraryFirst -> R.string.notification_first_add_to_library - Error -> R.string.notification_cover_update_failed - }) + toast( + when (result) { + Success -> R.string.cover_updated + AddToLibraryFirst -> R.string.notification_first_add_to_library + Error -> R.string.notification_cover_update_failed + } + ) } /** @@ -614,10 +621,10 @@ class ReaderActivity : BaseRxActivity() val sharedRotation = preferences.rotation().asObservable().share() val initialRotation = sharedRotation.take(1) val rotationUpdates = sharedRotation.skip(1) - .delay(250, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread()) + .delay(250, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread()) subscriptions += Observable.merge(initialRotation, rotationUpdates) - .subscribe { setOrientation(it) } + .subscribe { setOrientation(it) } preferences.readerTheme().asFlow() .drop(1) // We only care about updates @@ -700,10 +707,11 @@ class ReaderActivity : BaseRxActivity() * Sets the 32-bit color mode according to [enabled]. */ private fun setTrueColor(enabled: Boolean) { - if (enabled) + if (enabled) { SubsamplingScaleImageView.setPreferredBitmapConfig(Bitmap.Config.ARGB_8888) - else + } else { SubsamplingScaleImageView.setPreferredBitmapConfig(Bitmap.Config.RGB_565) + } } @TargetApi(Build.VERSION_CODES.P) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderColorFilterSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderColorFilterSheet.kt index c4f5a18e22..d4d064edad 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderColorFilterSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderColorFilterSheet.kt @@ -214,8 +214,9 @@ class ReaderColorFilterSheet(private val activity: ReaderActivity) : BottomSheet brightness_overlay.gone() } - if (!isDisabled) + if (!isDisabled) { txt_brightness_seekbar_value.text = value.toString() + } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderColorFilterView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderColorFilterView.kt index eb04c10133..4468ed32d3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderColorFilterView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderColorFilterView.kt @@ -17,14 +17,16 @@ class ReaderColorFilterView( fun setFilterColor(color: Int, filterMode: Int) { colorFilterPaint.color = color - colorFilterPaint.xfermode = PorterDuffXfermode(when (filterMode) { - 1 -> PorterDuff.Mode.MULTIPLY - 2 -> PorterDuff.Mode.SCREEN - 3 -> PorterDuff.Mode.OVERLAY - 4 -> PorterDuff.Mode.LIGHTEN - 5 -> PorterDuff.Mode.DARKEN - else -> PorterDuff.Mode.SRC_OVER - }) + colorFilterPaint.xfermode = PorterDuffXfermode( + when (filterMode) { + 1 -> PorterDuff.Mode.MULTIPLY + 2 -> PorterDuff.Mode.SCREEN + 3 -> PorterDuff.Mode.OVERLAY + 4 -> PorterDuff.Mode.LIGHTEN + 5 -> PorterDuff.Mode.DARKEN + else -> PorterDuff.Mode.SRC_OVER + } + ) invalidate() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPageSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPageSheet.kt index 3fcffb17f2..201c7d190a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPageSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPageSheet.kt @@ -44,13 +44,13 @@ class ReaderPageSheet( if (page.status != Page.READY) return MaterialDialog(activity) - .message(R.string.confirm_set_image_as_cover) - .positiveButton(android.R.string.ok) { - activity.setAsCover(page) - dismiss() - } - .negativeButton(android.R.string.cancel) - .show() + .message(R.string.confirm_set_image_as_cover) + .positiveButton(android.R.string.ok) { + activity.setAsCover(page) + dismiss() + } + .negativeButton(android.R.string.cancel) + .show() } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt index 983fb7333e..b6307bb083 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt @@ -88,38 +88,40 @@ class ReaderPresenter( val dbChapters = db.getChapters(manga).executeAsBlocking() val selectedChapter = dbChapters.find { it.id == chapterId } - ?: error("Requested chapter of id $chapterId not found in chapter list") + ?: error("Requested chapter of id $chapterId not found in chapter list") val chaptersForReader = - if (preferences.skipRead() || preferences.skipFiltered()) { - val list = dbChapters - .filter { - if (preferences.skipRead() && it.read) { + if (preferences.skipRead() || preferences.skipFiltered()) { + val list = dbChapters + .filter { + if (preferences.skipRead() && it.read) { + return@filter false + } else if (preferences.skipFiltered()) { + if ( + (manga.readFilter == Manga.SHOW_READ && !it.read) || + (manga.readFilter == Manga.SHOW_UNREAD && it.read) || + ( + manga.downloadedFilter == Manga.SHOW_DOWNLOADED && + !downloadManager.isChapterDownloaded(it, manga) + ) || + (manga.bookmarkedFilter == Manga.SHOW_BOOKMARKED && !it.bookmark) + ) { return@filter false - } else if (preferences.skipFiltered()) { - if ( - (manga.readFilter == Manga.SHOW_READ && !it.read) || - (manga.readFilter == Manga.SHOW_UNREAD && it.read) || - (manga.downloadedFilter == Manga.SHOW_DOWNLOADED && - !downloadManager.isChapterDownloaded(it, manga)) || - (manga.bookmarkedFilter == Manga.SHOW_BOOKMARKED && !it.bookmark) - ) { - return@filter false - } } - - true } - .toMutableList() - val find = list.find { it.id == chapterId } - if (find == null) { - list.add(selectedChapter) + true } - list - } else { - dbChapters + .toMutableList() + + val find = list.find { it.id == chapterId } + if (find == null) { + list.add(selectedChapter) } + list + } else { + dbChapters + } when (manga.sorting) { Manga.SORTING_SOURCE -> ChapterLoadBySource().get(chaptersForReader) @@ -198,12 +200,15 @@ class ReaderPresenter( if (!needsInit()) return db.getManga(mangaId).asRxObservable() - .first() - .observeOn(AndroidSchedulers.mainThread()) - .doOnNext { init(it, initialChapterId) } - .subscribeFirst({ _, _ -> + .first() + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext { init(it, initialChapterId) } + .subscribeFirst( + { _, _ -> // Ignore onNext event - }, ReaderActivity::setInitialChapterError) + }, + ReaderActivity::setInitialChapterError + ) } /** @@ -241,13 +246,16 @@ class ReaderPresenter( // Read chapterList from an io thread because it's retrieved lazily and would block main. activeChapterSubscription?.unsubscribe() activeChapterSubscription = Observable - .fromCallable { chapterList.first { chapterId == it.chapter.id } } - .flatMap { getLoadObservable(loader!!, it) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeFirst({ _, _ -> + .fromCallable { chapterList.first { chapterId == it.chapter.id } } + .flatMap { getLoadObservable(loader!!, it) } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeFirst( + { _, _ -> // Ignore onNext event - }, ReaderActivity::setInitialChapterError) + }, + ReaderActivity::setInitialChapterError + ) } /** @@ -262,23 +270,27 @@ class ReaderPresenter( chapter: ReaderChapter ): Observable { return loader.loadChapter(chapter) - .andThen(Observable.fromCallable { + .andThen( + Observable.fromCallable { val chapterPos = chapterList.indexOf(chapter) - ViewerChapters(chapter, - chapterList.getOrNull(chapterPos - 1), - chapterList.getOrNull(chapterPos + 1)) - }) - .observeOn(AndroidSchedulers.mainThread()) - .doOnNext { newChapters -> - val oldChapters = viewerChaptersRelay.value - - // Add new references first to avoid unnecessary recycling - newChapters.ref() - oldChapters?.unref() - - viewerChaptersRelay.call(newChapters) + ViewerChapters( + chapter, + chapterList.getOrNull(chapterPos - 1), + chapterList.getOrNull(chapterPos + 1) + ) } + ) + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext { newChapters -> + val oldChapters = viewerChaptersRelay.value + + // Add new references first to avoid unnecessary recycling + newChapters.ref() + oldChapters?.unref() + + viewerChaptersRelay.call(newChapters) + } } /** @@ -292,10 +304,10 @@ class ReaderPresenter( activeChapterSubscription?.unsubscribe() activeChapterSubscription = getLoadObservable(loader, chapter) - .toCompletable() - .onErrorComplete() - .subscribe() - .also(::add) + .toCompletable() + .onErrorComplete() + .subscribe() + .also(::add) } /** @@ -310,13 +322,16 @@ class ReaderPresenter( activeChapterSubscription?.unsubscribe() activeChapterSubscription = getLoadObservable(loader, chapter) - .doOnSubscribe { isLoadingAdjacentChapterRelay.call(true) } - .doOnUnsubscribe { isLoadingAdjacentChapterRelay.call(false) } - .subscribeFirst({ view, _ -> + .doOnSubscribe { isLoadingAdjacentChapterRelay.call(true) } + .doOnUnsubscribe { isLoadingAdjacentChapterRelay.call(false) } + .subscribeFirst( + { view, _ -> view.moveToPageIndex(0) - }, { _, _ -> + }, + { _, _ -> // Ignore onError event, viewers handle that state - }) + } + ) } /** @@ -333,12 +348,12 @@ class ReaderPresenter( val loader = loader ?: return loader.loadChapter(chapter) - .observeOn(AndroidSchedulers.mainThread()) - // Update current chapters whenever a chapter is preloaded - .doOnCompleted { viewerChaptersRelay.value?.let(viewerChaptersRelay::call) } - .onErrorComplete() - .subscribe() - .also(::add) + .observeOn(AndroidSchedulers.mainThread()) + // Update current chapters whenever a chapter is preloaded + .doOnCompleted { viewerChaptersRelay.value?.let(viewerChaptersRelay::call) } + .onErrorComplete() + .subscribe() + .also(::add) } /** @@ -380,9 +395,9 @@ class ReaderPresenter( */ private fun saveChapterProgress(chapter: ReaderChapter) { db.updateChapterProgress(chapter.chapter).asRxCompletable() - .onErrorComplete() - .subscribeOn(Schedulers.io()) - .subscribe() + .onErrorComplete() + .subscribeOn(Schedulers.io()) + .subscribe() } /** @@ -391,9 +406,9 @@ class ReaderPresenter( private fun saveChapterHistory(chapter: ReaderChapter) { val history = History.create(chapter.chapter).apply { last_read = Date().time } db.updateHistoryLastRead(history).asRxCompletable() - .onErrorComplete() - .subscribeOn(Schedulers.io()) - .subscribe() + .onErrorComplete() + .subscribeOn(Schedulers.io()) + .subscribe() } /** @@ -456,18 +471,18 @@ class ReaderPresenter( db.updateMangaViewer(manga).executeAsBlocking() Observable.timer(250, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread()) - .subscribeFirst({ view, _ -> - val currChapters = viewerChaptersRelay.value - if (currChapters != null) { - // Save current page - val currChapter = currChapters.currChapter - currChapter.requestedPage = currChapter.chapter.last_page_read + .subscribeFirst({ view, _ -> + val currChapters = viewerChaptersRelay.value + if (currChapters != null) { + // Save current page + val currChapter = currChapters.currChapter + currChapter.requestedPage = currChapter.chapter.last_page_read - // Emit manga and chapters to the new viewer - view.setManga(manga) - view.setChapters(currChapters) - } - }) + // Emit manga and chapters to the new viewer + view.setManga(manga) + view.setChapters(currChapters) + } + }) } /** @@ -484,7 +499,7 @@ class ReaderPresenter( // Build destination file. val filenameSuffix = " - ${page.number}.${type.extension}" val filename = DiskUtil.buildValidFilename( - "${manga.title} - ${chapter.name}".takeBytes(MAX_FILE_NAME_BYTES - filenameSuffix.byteSize()) + "${manga.title} - ${chapter.name}".takeBytes(MAX_FILE_NAME_BYTES - filenameSuffix.byteSize()) ) + filenameSuffix val destFile = File(directory, filename) @@ -509,23 +524,25 @@ class ReaderPresenter( notifier.onClear() // Pictures directory. - val destDir = File(Environment.getExternalStorageDirectory().absolutePath + + val destDir = File( + Environment.getExternalStorageDirectory().absolutePath + File.separator + Environment.DIRECTORY_PICTURES + - File.separator + "Tachiyomi") + File.separator + "Tachiyomi" + ) // Copy file in background. Observable.fromCallable { saveImage(page, destDir, manga) } - .doOnNext { file -> - DiskUtil.scanMedia(context, file) - notifier.onComplete(file) - } - .doOnError { notifier.onError(it.message) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeFirst( - { view, file -> view.onSaveImageResult(SaveImageResult.Success(file)) }, - { view, error -> view.onSaveImageResult(SaveImageResult.Error(error)) } - ) + .doOnNext { file -> + DiskUtil.scanMedia(context, file) + notifier.onComplete(file) + } + .doOnError { notifier.onError(it.message) } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeFirst( + { view, file -> view.onSaveImageResult(SaveImageResult.Success(file)) }, + { view, error -> view.onSaveImageResult(SaveImageResult.Error(error)) } + ) } /** @@ -543,13 +560,13 @@ class ReaderPresenter( val destDir = File(context.cacheDir, "shared_image") Observable.fromCallable { destDir.deleteRecursively() } // Keep only the last shared file - .map { saveImage(page, destDir, manga) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeFirst( - { view, file -> view.onShareImageResult(file) }, - { _, _ -> /* Empty */ } - ) + .map { saveImage(page, destDir, manga) } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeFirst( + { view, file -> view.onShareImageResult(file) }, + { _, _ -> /* Empty */ } + ) } /** @@ -561,28 +578,28 @@ class ReaderPresenter( val stream = page.stream ?: return Observable - .fromCallable { - if (manga.source == LocalSource.ID) { - val context = Injekt.get() - LocalSource.updateCover(context, manga, stream()) - R.string.cover_updated + .fromCallable { + if (manga.source == LocalSource.ID) { + val context = Injekt.get() + LocalSource.updateCover(context, manga, stream()) + R.string.cover_updated + SetAsCoverResult.Success + } else { + val thumbUrl = manga.thumbnail_url ?: throw Exception("Image url not found") + if (manga.favorite) { + coverCache.copyToCache(thumbUrl, stream()) SetAsCoverResult.Success } else { - val thumbUrl = manga.thumbnail_url ?: throw Exception("Image url not found") - if (manga.favorite) { - coverCache.copyToCache(thumbUrl, stream()) - SetAsCoverResult.Success - } else { - SetAsCoverResult.AddToLibraryFirst - } + SetAsCoverResult.AddToLibraryFirst } } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeFirst( - { view, result -> view.onSetAsCoverResult(result) }, - { view, _ -> view.onSetAsCoverResult(SetAsCoverResult.Error) } - ) + } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeFirst( + { view, result -> view.onSetAsCoverResult(result) }, + { view, _ -> view.onSetAsCoverResult(SetAsCoverResult.Error) } + ) } /** @@ -613,8 +630,9 @@ class ReaderPresenter( val trackManager = Injekt.get() db.getTracks(manga).asRxSingle() - .flatMapCompletable { trackList -> - Completable.concat(trackList.map { track -> + .flatMapCompletable { trackList -> + Completable.concat( + trackList.map { track -> val service = trackManager.getService(track.sync_id) if (service != null && service.isLogged && chapterRead > track.last_chapter_read) { track.last_chapter_read = chapterRead @@ -622,17 +640,18 @@ class ReaderPresenter( // We wan't these to execute even if the presenter is destroyed and leaks // for a while. The view can still be garbage collected. Observable.defer { service.update(track) } - .map { db.insertTrack(track).executeAsBlocking() } - .toCompletable() - .onErrorComplete() + .map { db.insertTrack(track).executeAsBlocking() } + .toCompletable() + .onErrorComplete() } else { Completable.complete() } - }) - } - .onErrorComplete() - .subscribeOn(Schedulers.io()) - .subscribe() + } + ) + } + .onErrorComplete() + .subscribeOn(Schedulers.io()) + .subscribe() } /** @@ -648,19 +667,19 @@ class ReaderPresenter( if (removeAfterReadSlots == -1) return Completable - .fromCallable { - // Position of the read chapter - val position = chapterList.indexOf(chapter) + .fromCallable { + // Position of the read chapter + val position = chapterList.indexOf(chapter) - // Retrieve chapter to delete according to preference - val chapterToDelete = chapterList.getOrNull(position - removeAfterReadSlots) - if (chapterToDelete != null) { - downloadManager.enqueueDeleteChapters(listOf(chapterToDelete.chapter), manga) - } + // Retrieve chapter to delete according to preference + val chapterToDelete = chapterList.getOrNull(position - removeAfterReadSlots) + if (chapterToDelete != null) { + downloadManager.enqueueDeleteChapters(listOf(chapterToDelete.chapter), manga) } - .onErrorComplete() - .subscribeOn(Schedulers.io()) - .subscribe() + } + .onErrorComplete() + .subscribeOn(Schedulers.io()) + .subscribe() } /** @@ -669,9 +688,9 @@ class ReaderPresenter( */ private fun deletePendingChapters() { Completable.fromCallable { downloadManager.deletePendingChapters() } - .onErrorComplete() - .subscribeOn(Schedulers.io()) - .subscribe() + .onErrorComplete() + .subscribeOn(Schedulers.io()) + .subscribe() } companion object { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/SaveImageNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/SaveImageNotifier.kt index 5045c6bb5c..2b9fe851d8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/SaveImageNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/SaveImageNotifier.kt @@ -37,12 +37,12 @@ class SaveImageNotifier(private val context: Context) { */ fun onComplete(file: File) { val bitmap = GlideApp.with(context) - .asBitmap() - .load(file) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .skipMemoryCache(true) - .submit(720, 1280) - .get() + .asBitmap() + .load(file) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .skipMemoryCache(true) + .submit(720, 1280) + .get() if (bitmap != null) { showCompleteNotification(file, bitmap) @@ -66,13 +66,17 @@ class SaveImageNotifier(private val context: Context) { setContentIntent(NotificationHandler.openImagePendingActivity(context, file)) // Share action - addAction(R.drawable.ic_share_24dp, - context.getString(R.string.action_share), - NotificationReceiver.shareImagePendingBroadcast(context, file.absolutePath, notificationId)) + addAction( + R.drawable.ic_share_24dp, + context.getString(R.string.action_share), + NotificationReceiver.shareImagePendingBroadcast(context, file.absolutePath, notificationId) + ) // Delete action - addAction(R.drawable.ic_delete_24dp, - context.getString(R.string.action_delete), - NotificationReceiver.deleteImagePendingBroadcast(context, file.absolutePath, notificationId)) + addAction( + R.drawable.ic_delete_24dp, + context.getString(R.string.action_delete), + NotificationReceiver.deleteImagePendingBroadcast(context, file.absolutePath, notificationId) + ) updateNotification() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt index fc83952bfb..9551ff90af 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt @@ -31,34 +31,34 @@ class ChapterLoader( } return Observable.just(chapter) - .doOnNext { chapter.state = ReaderChapter.State.Loading } - .observeOn(Schedulers.io()) - .flatMap { readerChapter -> - Timber.d("Loading pages for ${chapter.chapter.name}") + .doOnNext { chapter.state = ReaderChapter.State.Loading } + .observeOn(Schedulers.io()) + .flatMap { readerChapter -> + Timber.d("Loading pages for ${chapter.chapter.name}") - val loader = getPageLoader(readerChapter) - chapter.pageLoader = loader + val loader = getPageLoader(readerChapter) + chapter.pageLoader = loader - loader.getPages().take(1).doOnNext { pages -> - pages.forEach { it.chapter = chapter } - } + loader.getPages().take(1).doOnNext { pages -> + pages.forEach { it.chapter = chapter } } - .observeOn(AndroidSchedulers.mainThread()) - .doOnNext { pages -> - if (pages.isEmpty()) { - throw Exception("Page list is empty") - } - - chapter.state = ReaderChapter.State.Loaded(pages) - - // If the chapter is partially read, set the starting page to the last the user read - // otherwise use the requested page. - if (!chapter.chapter.read) { - chapter.requestedPage = chapter.chapter.last_page_read - } + } + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext { pages -> + if (pages.isEmpty()) { + throw Exception("Page list is empty") } - .toCompletable() - .doOnError { chapter.state = ReaderChapter.State.Error(it) } + + chapter.state = ReaderChapter.State.Loaded(pages) + + // If the chapter is partially read, set the starting page to the last the user read + // otherwise use the requested page. + if (!chapter.chapter.read) { + chapter.requestedPage = chapter.chapter.last_page_read + } + } + .toCompletable() + .doOnError { chapter.state = ReaderChapter.State.Error(it) } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DirectoryPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DirectoryPageLoader.kt index 77f921b5c2..95e7c6e5ea 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DirectoryPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DirectoryPageLoader.kt @@ -19,16 +19,16 @@ class DirectoryPageLoader(val file: File) : PageLoader() { */ override fun getPages(): Observable> { return file.listFiles() - .filter { !it.isDirectory && ImageUtil.isImage(it.name) { FileInputStream(it) } } - .sortedWith(Comparator { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) }) - .mapIndexed { i, file -> - val streamFn = { FileInputStream(file) } - ReaderPage(i).apply { - stream = streamFn - status = Page.READY - } + .filter { !it.isDirectory && ImageUtil.isImage(it.name) { FileInputStream(it) } } + .sortedWith(Comparator { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) }) + .mapIndexed { i, file -> + val streamFn = { FileInputStream(file) } + ReaderPage(i).apply { + stream = streamFn + status = Page.READY } - .let { Observable.just(it) } + } + .let { Observable.just(it) } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DownloadPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DownloadPageLoader.kt index b2d5540c2e..838242d22b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DownloadPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/DownloadPageLoader.kt @@ -31,15 +31,15 @@ class DownloadPageLoader( */ override fun getPages(): Observable> { return downloadManager.buildPageList(source, manga, chapter.chapter) - .map { pages -> - pages.map { page -> - ReaderPage(page.index, page.url, page.imageUrl) { - context.contentResolver.openInputStream(page.uri ?: Uri.EMPTY)!! - }.apply { - status = Page.READY - } + .map { pages -> + pages.map { page -> + ReaderPage(page.index, page.url, page.imageUrl) { + context.contentResolver.openInputStream(page.uri ?: Uri.EMPTY)!! + }.apply { + status = Page.READY } } + } } override fun getPage(page: ReaderPage): Observable { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt index 4e1bff8143..00895e9012 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/EpubPageLoader.kt @@ -30,24 +30,26 @@ class EpubPageLoader(file: File) : PageLoader() { */ override fun getPages(): Observable> { return epub.getImagesFromPages() - .mapIndexed { i, path -> - val streamFn = { epub.getInputStream(epub.getEntry(path)!!) } - ReaderPage(i).apply { - stream = streamFn - status = Page.READY - } + .mapIndexed { i, path -> + val streamFn = { epub.getInputStream(epub.getEntry(path)!!) } + ReaderPage(i).apply { + stream = streamFn + status = Page.READY } - .let { Observable.just(it) } + } + .let { Observable.just(it) } } /** * Returns an observable that emits a ready state unless the loader was recycled. */ override fun getPage(page: ReaderPage): Observable { - return Observable.just(if (isRecycled) { - Page.ERROR - } else { - Page.READY - }) + return Observable.just( + if (isRecycled) { + Page.ERROR + } else { + Page.READY + } + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/HttpPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/HttpPageLoader.kt index 4ce68f6bae..1cc6df6ba5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/HttpPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/HttpPageLoader.kt @@ -42,16 +42,19 @@ class HttpPageLoader( init { subscriptions += Observable.defer { Observable.just(queue.take().page) } - .filter { it.status == Page.QUEUE } - .concatMap { source.fetchImageFromCacheThenNet(it) } - .repeat() - .subscribeOn(Schedulers.io()) - .subscribe({ - }, { error -> + .filter { it.status == Page.QUEUE } + .concatMap { source.fetchImageFromCacheThenNet(it) } + .repeat() + .subscribeOn(Schedulers.io()) + .subscribe( + { + }, + { error -> if (error !is InterruptedException) { Timber.e(error) } - }) + } + ) } /** @@ -66,14 +69,14 @@ class HttpPageLoader( val pages = chapter.pages if (pages != null) { Completable - .fromAction { - // Convert to pages without reader information - val pagesToSave = pages.map { Page(it.index, it.url, it.imageUrl) } - chapterCache.putPageListToCache(chapter.chapter, pagesToSave) - } - .onErrorComplete() - .subscribeOn(Schedulers.io()) - .subscribe() + .fromAction { + // Convert to pages without reader information + val pagesToSave = pages.map { Page(it.index, it.url, it.imageUrl) } + chapterCache.putPageListToCache(chapter.chapter, pagesToSave) + } + .onErrorComplete() + .subscribeOn(Schedulers.io()) + .subscribe() } } @@ -83,14 +86,14 @@ class HttpPageLoader( */ override fun getPages(): Observable> { return chapterCache - .getPageListFromCache(chapter.chapter) - .onErrorResumeNext { source.fetchPageList(chapter.chapter) } - .map { pages -> - pages.mapIndexed { index, page -> - // Don't trust sources and use our own indexing - ReaderPage(index, page.url, page.imageUrl) - } + .getPageListFromCache(chapter.chapter) + .onErrorResumeNext { source.fetchPageList(chapter.chapter) } + .map { pages -> + pages.mapIndexed { index, page -> + // Don't trust sources and use our own indexing + ReaderPage(index, page.url, page.imageUrl) } + } } /** @@ -121,16 +124,16 @@ class HttpPageLoader( queuedPages += preloadNextPages(page, preloadSize) statusSubject.startWith(page.status) - .doOnUnsubscribe { - queuedPages.forEach { - if (it.page.status == Page.QUEUE) { - queue.remove(it) - } + .doOnUnsubscribe { + queuedPages.forEach { + if (it.page.status == Page.QUEUE) { + queue.remove(it) } } + } } - .subscribeOn(Schedulers.io()) - .unsubscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.io()) + .unsubscribeOn(Schedulers.io()) } /** @@ -143,12 +146,12 @@ class HttpPageLoader( if (pageIndex == pages.lastIndex) return emptyList() return pages - .subList(pageIndex + 1, min(pageIndex + 1 + amount, pages.size)) - .mapNotNull { - if (it.status == Page.QUEUE) { - PriorityPage(it, 0).apply { queue.offer(this) } - } else null - } + .subList(pageIndex + 1, min(pageIndex + 1 + amount, pages.size)) + .mapNotNull { + if (it.status == Page.QUEUE) { + PriorityPage(it, 0).apply { queue.offer(this) } + } else null + } } /** @@ -186,19 +189,20 @@ class HttpPageLoader( * @param page the page whose source image has to be downloaded. */ private fun HttpSource.fetchImageFromCacheThenNet(page: ReaderPage): Observable { - return if (page.imageUrl.isNullOrEmpty()) + return if (page.imageUrl.isNullOrEmpty()) { getImageUrl(page).flatMap { getCachedImage(it) } - else + } else { getCachedImage(page) + } } private fun HttpSource.getImageUrl(page: ReaderPage): Observable { page.status = Page.LOAD_PAGE return fetchImageUrl(page) - .doOnError { page.status = Page.ERROR } - .onErrorReturn { null } - .doOnNext { page.imageUrl = it } - .map { page } + .doOnError { page.status = Page.ERROR } + .onErrorReturn { null } + .doOnNext { page.imageUrl = it } + .map { page } } /** @@ -211,19 +215,19 @@ class HttpPageLoader( val imageUrl = page.imageUrl ?: return Observable.just(page) return Observable.just(page) - .flatMap { - if (!chapterCache.isImageInCache(imageUrl)) { - cacheImage(page) - } else { - Observable.just(page) - } + .flatMap { + if (!chapterCache.isImageInCache(imageUrl)) { + cacheImage(page) + } else { + Observable.just(page) } - .doOnNext { - page.stream = { chapterCache.getImageFile(imageUrl).inputStream() } - page.status = Page.READY - } - .doOnError { page.status = Page.ERROR } - .onErrorReturn { page } + } + .doOnNext { + page.stream = { chapterCache.getImageFile(imageUrl).inputStream() } + page.status = Page.READY + } + .doOnError { page.status = Page.ERROR } + .onErrorReturn { page } } /** @@ -234,7 +238,7 @@ class HttpPageLoader( private fun HttpSource.cacheImage(page: ReaderPage): Observable { page.status = Page.DOWNLOAD_IMAGE return fetchImage(page) - .doOnNext { chapterCache.putImageToCache(page.imageUrl!!, it) } - .map { page } + .doOnNext { chapterCache.putImageToCache(page.imageUrl!!, it) } + .map { page } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt index b37b2e06cc..37b35a97cb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt @@ -43,28 +43,30 @@ class RarPageLoader(file: File) : PageLoader() { */ override fun getPages(): Observable> { return archive.fileHeaders - .filter { !it.isDirectory && ImageUtil.isImage(it.fileNameString) { archive.getInputStream(it) } } - .sortedWith(Comparator { f1, f2 -> f1.fileNameString.compareToCaseInsensitiveNaturalOrder(f2.fileNameString) }) - .mapIndexed { i, header -> - val streamFn = { getStream(header) } + .filter { !it.isDirectory && ImageUtil.isImage(it.fileNameString) { archive.getInputStream(it) } } + .sortedWith(Comparator { f1, f2 -> f1.fileNameString.compareToCaseInsensitiveNaturalOrder(f2.fileNameString) }) + .mapIndexed { i, header -> + val streamFn = { getStream(header) } - ReaderPage(i).apply { - stream = streamFn - status = Page.READY - } + ReaderPage(i).apply { + stream = streamFn + status = Page.READY } - .let { Observable.just(it) } + } + .let { Observable.just(it) } } /** * Returns an observable that emits a ready state unless the loader was recycled. */ override fun getPage(page: ReaderPage): Observable { - return Observable.just(if (isRecycled) { - Page.ERROR - } else { - Page.READY - }) + return Observable.just( + if (isRecycled) { + Page.ERROR + } else { + Page.READY + } + ) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt index b55796d3aa..e2cca59fe9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt @@ -33,26 +33,28 @@ class ZipPageLoader(file: File) : PageLoader() { */ override fun getPages(): Observable> { return zip.entries().toList() - .filter { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } } - .sortedWith(Comparator { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) }) - .mapIndexed { i, entry -> - val streamFn = { zip.getInputStream(entry) } - ReaderPage(i).apply { - stream = streamFn - status = Page.READY - } + .filter { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } } + .sortedWith(Comparator { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) }) + .mapIndexed { i, entry -> + val streamFn = { zip.getInputStream(entry) } + ReaderPage(i).apply { + stream = streamFn + status = Page.READY } - .let { Observable.just(it) } + } + .let { Observable.just(it) } } /** * Returns an observable that emits a ready state unless the loader was recycled. */ override fun getPage(page: ReaderPage): Observable { - return Observable.just(if (isRecycled) { - Page.ERROR - } else { - Page.READY - }) + return Observable.just( + if (isRecycled) { + Page.ERROR + } else { + Page.READY + } + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/ReaderChapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/ReaderChapter.kt index 06f08b6db6..fe3285e9b7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/ReaderChapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/ReaderChapter.kt @@ -8,11 +8,11 @@ import timber.log.Timber data class ReaderChapter(val chapter: Chapter) { var state: State = - State.Wait + State.Wait set(value) { - field = value - stateRelay.call(value) - } + field = value + stateRelay.call(value) + } private val stateRelay by lazy { BehaviorRelay.create(state) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderProgressBar.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderProgressBar.kt index 1f58c25a1b..9b6eed602b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderProgressBar.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderProgressBar.kt @@ -61,9 +61,10 @@ class ReaderProgressBar @JvmOverloads constructor( * The rotation animation to use while the progress bar is visible. */ private val rotationAnimation by lazy { - RotateAnimation(0f, 360f, - Animation.RELATIVE_TO_SELF, 0.5f, - Animation.RELATIVE_TO_SELF, 0.5f + RotateAnimation( + 0f, 360f, + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f ).apply { interpolator = LinearInterpolator() repeatCount = Animation.INFINITE diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt index 7babac154e..544430a8ee 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt @@ -126,8 +126,8 @@ class PagerPageHolder( val loader = page.chapter.pageLoader ?: return statusSubscription = loader.getPage(page) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { processStatus(it) } + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { processStatus(it) } } /** @@ -137,11 +137,11 @@ class PagerPageHolder( progressSubscription?.unsubscribe() progressSubscription = Observable.interval(100, TimeUnit.MILLISECONDS) - .map { page.progress } - .distinctUntilChanged() - .onBackpressureLatest() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { value -> progressBar.setProgress(value) } + .map { page.progress } + .distinctUntilChanged() + .onBackpressureLatest() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { value -> progressBar.setProgress(value) } } /** @@ -233,25 +233,25 @@ class PagerPageHolder( var openStream: InputStream? = null readImageHeaderSubscription = Observable - .fromCallable { - val stream = streamFn().buffered(16) - openStream = stream + .fromCallable { + val stream = streamFn().buffered(16) + openStream = stream - ImageUtil.findImageType(stream) == ImageUtil.ImageType.GIF + ImageUtil.findImageType(stream) == ImageUtil.ImageType.GIF + } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext { isAnimated -> + if (!isAnimated) { + initSubsamplingImageView().setImage(ImageSource.inputStream(openStream!!)) + } else { + initImageView().setImage(openStream!!) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnNext { isAnimated -> - if (!isAnimated) { - initSubsamplingImageView().setImage(ImageSource.inputStream(openStream!!)) - } else { - initImageView().setImage(openStream!!) - } - } - // Keep the Rx stream alive to close the input stream only when unsubscribed - .flatMap { Observable.never() } - .doOnUnsubscribe { openStream?.close() } - .subscribe({}, {}) + } + // Keep the Rx stream alive to close the input stream only when unsubscribed + .flatMap { Observable.never() } + .doOnUnsubscribe { openStream?.close() } + .subscribe({}, {}) } /** @@ -283,7 +283,6 @@ class PagerPageHolder( @SuppressLint("PrivateResource") private fun createProgressBar(): ReaderProgressBar { return ReaderProgressBar(context, null).apply { - val size = 48.dpToPx layoutParams = LayoutParams(size, size).apply { gravity = Gravity.CENTER @@ -435,35 +434,35 @@ class PagerPageHolder( */ private fun ImageView.setImage(stream: InputStream) { GlideApp.with(this) - .load(stream) - .skipMemoryCache(true) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .transition(DrawableTransitionOptions.with(NoTransition.getFactory())) - .listener(object : RequestListener { - override fun onLoadFailed( - e: GlideException?, - model: Any?, - target: Target?, - isFirstResource: Boolean - ): Boolean { - onImageDecodeError() - return false - } + .load(stream) + .skipMemoryCache(true) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .transition(DrawableTransitionOptions.with(NoTransition.getFactory())) + .listener(object : RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + isFirstResource: Boolean + ): Boolean { + onImageDecodeError() + return false + } - override fun onResourceReady( - resource: Drawable?, - model: Any?, - target: Target?, - dataSource: DataSource?, - isFirstResource: Boolean - ): Boolean { - if (resource is GifDrawable) { - resource.setLoopCount(GifDrawable.LOOP_INTRINSIC) - } - onImageDecoded() - return false + override fun onResourceReady( + resource: Drawable?, + model: Any?, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + if (resource is GifDrawable) { + resource.setLoopCount(GifDrawable.LOOP_INTRINSIC) } - }) - .into(this) + onImageDecoded() + return false + } + }) + .into(this) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerTransitionHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerTransitionHolder.kt index 8f63dc1aac..fe9e2828f0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerTransitionHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerTransitionHolder.kt @@ -140,17 +140,17 @@ class PagerTransitionHolder( private fun observeStatus(chapter: ReaderChapter) { statusSubscription?.unsubscribe() statusSubscription = chapter.stateObserver - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { state -> - pagesContainer.removeAllViews() - when (state) { - is ReaderChapter.State.Wait -> { - } - is ReaderChapter.State.Loading -> setLoading() - is ReaderChapter.State.Error -> setError(state.error) - is ReaderChapter.State.Loaded -> setLoaded() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { state -> + pagesContainer.removeAllViews() + when (state) { + is ReaderChapter.State.Wait -> { } + is ReaderChapter.State.Loading -> setLoading() + is ReaderChapter.State.Error -> setError(state.error) + is ReaderChapter.State.Loaded -> setLoaded() } + } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewerAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewerAdapter.kt index e32471e14f..30e568b97c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewerAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewerAdapter.kt @@ -57,12 +57,13 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() { // Add next chapter transition and pages. nextTransition = ChapterTransition.Next(chapters.currChapter, chapters.nextChapter) - .also { - if (forceTransition || - chapters.nextChapter?.state !is ReaderChapter.State.Loaded) { - newItems.add(it) - } + .also { + if (forceTransition || + chapters.nextChapter?.state !is ReaderChapter.State.Loaded + ) { + newItems.add(it) } + } if (chapters.nextChapter != null) { // Add at most two pages, because this chapter will be selected before the user can diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonLayoutManager.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonLayoutManager.kt index 0268871697..74ced080cd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonLayoutManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonLayoutManager.kt @@ -37,17 +37,18 @@ class WebtoonLayoutManager(activity: ReaderActivity) : LinearLayoutManager(activ fun findLastEndVisibleItemPosition(): Int { ensureLayoutState() @ViewBoundsCheck.ViewBounds val preferredBoundsFlag = - (ViewBoundsCheck.FLAG_CVE_LT_PVE or ViewBoundsCheck.FLAG_CVE_EQ_PVE) + (ViewBoundsCheck.FLAG_CVE_LT_PVE or ViewBoundsCheck.FLAG_CVE_EQ_PVE) val fromIndex = childCount - 1 val toIndex = -1 - val child = if (mOrientation == HORIZONTAL) + val child = if (mOrientation == HORIZONTAL) { mHorizontalBoundCheck - .findOneViewWithinBoundFlags(fromIndex, toIndex, preferredBoundsFlag, 0) - else + .findOneViewWithinBoundFlags(fromIndex, toIndex, preferredBoundsFlag, 0) + } else { mVerticalBoundCheck - .findOneViewWithinBoundFlags(fromIndex, toIndex, preferredBoundsFlag, 0) + .findOneViewWithinBoundFlags(fromIndex, toIndex, preferredBoundsFlag, 0) + } return if (child == null) NO_POSITION else getPosition(child) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt index b963c749ba..384cc978d4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt @@ -162,8 +162,8 @@ class WebtoonPageHolder( val page = page ?: return val loader = page.chapter.pageLoader ?: return statusSubscription = loader.getPage(page) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { processStatus(it) } + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { processStatus(it) } addSubscription(statusSubscription) } @@ -177,11 +177,11 @@ class WebtoonPageHolder( val page = page ?: return progressSubscription = Observable.interval(100, TimeUnit.MILLISECONDS) - .map { page.progress } - .distinctUntilChanged() - .onBackpressureLatest() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { value -> progressBar.setProgress(value) } + .map { page.progress } + .distinctUntilChanged() + .onBackpressureLatest() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { value -> progressBar.setProgress(value) } addSubscription(progressSubscription) } @@ -279,29 +279,29 @@ class WebtoonPageHolder( var openStream: InputStream? = null readImageHeaderSubscription = Observable - .fromCallable { - val stream = streamFn().buffered(16) - openStream = stream + .fromCallable { + val stream = streamFn().buffered(16) + openStream = stream - ImageUtil.findImageType(stream) == ImageUtil.ImageType.GIF + ImageUtil.findImageType(stream) == ImageUtil.ImageType.GIF + } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext { isAnimated -> + if (!isAnimated) { + val subsamplingView = initSubsamplingImageView() + subsamplingView.visible() + subsamplingView.setImage(ImageSource.inputStream(openStream!!)) + } else { + val imageView = initImageView() + imageView.visible() + imageView.setImage(openStream!!) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnNext { isAnimated -> - if (!isAnimated) { - val subsamplingView = initSubsamplingImageView() - subsamplingView.visible() - subsamplingView.setImage(ImageSource.inputStream(openStream!!)) - } else { - val imageView = initImageView() - imageView.visible() - imageView.setImage(openStream!!) - } - } - // Keep the Rx stream alive to close the input stream only when unsubscribed - .flatMap { Observable.never() } - .doOnUnsubscribe { openStream?.close() } - .subscribe({}, {}) + } + // Keep the Rx stream alive to close the input stream only when unsubscribed + .flatMap { Observable.never() } + .doOnUnsubscribe { openStream?.close() } + .subscribe({}, {}) addSubscription(readImageHeaderSubscription) } @@ -489,35 +489,35 @@ class WebtoonPageHolder( */ private fun ImageView.setImage(stream: InputStream) { GlideApp.with(this) - .load(stream) - .skipMemoryCache(true) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .transition(DrawableTransitionOptions.with(NoTransition.getFactory())) - .listener(object : RequestListener { - override fun onLoadFailed( - e: GlideException?, - model: Any?, - target: Target?, - isFirstResource: Boolean - ): Boolean { - onImageDecodeError() - return false - } + .load(stream) + .skipMemoryCache(true) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .transition(DrawableTransitionOptions.with(NoTransition.getFactory())) + .listener(object : RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + isFirstResource: Boolean + ): Boolean { + onImageDecodeError() + return false + } - override fun onResourceReady( - resource: Drawable?, - model: Any?, - target: Target?, - dataSource: DataSource?, - isFirstResource: Boolean - ): Boolean { - if (resource is GifDrawable) { - resource.setLoopCount(GifDrawable.LOOP_INTRINSIC) - } - onImageDecoded() - return false + override fun onResourceReady( + resource: Drawable?, + model: Any?, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + if (resource is GifDrawable) { + resource.setLoopCount(GifDrawable.LOOP_INTRINSIC) } - }) - .into(this) + onImageDecoded() + return false + } + }) + .into(this) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt index 73dcd23f19..91c839ec86 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonRecyclerView.kt @@ -59,7 +59,7 @@ open class WebtoonRecyclerView @JvmOverloads constructor( super.onScrolled(dx, dy) val layoutManager = layoutManager lastVisibleItemPosition = - (layoutManager as LinearLayoutManager).findLastVisibleItemPosition() + (layoutManager as LinearLayoutManager).findLastVisibleItemPosition() firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition() } @@ -146,13 +146,13 @@ open class WebtoonRecyclerView @JvmOverloads constructor( } animate() - .apply { - newX?.let { x(it) } - newY?.let { y(it) } - } - .setInterpolator(DecelerateInterpolator()) - .setDuration(400) - .start() + .apply { + newX?.let { x(it) } + newY?.let { y(it) } + } + .setInterpolator(DecelerateInterpolator()) + .setDuration(400) + .start() return true } @@ -174,8 +174,9 @@ open class WebtoonRecyclerView @JvmOverloads constructor( fun onScale(scaleFactor: Float) { currentScale *= scaleFactor currentScale = currentScale.coerceIn( - MIN_RATE, - MAX_SCALE_RATE) + MIN_RATE, + MAX_SCALE_RATE + ) setScaleRate(currentScale) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonTransitionHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonTransitionHolder.kt index 22e1c2dd89..8086b72e50 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonTransitionHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonTransitionHolder.kt @@ -143,18 +143,18 @@ class WebtoonTransitionHolder( unsubscribeStatus() statusSubscription = chapter.stateObserver - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { state -> - pagesContainer.removeAllViews() - when (state) { - is ReaderChapter.State.Wait -> { - } - is ReaderChapter.State.Loading -> setLoading() - is ReaderChapter.State.Error -> setError(state.error, transition) - is ReaderChapter.State.Loaded -> setLoaded() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { state -> + pagesContainer.removeAllViews() + when (state) { + is ReaderChapter.State.Wait -> { } - pagesContainer.visibleIf { pagesContainer.childCount > 0 } + is ReaderChapter.State.Loading -> setLoading() + is ReaderChapter.State.Error -> setError(state.error, transition) + is ReaderChapter.State.Loaded -> setLoaded() } + pagesContainer.visibleIf { pagesContainer.childCount > 0 } + } addSubscription(statusSubscription) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt index 850fbf222d..baf7d898ce 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt @@ -291,6 +291,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr val position = layoutManager.findLastEndVisibleItemPosition() adapter.notifyItemRangeChanged( max(0, position - 2), - min(position + 2, adapter.itemCount - 1)) + min(position + 2, adapter.itemCount - 1) + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryAdapter.kt index 432b9768c4..98f2f42454 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryAdapter.kt @@ -26,8 +26,11 @@ class HistoryAdapter(controller: HistoryController) : /** * DecimalFormat used to display correct chapter number */ - val decimalFormat = DecimalFormat("#.###", DecimalFormatSymbols() - .apply { decimalSeparator = '.' }) + val decimalFormat = DecimalFormat( + "#.###", + DecimalFormatSymbols() + .apply { decimalSeparator = '.' } + ) init { setDisplayHeadersAtStartUp(true) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryController.kt index 2c0a4808d6..fa7d248b23 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryController.kt @@ -22,14 +22,15 @@ import eu.kanade.tachiyomi.util.system.toast * Uses [R.layout.history_controller]. * UI related actions should be called from here. */ -class HistoryController : NucleusController(), - RootController, - NoToolbarElevationController, - FlexibleAdapter.OnUpdateListener, - HistoryAdapter.OnRemoveClickListener, - HistoryAdapter.OnResumeClickListener, - HistoryAdapter.OnItemClickListener, - RemoveHistoryDialog.Listener { +class HistoryController : + NucleusController(), + RootController, + NoToolbarElevationController, + FlexibleAdapter.OnUpdateListener, + HistoryAdapter.OnRemoveClickListener, + HistoryAdapter.OnResumeClickListener, + HistoryAdapter.OnItemClickListener, + RemoveHistoryDialog.Listener { /** * Adapter containing the recent manga. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryHolder.kt index 88c9bc10d4..eb922988ad 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryHolder.kt @@ -59,16 +59,16 @@ class HistoryHolder( // Set chapter number + timestamp val formattedNumber = adapter.decimalFormat.format(chapter.chapter_number.toDouble()) manga_subtitle.text = itemView.context.getString(R.string.recent_manga_time) - .format(formattedNumber, Date(history.last_read).toTimestampString()) + .format(formattedNumber, Date(history.last_read).toTimestampString()) // Set cover GlideApp.with(itemView.context).clear(cover) if (!manga.thumbnail_url.isNullOrEmpty()) { GlideApp.with(itemView.context) - .load(manga.toMangaThumbnail()) - .diskCacheStrategy(DiskCacheStrategy.RESOURCE) - .centerCrop() - .into(cover) + .load(manga.toMangaThumbnail()) + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .centerCrop() + .into(cover) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryItem.kt index 41d5705387..9a10529b2a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryItem.kt @@ -10,7 +10,7 @@ import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory import eu.kanade.tachiyomi.ui.recent.DateSectionItem class HistoryItem(val mch: MangaChapterHistory, header: DateSectionItem) : - AbstractSectionableItem(header) { + AbstractSectionableItem(header) { override fun getLayoutRes(): Int { return R.layout.history_item diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryPresenter.kt index 3cd7ab593e..911b6fabd4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryPresenter.kt @@ -34,7 +34,7 @@ class HistoryPresenter : BasePresenter() { // Used to get a list of recently read manga getRecentMangaObservable() - .subscribeLatestCache(HistoryController::onNextManga) + .subscribeLatestCache(HistoryController::onNextManga) } /** @@ -49,16 +49,16 @@ class HistoryPresenter : BasePresenter() { } return db.getRecentManga(cal.time).asRxObservable() - .map { recents -> - val map = TreeMap> { d1, d2 -> d2.compareTo(d1) } - val byDay = recents - .groupByTo(map, { it.history.last_read.toDateKey() }) - byDay.flatMap { entry -> - val dateItem = DateSectionItem(entry.key) - entry.value.map { HistoryItem(it, dateItem) } - } + .map { recents -> + val map = TreeMap> { d1, d2 -> d2.compareTo(d1) } + val byDay = recents + .groupByTo(map, { it.history.last_read.toDateKey() }) + byDay.flatMap { entry -> + val dateItem = DateSectionItem(entry.key) + entry.value.map { HistoryItem(it, dateItem) } } - .observeOn(AndroidSchedulers.mainThread()) + } + .observeOn(AndroidSchedulers.mainThread()) } /** @@ -68,7 +68,7 @@ class HistoryPresenter : BasePresenter() { fun removeFromHistory(history: History) { history.last_read = 0L db.updateHistoryLastRead(history).asRxObservable() - .subscribe() + .subscribe() } /** @@ -77,11 +77,11 @@ class HistoryPresenter : BasePresenter() { */ fun removeAllFromHistory(mangaId: Long) { db.getHistoryByMangaId(mangaId).asRxSingle() - .map { list -> - list.forEach { it.last_read = 0L } - db.updateHistoryLastRead(list).executeAsBlocking() - } - .subscribe() + .map { list -> + list.forEach { it.last_read = 0L } + db.updateHistoryLastRead(list).executeAsBlocking() + } + .subscribe() } /** @@ -102,7 +102,7 @@ class HistoryPresenter : BasePresenter() { } val chapters = db.getChapters(manga).executeAsBlocking() - .sortedWith(Comparator { c1, c2 -> sortFunction(c1, c2) }) + .sortedWith(Comparator { c1, c2 -> sortFunction(c1, c2) }) val currChapterIndex = chapters.indexOfFirst { chapter.id == it.id } return when (manga.sorting) { @@ -111,11 +111,11 @@ class HistoryPresenter : BasePresenter() { val chapterNumber = chapter.chapter_number ((currChapterIndex + 1) until chapters.size) - .map { chapters[it] } - .firstOrNull { - it.chapter_number > chapterNumber && - it.chapter_number <= chapterNumber + 1 - } + .map { chapters[it] } + .firstOrNull { + it.chapter_number > chapterNumber && + it.chapter_number <= chapterNumber + 1 + } } else -> throw NotImplementedError("Unknown sorting method") } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/RemoveHistoryDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/RemoveHistoryDialog.kt index 0dd0075388..faeb1373ce 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/RemoveHistoryDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/RemoveHistoryDialog.kt @@ -34,10 +34,10 @@ class RemoveHistoryDialog(bundle: Bundle? = null) : DialogController(bundle) } return MaterialDialog(activity) - .title(R.string.action_remove) - .customView(view = dialogCheckboxView, horizontalPadding = true) - .positiveButton(R.string.action_remove) { onPositive(dialogCheckboxView.isChecked()) } - .negativeButton(android.R.string.cancel) + .title(R.string.action_remove) + .customView(view = dialogCheckboxView, horizontalPadding = true) + .positiveButton(R.string.action_remove) { onPositive(dialogCheckboxView.isChecked()) } + .negativeButton(android.R.string.cancel) } private fun onPositive(checked: Boolean) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/ConfirmDeleteChaptersDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/ConfirmDeleteChaptersDialog.kt index 797a8fa3e2..4d4c048069 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/ConfirmDeleteChaptersDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/ConfirmDeleteChaptersDialog.kt @@ -19,11 +19,11 @@ class ConfirmDeleteChaptersDialog(bundle: Bundle? = null) : DialogController( override fun onCreateDialog(savedViewState: Bundle?): Dialog { return MaterialDialog(activity!!) - .message(R.string.confirm_delete_chapters) - .positiveButton(android.R.string.ok) { - (targetController as? Listener)?.deleteChapters(chaptersToDelete) - } - .negativeButton(android.R.string.cancel) + .message(R.string.confirm_delete_chapters) + .positiveButton(android.R.string.ok) { + (targetController as? Listener)?.deleteChapters(chaptersToDelete) + } + .negativeButton(android.R.string.cancel) } interface Listener { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesAdapter.kt index f12b440b51..0d0c7d9e87 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesAdapter.kt @@ -4,7 +4,7 @@ import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.items.IFlexible class UpdatesAdapter(val controller: UpdatesController) : - FlexibleAdapter>(null, controller, true) { + FlexibleAdapter>(null, controller, true) { val coverClickListener: OnCoverClickListener = controller diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesController.kt index 3a0a0704dc..c4dc2ba5d7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesController.kt @@ -37,15 +37,16 @@ import timber.log.Timber * Uses [R.layout.updates_controller]. * UI related actions should be called from here. */ -class UpdatesController : NucleusController(), - RootController, - NoToolbarElevationController, - ActionMode.Callback, - FlexibleAdapter.OnItemClickListener, - FlexibleAdapter.OnItemLongClickListener, - FlexibleAdapter.OnUpdateListener, - ConfirmDeleteChaptersDialog.Listener, - UpdatesAdapter.OnCoverClickListener { +class UpdatesController : + NucleusController(), + RootController, + NoToolbarElevationController, + ActionMode.Callback, + FlexibleAdapter.OnItemClickListener, + FlexibleAdapter.OnItemLongClickListener, + FlexibleAdapter.OnUpdateListener, + ConfirmDeleteChaptersDialog.Listener, + UpdatesAdapter.OnCoverClickListener { /** * Action mode for multiple selection. @@ -172,8 +173,8 @@ class UpdatesController : NucleusController selectAll() R.id.action_select_inverse -> selectInverse() R.id.action_download -> downloadChapters(getSelectedChapters()) - R.id.action_delete -> ConfirmDeleteChaptersDialog(this, getSelectedChapters()) + R.id.action_delete -> + ConfirmDeleteChaptersDialog(this, getSelectedChapters()) .showDialog(router) R.id.action_mark_as_read -> markAsRead(getSelectedChapters()) R.id.action_mark_as_unread -> markAsUnread(getSelectedChapters()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesHolder.kt index d8beb1f13f..6452278c72 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesHolder.kt @@ -25,7 +25,7 @@ import kotlinx.android.synthetic.main.updates_item.manga_title * @constructor creates a new recent chapter holder. */ class UpdatesHolder(private val view: View, private val adapter: UpdatesAdapter) : - BaseFlexibleViewHolder(view, adapter) { + BaseFlexibleViewHolder(view, adapter) { private var readColor = ContextCompat.getColor(view.context, R.color.material_on_surface_disabled) private var unreadColor = view.context.getResourceColor(R.attr.colorOnSurface) @@ -59,10 +59,10 @@ class UpdatesHolder(private val view: View, private val adapter: UpdatesAdapter) GlideApp.with(itemView.context).clear(manga_cover) if (!item.manga.thumbnail_url.isNullOrEmpty()) { GlideApp.with(itemView.context) - .load(item.manga.toMangaThumbnail()) - .diskCacheStrategy(DiskCacheStrategy.RESOURCE) - .circleCrop() - .into(manga_cover) + .load(item.manga.toMangaThumbnail()) + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .circleCrop() + .into(manga_cover) } // Check if chapter is read and set correct color diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesItem.kt index 56f1b52bcb..ecfc486ecd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesItem.kt @@ -12,7 +12,7 @@ import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.ui.recent.DateSectionItem class UpdatesItem(val chapter: Chapter, val manga: Manga, header: DateSectionItem) : - AbstractSectionableItem(header) { + AbstractSectionableItem(header) { private var _status: Int = 0 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt index acb5d9d819..86a75cd2dc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesPresenter.kt @@ -36,13 +36,13 @@ class UpdatesPresenter( super.onCreate(savedState) getUpdatesObservable() - .observeOn(AndroidSchedulers.mainThread()) - .subscribeLatestCache(UpdatesController::onNextRecentChapters) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeLatestCache(UpdatesController::onNextRecentChapters) getChapterStatusObservable() - .subscribeLatestCache(UpdatesController::onChapterStatusChange) { _, error -> - Timber.e(error) - } + .subscribeLatestCache(UpdatesController::onChapterStatusChange) { _, error -> + Timber.e(error) + } } /** @@ -58,32 +58,32 @@ class UpdatesPresenter( } return db.getRecentChapters(cal.time).asRxObservable() - // Convert to a list of recent chapters. - .map { mangaChapters -> - val map = TreeMap> { d1, d2 -> d2.compareTo(d1) } - val byDay = mangaChapters - .groupByTo(map, { it.chapter.date_fetch.toDateKey() }) - byDay.flatMap { entry -> - val dateItem = DateSectionItem(entry.key) - entry.value - .sortedWith(compareBy({ it.chapter.date_fetch }, { it.chapter.chapter_number })).asReversed() - .map { UpdatesItem(it.chapter, it.manga, dateItem) } - } + // Convert to a list of recent chapters. + .map { mangaChapters -> + val map = TreeMap> { d1, d2 -> d2.compareTo(d1) } + val byDay = mangaChapters + .groupByTo(map, { it.chapter.date_fetch.toDateKey() }) + byDay.flatMap { entry -> + val dateItem = DateSectionItem(entry.key) + entry.value + .sortedWith(compareBy({ it.chapter.date_fetch }, { it.chapter.chapter_number })).asReversed() + .map { UpdatesItem(it.chapter, it.manga, dateItem) } } - .doOnNext { list -> - list.forEach { item -> - // Find an active download for this chapter. - val download = downloadManager.queue.find { it.chapter.id == item.chapter.id } + } + .doOnNext { list -> + list.forEach { item -> + // Find an active download for this chapter. + val download = downloadManager.queue.find { it.chapter.id == item.chapter.id } - // If there's an active download, assign it, otherwise ask the manager if - // the chapter is downloaded and assign it to the status. - if (download != null) { - item.download = download - } + // If there's an active download, assign it, otherwise ask the manager if + // the chapter is downloaded and assign it to the status. + if (download != null) { + item.download = download } - setDownloadedChapters(list) - chapters = list } + setDownloadedChapters(list) + chapters = list + } } /** @@ -93,8 +93,8 @@ class UpdatesPresenter( */ private fun getChapterStatusObservable(): Observable { return downloadManager.queue.getStatusObservable() - .observeOn(AndroidSchedulers.mainThread()) - .doOnNext { download -> onDownloadStatusChange(download) } + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext { download -> onDownloadStatusChange(download) } } /** @@ -144,8 +144,8 @@ class UpdatesPresenter( } Observable.fromCallable { db.updateChaptersProgress(chapters).executeAsBlocking() } - .subscribeOn(Schedulers.io()) - .subscribe() + .subscribeOn(Schedulers.io()) + .subscribe() } /** @@ -155,12 +155,15 @@ class UpdatesPresenter( */ fun deleteChapters(chapters: List) { Observable.just(chapters) - .doOnNext { deleteChaptersInternal(it) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeFirst({ view, _ -> + .doOnNext { deleteChaptersInternal(it) } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeFirst( + { view, _ -> view.onChaptersDeleted() - }, UpdatesController::onChaptersDeletedError) + }, + UpdatesController::onChaptersDeletedError + ) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/security/BiometricUnlockActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/security/BiometricUnlockActivity.kt index 93db297313..0cc210c48c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/security/BiometricUnlockActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/security/BiometricUnlockActivity.kt @@ -20,24 +20,27 @@ class BiometricUnlockActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - val biometricPrompt = BiometricPrompt(this, executor, object : BiometricPrompt.AuthenticationCallback() { - override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { - super.onAuthenticationError(errorCode, errString) - finishAffinity() - } + val biometricPrompt = BiometricPrompt( + this, executor, + object : BiometricPrompt.AuthenticationCallback() { + override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { + super.onAuthenticationError(errorCode, errString) + finishAffinity() + } - override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) { - super.onAuthenticationSucceeded(result) - SecureActivityDelegate.locked = false - preferences.lastAppUnlock().set(Date().time) - finish() + override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) { + super.onAuthenticationSucceeded(result) + SecureActivityDelegate.locked = false + preferences.lastAppUnlock().set(Date().time) + finish() + } } - }) + ) val promptInfo = BiometricPrompt.PromptInfo.Builder() - .setTitle(getString(R.string.unlock_app)) - .setDeviceCredentialAllowed(true) - .build() + .setTitle(getString(R.string.unlock_app)) + .setDeviceCredentialAllowed(true) + .build() biometricPrompt.authenticate(promptInfo) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/security/SecureActivityDelegate.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/security/SecureActivityDelegate.kt index ffd7c1384c..a34a13819b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/security/SecureActivityDelegate.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/security/SecureActivityDelegate.kt @@ -42,8 +42,10 @@ class SecureActivityDelegate(private val activity: FragmentActivity) { private fun isAppLocked(): Boolean { return locked && - (preferences.lockAppAfter().get() <= 0 || - Date().time >= preferences.lastAppUnlock().get() + 60 * 1000 * preferences.lockAppAfter().get()) + ( + preferences.lockAppAfter().get() <= 0 || + Date().time >= preferences.lastAppUnlock().get() + 60 * 1000 * preferences.lockAppAfter().get() + ) } companion object { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt index d342fafeae..b4a6c9d696 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt @@ -117,39 +117,39 @@ class SettingsAdvancedController : SettingsController() { var deletedFiles = 0 Observable.defer { Observable.from(files) } - .doOnNext { file -> - if (chapterCache.removeFileFromCache(file.name)) { - deletedFiles++ - } + .doOnNext { file -> + if (chapterCache.removeFileFromCache(file.name)) { + deletedFiles++ } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnError { - activity?.toast(R.string.cache_delete_error) - } - .doOnCompleted { - activity?.toast(resources?.getString(R.string.cache_deleted, deletedFiles)) - findPreference(CLEAR_CACHE_KEY)?.summary = - resources?.getString(R.string.used_cache, chapterCache.readableSize) - } - .subscribe() + } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnError { + activity?.toast(R.string.cache_delete_error) + } + .doOnCompleted { + activity?.toast(resources?.getString(R.string.cache_deleted, deletedFiles)) + findPreference(CLEAR_CACHE_KEY)?.summary = + resources?.getString(R.string.used_cache, chapterCache.readableSize) + } + .subscribe() } class ClearDatabaseDialogController : DialogController() { override fun onCreateDialog(savedViewState: Bundle?): Dialog { return MaterialDialog(activity!!) - .message(R.string.clear_database_confirmation) - .positiveButton(android.R.string.ok) { - (targetController as? SettingsAdvancedController)?.clearDatabase() - } - .negativeButton(android.R.string.cancel) + .message(R.string.clear_database_confirmation) + .positiveButton(android.R.string.ok) { + (targetController as? SettingsAdvancedController)?.clearDatabase() + } + .negativeButton(android.R.string.cancel) } } private fun clearDatabase() { // Avoid weird behavior by going back to the library. val newBackstack = listOf(RouterTransaction.with(LibraryController())) + - router.backstack.drop(1) + router.backstack.drop(1) router.setBackstack(newBackstack, FadeChangeHandler()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt index 3f56d7ed3b..f5fa0eb449 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt @@ -106,9 +106,11 @@ class SettingsBackupController : SettingsController() { intListPreference { key = Keys.backupInterval titleRes = R.string.pref_backup_interval - entriesRes = arrayOf(R.string.update_never, R.string.update_6hour, - R.string.update_12hour, R.string.update_24hour, - R.string.update_48hour, R.string.update_weekly) + entriesRes = arrayOf( + R.string.update_never, R.string.update_6hour, + R.string.update_12hour, R.string.update_24hour, + R.string.update_48hour, R.string.update_weekly + ) entryValues = arrayOf("0", "6", "12", "24", "48", "168") defaultValue = "0" summary = "%s" @@ -168,7 +170,7 @@ class SettingsBackupController : SettingsController() { // Get UriPermission so it's possible to write files val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or - Intent.FLAG_GRANT_WRITE_URI_PERMISSION + Intent.FLAG_GRANT_WRITE_URI_PERMISSION if (uri != null) { activity.contentResolver.takePersistableUriPermission(uri, flags) @@ -182,7 +184,7 @@ class SettingsBackupController : SettingsController() { val uri = data.data val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or - Intent.FLAG_GRANT_WRITE_URI_PERMISSION + Intent.FLAG_GRANT_WRITE_URI_PERMISSION if (uri != null) { activity.contentResolver.takePersistableUriPermission(uri, flags) @@ -215,9 +217,9 @@ class SettingsBackupController : SettingsController() { try { // Use Android's built-in file creator val intent = Intent(Intent.ACTION_CREATE_DOCUMENT) - .addCategory(Intent.CATEGORY_OPENABLE) - .setType("application/*") - .putExtra(Intent.EXTRA_TITLE, Backup.getDefaultFilename()) + .addCategory(Intent.CATEGORY_OPENABLE) + .setType("application/*") + .putExtra(Intent.EXTRA_TITLE, Backup.getDefaultFilename()) startActivityForResult(intent, CODE_BACKUP_CREATE) } catch (e: ActivityNotFoundException) { @@ -229,51 +231,55 @@ class SettingsBackupController : SettingsController() { class CreateBackupDialog : DialogController() { override fun onCreateDialog(savedViewState: Bundle?): Dialog { val activity = activity!! - val options = arrayOf(R.string.manga, R.string.categories, R.string.chapters, - R.string.track, R.string.history) - .map { activity.getString(it) } + val options = arrayOf( + R.string.manga, R.string.categories, R.string.chapters, + R.string.track, R.string.history + ) + .map { activity.getString(it) } return MaterialDialog(activity) - .title(R.string.pref_create_backup) - .message(R.string.backup_choice) - .listItemsMultiChoice( - items = options, - disabledIndices = intArrayOf(0), - initialSelection = intArrayOf(0, 1, 2, 3, 4) - ) { _, positions, _ -> - var flags = 0 - for (i in 1 until positions.size) { - when (positions[i]) { - 1 -> flags = flags or BackupCreateService.BACKUP_CATEGORY - 2 -> flags = flags or BackupCreateService.BACKUP_CHAPTER - 3 -> flags = flags or BackupCreateService.BACKUP_TRACK - 4 -> flags = flags or BackupCreateService.BACKUP_HISTORY - } + .title(R.string.pref_create_backup) + .message(R.string.backup_choice) + .listItemsMultiChoice( + items = options, + disabledIndices = intArrayOf(0), + initialSelection = intArrayOf(0, 1, 2, 3, 4) + ) { _, positions, _ -> + var flags = 0 + for (i in 1 until positions.size) { + when (positions[i]) { + 1 -> flags = flags or BackupCreateService.BACKUP_CATEGORY + 2 -> flags = flags or BackupCreateService.BACKUP_CHAPTER + 3 -> flags = flags or BackupCreateService.BACKUP_TRACK + 4 -> flags = flags or BackupCreateService.BACKUP_HISTORY } - - (targetController as? SettingsBackupController)?.createBackup(flags) } - .positiveButton(R.string.action_create) - .negativeButton(android.R.string.cancel) + + (targetController as? SettingsBackupController)?.createBackup(flags) + } + .positiveButton(R.string.action_create) + .negativeButton(android.R.string.cancel) } } class RestoreBackupDialog(bundle: Bundle? = null) : DialogController(bundle) { - constructor(uri: Uri) : this(Bundle().apply { - putParcelable(KEY_URI, uri) - }) + constructor(uri: Uri) : this( + Bundle().apply { + putParcelable(KEY_URI, uri) + } + ) override fun onCreateDialog(savedViewState: Bundle?): Dialog { return MaterialDialog(activity!!) - .title(R.string.pref_restore_backup) - .message(R.string.backup_restore_content) - .positiveButton(R.string.action_restore) { - val context = applicationContext - if (context != null) { - BackupRestoreService.start(context, args.getParcelable(KEY_URI)!!) - isRestoreStarted = true - } + .title(R.string.pref_restore_backup) + .message(R.string.backup_restore_content) + .positiveButton(R.string.action_restore) { + val context = applicationContext + if (context != null) { + BackupRestoreService.start(context, args.getParcelable(KEY_URI)!!) + isRestoreStarted = true } + } } private companion object { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt index 07a723b313..4e6cc5e39a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt @@ -74,9 +74,11 @@ class SettingsDownloadController : SettingsController() { intListPreference { key = Keys.removeAfterReadSlots titleRes = R.string.pref_remove_after_read - entriesRes = arrayOf(R.string.disabled, R.string.last_read_chapter, - R.string.second_to_last, R.string.third_to_last, R.string.fourth_to_last, - R.string.fifth_to_last) + entriesRes = arrayOf( + R.string.disabled, R.string.last_read_chapter, + R.string.second_to_last, R.string.third_to_last, R.string.fourth_to_last, + R.string.fifth_to_last + ) entryValues = arrayOf("-1", "0", "1", "2", "3", "4") defaultValue = "-1" summary = "%s" @@ -107,13 +109,14 @@ class SettingsDownloadController : SettingsController() { preferences.downloadNewCategories().asFlow() .onEach { mutableSet -> val selectedCategories = mutableSet - .mapNotNull { id -> categories.find { it.id == id.toInt() } } - .sortedBy { it.order } + .mapNotNull { id -> categories.find { it.id == id.toInt() } } + .sortedBy { it.order } - summary = if (selectedCategories.isEmpty()) + summary = if (selectedCategories.isEmpty()) { resources?.getString(R.string.all) - else + } else { selectedCategories.joinToString { it.name } + } } .launchIn(scope) } @@ -126,7 +129,7 @@ class SettingsDownloadController : SettingsController() { val context = applicationContext ?: return val uri = data.data val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or - Intent.FLAG_GRANT_WRITE_URI_PERMISSION + Intent.FLAG_GRANT_WRITE_URI_PERMISSION if (uri != null) { @Suppress("NewApi") @@ -164,26 +167,26 @@ class SettingsDownloadController : SettingsController() { val selectedIndex = externalDirs.indexOfFirst { it in currentDir } return MaterialDialog(activity) - .listItemsSingleChoice( - items = externalDirs, - initialSelection = selectedIndex - ) { _, position, text -> - val target = targetController as? SettingsDownloadController - if (position == externalDirs.lastIndex) { - target?.customDirectorySelected(currentDir) - } else { - target?.predefinedDirectorySelected(text.toString()) - } + .listItemsSingleChoice( + items = externalDirs, + initialSelection = selectedIndex + ) { _, position, text -> + val target = targetController as? SettingsDownloadController + if (position == externalDirs.lastIndex) { + target?.customDirectorySelected(currentDir) + } else { + target?.predefinedDirectorySelected(text.toString()) } + } } private fun getExternalDirs(): List { val defaultDir = Environment.getExternalStorageDirectory().absolutePath + - File.separator + resources?.getString(R.string.app_name) + - File.separator + "downloads" + File.separator + resources?.getString(R.string.app_name) + + File.separator + "downloads" return mutableListOf(File(defaultDir)) + - ContextCompat.getExternalFilesDirs(activity!!, "").filterNotNull() + ContextCompat.getExternalFilesDirs(activity!!, "").filterNotNull() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt index b58fe3851b..971535c9a6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt @@ -30,9 +30,10 @@ class SettingsGeneralController : SettingsController() { key = Keys.startScreen titleRes = R.string.pref_start_screen entriesRes = arrayOf( - R.string.label_library, - R.string.label_recent_updates, - R.string.label_recent_manga) + R.string.label_library, + R.string.label_recent_updates, + R.string.label_recent_manga + ) entryValues = arrayOf("1", "3", "2") defaultValue = "1" summary = "%s" @@ -107,21 +108,25 @@ class SettingsGeneralController : SettingsController() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { entriesRes = arrayOf( - R.string.theme_system, - R.string.theme_light, - R.string.theme_dark) + R.string.theme_system, + R.string.theme_light, + R.string.theme_dark + ) entryValues = arrayOf( - Values.THEME_MODE_SYSTEM, - Values.THEME_MODE_LIGHT, - Values.THEME_MODE_DARK) + Values.THEME_MODE_SYSTEM, + Values.THEME_MODE_LIGHT, + Values.THEME_MODE_DARK + ) defaultValue = Values.THEME_MODE_SYSTEM } else { entriesRes = arrayOf( - R.string.theme_light, - R.string.theme_dark) + R.string.theme_light, + R.string.theme_dark + ) entryValues = arrayOf( - Values.THEME_MODE_LIGHT, - Values.THEME_MODE_DARK) + Values.THEME_MODE_LIGHT, + Values.THEME_MODE_DARK + ) defaultValue = Values.THEME_MODE_LIGHT } @@ -136,11 +141,13 @@ class SettingsGeneralController : SettingsController() { key = Keys.themeLight titleRes = R.string.pref_theme_light entriesRes = arrayOf( - R.string.theme_light_default, - R.string.theme_light_blue) + R.string.theme_light_default, + R.string.theme_light_blue + ) entryValues = arrayOf( - Values.THEME_LIGHT_DEFAULT, - Values.THEME_LIGHT_BLUE) + Values.THEME_LIGHT_DEFAULT, + Values.THEME_LIGHT_BLUE + ) defaultValue = Values.THEME_LIGHT_DEFAULT summary = "%s" @@ -160,13 +167,15 @@ class SettingsGeneralController : SettingsController() { key = Keys.themeDark titleRes = R.string.pref_theme_dark entriesRes = arrayOf( - R.string.theme_dark_default, - R.string.theme_dark_blue, - R.string.theme_dark_amoled) + R.string.theme_dark_default, + R.string.theme_dark_blue, + R.string.theme_dark_amoled + ) entryValues = arrayOf( - Values.THEME_DARK_DEFAULT, - Values.THEME_DARK_BLUE, - Values.THEME_DARK_AMOLED) + Values.THEME_DARK_DEFAULT, + Values.THEME_DARK_BLUE, + Values.THEME_DARK_AMOLED + ) defaultValue = Values.THEME_DARK_DEFAULT summary = "%s" diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt index a75f0a7592..0dfa2f688a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt @@ -53,22 +53,23 @@ class SettingsLibraryController : SettingsController() { } fun getColumnValue(value: Int): String { - return if (value == 0) + return if (value == 0) { context.getString(R.string.default_columns) - else + } else { value.toString() + } } Observable.combineLatest( - preferences.portraitColumns().asObservable(), - preferences.landscapeColumns().asObservable() + preferences.portraitColumns().asObservable(), + preferences.landscapeColumns().asObservable() ) { portraitCols, landscapeCols -> Pair(portraitCols, landscapeCols) } - .subscribeUntilDestroy { (portraitCols, landscapeCols) -> - val portrait = getColumnValue(portraitCols) - val landscape = getColumnValue(landscapeCols) - summary = "${context.getString(R.string.portrait)}: $portrait, " + - "${context.getString(R.string.landscape)}: $landscape" - } + .subscribeUntilDestroy { (portraitCols, landscapeCols) -> + val portrait = getColumnValue(portraitCols) + val landscape = getColumnValue(landscapeCols) + summary = "${context.getString(R.string.portrait)}: $portrait, " + + "${context.getString(R.string.landscape)}: $landscape" + } } } @@ -81,9 +82,11 @@ class SettingsLibraryController : SettingsController() { intListPreference { key = Keys.libraryUpdateInterval titleRes = R.string.pref_library_update_interval - entriesRes = arrayOf(R.string.update_never, R.string.update_1hour, - R.string.update_2hour, R.string.update_3hour, R.string.update_6hour, - R.string.update_12hour, R.string.update_24hour, R.string.update_48hour) + entriesRes = arrayOf( + R.string.update_never, R.string.update_1hour, + R.string.update_2hour, R.string.update_3hour, R.string.update_6hour, + R.string.update_12hour, R.string.update_24hour, R.string.update_48hour + ) entryValues = arrayOf("0", "1", "2", "3", "6", "12", "24", "48") defaultValue = "0" summary = "%s" @@ -124,13 +127,14 @@ class SettingsLibraryController : SettingsController() { preferences.libraryUpdateCategories().asFlow() .onEach { mutableSet -> val selectedCategories = mutableSet - .mapNotNull { id -> categories.find { it.id == id.toInt() } } - .sortedBy { it.order } + .mapNotNull { id -> categories.find { it.id == id.toInt() } } + .sortedBy { it.order } - summary = if (selectedCategories.isEmpty()) + summary = if (selectedCategories.isEmpty()) { context.getString(R.string.all) - else + } else { selectedCategories.joinToString { it.name } + } } .launchIn(scope) } @@ -141,8 +145,8 @@ class SettingsLibraryController : SettingsController() { // The following array lines up with the list rankingScheme in: // ../../data/library/LibraryUpdateRanker.kt val priorities = arrayOf( - Pair("0", R.string.action_sort_alpha), - Pair("1", R.string.action_sort_last_checked) + Pair("0", R.string.action_sort_alpha), + Pair("1", R.string.action_sort_last_checked) ) val defaultPriority = priorities[0] @@ -176,13 +180,13 @@ class SettingsLibraryController : SettingsController() { titleRes = R.string.default_category entries = arrayOf(context.getString(R.string.default_category_summary)) + - categories.map { it.name }.toTypedArray() + categories.map { it.name }.toTypedArray() entryValues = arrayOf("-1") + categories.map { it.id.toString() }.toTypedArray() defaultValue = "-1" val selectedCategory = categories.find { it.id == preferences.defaultCategory() } summary = selectedCategory?.name - ?: context.getString(R.string.default_category_summary) + ?: context.getString(R.string.default_category_summary) onChange { newValue -> summary = categories.find { it.id == (newValue as String).toInt() @@ -202,13 +206,13 @@ class SettingsLibraryController : SettingsController() { override fun onCreateDialog(savedViewState: Bundle?): Dialog { val dialog = MaterialDialog(activity!!) - .title(R.string.pref_library_columns) - .customView(R.layout.pref_library_columns) - .positiveButton(android.R.string.ok) { - preferences.portraitColumns().set(portrait) - preferences.landscapeColumns().set(landscape) - } - .negativeButton(android.R.string.cancel) + .title(R.string.pref_library_columns) + .customView(R.layout.pref_library_columns) + .positiveButton(android.R.string.ok) { + preferences.portraitColumns().set(portrait) + preferences.landscapeColumns().set(landscape) + } + .negativeButton(android.R.string.cancel) onViewCreated(dialog.view) return dialog @@ -217,7 +221,7 @@ class SettingsLibraryController : SettingsController() { fun onViewCreated(view: View) { with(view.portrait_columns) { displayedValues = arrayOf(context.getString(R.string.default_columns)) + - IntRange(1, 10).map(Int::toString) + IntRange(1, 10).map(Int::toString) value = portrait setOnValueChangedListener { _, _, newValue -> @@ -226,7 +230,7 @@ class SettingsLibraryController : SettingsController() { } with(view.landscape_columns) { displayedValues = arrayOf(context.getString(R.string.default_columns)) + - IntRange(1, 10).map(Int::toString) + IntRange(1, 10).map(Int::toString) value = landscape setOnValueChangedListener { _, _, newValue -> diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt index e40e123946..f484fbef90 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt @@ -22,8 +22,10 @@ class SettingsReaderController : SettingsController() { intListPreference { key = Keys.defaultViewer titleRes = R.string.pref_viewer_type - entriesRes = arrayOf(R.string.left_to_right_viewer, R.string.right_to_left_viewer, - R.string.vertical_viewer, R.string.webtoon_viewer, R.string.vertical_plus_viewer) + entriesRes = arrayOf( + R.string.left_to_right_viewer, R.string.right_to_left_viewer, + R.string.vertical_viewer, R.string.webtoon_viewer, R.string.vertical_plus_viewer + ) entryValues = arrayOf("1", "2", "3", "4", "5") defaultValue = "1" summary = "%s" @@ -31,9 +33,11 @@ class SettingsReaderController : SettingsController() { intListPreference { key = Keys.imageScaleType titleRes = R.string.pref_image_scale_type - entriesRes = arrayOf(R.string.scale_type_fit_screen, R.string.scale_type_stretch, - R.string.scale_type_fit_width, R.string.scale_type_fit_height, - R.string.scale_type_original_size, R.string.scale_type_smart_fit) + entriesRes = arrayOf( + R.string.scale_type_fit_screen, R.string.scale_type_stretch, + R.string.scale_type_fit_width, R.string.scale_type_fit_height, + R.string.scale_type_original_size, R.string.scale_type_smart_fit + ) entryValues = arrayOf("1", "2", "3", "4", "5", "6") defaultValue = "1" summary = "%s" @@ -41,8 +45,10 @@ class SettingsReaderController : SettingsController() { intListPreference { key = Keys.zoomStart titleRes = R.string.pref_zoom_start - entriesRes = arrayOf(R.string.zoom_start_automatic, R.string.zoom_start_left, - R.string.zoom_start_right, R.string.zoom_start_center) + entriesRes = arrayOf( + R.string.zoom_start_automatic, R.string.zoom_start_left, + R.string.zoom_start_right, R.string.zoom_start_center + ) entryValues = arrayOf("1", "2", "3", "4") defaultValue = "1" summary = "%s" @@ -50,8 +56,10 @@ class SettingsReaderController : SettingsController() { intListPreference { key = Keys.rotation titleRes = R.string.pref_rotation_type - entriesRes = arrayOf(R.string.rotation_free, R.string.rotation_lock, - R.string.rotation_force_portrait, R.string.rotation_force_landscape) + entriesRes = arrayOf( + R.string.rotation_free, R.string.rotation_lock, + R.string.rotation_force_portrait, R.string.rotation_force_landscape + ) entryValues = arrayOf("1", "2", "3", "4") defaultValue = "1" summary = "%s" @@ -159,7 +167,8 @@ class SettingsReaderController : SettingsController() { R.string.webtoon_side_padding_10, R.string.webtoon_side_padding_15, R.string.webtoon_side_padding_20, - R.string.webtoon_side_padding_25) + R.string.webtoon_side_padding_25 + ) entryValues = arrayOf("0", "10", "15", "20", "25") defaultValue = "0" summary = "%s" diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSourcesController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSourcesController.kt index f1fcbdd7a0..8a44bd0aec 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSourcesController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSourcesController.kt @@ -31,7 +31,7 @@ class SettingsSourcesController : SettingsController() { // Order first by active languages, then inactive ones val orderedLangs = sourcesByLang.keys.filter { it in activeLangsCodes } + - sourcesByLang.keys.filterNot { it in activeLangsCodes } + sourcesByLang.keys.filterNot { it in activeLangsCodes } orderedLangs.forEach { lang -> val sources = sourcesByLang[lang].orEmpty().sortedBy { it.name } @@ -91,10 +91,13 @@ class SettingsSourcesController : SettingsController() { val checked = newValue as Boolean val current = preferences.hiddenCatalogues().get() - preferences.hiddenCatalogues().set(if (checked) - current - id - else - current + id) + preferences.hiddenCatalogues().set( + if (checked) { + current - id + } else { + current + id + } + ) true } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsTrackingController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsTrackingController.kt index 356b48f967..1c3ec5f0f7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsTrackingController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsTrackingController.kt @@ -23,9 +23,10 @@ import eu.kanade.tachiyomi.widget.preference.TrackLoginDialog import eu.kanade.tachiyomi.widget.preference.TrackLogoutDialog import uy.kohesive.injekt.injectLazy -class SettingsTrackingController : SettingsController(), - TrackLoginDialog.Listener, - TrackLogoutDialog.Listener { +class SettingsTrackingController : + SettingsController(), + TrackLoginDialog.Listener, + TrackLogoutDialog.Listener { private val trackManager: TrackManager by injectLazy() @@ -47,8 +48,8 @@ class SettingsTrackingController : SettingsController(), } trackPreference(trackManager.aniList) { val tabsIntent = CustomTabsIntent.Builder() - .setToolbarColor(context.getResourceColor(R.attr.colorPrimary)) - .build() + .setToolbarColor(context.getResourceColor(R.attr.colorPrimary)) + .build() tabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY) tabsIntent.launchUrl(activity!!, AnilistApi.authUrl()) } @@ -59,15 +60,15 @@ class SettingsTrackingController : SettingsController(), } trackPreference(trackManager.shikimori) { val tabsIntent = CustomTabsIntent.Builder() - .setToolbarColor(context.getResourceColor(R.attr.colorPrimary)) - .build() + .setToolbarColor(context.getResourceColor(R.attr.colorPrimary)) + .build() tabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY) tabsIntent.launchUrl(activity!!, ShikimoriApi.authUrl()) } trackPreference(trackManager.bangumi) { val tabsIntent = CustomTabsIntent.Builder() - .setToolbarColor(context.getResourceColor(R.attr.colorPrimary)) - .build() + .setToolbarColor(context.getResourceColor(R.attr.colorPrimary)) + .build() tabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY) tabsIntent.launchUrl(activity!!, BangumiApi.authUrl()) } @@ -78,20 +79,23 @@ class SettingsTrackingController : SettingsController(), service: TrackService, crossinline login: () -> Unit ): LoginPreference { - return initThenAdd(LoginPreference(context).apply { - key = Keys.trackUsername(service.id) - title = service.name - }, { - onClick { - if (service.isLogged) { - val dialog = TrackLogoutDialog(service) - dialog.targetController = this@SettingsTrackingController - dialog.showDialog(router) - } else { - login() + return initThenAdd( + LoginPreference(context).apply { + key = Keys.trackUsername(service.id) + title = service.name + }, + { + onClick { + if (service.isLogged) { + val dialog = TrackLogoutDialog(service) + dialog.targetController = this@SettingsTrackingController + dialog.showDialog(router) + } else { + login() + } } } - }) + ) } override fun onActivityResumed(activity: Activity) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/backup/BackupNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/backup/BackupNotifier.kt index 449ca2561f..1016eed5d1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/backup/BackupNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/backup/BackupNotifier.kt @@ -64,9 +64,11 @@ internal class BackupNotifier(private val context: Context) { mActions.clear() } - addAction(R.drawable.ic_share_24dp, + addAction( + R.drawable.ic_share_24dp, context.getString(R.string.action_share), - NotificationReceiver.shareBackupPendingBroadcast(context, unifile.uri, Notifications.ID_BACKUP)) + NotificationReceiver.shareBackupPendingBroadcast(context, unifile.uri, Notifications.ID_BACKUP) + ) } notificationBuilder.show(Notifications.ID_BACKUP) @@ -84,9 +86,11 @@ internal class BackupNotifier(private val context: Context) { mActions.clear() } - addAction(R.drawable.ic_close_24dp, + addAction( + R.drawable.ic_close_24dp, context.getString(R.string.action_stop), - NotificationReceiver.cancelRestorePendingBroadcast(context, Notifications.ID_RESTORE)) + NotificationReceiver.cancelRestorePendingBroadcast(context, Notifications.ID_RESTORE) + ) } builder.show(Notifications.ID_RESTORE) @@ -107,10 +111,12 @@ internal class BackupNotifier(private val context: Context) { } fun showRestoreComplete(time: Long, errorCount: Int, path: String?, file: String?) { - val timeString = String.format("%02d min, %02d sec", + val timeString = String.format( + "%02d min, %02d sec", TimeUnit.MILLISECONDS.toMinutes(time), TimeUnit.MILLISECONDS.toSeconds(time) - TimeUnit.MINUTES.toSeconds( - TimeUnit.MILLISECONDS.toMinutes(time)) + TimeUnit.MILLISECONDS.toMinutes(time) + ) ) with(notificationBuilder) { @@ -132,9 +138,11 @@ internal class BackupNotifier(private val context: Context) { val destFile = File(path, file) val uri = destFile.getUriCompat(context) - addAction(R.drawable.nnf_ic_file_folder, + addAction( + R.drawable.nnf_ic_file_folder, context.getString(R.string.action_open_log), - NotificationReceiver.openErrorLogPendingActivity(context, uri)) + NotificationReceiver.openErrorLogPendingActivity(context, uri) + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/AnilistLoginActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/AnilistLoginActivity.kt index d0ced84f05..ba2448705c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/AnilistLoginActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/AnilistLoginActivity.kt @@ -27,13 +27,16 @@ class AnilistLoginActivity : AppCompatActivity() { val matchResult = regex.find(intent.data?.fragment.toString()) if (matchResult?.groups?.get(1) != null) { trackManager.aniList.login(matchResult.groups[1]!!.value) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { returnToSettings() - }, { + }, + { returnToSettings() - }) + } + ) } else { trackManager.aniList.logout() returnToSettings() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/BangumiLoginActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/BangumiLoginActivity.kt index 772d3866f9..76e1ca3049 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/BangumiLoginActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/BangumiLoginActivity.kt @@ -26,13 +26,16 @@ class BangumiLoginActivity : AppCompatActivity() { val code = intent.data?.getQueryParameter("code") if (code != null) { trackManager.bangumi.login(code) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { returnToSettings() - }, { + }, + { returnToSettings() - }) + } + ) } else { trackManager.bangumi.logout() returnToSettings() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/ShikimoriLoginActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/ShikimoriLoginActivity.kt index b109d34214..4cb217d850 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/ShikimoriLoginActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/ShikimoriLoginActivity.kt @@ -26,13 +26,16 @@ class ShikimoriLoginActivity : AppCompatActivity() { val code = intent.data?.getQueryParameter("code") if (code != null) { trackManager.shikimori.login(code) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { returnToSettings() - }, { + }, + { returnToSettings() - }) + } + ) } else { trackManager.shikimori.logout() returnToSettings() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/LangHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/LangHolder.kt index 08c10d197b..f22bf6b02d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/LangHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/LangHolder.kt @@ -7,7 +7,7 @@ import eu.kanade.tachiyomi.util.system.LocaleHelper import kotlinx.android.synthetic.main.source_main_controller_card.title class LangHolder(view: View, adapter: FlexibleAdapter<*>) : - BaseFlexibleViewHolder(view, adapter) { + BaseFlexibleViewHolder(view, adapter) { fun bind(item: LangItem) { title.text = LocaleHelper.getSourceDisplayName(item.code, itemView.context) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceAdapter.kt index cb23a9deb0..206d26a915 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceAdapter.kt @@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.util.system.getResourceColor * @param controller instance of [SourceController]. */ class SourceAdapter(val controller: SourceController) : - FlexibleAdapter>(null, controller, true) { + FlexibleAdapter>(null, controller, true) { val cardBackground = controller.activity!!.getResourceColor(R.attr.colorSurface) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceController.kt index 8aa3f0e4d8..3d5fe1daca 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceController.kt @@ -28,7 +28,7 @@ import eu.kanade.tachiyomi.ui.base.controller.requestPermissionsSafe import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.setting.SettingsSourcesController import eu.kanade.tachiyomi.ui.source.browse.BrowseSourceController -import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchController +import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchController import eu.kanade.tachiyomi.ui.source.latest.LatestUpdatesController import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.launchIn @@ -44,12 +44,13 @@ import uy.kohesive.injekt.api.get * [SourceAdapter.OnBrowseClickListener] call function data on browse item click. * [SourceAdapter.OnLatestClickListener] call function data on latest item click */ -class SourceController : NucleusController(), - RootController, - FlexibleAdapter.OnItemClickListener, - FlexibleAdapter.OnItemLongClickListener, - SourceAdapter.OnBrowseClickListener, - SourceAdapter.OnLatestClickListener { +class SourceController : + NucleusController(), + RootController, + FlexibleAdapter.OnItemClickListener, + FlexibleAdapter.OnItemLongClickListener, + SourceAdapter.OnBrowseClickListener, + SourceAdapter.OnLatestClickListener { private val preferences: PreferencesHelper = Injekt.get() @@ -122,21 +123,21 @@ class SourceController : NucleusController - when (which) { - 0 -> hideCatalogue(item.source) - 1 -> pinCatalogue(item.source, isPinned) - } - dialog.dismiss() + .title(text = item.source.name) + .listItems( + items = listOf( + activity.getString(R.string.action_hide), + activity.getString(if (isPinned) R.string.action_unpin else R.string.action_pin) + ), + waitForPositiveButton = false + ) { dialog, which, _ -> + when (which) { + 0 -> hideCatalogue(item.source) + 1 -> pinCatalogue(item.source, isPinned) } - .show() + dialog.dismiss() + } + .show() } private fun hideCatalogue(source: Source) { @@ -218,9 +219,11 @@ class SourceController : NucleusController { - router.pushController((RouterTransaction.with(SettingsSourcesController())) + router.pushController( + (RouterTransaction.with(SettingsSourcesController())) .popChangeHandler(SettingsSourcesFadeChangeHandler()) - .pushChangeHandler(FadeChangeHandler())) + .pushChangeHandler(FadeChangeHandler()) + ) } } return super.onOptionsItemSelected(item) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceDividerItemDecoration.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceDividerItemDecoration.kt index 625696d75d..b5df257e92 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceDividerItemDecoration.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceDividerItemDecoration.kt @@ -23,7 +23,8 @@ class SourceDividerItemDecoration(context: Context) : RecyclerView.ItemDecoratio val child = parent.getChildAt(i) val holder = parent.getChildViewHolder(child) if (holder is SourceHolder && - parent.getChildViewHolder(parent.getChildAt(i + 1)) is SourceHolder) { + parent.getChildViewHolder(parent.getChildAt(i + 1)) is SourceHolder + ) { val params = child.layoutParams as RecyclerView.LayoutParams val top = child.bottom + params.bottomMargin val bottom = top + divider.intrinsicHeight diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceHolder.kt index 3388f85a35..43c9882dda 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceHolder.kt @@ -16,8 +16,8 @@ import kotlinx.android.synthetic.main.source_main_controller_card_item.source_la import kotlinx.android.synthetic.main.source_main_controller_card_item.title class SourceHolder(view: View, override val adapter: SourceAdapter) : - BaseFlexibleViewHolder(view, adapter), - SlicedHolder { + BaseFlexibleViewHolder(view, adapter), + SlicedHolder { override val slice = Slice(card).apply { setColor(adapter.cardBackground) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceItem.kt index e98180bed0..19a466e38e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceItem.kt @@ -15,7 +15,7 @@ import eu.kanade.tachiyomi.source.CatalogueSource * @param header The header for this item. */ data class SourceItem(val source: CatalogueSource, val header: LangItem? = null) : - AbstractSectionableItem(header) { + AbstractSectionableItem(header) { /** * Returns the layout resource of this item. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourcePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourcePresenter.kt index fc5c6a46f6..3c9225f67e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourcePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/SourcePresenter.kt @@ -75,7 +75,7 @@ class SourcePresenter( } sourceSubscription = Observable.just(sourceItems) - .subscribeLatestCache(SourceController::setSources) + .subscribeLatestCache(SourceController::setSources) } private fun loadLastUsedSource() { @@ -83,11 +83,12 @@ class SourcePresenter( // Emit the first item immediately but delay subsequent emissions by 500ms. Observable.merge( - sharedObs.take(1), - sharedObs.skip(1).delay(500, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())) - .distinctUntilChanged() - .map { item -> (sourceManager.get(item) as? CatalogueSource)?.let { SourceItem(it) } } - .subscribeLatestCache(SourceController::setLastUsedSource) + sharedObs.take(1), + sharedObs.skip(1).delay(500, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread()) + ) + .distinctUntilChanged() + .map { item -> (sourceManager.get(item) as? CatalogueSource)?.let { SourceItem(it) } } + .subscribeLatestCache(SourceController::setLastUsedSource) } fun updateSources() { @@ -105,10 +106,10 @@ class SourcePresenter( val hiddenCatalogues = preferences.hiddenCatalogues().get() return sourceManager.getCatalogueSources() - .filter { it.lang in languages } - .filterNot { it.id.toString() in hiddenCatalogues } - .sortedBy { "(${it.lang}) ${it.name}" } + - sourceManager.get(LocalSource.ID) as LocalSource + .filter { it.lang in languages } + .filterNot { it.id.toString() in hiddenCatalogues } + .sortedBy { "(${it.lang}) ${it.name}" } + + sourceManager.get(LocalSource.ID) as LocalSource } companion object { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourceController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourceController.kt index 94b346aa69..9544acef4d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourceController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourceController.kt @@ -56,15 +56,17 @@ import uy.kohesive.injekt.injectLazy * Controller to manage the catalogues available in the app. */ open class BrowseSourceController(bundle: Bundle) : - NucleusController(bundle), - FlexibleAdapter.OnItemClickListener, - FlexibleAdapter.OnItemLongClickListener, - FlexibleAdapter.EndlessScrollListener, - ChangeMangaCategoriesDialog.Listener { + NucleusController(bundle), + FlexibleAdapter.OnItemClickListener, + FlexibleAdapter.OnItemLongClickListener, + FlexibleAdapter.EndlessScrollListener, + ChangeMangaCategoriesDialog.Listener { - constructor(source: CatalogueSource) : this(Bundle().apply { - putLong(SOURCE_ID_KEY, source.id) - }) + constructor(source: CatalogueSource) : this( + Bundle().apply { + putLong(SOURCE_ID_KEY, source.id) + } + ) private val preferences: PreferencesHelper by injectLazy() @@ -185,10 +187,10 @@ open class BrowseSourceController(bundle: Bundle) : } else { (binding.catalogueView.inflate(R.layout.source_recycler_autofit) as AutofitRecyclerView).apply { numColumnsSubscription = getColumnsPreferenceForCurrentOrientation().asObservable() - .doOnNext { spanCount = it } - .skip(1) - // Set again the adapter to recalculate the covers height - .subscribe { adapter = this@BrowseSourceController.adapter } + .doOnNext { spanCount = it } + .skip(1) + // Set again the adapter to recalculate the covers height + .subscribe { adapter = this@BrowseSourceController.adapter } (layoutManager as GridLayoutManager).spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { @@ -246,19 +248,20 @@ open class BrowseSourceController(bundle: Bundle) : .launchIn(scope) searchItem.fixExpand( - onExpand = { invalidateMenuOnExpand() }, - onCollapse = { - searchWithQuery("") - true - } + onExpand = { invalidateMenuOnExpand() }, + onCollapse = { + searchWithQuery("") + true + } ) // Show next display mode menu.findItem(R.id.action_display_mode).apply { - val icon = if (presenter.isListMode) + val icon = if (presenter.isListMode) { R.drawable.ic_view_module_24dp - else + } else { R.drawable.ic_view_list_24dp + } setIcon(icon) } } @@ -302,8 +305,9 @@ open class BrowseSourceController(bundle: Bundle) : */ fun searchWithQuery(newQuery: String) { // If text didn't change, do nothing - if (presenter.query == newQuery) + if (presenter.query == newQuery) { return + } showProgressBar() adapter?.clear() @@ -342,7 +346,6 @@ open class BrowseSourceController(bundle: Bundle) : val message = getErrorMessage(error) val retryAction = View.OnClickListener { - // If not the first page, show bottom progress bar. if (adapter.mainItemCount > 0 && progressItem != null) { adapter.addScrollableFooterWithDelay(progressItem!!, 0, true) @@ -444,10 +447,11 @@ open class BrowseSourceController(bundle: Bundle) : * @return the preference. */ fun getColumnsPreferenceForCurrentOrientation(): Preference { - return if (resources?.configuration?.orientation == Configuration.ORIENTATION_PORTRAIT) + return if (resources?.configuration?.orientation == Configuration.ORIENTATION_PORTRAIT) { preferences.portraitColumns() - else + } else { preferences.landscapeColumns() + } } /** @@ -514,19 +518,19 @@ open class BrowseSourceController(bundle: Bundle) : if (manga.favorite) { MaterialDialog(activity) - .listItems( - items = listOf(activity.getString(R.string.remove_from_library)), - waitForPositiveButton = false - ) { _, which, _ -> - when (which) { - 0 -> { - presenter.changeMangaFavorite(manga) - adapter?.notifyItemChanged(position) - activity.toast(activity.getString(R.string.manga_removed_library)) - } + .listItems( + items = listOf(activity.getString(R.string.remove_from_library)), + waitForPositiveButton = false + ) { _, which, _ -> + when (which) { + 0 -> { + presenter.changeMangaFavorite(manga) + adapter?.notifyItemChanged(position) + activity.toast(activity.getString(R.string.manga_removed_library)) } } - .show() + } + .show() } else { val categories = presenter.getCategories() val defaultCategoryId = preferences.defaultCategory() @@ -559,7 +563,7 @@ open class BrowseSourceController(bundle: Bundle) : }.toTypedArray() ChangeMangaCategoriesDialog(this, listOf(manga), categories, preselected) - .showDialog(router) + .showDialog(router) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourcePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourcePresenter.kt index d382ed16c6..f342f2e651 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourcePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourcePresenter.kt @@ -115,8 +115,10 @@ open class BrowseSourcePresenter( query = savedState.getString(::query.name, "") } - add(prefs.catalogueAsList().asObservable() - .subscribe { setDisplayMode(it) }) + add( + prefs.catalogueAsList().asObservable() + .subscribe { setDisplayMode(it) } + ) restartPager() } @@ -148,16 +150,19 @@ open class BrowseSourcePresenter( // Prepare the pager. pagerSubscription?.let { remove(it) } pagerSubscription = pager.results() - .observeOn(Schedulers.io()) - .map { pair -> pair.first to pair.second.map { networkToLocalManga(it, sourceId) } } - .doOnNext { initializeMangas(it.second) } - .map { pair -> pair.first to pair.second.map { SourceItem(it, catalogueAsList) } } - .observeOn(AndroidSchedulers.mainThread()) - .subscribeReplay({ view, (page, mangas) -> + .observeOn(Schedulers.io()) + .map { pair -> pair.first to pair.second.map { networkToLocalManga(it, sourceId) } } + .doOnNext { initializeMangas(it.second) } + .map { pair -> pair.first to pair.second.map { SourceItem(it, catalogueAsList) } } + .observeOn(AndroidSchedulers.mainThread()) + .subscribeReplay( + { view, (page, mangas) -> view.onAddPage(page, mangas) - }, { _, error -> + }, + { _, error -> Timber.e(error) - }) + } + ) // Request first page. requestNext() @@ -171,9 +176,12 @@ open class BrowseSourcePresenter( pageSubscription?.let { remove(it) } pageSubscription = Observable.defer { pager.requestNext() } - .subscribeFirst({ _, _ -> + .subscribeFirst( + { _, _ -> // Nothing to do when onNext is emitted. - }, BrowseSourceController::onAddPageError) + }, + BrowseSourceController::onAddPageError + ) } /** @@ -199,18 +207,21 @@ open class BrowseSourcePresenter( private fun subscribeToMangaInitializer() { initializerSubscription?.let { remove(it) } initializerSubscription = mangaDetailSubject.observeOn(Schedulers.io()) - .flatMap { Observable.from(it) } - .filter { it.thumbnail_url == null && !it.initialized } - .concatMap { getMangaDetailsObservable(it) } - .onBackpressureBuffer() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ manga -> + .flatMap { Observable.from(it) } + .filter { it.thumbnail_url == null && !it.initialized } + .concatMap { getMangaDetailsObservable(it) } + .onBackpressureBuffer() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { manga -> @Suppress("DEPRECATION") view?.onMangaInitialized(manga) - }, { error -> + }, + { error -> Timber.e(error) - }) - .apply { add(this) } + } + ) + .apply { add(this) } } /** @@ -249,13 +260,13 @@ open class BrowseSourcePresenter( */ private fun getMangaDetailsObservable(manga: Manga): Observable { return source.fetchMangaDetails(manga) - .flatMap { networkManga -> - manga.copyFrom(networkManga) - manga.initialized = true - db.insertManga(manga).executeAsBlocking() - Observable.just(manga) - } - .onErrorResumeNext { Observable.just(manga) } + .flatMap { networkManga -> + manga.copyFrom(networkManga) + manga.initialized = true + db.insertManga(manga).executeAsBlocking() + Observable.just(manga) + } + .onErrorResumeNext { Observable.just(manga) } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/SourceGridHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/SourceGridHolder.kt index ffdf84b0e1..edbbe91a7d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/SourceGridHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/SourceGridHolder.kt @@ -20,7 +20,7 @@ import kotlinx.android.synthetic.main.source_grid_item.title * @constructor creates a new catalogue holder. */ class SourceGridHolder(private val view: View, private val adapter: FlexibleAdapter<*>) : - SourceHolder(view, adapter) { + SourceHolder(view, adapter) { /** * Method called from [CatalogueAdapter.onBindViewHolder]. It updates the data for this @@ -42,11 +42,11 @@ class SourceGridHolder(private val view: View, private val adapter: FlexibleAdap GlideApp.with(view.context).clear(thumbnail) if (!manga.thumbnail_url.isNullOrEmpty()) { GlideApp.with(view.context) - .load(manga.toMangaThumbnail()) - .diskCacheStrategy(DiskCacheStrategy.DATA) - .centerCrop() - .placeholder(android.R.color.transparent) - .into(StateImageViewTarget(thumbnail, progress)) + .load(manga.toMangaThumbnail()) + .diskCacheStrategy(DiskCacheStrategy.DATA) + .centerCrop() + .placeholder(android.R.color.transparent) + .into(StateImageViewTarget(thumbnail, progress)) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/SourceHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/SourceHolder.kt index f0dc346c76..c80ea9094b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/SourceHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/SourceHolder.kt @@ -12,7 +12,7 @@ import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder * @param adapter the adapter handling this holder. */ abstract class SourceHolder(view: View, adapter: FlexibleAdapter<*>) : - BaseFlexibleViewHolder(view, adapter) { + BaseFlexibleViewHolder(view, adapter) { /** * Method called from [CatalogueAdapter.onBindViewHolder]. It updates the data for this diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/SourceItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/SourceItem.kt index d12788c416..24fec5205c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/SourceItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/SourceItem.kt @@ -17,13 +17,14 @@ import kotlinx.android.synthetic.main.source_grid_item.view.card import kotlinx.android.synthetic.main.source_grid_item.view.gradient class SourceItem(val manga: Manga, private val catalogueAsList: Preference) : - AbstractFlexibleItem() { + AbstractFlexibleItem() { override fun getLayoutRes(): Int { - return if (catalogueAsList.getOrDefault()) + return if (catalogueAsList.getOrDefault()) { R.layout.source_list_item - else + } else { R.layout.source_grid_item + } } override fun createViewHolder( @@ -34,9 +35,11 @@ class SourceItem(val manga: Manga, private val catalogueAsList: Preference) : - SourceHolder(view, adapter) { + SourceHolder(view, adapter) { private val favoriteColor = ContextCompat.getColor(view.context, R.color.material_on_surface_disabled) private val unfavoriteColor = view.context.getResourceColor(R.attr.colorOnSurface) @@ -43,13 +43,13 @@ class SourceListHolder(private val view: View, adapter: FlexibleAdapter<*>) : GlideApp.with(view.context).clear(thumbnail) if (!manga.thumbnail_url.isNullOrEmpty()) { GlideApp.with(view.context) - .load(manga.toMangaThumbnail()) - .diskCacheStrategy(DiskCacheStrategy.DATA) - .centerCrop() - .circleCrop() - .dontAnimate() - .placeholder(android.R.color.transparent) - .into(thumbnail) + .load(manga.toMangaThumbnail()) + .diskCacheStrategy(DiskCacheStrategy.DATA) + .centerCrop() + .circleCrop() + .dontAnimate() + .placeholder(android.R.color.transparent) + .into(thumbnail) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/SourcePager.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/SourcePager.kt index ea9e050d95..7720dc8f54 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/SourcePager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/SourcePager.kt @@ -12,20 +12,21 @@ open class SourcePager(val source: CatalogueSource, val query: String, val filte override fun requestNext(): Observable { val page = currentPage - val observable = if (query.isBlank() && filters.isEmpty()) + val observable = if (query.isBlank() && filters.isEmpty()) { source.fetchPopularManga(page) - else + } else { source.fetchSearchManga(page, query, filters) + } return observable - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnNext { - if (it.mangas.isNotEmpty()) { - onPageReceived(it) - } else { - throw NoResultsException() - } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext { + if (it.mangas.isNotEmpty()) { + onPageReceived(it) + } else { + throw NoResultsException() } + } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/GroupItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/GroupItem.kt index 214f0c0c15..574f7e9bb0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/GroupItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/GroupItem.kt @@ -34,10 +34,13 @@ class GroupItem(val filter: Filter.Group<*>) : AbstractExpandableHeaderItem>, holder: Holder, position: Int, payloads: List?) { holder.title.text = filter.name - holder.icon.setVectorCompat(if (isExpanded) - R.drawable.ic_expand_more_white_24dp - else - R.drawable.ic_chevron_right_white_24dp) + holder.icon.setVectorCompat( + if (isExpanded) { + R.drawable.ic_expand_more_white_24dp + } else { + R.drawable.ic_chevron_right_white_24dp + } + ) holder.itemView.setOnClickListener(holder) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/SelectItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/SelectItem.kt index 0ded86435f..2c872e6c0c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/SelectItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/SelectItem.kt @@ -28,8 +28,10 @@ open class SelectItem(val filter: Filter.Select<*>) : AbstractFlexibleItem(holder.itemView.context, - android.R.layout.simple_spinner_item, filter.values).apply { + spinner.adapter = ArrayAdapter( + holder.itemView.context, + android.R.layout.simple_spinner_item, filter.values + ).apply { setDropDownViewResource(R.layout.common_spinner_item) } spinner.onItemSelectedListener = IgnoreFirstSpinnerListener { pos -> diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/SortGroup.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/SortGroup.kt index 73c96f2247..e0023268ea 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/SortGroup.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/SortGroup.kt @@ -31,10 +31,13 @@ class SortGroup(val filter: Filter.Sort) : AbstractExpandableHeaderItem>, holder: Holder, position: Int, payloads: List?) { holder.title.text = filter.name - holder.icon.setVectorCompat(if (isExpanded) - R.drawable.ic_expand_more_white_24dp - else - R.drawable.ic_chevron_right_white_24dp) + holder.icon.setVectorCompat( + if (isExpanded) { + R.drawable.ic_expand_more_white_24dp + } else { + R.drawable.ic_chevron_right_white_24dp + } + ) holder.itemView.setOnClickListener(holder) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/SortItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/SortItem.kt index ae557773d8..0341669b47 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/SortItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/SortItem.kt @@ -35,9 +35,11 @@ class SortItem(val name: String, val group: SortGroup) : AbstractSectionableItem val i = filter.values.indexOf(name) fun getIcon() = when (filter.state) { - Filter.Sort.Selection(i, false) -> VectorDrawableCompat.create(view.resources, R.drawable.ic_arrow_down_white_32dp, null) + Filter.Sort.Selection(i, false) -> + VectorDrawableCompat.create(view.resources, R.drawable.ic_arrow_down_white_32dp, null) ?.apply { setTint(view.context.getResourceColor(R.attr.colorAccent)) } - Filter.Sort.Selection(i, true) -> VectorDrawableCompat.create(view.resources, R.drawable.ic_arrow_up_white_32dp, null) + Filter.Sort.Selection(i, true) -> + VectorDrawableCompat.create(view.resources, R.drawable.ic_arrow_up_white_32dp, null) ?.apply { setTint(view.context.getResourceColor(R.attr.colorAccent)) } else -> ContextCompat.getDrawable(view.context, R.drawable.empty_drawable_32dp) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/TriStateItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/TriStateItem.kt index ee60e504e0..1237b0329e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/TriStateItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/filter/TriStateItem.kt @@ -33,16 +33,21 @@ open class TriStateItem(val filter: Filter.TriState) : AbstractFlexibleItem TR.drawable.ic_check_box_outline_blank_24dp - Filter.TriState.STATE_INCLUDE -> TR.drawable.ic_check_box_24dp - Filter.TriState.STATE_EXCLUDE -> TR.drawable.ic_check_box_x_24dp - else -> throw Exception("Unknown state") - }, null)?.apply { - val color = if (filter.state == Filter.TriState.STATE_INCLUDE) + fun getIcon() = VectorDrawableCompat.create( + view.resources, + when (filter.state) { + Filter.TriState.STATE_IGNORE -> TR.drawable.ic_check_box_outline_blank_24dp + Filter.TriState.STATE_INCLUDE -> TR.drawable.ic_check_box_24dp + Filter.TriState.STATE_EXCLUDE -> TR.drawable.ic_check_box_x_24dp + else -> throw Exception("Unknown state") + }, + null + )?.apply { + val color = if (filter.state == Filter.TriState.STATE_INCLUDE) { view.context.getResourceColor(R.attr.colorAccent) - else + } else { ContextCompat.getColor(view.context, R.color.material_on_background_disabled) + } setTint(color) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchAdapter.kt similarity index 95% rename from app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchAdapter.kt rename to app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchAdapter.kt index ecf15d1991..e9f520291d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchAdapter.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.ui.source.global_search +package eu.kanade.tachiyomi.ui.source.globalsearch import android.os.Bundle import android.os.Parcelable @@ -12,7 +12,7 @@ import eu.davidea.flexibleadapter.FlexibleAdapter * @param controller instance of [GlobalSearchController]. */ class GlobalSearchAdapter(val controller: GlobalSearchController) : - FlexibleAdapter(null, controller, true) { + FlexibleAdapter(null, controller, true) { /** * Bundle where the view state of the holders is saved. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchCardAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchCardAdapter.kt similarity index 84% rename from app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchCardAdapter.kt rename to app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchCardAdapter.kt index c684ab2570..f0ca3e11b2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchCardAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchCardAdapter.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.ui.source.global_search +package eu.kanade.tachiyomi.ui.source.globalsearch import eu.davidea.flexibleadapter.FlexibleAdapter import eu.kanade.tachiyomi.data.database.models.Manga @@ -9,7 +9,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga * @param controller instance of [GlobalSearchController]. */ class GlobalSearchCardAdapter(controller: GlobalSearchController) : - FlexibleAdapter(null, controller, true) { + FlexibleAdapter(null, controller, true) { /** * Listen for browse item clicks. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchCardHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchCardHolder.kt similarity index 81% rename from app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchCardHolder.kt rename to app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchCardHolder.kt index 0cb9f69e56..8fd987cbf8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchCardHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchCardHolder.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.ui.source.global_search +package eu.kanade.tachiyomi.ui.source.globalsearch import android.view.View import com.bumptech.glide.load.engine.DiskCacheStrategy @@ -43,12 +43,12 @@ class GlobalSearchCardHolder(view: View, adapter: GlobalSearchCardAdapter) : GlideApp.with(itemView.context).clear(itemImage) if (!manga.thumbnail_url.isNullOrEmpty()) { GlideApp.with(itemView.context) - .load(manga.toMangaThumbnail()) - .diskCacheStrategy(DiskCacheStrategy.DATA) - .centerCrop() - .skipMemoryCache(true) - .placeholder(android.R.color.transparent) - .into(StateImageViewTarget(itemImage, progress)) + .load(manga.toMangaThumbnail()) + .diskCacheStrategy(DiskCacheStrategy.DATA) + .centerCrop() + .skipMemoryCache(true) + .placeholder(android.R.color.transparent) + .into(StateImageViewTarget(itemImage, progress)) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchCardItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchCardItem.kt similarity index 95% rename from app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchCardItem.kt rename to app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchCardItem.kt index fdcf85cdc5..4fd8fe358b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchCardItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchCardItem.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.ui.source.global_search +package eu.kanade.tachiyomi.ui.source.globalsearch import android.view.View import androidx.recyclerview.widget.RecyclerView diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchController.kt similarity index 98% rename from app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchController.kt rename to app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchController.kt index 32da8a8e3c..e70b247c4d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchController.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.ui.source.global_search +package eu.kanade.tachiyomi.ui.source.globalsearch import android.os.Bundle import android.view.LayoutInflater @@ -31,7 +31,7 @@ open class GlobalSearchController( protected val initialQuery: String? = null, protected val extensionFilter: String? = null ) : NucleusController(), - GlobalSearchCardAdapter.OnMangaClickListener { + GlobalSearchCardAdapter.OnMangaClickListener { /** * Adapter containing search results grouped by lang. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchHolder.kt similarity index 96% rename from app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchHolder.kt rename to app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchHolder.kt index 54e8b51036..91db3e83a4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchHolder.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.ui.source.global_search +package eu.kanade.tachiyomi.ui.source.globalsearch import android.view.View import androidx.recyclerview.widget.LinearLayoutManager @@ -18,7 +18,7 @@ import kotlinx.android.synthetic.main.global_search_controller_card.title * @param adapter instance of [GlobalSearchAdapter] */ class GlobalSearchHolder(view: View, val adapter: GlobalSearchAdapter) : - BaseFlexibleViewHolder(view, adapter) { + BaseFlexibleViewHolder(view, adapter) { /** * Adapter containing manga from search results. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchItem.kt similarity index 97% rename from app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchItem.kt rename to app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchItem.kt index 14ec8617f5..34dd955030 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchItem.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.ui.source.global_search +package eu.kanade.tachiyomi.ui.source.globalsearch import android.view.View import androidx.recyclerview.widget.RecyclerView diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchPresenter.kt similarity index 71% rename from app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchPresenter.kt rename to app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchPresenter.kt index d48713c9f8..a71370f252 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/globalsearch/GlobalSearchPresenter.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.ui.source.global_search +package eu.kanade.tachiyomi.ui.source.globalsearch import android.os.Bundle import eu.kanade.tachiyomi.data.database.DatabaseHelper @@ -73,11 +73,13 @@ open class GlobalSearchPresenter( super.onCreate(savedState) extensionFilter = savedState?.getString(GlobalSearchPresenter::extensionFilter.name) - ?: initialExtensionFilter + ?: initialExtensionFilter // Perform a search with previous or initial state - search(savedState?.getString(BrowseSourcePresenter::query.name) - ?: initialQuery.orEmpty()) + search( + savedState?.getString(BrowseSourcePresenter::query.name) + ?: initialQuery.orEmpty() + ) } override fun onDestroy() { @@ -104,9 +106,9 @@ open class GlobalSearchPresenter( val pinnedCatalogues = preferences.pinnedCatalogues().get() return sourceManager.getCatalogueSources() - .filter { it.lang in languages } - .filterNot { it.id.toString() in hiddenCatalogues } - .sortedWith(compareBy({ it.id.toString() !in pinnedCatalogues }, { "(${it.lang}) ${it.name}" })) + .filter { it.lang in languages } + .filterNot { it.id.toString() in hiddenCatalogues } + .sortedWith(compareBy({ it.id.toString() !in pinnedCatalogues }, { "(${it.lang}) ${it.name}" })) } private fun getSourcesToQuery(): List { @@ -117,10 +119,10 @@ open class GlobalSearchPresenter( } val filterSources = extensionManager.installedExtensions - .filter { it.pkgName == filter } - .flatMap { it.sources } - .filter { it in enabledSources } - .filterIsInstance() + .filter { it.pkgName == filter } + .flatMap { it.sources } + .filter { it in enabledSources } + .filterIsInstance() if (filterSources.isEmpty()) { return enabledSources @@ -157,29 +159,35 @@ open class GlobalSearchPresenter( fetchSourcesSubscription?.unsubscribe() fetchSourcesSubscription = Observable.from(sources) - .flatMap({ source -> + .flatMap( + { source -> Observable.defer { source.fetchSearchManga(1, query, FilterList()) } - .subscribeOn(Schedulers.io()) - .onErrorReturn { MangasPage(emptyList(), false) } // Ignore timeouts or other exceptions - .map { it.mangas.take(10) } // Get at most 10 manga from search result. - .map { list -> list.map { networkToLocalManga(it, source.id) } } // Convert to local manga. - .doOnNext { fetchImage(it, source) } // Load manga covers. - .map { list -> createCatalogueSearchItem(source, list.map { GlobalSearchCardItem(it) }) } - }, 5) - .observeOn(AndroidSchedulers.mainThread()) - // Update matching source with the obtained results - .map { result -> - items.map { item -> if (item.source == result.source) result else item } - } - // Update current state - .doOnNext { items = it } - // Deliver initial state - .startWith(initialItems) - .subscribeLatestCache({ view, manga -> + .subscribeOn(Schedulers.io()) + .onErrorReturn { MangasPage(emptyList(), false) } // Ignore timeouts or other exceptions + .map { it.mangas.take(10) } // Get at most 10 manga from search result. + .map { list -> list.map { networkToLocalManga(it, source.id) } } // Convert to local manga. + .doOnNext { fetchImage(it, source) } // Load manga covers. + .map { list -> createCatalogueSearchItem(source, list.map { GlobalSearchCardItem(it) }) } + }, + 5 + ) + .observeOn(AndroidSchedulers.mainThread()) + // Update matching source with the obtained results + .map { result -> + items.map { item -> if (item.source == result.source) result else item } + } + // Update current state + .doOnNext { items = it } + // Deliver initial state + .startWith(initialItems) + .subscribeLatestCache( + { view, manga -> view.setItems(manga) - }, { _, error -> + }, + { _, error -> Timber.e(error) - }) + } + ) } /** @@ -197,21 +205,24 @@ open class GlobalSearchPresenter( private fun initializeFetchImageSubscription() { fetchImageSubscription?.unsubscribe() fetchImageSubscription = fetchImageSubject.observeOn(Schedulers.io()) - .flatMap { pair -> - val source = pair.second - Observable.from(pair.first).filter { it.thumbnail_url == null && !it.initialized } - .map { Pair(it, source) } - .concatMap { getMangaDetailsObservable(it.first, it.second) } - .map { Pair(source as CatalogueSource, it) } - } - .onBackpressureBuffer() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ (source, manga) -> + .flatMap { pair -> + val source = pair.second + Observable.from(pair.first).filter { it.thumbnail_url == null && !it.initialized } + .map { Pair(it, source) } + .concatMap { getMangaDetailsObservable(it.first, it.second) } + .map { Pair(source as CatalogueSource, it) } + } + .onBackpressureBuffer() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { (source, manga) -> @Suppress("DEPRECATION") view?.onMangaInitialized(source, manga) - }, { error -> + }, + { error -> Timber.e(error) - }) + } + ) } /** @@ -222,13 +233,13 @@ open class GlobalSearchPresenter( */ private fun getMangaDetailsObservable(manga: Manga, source: Source): Observable { return source.fetchMangaDetails(manga) - .flatMap { networkManga -> - manga.copyFrom(networkManga) - manga.initialized = true - db.insertManga(manga).executeAsBlocking() - Observable.just(manga) - } - .onErrorResumeNext { Observable.just(manga) } + .flatMap { networkManga -> + manga.copyFrom(networkManga) + manga.initialized = true + db.insertManga(manga).executeAsBlocking() + Observable.just(manga) + } + .onErrorResumeNext { Observable.just(manga) } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/latest/LatestUpdatesController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/latest/LatestUpdatesController.kt index 4842dcdf88..19df0b0146 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/latest/LatestUpdatesController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/latest/LatestUpdatesController.kt @@ -12,9 +12,11 @@ import eu.kanade.tachiyomi.ui.source.browse.BrowseSourcePresenter */ class LatestUpdatesController(bundle: Bundle) : BrowseSourceController(bundle) { - constructor(source: CatalogueSource) : this(Bundle().apply { - putLong(SOURCE_ID_KEY, source.id) - }) + constructor(source: CatalogueSource) : this( + Bundle().apply { + putLong(SOURCE_ID_KEY, source.id) + } + ) override fun createPresenter(): BrowseSourcePresenter { return LatestUpdatesPresenter(args.getLong(SOURCE_ID_KEY)) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/latest/LatestUpdatesPager.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/latest/LatestUpdatesPager.kt index ff908a40b8..ca55cdcf97 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/latest/LatestUpdatesPager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/latest/LatestUpdatesPager.kt @@ -14,8 +14,8 @@ class LatestUpdatesPager(val source: CatalogueSource) : Pager() { override fun requestNext(): Observable { return source.fetchLatestUpdates(currentPage) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnNext { onPageReceived(it) } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext { onPageReceived(it) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognition.kt b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognition.kt index 77254f6ce2..bb1524f0b0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognition.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterRecognition.kt @@ -39,8 +39,9 @@ object ChapterRecognition { fun parseChapterNumber(chapter: SChapter, manga: SManga) { // If chapter number is known return. - if (chapter.chapter_number == -2f || chapter.chapter_number > -1f) + if (chapter.chapter_number == -2f || chapter.chapter_number > -1f) { return + } // Get chapter title with lower case var name = chapter.name.toLowerCase() @@ -59,8 +60,9 @@ object ChapterRecognition { } // Check base case ch.xx - if (updateChapter(basic.find(name), chapter)) + if (updateChapter(basic.find(name), chapter)) { return + } // Check one number occurrence. val occurrences: MutableList = arrayListOf() @@ -69,20 +71,23 @@ object ChapterRecognition { } if (occurrences.size == 1) { - if (updateChapter(occurrences[0], chapter)) + if (updateChapter(occurrences[0], chapter)) { return + } } // Remove manga title from chapter title. val nameWithoutManga = name.replace(manga.title.toLowerCase(), "").trim() // Check if first value is number after title remove. - if (updateChapter(withoutManga.find(nameWithoutManga), chapter)) + if (updateChapter(withoutManga.find(nameWithoutManga), chapter)) { return + } // Take the first number encountered. - if (updateChapter(occurrence.find(nameWithoutManga), chapter)) + if (updateChapter(occurrence.find(nameWithoutManga), chapter)) { return + } } /** @@ -110,18 +115,22 @@ object ChapterRecognition { * @return decimal/alpha float value */ private fun checkForDecimal(decimal: String?, alpha: String?): Float { - if (!decimal.isNullOrEmpty()) + if (!decimal.isNullOrEmpty()) { return decimal.toFloat() + } if (!alpha.isNullOrEmpty()) { - if (alpha.contains("extra")) + if (alpha.contains("extra")) { return .99f + } - if (alpha.contains("omake")) + if (alpha.contains("omake")) { return .98f + } - if (alpha.contains("special")) + if (alpha.contains("special")) { return .97f + } return if (alpha[0] == '.') { // Take value after (.) diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSourceSync.kt b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSourceSync.kt index 8eb1e6ea2f..5a2486642b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSourceSync.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSourceSync.kt @@ -24,7 +24,6 @@ fun syncChaptersWithSource( manga: Manga, source: Source ): Pair, List> { - if (rawSourceChapters.isEmpty()) { throw Exception("No chapters found") } @@ -142,6 +141,6 @@ fun syncChaptersWithSource( // checks if the chapter in db needs updated private fun shouldUpdateDbChapter(dbChapter: Chapter, sourceChapter: SChapter): Boolean { return dbChapter.scanlator != sourceChapter.scanlator || dbChapter.name != sourceChapter.name || - dbChapter.date_upload != sourceChapter.date_upload || - dbChapter.chapter_number != sourceChapter.chapter_number + dbChapter.date_upload != sourceChapter.date_upload || + dbChapter.chapter_number != sourceChapter.chapter_number } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt index 1dedec97e4..c126c028a0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt @@ -9,11 +9,11 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch fun launchUI(block: suspend CoroutineScope.() -> Unit): Job = - GlobalScope.launch(Dispatchers.Main, CoroutineStart.DEFAULT, block) + GlobalScope.launch(Dispatchers.Main, CoroutineStart.DEFAULT, block) fun launchIO(block: suspend CoroutineScope.() -> Unit): Job = - GlobalScope.launch(Dispatchers.IO, CoroutineStart.DEFAULT, block) + GlobalScope.launch(Dispatchers.IO, CoroutineStart.DEFAULT, block) @OptIn(ExperimentalCoroutinesApi::class) fun launchNow(block: suspend CoroutineScope.() -> Unit): Job = - GlobalScope.launch(Dispatchers.Main, CoroutineStart.UNDISPATCHED, block) + GlobalScope.launch(Dispatchers.Main, CoroutineStart.UNDISPATCHED, block) diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt index 1f1aa6c9ab..2b4f4d8af4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt @@ -36,8 +36,9 @@ fun Long.toDateKey(): Date { * @return Calendar instance at supplied epoch time. Null if epoch was 0. */ fun Long.toCalendar(): Calendar? { - if (this == 0L) + if (this == 0L) { return null + } val cal = Calendar.getInstance() cal.timeInMillis = this return cal diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/lang/Hash.kt b/app/src/main/java/eu/kanade/tachiyomi/util/lang/Hash.kt index 4410274276..a890632080 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/lang/Hash.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/lang/Hash.kt @@ -4,8 +4,10 @@ import java.security.MessageDigest object Hash { - private val chars = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'a', 'b', 'c', 'd', 'e', 'f') + private val chars = charArrayOf( + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' + ) private val MD5 get() = MessageDigest.getInstance("MD5") diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/lang/StringExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/lang/StringExtensions.kt index 2dfe6f743d..ae12de3465 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/lang/StringExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/lang/StringExtensions.kt @@ -7,10 +7,11 @@ import kotlin.math.floor * If [replacement] is longer than [count] an exception will be thrown when `length > count`. */ fun String.chop(count: Int, replacement: String = "..."): String { - return if (length > count) + return if (length > count) { take(count - replacement.length) + replacement - else + } else { this + } } /** @@ -18,8 +19,9 @@ fun String.chop(count: Int, replacement: String = "..."): String { * If [replacement] is longer than [count] an exception will be thrown when `length > count`. */ fun String.truncateCenter(count: Int, replacement: String = "..."): String { - if (length <= count) + if (length <= count) { return this + } val pieceLength: Int = floor((count - replacement.length).div(2.0)).toInt() diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/storage/DiskUtil.kt b/app/src/main/java/eu/kanade/tachiyomi/util/storage/DiskUtil.kt index d141421e07..d44a63b5d7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/storage/DiskUtil.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/storage/DiskUtil.kt @@ -34,16 +34,16 @@ object DiskUtil { fun getExternalStorages(context: Context): Collection { val directories = mutableSetOf() directories += ContextCompat.getExternalFilesDirs(context, null) - .filterNotNull() - .mapNotNull { - val file = File(it.absolutePath.substringBefore("/Android/")) - val state = EnvironmentCompat.getStorageState(file) - if (state == Environment.MEDIA_MOUNTED || state == Environment.MEDIA_MOUNTED_READ_ONLY) { - file - } else { - null - } + .filterNotNull() + .mapNotNull { + val file = File(it.absolutePath.substringBefore("/Android/")) + val state = EnvironmentCompat.getStorageState(file) + if (state == Environment.MEDIA_MOUNTED || state == Environment.MEDIA_MOUNTED_READ_ONLY) { + file + } else { + null } + } return directories } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt b/app/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt index c2a2b7869e..0763abb2e2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/storage/EpubFile.kt @@ -79,8 +79,8 @@ class EpubFile(file: File) : Closeable { */ private fun getPagesFromDocument(document: Document): List { val pages = document.select("manifest > item") - .filter { "application/xhtml+xml" == it.attr("media-type") } - .associateBy { it.attr("id") } + .filter { "application/xhtml+xml" == it.attr("media-type") } + .associateBy { it.attr("id") } val spine = document.select("spine > itemref").map { it.attr("idref") } return spine.mapNotNull { pages[it] }.map { it.attr("href") } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt index 53523c6d4c..6ca1bd6463 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt @@ -13,7 +13,9 @@ import java.io.File * @param context context of application */ fun File.getUriCompat(context: Context): Uri { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", this) - else Uri.fromFile(this) + } else { + Uri.fromFile(this) + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt index 09684540a5..a89dae8cf0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt @@ -52,7 +52,7 @@ fun Context.toast(text: String?, duration: Int = Toast.LENGTH_SHORT) { */ fun Context.notificationBuilder(channelId: String, block: (NotificationCompat.Builder.() -> Unit)? = null): NotificationCompat.Builder { val builder = NotificationCompat.Builder(this, channelId) - .setColor(ContextCompat.getColor(this, R.color.colorPrimary)) + .setColor(ContextCompat.getColor(this, R.color.colorPrimary)) if (block != null) { builder.block() } @@ -78,10 +78,10 @@ fun Context.notification(channelId: String, block: (NotificationCompat.Builder.( */ fun Context.getFilePicker(currentDir: String): Intent { return Intent(this, CustomLayoutPickerActivity::class.java) - .putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false) - .putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true) - .putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR) - .putExtra(FilePickerActivity.EXTRA_START_PATH, currentDir) + .putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false) + .putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true) + .putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR) + .putExtra(FilePickerActivity.EXTRA_START_PATH, currentDir) } /** @@ -178,7 +178,7 @@ fun Context.isServiceRunning(serviceClass: Class<*>): Boolean { val manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager @Suppress("DEPRECATION") return manager.getRunningServices(Integer.MAX_VALUE) - .any { className == it.service.className } + .any { className == it.service.className } } /** @@ -188,8 +188,8 @@ fun Context.openInBrowser(url: String) { try { val parsedUrl = Uri.parse(url) val intent = CustomTabsIntent.Builder() - .setToolbarColor(getResourceColor(R.attr.colorPrimary)) - .build() + .setToolbarColor(getResourceColor(R.attr.colorPrimary)) + .build() intent.launchUrl(this, parsedUrl) } catch (e: Exception) { toast(e.message) diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt index f59708a0cb..b519a3361e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt @@ -29,8 +29,9 @@ object ImageUtil { stream.read(bytes, 0, bytes.size) } - if (length == -1) + if (length == -1) { return null + } if (bytes.compareWith(charByteArrayOf(0xFF, 0xD8, 0xFF))) { return ImageType.JPG diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt index 0699214c88..d32cc11410 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt @@ -60,8 +60,10 @@ abstract class WebViewClientCompat : WebViewClient() { request: WebResourceRequest, error: WebResourceError ) { - onReceivedErrorCompat(view, error.errorCode, error.description?.toString(), - request.url.toString(), request.isForMainFrame) + onReceivedErrorCompat( + view, error.errorCode, error.description?.toString(), + request.url.toString(), request.isForMainFrame + ) } final override fun onReceivedError( @@ -79,7 +81,11 @@ abstract class WebViewClientCompat : WebViewClient() { request: WebResourceRequest, error: WebResourceResponse ) { - onReceivedErrorCompat(view, error.statusCode, error.reasonPhrase, request.url - .toString(), request.isForMainFrame) + onReceivedErrorCompat( + view, error.statusCode, error.reasonPhrase, + request.url + .toString(), + request.isForMainFrame + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt index 51dfcda571..c27f4c2cba 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt @@ -95,7 +95,8 @@ fun ImageView.roundTextIcon(text: String) { val letter = text.take(1).toUpperCase() val size = min(this.width, this.height) - setImageDrawable(TextDrawable( + setImageDrawable( + TextDrawable( shape = TextDrawable.DRAWABLE_SHAPE_OVAL, desiredWidth = size, desiredHeight = size, @@ -103,7 +104,8 @@ fun ImageView.roundTextIcon(text: String) { textColor = Color.WHITE, text = letter, color = ColorGenerator.MATERIAL.getColor(letter) - )) + ) + ) } /** @@ -114,10 +116,11 @@ fun ImageView.roundTextIcon(text: String) { fun ExtendedFloatingActionButton.shrinkOnScroll(recycler: RecyclerView) { recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { - if (dy <= 0) + if (dy <= 0) { extend() - else + } else { shrink() + } } }) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/view/WindowExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/view/WindowExtensions.kt index 8a0fe9d4af..3ae882af3d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/view/WindowExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/view/WindowExtensions.kt @@ -5,17 +5,17 @@ import android.view.Window fun Window.showBar() { val uiFlags = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or - View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or - View.SYSTEM_UI_FLAG_LAYOUT_STABLE + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or + View.SYSTEM_UI_FLAG_LAYOUT_STABLE decorView.systemUiVisibility = uiFlags } fun Window.hideBar() { val uiFlags = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or - View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or - View.SYSTEM_UI_FLAG_FULLSCREEN or - View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or - View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or + View.SYSTEM_UI_FLAG_FULLSCREEN or + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY decorView.systemUiVisibility = uiFlags } diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/ActionToolbar.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/ActionToolbar.kt index ef88459ab2..c25cb15393 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/ActionToolbar.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/ActionToolbar.kt @@ -17,7 +17,7 @@ import kotlinx.android.synthetic.main.common_action_toolbar.view.common_action_t * A toolbar holding only menu items. */ class ActionToolbar @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - FrameLayout(context, attrs) { + FrameLayout(context, attrs) { init { inflate(context, R.layout.common_action_toolbar, this) diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt index e843e628aa..565dfbe3c4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt @@ -7,7 +7,7 @@ import androidx.recyclerview.widget.RecyclerView import kotlin.math.max class AutofitRecyclerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - RecyclerView(context, attrs) { + RecyclerView(context, attrs) { private val manager = GridLayoutManager(context, 1) diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/CustomLayoutPicker.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/CustomLayoutPicker.kt index 2f71a21077..40f7b8ba8a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/CustomLayoutPicker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/CustomLayoutPicker.kt @@ -13,11 +13,11 @@ import java.io.File class CustomLayoutPickerActivity : FilePickerActivity() { override fun getFragment(startPath: String?, mode: Int, allowMultiple: Boolean, allowCreateDir: Boolean): - AbstractFilePickerFragment { - val fragment = CustomLayoutFilePickerFragment() - fragment.setArgs(startPath, mode, allowMultiple, allowCreateDir) - return fragment - } + AbstractFilePickerFragment { + val fragment = CustomLayoutFilePickerFragment() + fragment.setArgs(startPath, mode, allowMultiple, allowCreateDir) + return fragment + } } class CustomLayoutFilePickerFragment : FilePickerFragment() { diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCheckboxView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCheckboxView.kt index f85efff784..4d5fd2569e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCheckboxView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCheckboxView.kt @@ -10,7 +10,7 @@ import kotlinx.android.synthetic.main.common_dialog_with_checkbox.view.checkbox_ import kotlinx.android.synthetic.main.common_dialog_with_checkbox.view.description class DialogCheckboxView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - LinearLayout(context, attrs) { + LinearLayout(context, attrs) { init { addView(inflate(R.layout.common_dialog_with_checkbox)) diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCustomDownloadView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCustomDownloadView.kt index 45de86d37c..60af361139 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCustomDownloadView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCustomDownloadView.kt @@ -24,7 +24,7 @@ import timber.log.Timber * Custom dialog to select how many chapters to download. */ class DialogCustomDownloadView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - LinearLayout(context, attrs) { + LinearLayout(context, attrs) { private val scope = CoroutineScope(Job() + Dispatchers.Main) diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/ElevationAppBarLayout.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/ElevationAppBarLayout.kt index e7d0f70c84..838bcab8e8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/ElevationAppBarLayout.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/ElevationAppBarLayout.kt @@ -27,8 +27,10 @@ class ElevationAppBarLayout @JvmOverloads constructor( val objAnimator = ObjectAnimator.ofFloat(this, "elevation", 0f) // Enabled and collapsible, but not collapsed means not elevated - addState(intArrayOf(android.R.attr.enabled, R.attr.state_collapsible, -R.attr.state_collapsed), - objAnimator) + addState( + intArrayOf(android.R.attr.enabled, R.attr.state_collapsible, -R.attr.state_collapsed), + objAnimator + ) // Default enabled state addState(intArrayOf(android.R.attr.enabled), objAnimator) diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/EmptyView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/EmptyView.kt index bc9e45b83d..fbe21cd995 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/EmptyView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/EmptyView.kt @@ -15,7 +15,7 @@ import kotlinx.android.synthetic.main.common_view_empty.view.text_face import kotlinx.android.synthetic.main.common_view_empty.view.text_label class EmptyView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - RelativeLayout(context, attrs) { + RelativeLayout(context, attrs) { init { inflate(context, R.layout.common_view_empty, this) @@ -46,7 +46,8 @@ class EmptyView @JvmOverloads constructor(context: Context, attrs: AttributeSet? val button = AppCompatButton(context).apply { layoutParams = LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT) + LinearLayout.LayoutParams.WRAP_CONTENT + ) setText(it.resId) setOnClickListener(it.listener) diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/MinMaxNumberPicker.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/MinMaxNumberPicker.kt index bdc7d79d14..a041db442b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/MinMaxNumberPicker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/MinMaxNumberPicker.kt @@ -6,7 +6,7 @@ import android.widget.NumberPicker import eu.kanade.tachiyomi.R class MinMaxNumberPicker @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - NumberPicker(context, attrs) { + NumberPicker(context, attrs) { init { if (attrs != null) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/NegativeSeekBar.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/NegativeSeekBar.kt index 44587bc8e1..10f4f12967 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/NegativeSeekBar.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/NegativeSeekBar.kt @@ -9,7 +9,7 @@ import eu.kanade.tachiyomi.R import kotlin.math.abs class NegativeSeekBar @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - AppCompatSeekBar(context, attrs) { + AppCompatSeekBar(context, attrs) { private var minValue: Int = 0 private var maxValue: Int = 0 @@ -17,8 +17,9 @@ class NegativeSeekBar @JvmOverloads constructor(context: Context, attrs: Attribu init { val styledAttributes = context.obtainStyledAttributes( - attrs, - R.styleable.NegativeSeekBar, 0, 0) + attrs, + R.styleable.NegativeSeekBar, 0, 0 + ) try { setMinSeek(styledAttributes.getInt(R.styleable.NegativeSeekBar_min_seek, 0)) diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/RevealAnimationView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/RevealAnimationView.kt index 94594dc213..b8aa1764f5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/RevealAnimationView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/RevealAnimationView.kt @@ -10,7 +10,7 @@ import eu.kanade.tachiyomi.util.view.invisible import eu.kanade.tachiyomi.util.view.visible class RevealAnimationView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - View(context, attrs) { + View(context, attrs) { /** * Hides the animation view with a animation @@ -25,7 +25,8 @@ class RevealAnimationView @JvmOverloads constructor(context: Context, attrs: Att // Create the animation (the final radius is zero). val anim = ViewAnimationUtils.createCircularReveal( - this, centerX, centerY, initialRadius.toFloat(), 0f) + this, centerX, centerY, initialRadius.toFloat(), 0f + ) // Set duration of animation. anim.duration = 500 @@ -57,7 +58,8 @@ class RevealAnimationView @JvmOverloads constructor(context: Context, attrs: Att // Create animation val anim = ViewAnimationUtils.createCircularReveal( - this, centerX, centerY, 0f, height.toFloat()) + this, centerX, centerY, 0f, height.toFloat() + ) // Set duration of animation anim.duration = 350 diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleNavigationView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleNavigationView.kt index 04a0f255d7..1d91b7b76d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleNavigationView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleNavigationView.kt @@ -36,16 +36,23 @@ open class SimpleNavigationView @JvmOverloads constructor( init { // Custom attributes - val a = TintTypedArray.obtainStyledAttributes(context, attrs, - R.styleable.NavigationView, defStyleAttr, - R.style.Widget_Design_NavigationView) + val a = TintTypedArray.obtainStyledAttributes( + context, attrs, + R.styleable.NavigationView, defStyleAttr, + R.style.Widget_Design_NavigationView + ) ViewCompat.setBackground( - this, a.getDrawable(R.styleable.NavigationView_android_background)) + this, a.getDrawable(R.styleable.NavigationView_android_background) + ) if (a.hasValue(R.styleable.NavigationView_elevation)) { - ViewCompat.setElevation(this, a.getDimensionPixelSize( - R.styleable.NavigationView_elevation, 0).toFloat()) + ViewCompat.setElevation( + this, + a.getDimensionPixelSize( + R.styleable.NavigationView_elevation, 0 + ).toFloat() + ) } a.recycle() diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/ThemedSwipeRefreshLayout.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/ThemedSwipeRefreshLayout.kt index 22c549be18..45d6d01cad 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/ThemedSwipeRefreshLayout.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/ThemedSwipeRefreshLayout.kt @@ -8,7 +8,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.util.system.getResourceColor class ThemedSwipeRefreshLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - SwipeRefreshLayout(context, attrs) { + SwipeRefreshLayout(context, attrs) { init { setColors() @@ -17,8 +17,9 @@ class ThemedSwipeRefreshLayout @JvmOverloads constructor(context: Context, attrs private fun setColors() { setProgressBackgroundColorSchemeColor(context.getResourceColor(R.attr.colorAccent)) setColorSchemeColors( - ContextCompat.getColor(context, R.color.md_white_1000), - ContextCompat.getColor(context, R.color.md_white_1000), - ContextCompat.getColor(context, R.color.md_white_1000)) + ContextCompat.getColor(context, R.color.md_white_1000), + ContextCompat.getColor(context, R.color.md_white_1000), + ContextCompat.getColor(context, R.color.md_white_1000) + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListPreference.kt index 37873398f9..63b52eb2a9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListPreference.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListPreference.kt @@ -5,7 +5,7 @@ import android.util.AttributeSet import androidx.preference.ListPreference class IntListPreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - ListPreference(context, attrs) { + ListPreference(context, attrs) { override fun persistString(value: String?): Boolean { return value != null && persistInt(value.toInt()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginDialogPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginDialogPreference.kt index 64e5459053..3b9c65355a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginDialogPreference.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginDialogPreference.kt @@ -36,8 +36,8 @@ abstract class LoginDialogPreference( override fun onCreateDialog(savedViewState: Bundle?): Dialog { var dialog = MaterialDialog(activity!!) - .customView(R.layout.pref_account_login) - .negativeButton(android.R.string.cancel) + .customView(R.layout.pref_account_login) + .negativeButton(android.R.string.cancel) if (titleRes != null) { dialog = dialog.title(text = activity!!.getString(titleRes, titleFormatArgs)) @@ -51,10 +51,11 @@ abstract class LoginDialogPreference( fun onViewCreated(view: View) { v = view.apply { show_password.setOnCheckedChangeListener { _, isChecked -> - if (isChecked) + if (isChecked) { password.transformationMethod = null - else + } else { password.transformationMethod = PasswordTransformationMethod() + } } if (usernameLabelRes != null) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginPreference.kt index a0fa99dd73..32ca1d7209 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginPreference.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginPreference.kt @@ -8,7 +8,7 @@ import eu.kanade.tachiyomi.R import kotlinx.android.synthetic.main.pref_widget_imageview.view.image_view class LoginPreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - Preference(context, attrs) { + Preference(context, attrs) { init { widgetLayoutResource = R.layout.pref_widget_imageview @@ -17,10 +17,13 @@ class LoginPreference @JvmOverloads constructor(context: Context, attrs: Attribu override fun onBindViewHolder(holder: PreferenceViewHolder) { super.onBindViewHolder(holder) - holder.itemView.image_view.setImageResource(if (getPersistedString("").isNullOrEmpty()) - android.R.color.transparent - else - R.drawable.ic_done_green_24dp) + holder.itemView.image_view.setImageResource( + if (getPersistedString("").isNullOrEmpty()) { + android.R.color.transparent + } else { + R.drawable.ic_done_green_24dp + } + ) } public override fun notifyChanged() { diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/SwitchPreferenceCategory.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/SwitchPreferenceCategory.kt index 92ee4f096d..15d64392a6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/SwitchPreferenceCategory.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/SwitchPreferenceCategory.kt @@ -20,8 +20,9 @@ class SwitchPreferenceCategory @JvmOverloads constructor( PreferenceCategory( context, attrs, - R.attr.switchPreferenceCompatStyle), - CompoundButton.OnCheckedChangeListener { + R.attr.switchPreferenceCompatStyle + ), + CompoundButton.OnCheckedChangeListener { private var mChecked = false @@ -114,9 +115,12 @@ class SwitchPreferenceCategory @JvmOverloads constructor( } override fun onSetInitialValue(restoreValue: Boolean, defaultValue: Any?) { - setChecked(if (restoreValue) - getPersistedBoolean(mChecked) - else - defaultValue as Boolean) + setChecked( + if (restoreValue) { + getPersistedBoolean(mChecked) + } else { + defaultValue as Boolean + } + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/TrackLoginDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/TrackLoginDialog.kt index d5278d50d0..40cce109a6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/TrackLoginDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/TrackLoginDialog.kt @@ -27,7 +27,7 @@ class TrackLoginDialog( constructor(service: TrackService) : this(service, null) constructor(service: TrackService, @StringRes usernameLabelRes: Int?) : - this(R.string.login_title, service.name, usernameLabelRes, Bundle().apply { putInt("key", service.id) }) + this(R.string.login_title, service.name, usernameLabelRes, Bundle().apply { putInt("key", service.id) }) override fun setCredentialsOnView(view: View) = with(view) { username.setText(service.getUsername()) @@ -38,24 +38,28 @@ class TrackLoginDialog( requestSubscription?.unsubscribe() v?.apply { - if (username.text.isNullOrEmpty() || password.text.isNullOrEmpty()) + if (username.text.isNullOrEmpty() || password.text.isNullOrEmpty()) { return + } login.progress = 1 val user = username.text.toString() val pass = password.text.toString() requestSubscription = service.login(user, pass) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { dialog?.dismiss() context.toast(R.string.login_success) - }, { error -> + }, + { error -> login.progress = -1 login.setText(R.string.unknown_error) error.message?.let { context.toast(it) } - }) + } + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/TrackLogoutDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/TrackLogoutDialog.kt index 48efea0877..740a3681b3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/TrackLogoutDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/TrackLogoutDialog.kt @@ -19,13 +19,13 @@ class TrackLogoutDialog(bundle: Bundle? = null) : DialogController(bundle) { override fun onCreateDialog(savedViewState: Bundle?): Dialog { return MaterialDialog(activity!!) - .title(R.string.logout_title, service.name) - .positiveButton(R.string.logout) { - service.logout() - (targetController as? Listener)?.trackLogoutDialogClosed(service) - activity?.toast(R.string.logout_success) - } - .negativeButton(android.R.string.cancel) + .title(R.string.logout_title, service.name) + .positiveButton(R.string.logout) { + service.logout() + (targetController as? Listener)?.trackLogoutDialogClosed(service) + activity?.toast(R.string.logout_success) + } + .negativeButton(android.R.string.cancel) } interface Listener { diff --git a/app/src/test/java/eu/kanade/tachiyomi/data/library/LibraryUpdateServiceTest.kt b/app/src/test/java/eu/kanade/tachiyomi/data/library/LibraryUpdateServiceTest.kt index 4d28a25a6c..fa6c1ed9b9 100644 --- a/app/src/test/java/eu/kanade/tachiyomi/data/library/LibraryUpdateServiceTest.kt +++ b/app/src/test/java/eu/kanade/tachiyomi/data/library/LibraryUpdateServiceTest.kt @@ -60,11 +60,11 @@ class LibraryUpdateServiceTest { fun testLifecycle() { // Smoke test Robolectric.buildService(LibraryUpdateService::class.java) - .attach() - .create() - .startCommand(0, 0) - .destroy() - .get() + .attach() + .create() + .startCommand(0, 0) + .destroy() + .get() } @Test