mirror of
https://github.com/mihonapp/mihon.git
synced 2024-11-07 19:27:25 +01:00
Linting fixes
This commit is contained in:
parent
4da760d614
commit
3f63b320c4
@ -22,7 +22,6 @@ import uy.kohesive.injekt.api.get
|
|||||||
class AppModule(val app: Application) : InjektModule {
|
class AppModule(val app: Application) : InjektModule {
|
||||||
|
|
||||||
override fun InjektRegistrar.registerInjectables() {
|
override fun InjektRegistrar.registerInjectables() {
|
||||||
|
|
||||||
addSingleton(app)
|
addSingleton(app)
|
||||||
|
|
||||||
addSingletonFactory { PreferencesHelper(app) }
|
addSingletonFactory { PreferencesHelper(app) }
|
||||||
|
@ -33,7 +33,8 @@ class BackupCreatorJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
if (interval > 0) {
|
if (interval > 0) {
|
||||||
val request = PeriodicWorkRequestBuilder<BackupCreatorJob>(
|
val request = PeriodicWorkRequestBuilder<BackupCreatorJob>(
|
||||||
interval.toLong(), TimeUnit.HOURS,
|
interval.toLong(), TimeUnit.HOURS,
|
||||||
10, TimeUnit.MINUTES)
|
10, TimeUnit.MINUTES
|
||||||
|
)
|
||||||
.addTag(TAG)
|
.addTag(TAG)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
@ -85,7 +85,8 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
|
|||||||
|
|
||||||
private fun initParser(): Gson = when (version) {
|
private fun initParser(): Gson = when (version) {
|
||||||
1 -> GsonBuilder().create()
|
1 -> GsonBuilder().create()
|
||||||
2 -> GsonBuilder()
|
2 ->
|
||||||
|
GsonBuilder()
|
||||||
.registerTypeAdapter<MangaImpl>(MangaTypeAdapter.build())
|
.registerTypeAdapter<MangaImpl>(MangaTypeAdapter.build())
|
||||||
.registerTypeHierarchyAdapter<ChapterImpl>(ChapterTypeAdapter.build())
|
.registerTypeHierarchyAdapter<ChapterImpl>(ChapterTypeAdapter.build())
|
||||||
.registerTypeAdapter<CategoryImpl>(CategoryTypeAdapter.build())
|
.registerTypeAdapter<CategoryImpl>(CategoryTypeAdapter.build())
|
||||||
@ -442,8 +443,9 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
|
|||||||
val dbChapters = databaseHelper.getChapters(manga).executeAsBlocking()
|
val dbChapters = databaseHelper.getChapters(manga).executeAsBlocking()
|
||||||
|
|
||||||
// Return if fetch is needed
|
// Return if fetch is needed
|
||||||
if (dbChapters.isEmpty() || dbChapters.size < chapters.size)
|
if (dbChapters.isEmpty() || dbChapters.size < chapters.size) {
|
||||||
return false
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
for (chapter in chapters) {
|
for (chapter in chapters) {
|
||||||
val pos = dbChapters.indexOf(chapter)
|
val pos = dbChapters.indexOf(chapter)
|
||||||
|
@ -143,7 +143,8 @@ class BackupRestoreService : Service() {
|
|||||||
startForeground(Notifications.ID_RESTORE, notifier.showRestoreProgress().build())
|
startForeground(Notifications.ID_RESTORE, notifier.showRestoreProgress().build())
|
||||||
|
|
||||||
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
|
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
|
||||||
PowerManager.PARTIAL_WAKE_LOCK, "BackupRestoreService:WakeLock")
|
PowerManager.PARTIAL_WAKE_LOCK, "BackupRestoreService:WakeLock"
|
||||||
|
)
|
||||||
wakeLock.acquire()
|
wakeLock.acquire()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,7 +185,8 @@ class BackupRestoreService : Service() {
|
|||||||
subscription = Observable.using(
|
subscription = Observable.using(
|
||||||
{ db.lowLevel().beginTransaction() },
|
{ db.lowLevel().beginTransaction() },
|
||||||
{ getRestoreObservable(uri).doOnNext { db.lowLevel().setTransactionSuccessful() } },
|
{ getRestoreObservable(uri).doOnNext { db.lowLevel().setTransactionSuccessful() } },
|
||||||
{ executor.execute { db.lowLevel().endTransaction() } })
|
{ executor.execute { db.lowLevel().endTransaction() } }
|
||||||
|
)
|
||||||
.doAfterTerminate { stopSelf(startId) }
|
.doAfterTerminate { stopSelf(startId) }
|
||||||
.subscribeOn(Schedulers.from(executor))
|
.subscribeOn(Schedulers.from(executor))
|
||||||
.subscribe()
|
.subscribe()
|
||||||
@ -231,14 +233,22 @@ class BackupRestoreService : Service() {
|
|||||||
.concatMap {
|
.concatMap {
|
||||||
val obj = it.asJsonObject
|
val obj = it.asJsonObject
|
||||||
val manga = backupManager.parser.fromJson<MangaImpl>(obj.get(MANGA))
|
val manga = backupManager.parser.fromJson<MangaImpl>(obj.get(MANGA))
|
||||||
val chapters = backupManager.parser.fromJson<List<ChapterImpl>>(obj.get(CHAPTERS)
|
val chapters = backupManager.parser.fromJson<List<ChapterImpl>>(
|
||||||
?: JsonArray())
|
obj.get(CHAPTERS)
|
||||||
val categories = backupManager.parser.fromJson<List<String>>(obj.get(CATEGORIES)
|
?: JsonArray()
|
||||||
?: JsonArray())
|
)
|
||||||
val history = backupManager.parser.fromJson<List<DHistory>>(obj.get(HISTORY)
|
val categories = backupManager.parser.fromJson<List<String>>(
|
||||||
?: JsonArray())
|
obj.get(CATEGORIES)
|
||||||
val tracks = backupManager.parser.fromJson<List<TrackImpl>>(obj.get(TRACK)
|
?: JsonArray()
|
||||||
?: JsonArray())
|
)
|
||||||
|
val history = backupManager.parser.fromJson<List<DHistory>>(
|
||||||
|
obj.get(HISTORY)
|
||||||
|
?: JsonArray()
|
||||||
|
)
|
||||||
|
val tracks = backupManager.parser.fromJson<List<TrackImpl>>(
|
||||||
|
obj.get(TRACK)
|
||||||
|
?: JsonArray()
|
||||||
|
)
|
||||||
|
|
||||||
val observable = getMangaRestoreObservable(manga, chapters, categories, history, tracks)
|
val observable = getMangaRestoreObservable(manga, chapters, categories, history, tracks)
|
||||||
if (observable != null) {
|
if (observable != null) {
|
||||||
@ -379,7 +389,6 @@ class BackupRestoreService : Service() {
|
|||||||
history: List<DHistory>,
|
history: List<DHistory>,
|
||||||
tracks: List<Track>
|
tracks: List<Track>
|
||||||
): Observable<Manga> {
|
): Observable<Manga> {
|
||||||
|
|
||||||
return Observable.just(backupManga)
|
return Observable.just(backupManga)
|
||||||
.flatMap { manga ->
|
.flatMap { manga ->
|
||||||
if (!backupManager.restoreChaptersForManga(manga, chapters)) {
|
if (!backupManager.restoreChaptersForManga(manga, chapters)) {
|
||||||
|
@ -46,10 +46,12 @@ class ChapterCache(private val context: Context) {
|
|||||||
private val gson: Gson by injectLazy()
|
private val gson: Gson by injectLazy()
|
||||||
|
|
||||||
/** Cache class used for cache management. */
|
/** Cache class used for cache management. */
|
||||||
private val diskCache = DiskLruCache.open(File(context.cacheDir, PARAMETER_CACHE_DIRECTORY),
|
private val diskCache = DiskLruCache.open(
|
||||||
|
File(context.cacheDir, PARAMETER_CACHE_DIRECTORY),
|
||||||
PARAMETER_APP_VERSION,
|
PARAMETER_APP_VERSION,
|
||||||
PARAMETER_VALUE_COUNT,
|
PARAMETER_VALUE_COUNT,
|
||||||
PARAMETER_CACHE_SIZE)
|
PARAMETER_CACHE_SIZE
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns directory of cache.
|
* Returns directory of cache.
|
||||||
@ -77,8 +79,9 @@ class ChapterCache(private val context: Context) {
|
|||||||
*/
|
*/
|
||||||
fun removeFileFromCache(file: String): Boolean {
|
fun removeFileFromCache(file: String): Boolean {
|
||||||
// Make sure we don't delete the journal file (keeps track of cache).
|
// 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 false
|
||||||
|
}
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
// Remove the extension from the file to get the key of the cache
|
// Remove the extension from the file to get the key of the cache
|
||||||
|
@ -56,8 +56,9 @@ class CoverCache(private val context: Context) {
|
|||||||
*/
|
*/
|
||||||
fun deleteFromCache(thumbnailUrl: String?): Boolean {
|
fun deleteFromCache(thumbnailUrl: String?): Boolean {
|
||||||
// Check if url is empty.
|
// Check if url is empty.
|
||||||
if (thumbnailUrl.isNullOrEmpty())
|
if (thumbnailUrl.isNullOrEmpty()) {
|
||||||
return false
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Remove file.
|
// Remove file.
|
||||||
val file = getCoverFile(thumbnailUrl)
|
val file = getCoverFile(thumbnailUrl)
|
||||||
|
@ -44,8 +44,10 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
|
|||||||
db.execSQL(ChapterTable.sourceOrderUpdateQuery)
|
db.execSQL(ChapterTable.sourceOrderUpdateQuery)
|
||||||
|
|
||||||
// Fix kissmanga covers after supporting cloudflare
|
// Fix kissmanga covers after supporting cloudflare
|
||||||
db.execSQL("""UPDATE mangas SET thumbnail_url =
|
db.execSQL(
|
||||||
REPLACE(thumbnail_url, '93.174.95.110', 'kissmanga.com') WHERE source = 4""")
|
"""UPDATE mangas SET thumbnail_url =
|
||||||
|
REPLACE(thumbnail_url, '93.174.95.110', 'kissmanga.com') WHERE source = 4"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (oldVersion < 3) {
|
if (oldVersion < 3) {
|
||||||
// Initialize history tables
|
// Initialize history tables
|
||||||
|
@ -11,18 +11,22 @@ interface CategoryQueries : DbProvider {
|
|||||||
|
|
||||||
fun getCategories() = db.get()
|
fun getCategories() = db.get()
|
||||||
.listOfObjects(Category::class.java)
|
.listOfObjects(Category::class.java)
|
||||||
.withQuery(Query.builder()
|
.withQuery(
|
||||||
|
Query.builder()
|
||||||
.table(CategoryTable.TABLE)
|
.table(CategoryTable.TABLE)
|
||||||
.orderBy(CategoryTable.COL_ORDER)
|
.orderBy(CategoryTable.COL_ORDER)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun getCategoriesForManga(manga: Manga) = db.get()
|
fun getCategoriesForManga(manga: Manga) = db.get()
|
||||||
.listOfObjects(Category::class.java)
|
.listOfObjects(Category::class.java)
|
||||||
.withQuery(RawQuery.builder()
|
.withQuery(
|
||||||
|
RawQuery.builder()
|
||||||
.query(getCategoriesForMangaQuery())
|
.query(getCategoriesForMangaQuery())
|
||||||
.args(manga.id)
|
.args(manga.id)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun insertCategory(category: Category) = db.put().`object`(category).prepare()
|
fun insertCategory(category: Category) = db.put().`object`(category).prepare()
|
||||||
|
@ -17,48 +17,58 @@ interface ChapterQueries : DbProvider {
|
|||||||
|
|
||||||
fun getChapters(manga: Manga) = db.get()
|
fun getChapters(manga: Manga) = db.get()
|
||||||
.listOfObjects(Chapter::class.java)
|
.listOfObjects(Chapter::class.java)
|
||||||
.withQuery(Query.builder()
|
.withQuery(
|
||||||
|
Query.builder()
|
||||||
.table(ChapterTable.TABLE)
|
.table(ChapterTable.TABLE)
|
||||||
.where("${ChapterTable.COL_MANGA_ID} = ?")
|
.where("${ChapterTable.COL_MANGA_ID} = ?")
|
||||||
.whereArgs(manga.id)
|
.whereArgs(manga.id)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun getRecentChapters(date: Date) = db.get()
|
fun getRecentChapters(date: Date) = db.get()
|
||||||
.listOfObjects(MangaChapter::class.java)
|
.listOfObjects(MangaChapter::class.java)
|
||||||
.withQuery(RawQuery.builder()
|
.withQuery(
|
||||||
|
RawQuery.builder()
|
||||||
.query(getRecentsQuery())
|
.query(getRecentsQuery())
|
||||||
.args(date.time)
|
.args(date.time)
|
||||||
.observesTables(ChapterTable.TABLE)
|
.observesTables(ChapterTable.TABLE)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.withGetResolver(MangaChapterGetResolver.INSTANCE)
|
.withGetResolver(MangaChapterGetResolver.INSTANCE)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun getChapter(id: Long) = db.get()
|
fun getChapter(id: Long) = db.get()
|
||||||
.`object`(Chapter::class.java)
|
.`object`(Chapter::class.java)
|
||||||
.withQuery(Query.builder()
|
.withQuery(
|
||||||
|
Query.builder()
|
||||||
.table(ChapterTable.TABLE)
|
.table(ChapterTable.TABLE)
|
||||||
.where("${ChapterTable.COL_ID} = ?")
|
.where("${ChapterTable.COL_ID} = ?")
|
||||||
.whereArgs(id)
|
.whereArgs(id)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun getChapter(url: String) = db.get()
|
fun getChapter(url: String) = db.get()
|
||||||
.`object`(Chapter::class.java)
|
.`object`(Chapter::class.java)
|
||||||
.withQuery(Query.builder()
|
.withQuery(
|
||||||
|
Query.builder()
|
||||||
.table(ChapterTable.TABLE)
|
.table(ChapterTable.TABLE)
|
||||||
.where("${ChapterTable.COL_URL} = ?")
|
.where("${ChapterTable.COL_URL} = ?")
|
||||||
.whereArgs(url)
|
.whereArgs(url)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun getChapter(url: String, mangaId: Long) = db.get()
|
fun getChapter(url: String, mangaId: Long) = db.get()
|
||||||
.`object`(Chapter::class.java)
|
.`object`(Chapter::class.java)
|
||||||
.withQuery(Query.builder()
|
.withQuery(
|
||||||
|
Query.builder()
|
||||||
.table(ChapterTable.TABLE)
|
.table(ChapterTable.TABLE)
|
||||||
.where("${ChapterTable.COL_URL} = ? AND ${ChapterTable.COL_MANGA_ID} = ?")
|
.where("${ChapterTable.COL_URL} = ? AND ${ChapterTable.COL_MANGA_ID} = ?")
|
||||||
.whereArgs(url, mangaId)
|
.whereArgs(url, mangaId)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun insertChapter(chapter: Chapter) = db.put().`object`(chapter).prepare()
|
fun insertChapter(chapter: Chapter) = db.put().`object`(chapter).prepare()
|
||||||
|
@ -24,30 +24,36 @@ interface HistoryQueries : DbProvider {
|
|||||||
*/
|
*/
|
||||||
fun getRecentManga(date: Date) = db.get()
|
fun getRecentManga(date: Date) = db.get()
|
||||||
.listOfObjects(MangaChapterHistory::class.java)
|
.listOfObjects(MangaChapterHistory::class.java)
|
||||||
.withQuery(RawQuery.builder()
|
.withQuery(
|
||||||
|
RawQuery.builder()
|
||||||
.query(getRecentMangasQuery())
|
.query(getRecentMangasQuery())
|
||||||
.args(date.time)
|
.args(date.time)
|
||||||
.observesTables(HistoryTable.TABLE)
|
.observesTables(HistoryTable.TABLE)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
|
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun getHistoryByMangaId(mangaId: Long) = db.get()
|
fun getHistoryByMangaId(mangaId: Long) = db.get()
|
||||||
.listOfObjects(History::class.java)
|
.listOfObjects(History::class.java)
|
||||||
.withQuery(RawQuery.builder()
|
.withQuery(
|
||||||
|
RawQuery.builder()
|
||||||
.query(getHistoryByMangaId())
|
.query(getHistoryByMangaId())
|
||||||
.args(mangaId)
|
.args(mangaId)
|
||||||
.observesTables(HistoryTable.TABLE)
|
.observesTables(HistoryTable.TABLE)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun getHistoryByChapterUrl(chapterUrl: String) = db.get()
|
fun getHistoryByChapterUrl(chapterUrl: String) = db.get()
|
||||||
.`object`(History::class.java)
|
.`object`(History::class.java)
|
||||||
.withQuery(RawQuery.builder()
|
.withQuery(
|
||||||
|
RawQuery.builder()
|
||||||
.query(getHistoryByChapterUrl())
|
.query(getHistoryByChapterUrl())
|
||||||
.args(chapterUrl)
|
.args(chapterUrl)
|
||||||
.observesTables(HistoryTable.TABLE)
|
.observesTables(HistoryTable.TABLE)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,16 +77,20 @@ interface HistoryQueries : DbProvider {
|
|||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun deleteHistory() = db.delete()
|
fun deleteHistory() = db.delete()
|
||||||
.byQuery(DeleteQuery.builder()
|
.byQuery(
|
||||||
|
DeleteQuery.builder()
|
||||||
.table(HistoryTable.TABLE)
|
.table(HistoryTable.TABLE)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun deleteHistoryNoLastRead() = db.delete()
|
fun deleteHistoryNoLastRead() = db.delete()
|
||||||
.byQuery(DeleteQuery.builder()
|
.byQuery(
|
||||||
|
DeleteQuery.builder()
|
||||||
.table(HistoryTable.TABLE)
|
.table(HistoryTable.TABLE)
|
||||||
.where("${HistoryTable.COL_LAST_READ} = ?")
|
.where("${HistoryTable.COL_LAST_READ} = ?")
|
||||||
.whereArgs(0)
|
.whereArgs(0)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,13 @@ interface MangaCategoryQueries : DbProvider {
|
|||||||
fun insertMangasCategories(mangasCategories: List<MangaCategory>) = db.put().objects(mangasCategories).prepare()
|
fun insertMangasCategories(mangasCategories: List<MangaCategory>) = db.put().objects(mangasCategories).prepare()
|
||||||
|
|
||||||
fun deleteOldMangasCategories(mangas: List<Manga>) = db.delete()
|
fun deleteOldMangasCategories(mangas: List<Manga>) = db.delete()
|
||||||
.byQuery(DeleteQuery.builder()
|
.byQuery(
|
||||||
|
DeleteQuery.builder()
|
||||||
.table(MangaCategoryTable.TABLE)
|
.table(MangaCategoryTable.TABLE)
|
||||||
.where("${MangaCategoryTable.COL_MANGA_ID} IN (${Queries.placeholders(mangas.size)})")
|
.where("${MangaCategoryTable.COL_MANGA_ID} IN (${Queries.placeholders(mangas.size)})")
|
||||||
.whereArgs(*mangas.map { it.id }.toTypedArray())
|
.whereArgs(*mangas.map { it.id }.toTypedArray())
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun setMangaCategories(mangasCategories: List<MangaCategory>, mangas: List<Manga>) {
|
fun setMangaCategories(mangasCategories: List<MangaCategory>, mangas: List<Manga>) {
|
||||||
|
@ -21,46 +21,56 @@ interface MangaQueries : DbProvider {
|
|||||||
|
|
||||||
fun getMangas() = db.get()
|
fun getMangas() = db.get()
|
||||||
.listOfObjects(Manga::class.java)
|
.listOfObjects(Manga::class.java)
|
||||||
.withQuery(Query.builder()
|
.withQuery(
|
||||||
|
Query.builder()
|
||||||
.table(MangaTable.TABLE)
|
.table(MangaTable.TABLE)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun getLibraryMangas() = db.get()
|
fun getLibraryMangas() = db.get()
|
||||||
.listOfObjects(LibraryManga::class.java)
|
.listOfObjects(LibraryManga::class.java)
|
||||||
.withQuery(RawQuery.builder()
|
.withQuery(
|
||||||
|
RawQuery.builder()
|
||||||
.query(libraryQuery)
|
.query(libraryQuery)
|
||||||
.observesTables(MangaTable.TABLE, ChapterTable.TABLE, MangaCategoryTable.TABLE, CategoryTable.TABLE)
|
.observesTables(MangaTable.TABLE, ChapterTable.TABLE, MangaCategoryTable.TABLE, CategoryTable.TABLE)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.withGetResolver(LibraryMangaGetResolver.INSTANCE)
|
.withGetResolver(LibraryMangaGetResolver.INSTANCE)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun getFavoriteMangas() = db.get()
|
fun getFavoriteMangas() = db.get()
|
||||||
.listOfObjects(Manga::class.java)
|
.listOfObjects(Manga::class.java)
|
||||||
.withQuery(Query.builder()
|
.withQuery(
|
||||||
|
Query.builder()
|
||||||
.table(MangaTable.TABLE)
|
.table(MangaTable.TABLE)
|
||||||
.where("${MangaTable.COL_FAVORITE} = ?")
|
.where("${MangaTable.COL_FAVORITE} = ?")
|
||||||
.whereArgs(1)
|
.whereArgs(1)
|
||||||
.orderBy(MangaTable.COL_TITLE)
|
.orderBy(MangaTable.COL_TITLE)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun getManga(url: String, sourceId: Long) = db.get()
|
fun getManga(url: String, sourceId: Long) = db.get()
|
||||||
.`object`(Manga::class.java)
|
.`object`(Manga::class.java)
|
||||||
.withQuery(Query.builder()
|
.withQuery(
|
||||||
|
Query.builder()
|
||||||
.table(MangaTable.TABLE)
|
.table(MangaTable.TABLE)
|
||||||
.where("${MangaTable.COL_URL} = ? AND ${MangaTable.COL_SOURCE} = ?")
|
.where("${MangaTable.COL_URL} = ? AND ${MangaTable.COL_SOURCE} = ?")
|
||||||
.whereArgs(url, sourceId)
|
.whereArgs(url, sourceId)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun getManga(id: Long) = db.get()
|
fun getManga(id: Long) = db.get()
|
||||||
.`object`(Manga::class.java)
|
.`object`(Manga::class.java)
|
||||||
.withQuery(Query.builder()
|
.withQuery(
|
||||||
|
Query.builder()
|
||||||
.table(MangaTable.TABLE)
|
.table(MangaTable.TABLE)
|
||||||
.where("${MangaTable.COL_ID} = ?")
|
.where("${MangaTable.COL_ID} = ?")
|
||||||
.whereArgs(id)
|
.whereArgs(id)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun insertManga(manga: Manga) = db.put().`object`(manga).prepare()
|
fun insertManga(manga: Manga) = db.put().`object`(manga).prepare()
|
||||||
@ -97,40 +107,50 @@ interface MangaQueries : DbProvider {
|
|||||||
fun deleteMangas(mangas: List<Manga>) = db.delete().objects(mangas).prepare()
|
fun deleteMangas(mangas: List<Manga>) = db.delete().objects(mangas).prepare()
|
||||||
|
|
||||||
fun deleteMangasNotInLibrary() = db.delete()
|
fun deleteMangasNotInLibrary() = db.delete()
|
||||||
.byQuery(DeleteQuery.builder()
|
.byQuery(
|
||||||
|
DeleteQuery.builder()
|
||||||
.table(MangaTable.TABLE)
|
.table(MangaTable.TABLE)
|
||||||
.where("${MangaTable.COL_FAVORITE} = ?")
|
.where("${MangaTable.COL_FAVORITE} = ?")
|
||||||
.whereArgs(0)
|
.whereArgs(0)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun deleteMangas() = db.delete()
|
fun deleteMangas() = db.delete()
|
||||||
.byQuery(DeleteQuery.builder()
|
.byQuery(
|
||||||
|
DeleteQuery.builder()
|
||||||
.table(MangaTable.TABLE)
|
.table(MangaTable.TABLE)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun getLastReadManga() = db.get()
|
fun getLastReadManga() = db.get()
|
||||||
.listOfObjects(Manga::class.java)
|
.listOfObjects(Manga::class.java)
|
||||||
.withQuery(RawQuery.builder()
|
.withQuery(
|
||||||
|
RawQuery.builder()
|
||||||
.query(getLastReadMangaQuery())
|
.query(getLastReadMangaQuery())
|
||||||
.observesTables(MangaTable.TABLE)
|
.observesTables(MangaTable.TABLE)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun getTotalChapterManga() = db.get()
|
fun getTotalChapterManga() = db.get()
|
||||||
.listOfObjects(Manga::class.java)
|
.listOfObjects(Manga::class.java)
|
||||||
.withQuery(RawQuery.builder()
|
.withQuery(
|
||||||
|
RawQuery.builder()
|
||||||
.query(getTotalChapterMangaQuery())
|
.query(getTotalChapterMangaQuery())
|
||||||
.observesTables(MangaTable.TABLE)
|
.observesTables(MangaTable.TABLE)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun getLatestChapterManga() = db.get()
|
fun getLatestChapterManga() = db.get()
|
||||||
.listOfObjects(Manga::class.java)
|
.listOfObjects(Manga::class.java)
|
||||||
.withQuery(RawQuery.builder()
|
.withQuery(
|
||||||
|
RawQuery.builder()
|
||||||
.query(getLatestChapterMangaQuery())
|
.query(getLatestChapterMangaQuery())
|
||||||
.observesTables(MangaTable.TABLE)
|
.observesTables(MangaTable.TABLE)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* 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}
|
SELECT M.*, COALESCE(MC.${MangaCategory.COL_CATEGORY_ID}, 0) AS ${Manga.COL_CATEGORY}
|
||||||
FROM (
|
FROM (
|
||||||
SELECT ${Manga.TABLE}.*, COALESCE(C.unread, 0) AS ${Manga.COL_UNREAD}
|
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.
|
* 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}
|
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}
|
ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}
|
||||||
WHERE ${Manga.COL_FAVORITE} = 1 AND ${Chapter.COL_DATE_UPLOAD} > ?
|
WHERE ${Manga.COL_FAVORITE} = 1 AND ${Chapter.COL_DATE_UPLOAD} > ?
|
||||||
@ -47,7 +49,8 @@ fun getRecentsQuery() = """
|
|||||||
* and are read after the given time period
|
* and are read after the given time period
|
||||||
* @return return limit is 25
|
* @return return limit is 25
|
||||||
*/
|
*/
|
||||||
fun getRecentMangasQuery() = """
|
fun getRecentMangasQuery() =
|
||||||
|
"""
|
||||||
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.*
|
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.*
|
||||||
FROM ${Manga.TABLE}
|
FROM ${Manga.TABLE}
|
||||||
JOIN ${Chapter.TABLE}
|
JOIN ${Chapter.TABLE}
|
||||||
@ -65,7 +68,8 @@ fun getRecentMangasQuery() = """
|
|||||||
LIMIT 25
|
LIMIT 25
|
||||||
"""
|
"""
|
||||||
|
|
||||||
fun getHistoryByMangaId() = """
|
fun getHistoryByMangaId() =
|
||||||
|
"""
|
||||||
SELECT ${History.TABLE}.*
|
SELECT ${History.TABLE}.*
|
||||||
FROM ${History.TABLE}
|
FROM ${History.TABLE}
|
||||||
JOIN ${Chapter.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}
|
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}.*
|
SELECT ${History.TABLE}.*
|
||||||
FROM ${History.TABLE}
|
FROM ${History.TABLE}
|
||||||
JOIN ${Chapter.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}
|
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
|
SELECT ${Manga.TABLE}.*, MAX(${History.TABLE}.${History.COL_LAST_READ}) AS max
|
||||||
FROM ${Manga.TABLE}
|
FROM ${Manga.TABLE}
|
||||||
JOIN ${Chapter.TABLE}
|
JOIN ${Chapter.TABLE}
|
||||||
@ -93,7 +99,8 @@ fun getLastReadMangaQuery() = """
|
|||||||
ORDER BY max DESC
|
ORDER BY max DESC
|
||||||
"""
|
"""
|
||||||
|
|
||||||
fun getTotalChapterMangaQuery() = """
|
fun getTotalChapterMangaQuery() =
|
||||||
|
"""
|
||||||
SELECT ${Manga.TABLE}.*
|
SELECT ${Manga.TABLE}.*
|
||||||
FROM ${Manga.TABLE}
|
FROM ${Manga.TABLE}
|
||||||
JOIN ${Chapter.TABLE}
|
JOIN ${Chapter.TABLE}
|
||||||
@ -102,7 +109,8 @@ fun getTotalChapterMangaQuery() = """
|
|||||||
ORDER by COUNT(*)
|
ORDER by COUNT(*)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
fun getLatestChapterMangaQuery() = """
|
fun getLatestChapterMangaQuery() =
|
||||||
|
"""
|
||||||
SELECT ${Manga.TABLE}.*, MAX(${Chapter.TABLE}.${Chapter.COL_DATE_UPLOAD}) AS max
|
SELECT ${Manga.TABLE}.*, MAX(${Chapter.TABLE}.${Chapter.COL_DATE_UPLOAD}) AS max
|
||||||
FROM ${Manga.TABLE}
|
FROM ${Manga.TABLE}
|
||||||
JOIN ${Chapter.TABLE}
|
JOIN ${Chapter.TABLE}
|
||||||
@ -114,7 +122,8 @@ fun getLatestChapterMangaQuery() = """
|
|||||||
/**
|
/**
|
||||||
* Query to get the categories for a manga.
|
* Query to get the categories for a manga.
|
||||||
*/
|
*/
|
||||||
fun getCategoriesForMangaQuery() = """
|
fun getCategoriesForMangaQuery() =
|
||||||
|
"""
|
||||||
SELECT ${Category.TABLE}.* FROM ${Category.TABLE}
|
SELECT ${Category.TABLE}.* FROM ${Category.TABLE}
|
||||||
JOIN ${MangaCategory.TABLE} ON ${Category.TABLE}.${Category.COL_ID} =
|
JOIN ${MangaCategory.TABLE} ON ${Category.TABLE}.${Category.COL_ID} =
|
||||||
${MangaCategory.TABLE}.${MangaCategory.COL_CATEGORY_ID}
|
${MangaCategory.TABLE}.${MangaCategory.COL_CATEGORY_ID}
|
||||||
|
@ -12,11 +12,13 @@ interface TrackQueries : DbProvider {
|
|||||||
|
|
||||||
fun getTracks(manga: Manga) = db.get()
|
fun getTracks(manga: Manga) = db.get()
|
||||||
.listOfObjects(Track::class.java)
|
.listOfObjects(Track::class.java)
|
||||||
.withQuery(Query.builder()
|
.withQuery(
|
||||||
|
Query.builder()
|
||||||
.table(TrackTable.TABLE)
|
.table(TrackTable.TABLE)
|
||||||
.where("${TrackTable.COL_MANGA_ID} = ?")
|
.where("${TrackTable.COL_MANGA_ID} = ?")
|
||||||
.whereArgs(manga.id)
|
.whereArgs(manga.id)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
fun insertTrack(track: Track) = db.put().`object`(track).prepare()
|
fun insertTrack(track: Track) = db.put().`object`(track).prepare()
|
||||||
@ -24,10 +26,12 @@ interface TrackQueries : DbProvider {
|
|||||||
fun insertTracks(tracks: List<Track>) = db.put().objects(tracks).prepare()
|
fun insertTracks(tracks: List<Track>) = db.put().objects(tracks).prepare()
|
||||||
|
|
||||||
fun deleteTrackForManga(manga: Manga, sync: TrackService) = db.delete()
|
fun deleteTrackForManga(manga: Manga, sync: TrackService) = db.delete()
|
||||||
.byQuery(DeleteQuery.builder()
|
.byQuery(
|
||||||
|
DeleteQuery.builder()
|
||||||
.table(TrackTable.TABLE)
|
.table(TrackTable.TABLE)
|
||||||
.where("${TrackTable.COL_MANGA_ID} = ? AND ${TrackTable.COL_SYNC_ID} = ?")
|
.where("${TrackTable.COL_MANGA_ID} = ? AND ${TrackTable.COL_SYNC_ID} = ?")
|
||||||
.whereArgs(manga.id, sync.id)
|
.whereArgs(manga.id, sync.id)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,13 @@ class HistoryLastReadPutResolver : HistoryPutResolver() {
|
|||||||
override fun performPut(@NonNull db: StorIOSQLite, @NonNull history: History): PutResult = db.inTransactionReturn {
|
override fun performPut(@NonNull db: StorIOSQLite, @NonNull history: History): PutResult = db.inTransactionReturn {
|
||||||
val updateQuery = mapToUpdateQuery(history)
|
val updateQuery = mapToUpdateQuery(history)
|
||||||
|
|
||||||
val cursor = db.lowLevel().query(Query.builder()
|
val cursor = db.lowLevel().query(
|
||||||
|
Query.builder()
|
||||||
.table(updateQuery.table())
|
.table(updateQuery.table())
|
||||||
.where(updateQuery.where())
|
.where(updateQuery.where())
|
||||||
.whereArgs(updateQuery.whereArgs())
|
.whereArgs(updateQuery.whereArgs())
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
|
|
||||||
val putResult: PutResult
|
val putResult: PutResult
|
||||||
|
|
||||||
|
@ -13,7 +13,8 @@ object CategoryTable {
|
|||||||
const val COL_FLAGS = "flags"
|
const val COL_FLAGS = "flags"
|
||||||
|
|
||||||
val createTableQuery: String
|
val createTableQuery: String
|
||||||
get() = """CREATE TABLE $TABLE(
|
get() =
|
||||||
|
"""CREATE TABLE $TABLE(
|
||||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||||
$COL_NAME TEXT NOT NULL,
|
$COL_NAME TEXT NOT NULL,
|
||||||
$COL_ORDER INTEGER NOT NULL,
|
$COL_ORDER INTEGER NOT NULL,
|
||||||
|
@ -29,7 +29,8 @@ object ChapterTable {
|
|||||||
const val COL_SOURCE_ORDER = "source_order"
|
const val COL_SOURCE_ORDER = "source_order"
|
||||||
|
|
||||||
val createTableQuery: String
|
val createTableQuery: String
|
||||||
get() = """CREATE TABLE $TABLE(
|
get() =
|
||||||
|
"""CREATE TABLE $TABLE(
|
||||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||||
$COL_MANGA_ID INTEGER NOT NULL,
|
$COL_MANGA_ID INTEGER NOT NULL,
|
||||||
$COL_URL TEXT NOT NULL,
|
$COL_URL TEXT NOT NULL,
|
||||||
|
@ -31,7 +31,8 @@ object HistoryTable {
|
|||||||
* query to create history table
|
* query to create history table
|
||||||
*/
|
*/
|
||||||
val createTableQuery: String
|
val createTableQuery: String
|
||||||
get() = """CREATE TABLE $TABLE(
|
get() =
|
||||||
|
"""CREATE TABLE $TABLE(
|
||||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||||
$COL_CHAPTER_ID INTEGER NOT NULL UNIQUE,
|
$COL_CHAPTER_ID INTEGER NOT NULL UNIQUE,
|
||||||
$COL_LAST_READ LONG,
|
$COL_LAST_READ LONG,
|
||||||
|
@ -11,7 +11,8 @@ object MangaCategoryTable {
|
|||||||
const val COL_CATEGORY_ID = "category_id"
|
const val COL_CATEGORY_ID = "category_id"
|
||||||
|
|
||||||
val createTableQuery: String
|
val createTableQuery: String
|
||||||
get() = """CREATE TABLE $TABLE(
|
get() =
|
||||||
|
"""CREATE TABLE $TABLE(
|
||||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||||
$COL_MANGA_ID INTEGER NOT NULL,
|
$COL_MANGA_ID INTEGER NOT NULL,
|
||||||
$COL_CATEGORY_ID INTEGER NOT NULL,
|
$COL_CATEGORY_ID INTEGER NOT NULL,
|
||||||
|
@ -39,7 +39,8 @@ object MangaTable {
|
|||||||
const val COL_CATEGORY = "category"
|
const val COL_CATEGORY = "category"
|
||||||
|
|
||||||
val createTableQuery: String
|
val createTableQuery: String
|
||||||
get() = """CREATE TABLE $TABLE(
|
get() =
|
||||||
|
"""CREATE TABLE $TABLE(
|
||||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||||
$COL_SOURCE INTEGER NOT NULL,
|
$COL_SOURCE INTEGER NOT NULL,
|
||||||
$COL_URL TEXT NOT NULL,
|
$COL_URL TEXT NOT NULL,
|
||||||
|
@ -31,7 +31,8 @@ object TrackTable {
|
|||||||
const val COL_FINISH_DATE = "finish_date"
|
const val COL_FINISH_DATE = "finish_date"
|
||||||
|
|
||||||
val createTableQuery: String
|
val createTableQuery: String
|
||||||
get() = """CREATE TABLE $TABLE(
|
get() =
|
||||||
|
"""CREATE TABLE $TABLE(
|
||||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||||
$COL_MANGA_ID INTEGER NOT NULL,
|
$COL_MANGA_ID INTEGER NOT NULL,
|
||||||
$COL_SYNC_ID INTEGER NOT NULL,
|
$COL_SYNC_ID INTEGER NOT NULL,
|
||||||
|
@ -87,9 +87,11 @@ internal class DownloadNotifier(private val context: Context) {
|
|||||||
setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
|
setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
|
||||||
isDownloading = true
|
isDownloading = true
|
||||||
// Pause action
|
// Pause action
|
||||||
addAction(R.drawable.ic_pause_24dp,
|
addAction(
|
||||||
|
R.drawable.ic_pause_24dp,
|
||||||
context.getString(R.string.action_pause),
|
context.getString(R.string.action_pause),
|
||||||
NotificationReceiver.pauseDownloadsPendingBroadcast(context))
|
NotificationReceiver.pauseDownloadsPendingBroadcast(context)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val downloadingProgressText = context.getString(R.string.chapter_downloading_progress)
|
val downloadingProgressText = context.getString(R.string.chapter_downloading_progress)
|
||||||
@ -126,13 +128,17 @@ internal class DownloadNotifier(private val context: Context) {
|
|||||||
// Open download manager when clicked
|
// Open download manager when clicked
|
||||||
setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
|
setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
|
||||||
// Resume action
|
// Resume action
|
||||||
addAction(R.drawable.ic_play_arrow_24dp,
|
addAction(
|
||||||
|
R.drawable.ic_play_arrow_24dp,
|
||||||
context.getString(R.string.action_resume),
|
context.getString(R.string.action_resume),
|
||||||
NotificationReceiver.resumeDownloadsPendingBroadcast(context))
|
NotificationReceiver.resumeDownloadsPendingBroadcast(context)
|
||||||
|
)
|
||||||
// Clear action
|
// Clear action
|
||||||
addAction(R.drawable.ic_close_24dp,
|
addAction(
|
||||||
|
R.drawable.ic_close_24dp,
|
||||||
context.getString(R.string.action_cancel_all),
|
context.getString(R.string.action_cancel_all),
|
||||||
NotificationReceiver.clearDownloadsPendingBroadcast(context))
|
NotificationReceiver.clearDownloadsPendingBroadcast(context)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show notification.
|
// Show notification.
|
||||||
@ -173,8 +179,10 @@ internal class DownloadNotifier(private val context: Context) {
|
|||||||
fun onError(error: String? = null, chapter: String? = null) {
|
fun onError(error: String? = null, chapter: String? = null) {
|
||||||
// Create notification
|
// Create notification
|
||||||
with(notificationBuilder) {
|
with(notificationBuilder) {
|
||||||
setContentTitle(chapter
|
setContentTitle(
|
||||||
?: context.getString(R.string.download_notifier_downloader_title))
|
chapter
|
||||||
|
?: context.getString(R.string.download_notifier_downloader_title)
|
||||||
|
)
|
||||||
setContentText(error ?: context.getString(R.string.download_notifier_unknown_error))
|
setContentText(error ?: context.getString(R.string.download_notifier_unknown_error))
|
||||||
setSmallIcon(android.R.drawable.stat_sys_warning)
|
setSmallIcon(android.R.drawable.stat_sys_warning)
|
||||||
clearActions()
|
clearActions()
|
||||||
|
@ -125,12 +125,15 @@ class DownloadService : Service() {
|
|||||||
subscriptions += ReactiveNetwork.observeNetworkConnectivity(applicationContext)
|
subscriptions += ReactiveNetwork.observeNetworkConnectivity(applicationContext)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe({ state ->
|
.subscribe(
|
||||||
|
{ state ->
|
||||||
onNetworkStateChanged(state)
|
onNetworkStateChanged(state)
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
toast(R.string.download_queue_error)
|
toast(R.string.download_queue_error)
|
||||||
stopSelf()
|
stopSelf()
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -162,12 +165,13 @@ class DownloadService : Service() {
|
|||||||
*/
|
*/
|
||||||
private fun listenDownloaderState() {
|
private fun listenDownloaderState() {
|
||||||
subscriptions += downloadManager.runningRelay.subscribe { running ->
|
subscriptions += downloadManager.runningRelay.subscribe { running ->
|
||||||
if (running)
|
if (running) {
|
||||||
wakeLock.acquireIfNeeded()
|
wakeLock.acquireIfNeeded()
|
||||||
else
|
} else {
|
||||||
wakeLock.releaseIfNeeded()
|
wakeLock.releaseIfNeeded()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Releases the wake lock if it's held.
|
* Releases the wake lock if it's held.
|
||||||
|
@ -100,11 +100,13 @@ class Downloader(
|
|||||||
* @return true if the downloader is started, false otherwise.
|
* @return true if the downloader is started, false otherwise.
|
||||||
*/
|
*/
|
||||||
fun start(): Boolean {
|
fun start(): Boolean {
|
||||||
if (isRunning || queue.isEmpty())
|
if (isRunning || queue.isEmpty()) {
|
||||||
return false
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if (!subscriptions.hasSubscriptions())
|
if (!subscriptions.hasSubscriptions()) {
|
||||||
initializeSubscriptions()
|
initializeSubscriptions()
|
||||||
|
}
|
||||||
|
|
||||||
val pending = queue.filter { it.status != Download.DOWNLOADED }
|
val pending = queue.filter { it.status != Download.DOWNLOADED }
|
||||||
pending.forEach { if (it.status != Download.QUEUE) it.status = Download.QUEUE }
|
pending.forEach { if (it.status != Download.QUEUE) it.status = Download.QUEUE }
|
||||||
@ -177,13 +179,16 @@ class Downloader(
|
|||||||
.concatMap { downloadChapter(it).subscribeOn(Schedulers.io()) }
|
.concatMap { downloadChapter(it).subscribeOn(Schedulers.io()) }
|
||||||
.onBackpressureBuffer()
|
.onBackpressureBuffer()
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe({
|
.subscribe(
|
||||||
|
{
|
||||||
completeDownload(it)
|
completeDownload(it)
|
||||||
}, { error ->
|
},
|
||||||
|
{ error ->
|
||||||
DownloadService.stop(context)
|
DownloadService.stop(context)
|
||||||
Timber.e(error)
|
Timber.e(error)
|
||||||
notifier.onError(error.message)
|
notifier.onError(error.message)
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -304,8 +309,9 @@ class Downloader(
|
|||||||
*/
|
*/
|
||||||
private fun getOrDownloadImage(page: Page, download: Download, tmpDir: UniFile): Observable<Page> {
|
private fun getOrDownloadImage(page: Page, download: Download, tmpDir: UniFile): Observable<Page> {
|
||||||
// If the image URL is empty, do nothing
|
// If the image URL is empty, do nothing
|
||||||
if (page.imageUrl == null)
|
if (page.imageUrl == null) {
|
||||||
return Observable.just(page)
|
return Observable.just(page)
|
||||||
|
}
|
||||||
|
|
||||||
val filename = String.format("%03d", page.number)
|
val filename = String.format("%03d", page.number)
|
||||||
val tmpFile = tmpDir.findFile("$filename.tmp")
|
val tmpFile = tmpDir.findFile("$filename.tmp")
|
||||||
@ -317,10 +323,11 @@ class Downloader(
|
|||||||
val imageFile = tmpDir.listFiles()!!.find { it.name!!.startsWith("$filename.") }
|
val imageFile = tmpDir.listFiles()!!.find { it.name!!.startsWith("$filename.") }
|
||||||
|
|
||||||
// If the image is already downloaded, do nothing. Otherwise download from network
|
// 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)
|
Observable.just(imageFile)
|
||||||
else
|
} else {
|
||||||
downloadImage(page, download.source, tmpDir, filename)
|
downloadImage(page, download.source, tmpDir, filename)
|
||||||
|
}
|
||||||
|
|
||||||
return pageObservable
|
return pageObservable
|
||||||
// When the image is ready, set image path, progress (just in case) and status
|
// When the image is ready, set image path, progress (just in case) and status
|
||||||
@ -400,7 +407,6 @@ class Downloader(
|
|||||||
tmpDir: UniFile,
|
tmpDir: UniFile,
|
||||||
dirname: String
|
dirname: String
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// Ensure that the chapter folder has all the images.
|
// Ensure that the chapter folder has all the images.
|
||||||
val downloadedImages = tmpDir.listFiles().orEmpty().filterNot { it.name!!.endsWith(".tmp") }
|
val downloadedImages = tmpDir.listFiles().orEmpty().filterNot { it.name!!.endsWith(".tmp") }
|
||||||
|
|
||||||
|
@ -25,7 +25,9 @@ class LibraryMangaUrlFetcher(
|
|||||||
|
|
||||||
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
|
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
networkFetcher.loadData(priority, object : DataFetcher.DataCallback<InputStream> {
|
networkFetcher.loadData(
|
||||||
|
priority,
|
||||||
|
object : DataFetcher.DataCallback<InputStream> {
|
||||||
override fun onDataReady(data: InputStream?) {
|
override fun onDataReady(data: InputStream?) {
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
val tmpFile = File(file.path + ".tmp")
|
val tmpFile = File(file.path + ".tmp")
|
||||||
@ -54,7 +56,8 @@ class LibraryMangaUrlFetcher(
|
|||||||
override fun onLoadFailed(e: Exception) {
|
override fun onLoadFailed(e: Exception) {
|
||||||
callback.onLoadFailed(e)
|
callback.onLoadFailed(e)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
loadFromFile(callback)
|
loadFromFile(callback)
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,10 @@ class TachiGlideModule : AppGlideModule() {
|
|||||||
override fun applyOptions(context: Context, builder: GlideBuilder) {
|
override fun applyOptions(context: Context, builder: GlideBuilder) {
|
||||||
builder.setDiskCache(InternalCacheDiskCacheFactory(context, 50 * 1024 * 1024))
|
builder.setDiskCache(InternalCacheDiskCacheFactory(context, 50 * 1024 * 1024))
|
||||||
builder.setDefaultRequestOptions(RequestOptions().format(DecodeFormat.PREFER_RGB_565))
|
builder.setDefaultRequestOptions(RequestOptions().format(DecodeFormat.PREFER_RGB_565))
|
||||||
builder.setDefaultTransitionOptions(Drawable::class.java,
|
builder.setDefaultTransitionOptions(
|
||||||
DrawableTransitionOptions.withCrossFade())
|
Drawable::class.java,
|
||||||
|
DrawableTransitionOptions.withCrossFade()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
|
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.replace(GlideUrl::class.java, InputStream::class.java, networkFactory)
|
||||||
registry.append(MangaThumbnail::class.java, InputStream::class.java, MangaThumbnailModelLoader.Factory())
|
registry.append(MangaThumbnail::class.java, InputStream::class.java, MangaThumbnailModelLoader.Factory())
|
||||||
registry.append(InputStream::class.java, InputStream::class.java, PassthroughModelLoader
|
registry.append(
|
||||||
.Factory())
|
InputStream::class.java, InputStream::class.java,
|
||||||
|
PassthroughModelLoader
|
||||||
|
.Factory()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,10 +30,11 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
if (interval > 0) {
|
if (interval > 0) {
|
||||||
val restrictions = preferences.libraryUpdateRestriction()!!
|
val restrictions = preferences.libraryUpdateRestriction()!!
|
||||||
val acRestriction = "ac" in restrictions
|
val acRestriction = "ac" in restrictions
|
||||||
val wifiRestriction = if ("wifi" in restrictions)
|
val wifiRestriction = if ("wifi" in restrictions) {
|
||||||
NetworkType.UNMETERED
|
NetworkType.UNMETERED
|
||||||
else
|
} else {
|
||||||
NetworkType.CONNECTED
|
NetworkType.CONNECTED
|
||||||
|
}
|
||||||
|
|
||||||
val constraints = Constraints.Builder()
|
val constraints = Constraints.Builder()
|
||||||
.setRequiredNetworkType(wifiRestriction)
|
.setRequiredNetworkType(wifiRestriction)
|
||||||
@ -42,7 +43,8 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
|
|
||||||
val request = PeriodicWorkRequestBuilder<LibraryUpdateJob>(
|
val request = PeriodicWorkRequestBuilder<LibraryUpdateJob>(
|
||||||
interval.toLong(), TimeUnit.HOURS,
|
interval.toLong(), TimeUnit.HOURS,
|
||||||
10, TimeUnit.MINUTES)
|
10, TimeUnit.MINUTES
|
||||||
|
)
|
||||||
.addTag(TAG)
|
.addTag(TAG)
|
||||||
.setConstraints(constraints)
|
.setConstraints(constraints)
|
||||||
.build()
|
.build()
|
||||||
|
@ -9,7 +9,8 @@ object LibraryUpdateRanker {
|
|||||||
|
|
||||||
val rankingScheme = listOf(
|
val rankingScheme = listOf(
|
||||||
(this::lexicographicRanking)(),
|
(this::lexicographicRanking)(),
|
||||||
(this::latestFirstRanking)())
|
(this::latestFirstRanking)()
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a total ordering over all the Mangas.
|
* Provides a total ordering over all the Mangas.
|
||||||
|
@ -184,7 +184,8 @@ class LibraryUpdateService(
|
|||||||
super.onCreate()
|
super.onCreate()
|
||||||
startForeground(Notifications.ID_LIBRARY_PROGRESS, progressNotificationBuilder.build())
|
startForeground(Notifications.ID_LIBRARY_PROGRESS, progressNotificationBuilder.build())
|
||||||
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
|
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
|
||||||
PowerManager.PARTIAL_WAKE_LOCK, "LibraryUpdateService:WakeLock")
|
PowerManager.PARTIAL_WAKE_LOCK, "LibraryUpdateService:WakeLock"
|
||||||
|
)
|
||||||
wakeLock.acquire()
|
wakeLock.acquire()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,13 +239,17 @@ class LibraryUpdateService(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.subscribe({
|
.subscribe(
|
||||||
}, {
|
{
|
||||||
|
},
|
||||||
|
{
|
||||||
Timber.e(it)
|
Timber.e(it)
|
||||||
stopSelf(startId)
|
stopSelf(startId)
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
stopSelf(startId)
|
stopSelf(startId)
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return START_REDELIVER_INTENT
|
return START_REDELIVER_INTENT
|
||||||
}
|
}
|
||||||
@ -259,17 +264,18 @@ class LibraryUpdateService(
|
|||||||
fun getMangaToUpdate(intent: Intent, target: Target): List<LibraryManga> {
|
fun getMangaToUpdate(intent: Intent, target: Target): List<LibraryManga> {
|
||||||
val categoryId = intent.getIntExtra(KEY_CATEGORY, -1)
|
val categoryId = intent.getIntExtra(KEY_CATEGORY, -1)
|
||||||
|
|
||||||
var listToUpdate = if (categoryId != -1)
|
var listToUpdate = if (categoryId != -1) {
|
||||||
db.getLibraryMangas().executeAsBlocking().filter { it.category == categoryId }
|
db.getLibraryMangas().executeAsBlocking().filter { it.category == categoryId }
|
||||||
else {
|
} else {
|
||||||
val categoriesToUpdate = preferences.libraryUpdateCategories().get().map(String::toInt)
|
val categoriesToUpdate = preferences.libraryUpdateCategories().get().map(String::toInt)
|
||||||
if (categoriesToUpdate.isNotEmpty())
|
if (categoriesToUpdate.isNotEmpty()) {
|
||||||
db.getLibraryMangas().executeAsBlocking()
|
db.getLibraryMangas().executeAsBlocking()
|
||||||
.filter { it.category in categoriesToUpdate }
|
.filter { it.category in categoriesToUpdate }
|
||||||
.distinctBy { it.id }
|
.distinctBy { it.id }
|
||||||
else
|
} else {
|
||||||
db.getLibraryMangas().executeAsBlocking().distinctBy { it.id }
|
db.getLibraryMangas().executeAsBlocking().distinctBy { it.id }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (target == Target.CHAPTERS && preferences.updateOnlyNonCompleted()) {
|
if (target == Target.CHAPTERS && preferences.updateOnlyNonCompleted()) {
|
||||||
listToUpdate = listToUpdate.filter { it.status != SManga.COMPLETED }
|
listToUpdate = listToUpdate.filter { it.status != SManga.COMPLETED }
|
||||||
}
|
}
|
||||||
@ -315,9 +321,11 @@ class LibraryUpdateService(
|
|||||||
// Filter out mangas without new chapters (or failed).
|
// Filter out mangas without new chapters (or failed).
|
||||||
.filter { pair -> pair.first.isNotEmpty() }
|
.filter { pair -> pair.first.isNotEmpty() }
|
||||||
.doOnNext {
|
.doOnNext {
|
||||||
if (downloadNew && (categoriesToDownload.isEmpty() ||
|
if (downloadNew && (
|
||||||
manga.category in categoriesToDownload)) {
|
categoriesToDownload.isEmpty() ||
|
||||||
|
manga.category in categoriesToDownload
|
||||||
|
)
|
||||||
|
) {
|
||||||
downloadChapters(manga, it.first)
|
downloadChapters(manga, it.first)
|
||||||
hasDownloads = true
|
hasDownloads = true
|
||||||
}
|
}
|
||||||
@ -453,15 +461,19 @@ class LibraryUpdateService(
|
|||||||
* @param total the total progress.
|
* @param total the total progress.
|
||||||
*/
|
*/
|
||||||
private fun showProgressNotification(manga: Manga, current: Int, total: Int) {
|
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)
|
getString(R.string.notification_check_updates)
|
||||||
else
|
} else {
|
||||||
manga.title
|
manga.title
|
||||||
|
}
|
||||||
|
|
||||||
notificationManager.notify(Notifications.ID_LIBRARY_PROGRESS, progressNotificationBuilder
|
notificationManager.notify(
|
||||||
|
Notifications.ID_LIBRARY_PROGRESS,
|
||||||
|
progressNotificationBuilder
|
||||||
.setContentTitle(title)
|
.setContentTitle(title)
|
||||||
.setProgress(total, current, false)
|
.setProgress(total, current, false)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -476,7 +488,9 @@ class LibraryUpdateService(
|
|||||||
|
|
||||||
NotificationManagerCompat.from(this).apply {
|
NotificationManagerCompat.from(this).apply {
|
||||||
// Parent group notification
|
// Parent group notification
|
||||||
notify(Notifications.ID_NEW_CHAPTERS, notification(Notifications.CHANNEL_NEW_CHAPTERS) {
|
notify(
|
||||||
|
Notifications.ID_NEW_CHAPTERS,
|
||||||
|
notification(Notifications.CHANNEL_NEW_CHAPTERS) {
|
||||||
setContentTitle(getString(R.string.notification_new_chapters))
|
setContentTitle(getString(R.string.notification_new_chapters))
|
||||||
if (updates.size == 1 && !preferences.hideNotificationContent()) {
|
if (updates.size == 1 && !preferences.hideNotificationContent()) {
|
||||||
setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN))
|
setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN))
|
||||||
@ -484,9 +498,13 @@ class LibraryUpdateService(
|
|||||||
setContentText(resources.getQuantityString(R.plurals.notification_new_chapters_summary, updates.size, updates.size))
|
setContentText(resources.getQuantityString(R.plurals.notification_new_chapters_summary, updates.size, updates.size))
|
||||||
|
|
||||||
if (!preferences.hideNotificationContent()) {
|
if (!preferences.hideNotificationContent()) {
|
||||||
setStyle(NotificationCompat.BigTextStyle().bigText(updates.joinToString("\n") {
|
setStyle(
|
||||||
|
NotificationCompat.BigTextStyle().bigText(
|
||||||
|
updates.joinToString("\n") {
|
||||||
it.first.title.chop(NOTIF_TITLE_MAX_LEN)
|
it.first.title.chop(NOTIF_TITLE_MAX_LEN)
|
||||||
}))
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -500,7 +518,8 @@ class LibraryUpdateService(
|
|||||||
|
|
||||||
setContentIntent(getNotificationIntent())
|
setContentIntent(getNotificationIntent())
|
||||||
setAutoCancel(true)
|
setAutoCancel(true)
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// Per-manga notification
|
// Per-manga notification
|
||||||
if (!preferences.hideNotificationContent()) {
|
if (!preferences.hideNotificationContent()) {
|
||||||
@ -536,13 +555,21 @@ class LibraryUpdateService(
|
|||||||
setAutoCancel(true)
|
setAutoCancel(true)
|
||||||
|
|
||||||
// Mark chapters as read action
|
// Mark chapters as read action
|
||||||
addAction(R.drawable.ic_glasses_black_24dp, getString(R.string.action_mark_as_read),
|
addAction(
|
||||||
NotificationReceiver.markAsReadPendingBroadcast(this@LibraryUpdateService,
|
R.drawable.ic_glasses_black_24dp, getString(R.string.action_mark_as_read),
|
||||||
manga, chapters, Notifications.ID_NEW_CHAPTERS))
|
NotificationReceiver.markAsReadPendingBroadcast(
|
||||||
|
this@LibraryUpdateService,
|
||||||
|
manga, chapters, Notifications.ID_NEW_CHAPTERS
|
||||||
|
)
|
||||||
|
)
|
||||||
// View chapters action
|
// View chapters action
|
||||||
addAction(R.drawable.ic_book_24dp, getString(R.string.action_view_chapters),
|
addAction(
|
||||||
NotificationReceiver.openChapterPendingActivity(this@LibraryUpdateService,
|
R.drawable.ic_book_24dp, getString(R.string.action_view_chapters),
|
||||||
manga, Notifications.ID_NEW_CHAPTERS))
|
NotificationReceiver.openChapterPendingActivity(
|
||||||
|
this@LibraryUpdateService,
|
||||||
|
manga, Notifications.ID_NEW_CHAPTERS
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,8 +597,11 @@ class LibraryUpdateService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getNewChaptersDescription(chapters: Array<Chapter>): String {
|
private fun getNewChaptersDescription(chapters: Array<Chapter>): String {
|
||||||
val formatter = DecimalFormat("#.###", DecimalFormatSymbols()
|
val formatter = DecimalFormat(
|
||||||
.apply { decimalSeparator = '.' })
|
"#.###",
|
||||||
|
DecimalFormatSymbols()
|
||||||
|
.apply { decimalSeparator = '.' }
|
||||||
|
)
|
||||||
|
|
||||||
val displayableChapterNumbers = chapters
|
val displayableChapterNumbers = chapters
|
||||||
.filter { it.isRecognizedNumber }
|
.filter { it.isRecognizedNumber }
|
||||||
|
@ -54,22 +54,35 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
// Clear the download queue
|
// Clear the download queue
|
||||||
ACTION_CLEAR_DOWNLOADS -> downloadManager.clearQueue(true)
|
ACTION_CLEAR_DOWNLOADS -> downloadManager.clearQueue(true)
|
||||||
// Launch share activity and dismiss notification
|
// Launch share activity and dismiss notification
|
||||||
ACTION_SHARE_IMAGE -> shareImage(context, intent.getStringExtra(EXTRA_FILE_LOCATION),
|
ACTION_SHARE_IMAGE ->
|
||||||
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
|
shareImage(
|
||||||
|
context, intent.getStringExtra(EXTRA_FILE_LOCATION),
|
||||||
|
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
|
||||||
|
)
|
||||||
// Delete image from path and dismiss notification
|
// Delete image from path and dismiss notification
|
||||||
ACTION_DELETE_IMAGE -> deleteImage(context, intent.getStringExtra(EXTRA_FILE_LOCATION),
|
ACTION_DELETE_IMAGE ->
|
||||||
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
|
deleteImage(
|
||||||
|
context, intent.getStringExtra(EXTRA_FILE_LOCATION),
|
||||||
|
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
|
||||||
|
)
|
||||||
// Share backup file
|
// Share backup file
|
||||||
ACTION_SHARE_BACKUP -> shareBackup(context, intent.getParcelableExtra(EXTRA_URI),
|
ACTION_SHARE_BACKUP ->
|
||||||
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
|
shareBackup(
|
||||||
ACTION_CANCEL_RESTORE -> cancelRestore(context,
|
context, intent.getParcelableExtra(EXTRA_URI),
|
||||||
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
|
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
|
||||||
|
)
|
||||||
|
ACTION_CANCEL_RESTORE -> cancelRestore(
|
||||||
|
context,
|
||||||
|
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
|
||||||
|
)
|
||||||
// Cancel library update and dismiss notification
|
// Cancel library update and dismiss notification
|
||||||
ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context, Notifications.ID_LIBRARY_PROGRESS)
|
ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context, Notifications.ID_LIBRARY_PROGRESS)
|
||||||
// Open reader activity
|
// Open reader activity
|
||||||
ACTION_OPEN_CHAPTER -> {
|
ACTION_OPEN_CHAPTER -> {
|
||||||
openChapter(context, intent.getLongExtra(EXTRA_MANGA_ID, -1),
|
openChapter(
|
||||||
intent.getLongExtra(EXTRA_CHAPTER_ID, -1))
|
context, intent.getLongExtra(EXTRA_MANGA_ID, -1),
|
||||||
|
intent.getLongExtra(EXTRA_CHAPTER_ID, -1)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
// Mark updated manga chapters as read
|
// Mark updated manga chapters as read
|
||||||
ACTION_MARK_AS_READ -> {
|
ACTION_MARK_AS_READ -> {
|
||||||
|
@ -61,22 +61,34 @@ object Notifications {
|
|||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
|
||||||
|
|
||||||
val channels = listOf(
|
val channels = listOf(
|
||||||
NotificationChannel(CHANNEL_COMMON, context.getString(R.string.channel_common),
|
NotificationChannel(
|
||||||
NotificationManager.IMPORTANCE_LOW),
|
CHANNEL_COMMON, context.getString(R.string.channel_common),
|
||||||
NotificationChannel(CHANNEL_LIBRARY, context.getString(R.string.channel_library),
|
NotificationManager.IMPORTANCE_LOW
|
||||||
NotificationManager.IMPORTANCE_LOW).apply {
|
),
|
||||||
|
NotificationChannel(
|
||||||
|
CHANNEL_LIBRARY, context.getString(R.string.channel_library),
|
||||||
|
NotificationManager.IMPORTANCE_LOW
|
||||||
|
).apply {
|
||||||
setShowBadge(false)
|
setShowBadge(false)
|
||||||
},
|
},
|
||||||
NotificationChannel(CHANNEL_DOWNLOADER, context.getString(R.string.channel_downloader),
|
NotificationChannel(
|
||||||
NotificationManager.IMPORTANCE_LOW).apply {
|
CHANNEL_DOWNLOADER, context.getString(R.string.channel_downloader),
|
||||||
|
NotificationManager.IMPORTANCE_LOW
|
||||||
|
).apply {
|
||||||
setShowBadge(false)
|
setShowBadge(false)
|
||||||
},
|
},
|
||||||
NotificationChannel(CHANNEL_NEW_CHAPTERS, context.getString(R.string.channel_new_chapters),
|
NotificationChannel(
|
||||||
NotificationManager.IMPORTANCE_DEFAULT),
|
CHANNEL_NEW_CHAPTERS, context.getString(R.string.channel_new_chapters),
|
||||||
NotificationChannel(CHANNEL_UPDATES_TO_EXTS, context.getString(R.string.channel_ext_updates),
|
NotificationManager.IMPORTANCE_DEFAULT
|
||||||
NotificationManager.IMPORTANCE_DEFAULT),
|
),
|
||||||
NotificationChannel(CHANNEL_BACKUP_RESTORE, context.getString(R.string.channel_backup_restore),
|
NotificationChannel(
|
||||||
NotificationManager.IMPORTANCE_HIGH).apply {
|
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)
|
setShowBadge(false)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -45,12 +45,20 @@ class PreferencesHelper(val context: Context) {
|
|||||||
private val flowPrefs = FlowSharedPreferences(prefs)
|
private val flowPrefs = FlowSharedPreferences(prefs)
|
||||||
|
|
||||||
private val defaultDownloadsDir = Uri.fromFile(
|
private val defaultDownloadsDir = Uri.fromFile(
|
||||||
File(Environment.getExternalStorageDirectory().absolutePath + File.separator +
|
File(
|
||||||
context.getString(R.string.app_name), "downloads"))
|
Environment.getExternalStorageDirectory().absolutePath + File.separator +
|
||||||
|
context.getString(R.string.app_name),
|
||||||
|
"downloads"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
private val defaultBackupDir = Uri.fromFile(
|
private val defaultBackupDir = Uri.fromFile(
|
||||||
File(Environment.getExternalStorageDirectory().absolutePath + File.separator +
|
File(
|
||||||
context.getString(R.string.app_name), "backup"))
|
Environment.getExternalStorageDirectory().absolutePath + File.separator +
|
||||||
|
context.getString(R.string.app_name),
|
||||||
|
"backup"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
fun startScreen() = prefs.getInt(Keys.startScreen, 1)
|
fun startScreen() = prefs.getInt(Keys.startScreen, 1)
|
||||||
|
|
||||||
|
@ -25,7 +25,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
private val authClient = client.newBuilder().addInterceptor(interceptor).build()
|
private val authClient = client.newBuilder().addInterceptor(interceptor).build()
|
||||||
|
|
||||||
fun addLibManga(track: Track): Observable<Track> {
|
fun addLibManga(track: Track): Observable<Track> {
|
||||||
val query = """
|
val query =
|
||||||
|
"""
|
||||||
|mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) {
|
|mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) {
|
||||||
|SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status) {
|
|SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status) {
|
||||||
| id
|
| id
|
||||||
@ -62,7 +63,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun updateLibManga(track: Track): Observable<Track> {
|
fun updateLibManga(track: Track): Observable<Track> {
|
||||||
val query = """
|
val query =
|
||||||
|
"""
|
||||||
|mutation UpdateManga(${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}score: Int) {
|
|mutation UpdateManga(${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}score: Int) {
|
||||||
|SaveMediaListEntry (id: ${'$'}listId, progress: ${'$'}progress, status: ${'$'}status, scoreRaw: ${'$'}score) {
|
|SaveMediaListEntry (id: ${'$'}listId, progress: ${'$'}progress, status: ${'$'}status, scoreRaw: ${'$'}score) {
|
||||||
|id
|
|id
|
||||||
@ -94,7 +96,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun search(search: String): Observable<List<TrackSearch>> {
|
fun search(search: String): Observable<List<TrackSearch>> {
|
||||||
val query = """
|
val query =
|
||||||
|
"""
|
||||||
|query Search(${'$'}query: String) {
|
|query Search(${'$'}query: String) {
|
||||||
|Page (perPage: 50) {
|
|Page (perPage: 50) {
|
||||||
|media(search: ${'$'}query, type: MANGA, format_not_in: [NOVEL]) {
|
|media(search: ${'$'}query, type: MANGA, format_not_in: [NOVEL]) {
|
||||||
@ -147,7 +150,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun findLibManga(track: Track, userid: Int): Observable<Track?> {
|
fun findLibManga(track: Track, userid: Int): Observable<Track?> {
|
||||||
val query = """
|
val query =
|
||||||
|
"""
|
||||||
|query (${'$'}id: Int!, ${'$'}manga_id: Int!) {
|
|query (${'$'}id: Int!, ${'$'}manga_id: Int!) {
|
||||||
|Page {
|
|Page {
|
||||||
|mediaList(userId: ${'$'}id, type: MANGA, mediaId: ${'$'}manga_id) {
|
|mediaList(userId: ${'$'}id, type: MANGA, mediaId: ${'$'}manga_id) {
|
||||||
@ -216,7 +220,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getCurrentUser(): Observable<Pair<Int, String>> {
|
fun getCurrentUser(): Observable<Pair<Int, String>> {
|
||||||
val query = """
|
val query =
|
||||||
|
"""
|
||||||
|query User {
|
|query User {
|
||||||
|Viewer {
|
|Viewer {
|
||||||
|id
|
|id
|
||||||
@ -251,17 +256,24 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
private fun jsonToALManga(struct: JsonObject): ALManga {
|
private fun jsonToALManga(struct: JsonObject): ALManga {
|
||||||
val date = try {
|
val date = try {
|
||||||
val date = Calendar.getInstance()
|
val date = Calendar.getInstance()
|
||||||
date.set(struct["startDate"]["year"].nullInt ?: 0, (struct["startDate"]["month"].nullInt
|
date.set(
|
||||||
?: 0) - 1,
|
struct["startDate"]["year"].nullInt ?: 0,
|
||||||
struct["startDate"]["day"].nullInt ?: 0)
|
(
|
||||||
|
struct["startDate"]["month"].nullInt
|
||||||
|
?: 0
|
||||||
|
) - 1,
|
||||||
|
struct["startDate"]["day"].nullInt ?: 0
|
||||||
|
)
|
||||||
date.timeInMillis
|
date.timeInMillis
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
0L
|
0L
|
||||||
}
|
}
|
||||||
|
|
||||||
return ALManga(struct["id"].asInt, struct["title"]["romaji"].asString, struct["coverImage"]["large"].asString,
|
return ALManga(
|
||||||
|
struct["id"].asInt, struct["title"]["romaji"].asString, struct["coverImage"]["large"].asString,
|
||||||
struct["description"].nullString.orEmpty(), struct["type"].asString, struct["status"].asString,
|
struct["description"].nullString.orEmpty(), struct["type"].asString, struct["status"].asString,
|
||||||
date, struct["chapters"].nullInt ?: 0)
|
date, struct["chapters"].nullInt ?: 0
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun jsonToALUserManga(struct: JsonObject): ALUserManga {
|
private fun jsonToALUserManga(struct: JsonObject): ALUserManga {
|
||||||
|
@ -73,7 +73,8 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
|||||||
|
|
||||||
fun search(search: String): Observable<List<TrackSearch>> {
|
fun search(search: String): Observable<List<TrackSearch>> {
|
||||||
val url = Uri.parse(
|
val url = Uri.parse(
|
||||||
"$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}").buildUpon()
|
"$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}"
|
||||||
|
).buildUpon()
|
||||||
.appendQueryParameter("max_results", "20")
|
.appendQueryParameter("max_results", "20")
|
||||||
.build()
|
.build()
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
@ -109,9 +110,15 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
|||||||
return Track.create(TrackManager.BANGUMI).apply {
|
return Track.create(TrackManager.BANGUMI).apply {
|
||||||
title = mangas["name"].asString
|
title = mangas["name"].asString
|
||||||
media_id = mangas["id"].asInt
|
media_id = mangas["id"].asInt
|
||||||
score = if (mangas["rating"] != null)
|
score = if (mangas["rating"] != null) {
|
||||||
(if (mangas["rating"].isJsonObject) mangas["rating"].obj["score"].asFloat else 0f)
|
if (mangas["rating"].isJsonObject) {
|
||||||
else 0f
|
mangas["rating"].obj["score"].asFloat
|
||||||
|
} else {
|
||||||
|
0f
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
0f
|
||||||
|
}
|
||||||
status = Bangumi.DEFAULT_STATUS
|
status = Bangumi.DEFAULT_STATUS
|
||||||
tracking_url = mangas["url"].asString
|
tracking_url = mangas["url"].asString
|
||||||
}
|
}
|
||||||
@ -163,7 +170,8 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun accessTokenRequest(code: String) = POST(oauthUrl,
|
private fun accessTokenRequest(code: String) = POST(
|
||||||
|
oauthUrl,
|
||||||
body = FormBody.Builder()
|
body = FormBody.Builder()
|
||||||
.add("grant_type", "authorization_code")
|
.add("grant_type", "authorization_code")
|
||||||
.add("client_id", clientId)
|
.add("client_id", clientId)
|
||||||
@ -196,13 +204,15 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
|||||||
.appendQueryParameter("redirect_uri", redirectUrl)
|
.appendQueryParameter("redirect_uri", redirectUrl)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
fun refreshTokenRequest(token: String) = POST(oauthUrl,
|
fun refreshTokenRequest(token: String) = POST(
|
||||||
|
oauthUrl,
|
||||||
body = FormBody.Builder()
|
body = FormBody.Builder()
|
||||||
.add("grant_type", "refresh_token")
|
.add("grant_type", "refresh_token")
|
||||||
.add("client_id", clientId)
|
.add("client_id", clientId)
|
||||||
.add("client_secret", clientSecret)
|
.add("client_secret", clientSecret)
|
||||||
.add("refresh_token", token)
|
.add("refresh_token", token)
|
||||||
.add("redirect_uri", redirectUrl)
|
.add("redirect_uri", redirectUrl)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,10 @@ class BangumiInterceptor(val bangumi: Bangumi, val gson: Gson) : Interceptor {
|
|||||||
|
|
||||||
val authRequest = if (originalRequest.method == "GET") originalRequest.newBuilder()
|
val authRequest = if (originalRequest.method == "GET") originalRequest.newBuilder()
|
||||||
.header("User-Agent", "Tachiyomi")
|
.header("User-Agent", "Tachiyomi")
|
||||||
.url(originalRequest.url.newBuilder()
|
.url(
|
||||||
.addQueryParameter("access_token", currAuth.access_token).build())
|
originalRequest.url.newBuilder()
|
||||||
|
.addQueryParameter("access_token", currAuth.access_token).build()
|
||||||
|
)
|
||||||
.build() else originalRequest.newBuilder()
|
.build() else originalRequest.newBuilder()
|
||||||
.post(addTocken(currAuth.access_token, originalRequest.body as FormBody))
|
.post(addTocken(currAuth.access_token, originalRequest.body as FormBody))
|
||||||
.header("User-Agent", "Tachiyomi")
|
.header("User-Agent", "Tachiyomi")
|
||||||
@ -54,7 +56,8 @@ class BangumiInterceptor(val bangumi: Bangumi, val gson: Gson) : Interceptor {
|
|||||||
System.currentTimeMillis() / 1000,
|
System.currentTimeMillis() / 1000,
|
||||||
oauth.expires_in,
|
oauth.expires_in,
|
||||||
oauth.refresh_token,
|
oauth.refresh_token,
|
||||||
this.oauth?.user_id)
|
this.oauth?.user_id
|
||||||
|
)
|
||||||
|
|
||||||
bangumi.saveToken(oauth)
|
bangumi.saveToken(oauth)
|
||||||
}
|
}
|
||||||
|
@ -242,12 +242,14 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||||||
return baseMangaUrl + remoteId
|
return baseMangaUrl + remoteId
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refreshTokenRequest(token: String) = POST("${loginUrl}oauth/token",
|
fun refreshTokenRequest(token: String) = POST(
|
||||||
|
"${loginUrl}oauth/token",
|
||||||
body = FormBody.Builder()
|
body = FormBody.Builder()
|
||||||
.add("grant_type", "refresh_token")
|
.add("grant_type", "refresh_token")
|
||||||
.add("client_id", clientId)
|
.add("client_id", clientId)
|
||||||
.add("client_secret", clientSecret)
|
.add("client_secret", clientSecret)
|
||||||
.add("refresh_token", token)
|
.add("refresh_token", token)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,9 +152,10 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) {
|
|||||||
var ckCount = 0
|
var ckCount = 0
|
||||||
val url = BASE_URL.toHttpUrlOrNull()!!
|
val url = BASE_URL.toHttpUrlOrNull()!!
|
||||||
for (ck in networkService.cookieManager.get(url)) {
|
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++
|
ckCount++
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ckCount == 2
|
return ckCount == 2
|
||||||
}
|
}
|
||||||
|
@ -46,10 +46,12 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
|||||||
client.newCall(GET(searchUrl(query)))
|
client.newCall(GET(searchUrl(query)))
|
||||||
.asObservable()
|
.asObservable()
|
||||||
.flatMap { response ->
|
.flatMap { response ->
|
||||||
Observable.from(Jsoup.parse(response.consumeBody())
|
Observable.from(
|
||||||
|
Jsoup.parse(response.consumeBody())
|
||||||
.select("div.js-categories-seasonal.js-block-list.list")
|
.select("div.js-categories-seasonal.js-block-list.list")
|
||||||
.select("table").select("tbody")
|
.select("table").select("tbody")
|
||||||
.select("tr").drop(1))
|
.select("tr").drop(1)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.filter { row ->
|
.filter { row ->
|
||||||
row.select(TD)[2].text() != "Novel"
|
row.select(TD)[2].text() != "Novel"
|
||||||
@ -349,8 +351,9 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
|||||||
private fun Element.searchDateXml(field: String): Long {
|
private fun Element.searchDateXml(field: String): Long {
|
||||||
val text = selectText(field, "0000-00-00")!!
|
val text = selectText(field, "0000-00-00")!!
|
||||||
// MAL sets the data to 0000-00-00 when date is invalid or missing
|
// 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 0L
|
||||||
|
}
|
||||||
|
|
||||||
return SimpleDateFormat("yyyy-MM-dd", Locale.US).parse(text)?.time ?: 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 month = select(id + "_month > option[selected]").`val`().toIntOrNull()
|
||||||
val day = select(id + "_day > option[selected]").`val`().toIntOrNull()
|
val day = select(id + "_day > option[selected]").`val`().toIntOrNull()
|
||||||
val year = select(id + "_year > 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 0L
|
||||||
|
}
|
||||||
|
|
||||||
return GregorianCalendar(year, month - 1, day).timeInMillis
|
return GregorianCalendar(year, month - 1, day).timeInMillis
|
||||||
}
|
}
|
||||||
@ -472,8 +476,9 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
|||||||
fun copyPersonalFrom(track: Track) {
|
fun copyPersonalFrom(track: Track) {
|
||||||
num_read_chapters = track.last_chapter_read.toString()
|
num_read_chapters = track.last_chapter_read.toString()
|
||||||
val numScore = track.score.toInt()
|
val numScore = track.score.toInt()
|
||||||
if (numScore in 1..9)
|
if (numScore in 1..9) {
|
||||||
score = numScore.toString()
|
score = numScore.toString()
|
||||||
|
}
|
||||||
status = track.status.toString()
|
status = track.status.toString()
|
||||||
if (track.started_reading_date == 0L) {
|
if (track.started_reading_date == 0L) {
|
||||||
start_date_month = ""
|
start_date_month = ""
|
||||||
|
@ -159,7 +159,8 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun accessTokenRequest(code: String) = POST(oauthUrl,
|
private fun accessTokenRequest(code: String) = POST(
|
||||||
|
oauthUrl,
|
||||||
body = FormBody.Builder()
|
body = FormBody.Builder()
|
||||||
.add("grant_type", "authorization_code")
|
.add("grant_type", "authorization_code")
|
||||||
.add("client_id", clientId)
|
.add("client_id", clientId)
|
||||||
@ -192,12 +193,14 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
|||||||
.appendQueryParameter("response_type", "code")
|
.appendQueryParameter("response_type", "code")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
fun refreshTokenRequest(token: String) = POST(oauthUrl,
|
fun refreshTokenRequest(token: String) = POST(
|
||||||
|
oauthUrl,
|
||||||
body = FormBody.Builder()
|
body = FormBody.Builder()
|
||||||
.add("grant_type", "refresh_token")
|
.add("grant_type", "refresh_token")
|
||||||
.add("client_id", clientId)
|
.add("client_id", clientId)
|
||||||
.add("client_secret", clientSecret)
|
.add("client_secret", clientSecret)
|
||||||
.add("refresh_token", token)
|
.add("refresh_token", token)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,9 +37,11 @@ class UpdaterJob(private val context: Context, workerParams: WorkerParameters) :
|
|||||||
setContentText(context.getString(R.string.update_check_notification_update_available))
|
setContentText(context.getString(R.string.update_check_notification_update_available))
|
||||||
setSmallIcon(android.R.drawable.stat_sys_download_done)
|
setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||||
// Download action
|
// Download action
|
||||||
addAction(android.R.drawable.stat_sys_download_done,
|
addAction(
|
||||||
|
android.R.drawable.stat_sys_download_done,
|
||||||
context.getString(R.string.action_download),
|
context.getString(R.string.action_download),
|
||||||
PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT))
|
PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Result.success()
|
Result.success()
|
||||||
@ -64,7 +66,8 @@ class UpdaterJob(private val context: Context, workerParams: WorkerParameters) :
|
|||||||
|
|
||||||
val request = PeriodicWorkRequestBuilder<UpdaterJob>(
|
val request = PeriodicWorkRequestBuilder<UpdaterJob>(
|
||||||
3, TimeUnit.DAYS,
|
3, TimeUnit.DAYS,
|
||||||
3, TimeUnit.HOURS)
|
3, TimeUnit.HOURS
|
||||||
|
)
|
||||||
.addTag(TAG)
|
.addTag(TAG)
|
||||||
.setConstraints(constraints)
|
.setConstraints(constraints)
|
||||||
.build()
|
.build()
|
||||||
|
@ -69,13 +69,17 @@ internal class UpdaterNotifier(private val context: Context) {
|
|||||||
setProgress(0, 0, false)
|
setProgress(0, 0, false)
|
||||||
// Install action
|
// Install action
|
||||||
setContentIntent(NotificationHandler.installApkPendingActivity(context, uri))
|
setContentIntent(NotificationHandler.installApkPendingActivity(context, uri))
|
||||||
addAction(R.drawable.ic_system_update_alt_white_24dp,
|
addAction(
|
||||||
|
R.drawable.ic_system_update_alt_white_24dp,
|
||||||
context.getString(R.string.action_install),
|
context.getString(R.string.action_install),
|
||||||
NotificationHandler.installApkPendingActivity(context, uri))
|
NotificationHandler.installApkPendingActivity(context, uri)
|
||||||
|
)
|
||||||
// Cancel action
|
// Cancel action
|
||||||
addAction(R.drawable.ic_close_24dp,
|
addAction(
|
||||||
|
R.drawable.ic_close_24dp,
|
||||||
context.getString(R.string.action_cancel),
|
context.getString(R.string.action_cancel),
|
||||||
NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER))
|
NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
notificationBuilder.show()
|
notificationBuilder.show()
|
||||||
}
|
}
|
||||||
@ -92,13 +96,17 @@ internal class UpdaterNotifier(private val context: Context) {
|
|||||||
setOnlyAlertOnce(false)
|
setOnlyAlertOnce(false)
|
||||||
setProgress(0, 0, false)
|
setProgress(0, 0, false)
|
||||||
// Retry action
|
// Retry action
|
||||||
addAction(R.drawable.ic_refresh_24dp,
|
addAction(
|
||||||
|
R.drawable.ic_refresh_24dp,
|
||||||
context.getString(R.string.action_retry),
|
context.getString(R.string.action_retry),
|
||||||
UpdaterService.downloadApkPendingService(context, url))
|
UpdaterService.downloadApkPendingService(context, url)
|
||||||
|
)
|
||||||
// Cancel action
|
// Cancel action
|
||||||
addAction(R.drawable.ic_close_24dp,
|
addAction(
|
||||||
|
R.drawable.ic_close_24dp,
|
||||||
context.getString(R.string.action_cancel),
|
context.getString(R.string.action_cancel),
|
||||||
NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER))
|
NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
notificationBuilder.show(Notifications.ID_UPDATER)
|
notificationBuilder.show(Notifications.ID_UPDATER)
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,8 @@ class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParam
|
|||||||
|
|
||||||
private fun createUpdateNotification(names: List<String>) {
|
private fun createUpdateNotification(names: List<String>) {
|
||||||
NotificationManagerCompat.from(context).apply {
|
NotificationManagerCompat.from(context).apply {
|
||||||
notify(Notifications.ID_UPDATES_TO_EXTS,
|
notify(
|
||||||
|
Notifications.ID_UPDATES_TO_EXTS,
|
||||||
context.notification(Notifications.CHANNEL_UPDATES_TO_EXTS) {
|
context.notification(Notifications.CHANNEL_UPDATES_TO_EXTS) {
|
||||||
setContentTitle(
|
setContentTitle(
|
||||||
context.resources.getQuantityString(
|
context.resources.getQuantityString(
|
||||||
@ -55,7 +56,8 @@ class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParam
|
|||||||
setSmallIcon(R.drawable.ic_extension_24dp)
|
setSmallIcon(R.drawable.ic_extension_24dp)
|
||||||
setContentIntent(NotificationReceiver.openExtensionsPendingActivity(context))
|
setContentIntent(NotificationReceiver.openExtensionsPendingActivity(context))
|
||||||
setAutoCancel(true)
|
setAutoCancel(true)
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +74,8 @@ class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParam
|
|||||||
|
|
||||||
val request = PeriodicWorkRequestBuilder<ExtensionUpdateJob>(
|
val request = PeriodicWorkRequestBuilder<ExtensionUpdateJob>(
|
||||||
12, TimeUnit.HOURS,
|
12, TimeUnit.HOURS,
|
||||||
1, TimeUnit.HOURS)
|
1, TimeUnit.HOURS
|
||||||
|
)
|
||||||
.addTag(TAG)
|
.addTag(TAG)
|
||||||
.setConstraints(constraints)
|
.setConstraints(constraints)
|
||||||
.build()
|
.build()
|
||||||
|
@ -107,8 +107,10 @@ internal object ExtensionLoader {
|
|||||||
// Validate lib version
|
// Validate lib version
|
||||||
val libVersion = versionName.substringBeforeLast('.').toDouble()
|
val libVersion = versionName.substringBeforeLast('.').toDouble()
|
||||||
if (libVersion < LIB_VERSION_MIN || libVersion > LIB_VERSION_MAX) {
|
if (libVersion < LIB_VERSION_MIN || libVersion > LIB_VERSION_MAX) {
|
||||||
val exception = Exception("Lib version is $libVersion, while only versions " +
|
val exception = Exception(
|
||||||
"$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed")
|
"Lib version is $libVersion, while only versions " +
|
||||||
|
"$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed"
|
||||||
|
)
|
||||||
Timber.w(exception)
|
Timber.w(exception)
|
||||||
return LoadResult.Error(exception)
|
return LoadResult.Error(exception)
|
||||||
}
|
}
|
||||||
@ -129,11 +131,12 @@ internal object ExtensionLoader {
|
|||||||
.split(";")
|
.split(";")
|
||||||
.map {
|
.map {
|
||||||
val sourceClass = it.trim()
|
val sourceClass = it.trim()
|
||||||
if (sourceClass.startsWith("."))
|
if (sourceClass.startsWith(".")) {
|
||||||
pkgInfo.packageName + sourceClass
|
pkgInfo.packageName + sourceClass
|
||||||
else
|
} else {
|
||||||
sourceClass
|
sourceClass
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.flatMap {
|
.flatMap {
|
||||||
try {
|
try {
|
||||||
when (val obj = Class.forName(it, false, classLoader).newInstance()) {
|
when (val obj = Class.forName(it, false, classLoader).newInstance()) {
|
||||||
|
@ -83,18 +83,20 @@ class LocalSource(private val context: Context) : CatalogueSource {
|
|||||||
val state = ((if (filters.isEmpty()) POPULAR_FILTERS else filters)[0] as OrderBy).state
|
val state = ((if (filters.isEmpty()) POPULAR_FILTERS else filters)[0] as OrderBy).state
|
||||||
when (state?.index) {
|
when (state?.index) {
|
||||||
0 -> {
|
0 -> {
|
||||||
mangaDirs = if (state.ascending)
|
mangaDirs = if (state.ascending) {
|
||||||
mangaDirs.sortedBy { it.name.toLowerCase(Locale.ENGLISH) }
|
mangaDirs.sortedBy { it.name.toLowerCase(Locale.ENGLISH) }
|
||||||
else
|
} else {
|
||||||
mangaDirs.sortedByDescending { it.name.toLowerCase(Locale.ENGLISH) }
|
mangaDirs.sortedByDescending { it.name.toLowerCase(Locale.ENGLISH) }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
1 -> {
|
1 -> {
|
||||||
mangaDirs = if (state.ascending)
|
mangaDirs = if (state.ascending) {
|
||||||
mangaDirs.sortedBy(File::lastModified)
|
mangaDirs.sortedBy(File::lastModified)
|
||||||
else
|
} else {
|
||||||
mangaDirs.sortedByDescending(File::lastModified)
|
mangaDirs.sortedByDescending(File::lastModified)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val mangas = mangaDirs.map { mangaDir ->
|
val mangas = mangaDirs.map { mangaDir ->
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
@ -167,10 +169,12 @@ class LocalSource(private val context: Context) : CatalogueSource {
|
|||||||
ChapterRecognition.parseChapterNumber(this, manga)
|
ChapterRecognition.parseChapterNumber(this, manga)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.sortedWith(Comparator { c1, c2 ->
|
.sortedWith(
|
||||||
|
Comparator { c1, c2 ->
|
||||||
val c = c2.chapter_number.compareTo(c1.chapter_number)
|
val c = c2.chapter_number.compareTo(c1.chapter_number)
|
||||||
if (c == 0) c2.name.compareToCaseInsensitiveNaturalOrder(c1.name) else c
|
if (c == 0) c2.name.compareToCaseInsensitiveNaturalOrder(c1.name) else c
|
||||||
})
|
}
|
||||||
|
)
|
||||||
.toList()
|
.toList()
|
||||||
|
|
||||||
return Observable.just(chapters)
|
return Observable.just(chapters)
|
||||||
|
@ -23,26 +23,32 @@ interface SManga : Serializable {
|
|||||||
var initialized: Boolean
|
var initialized: Boolean
|
||||||
|
|
||||||
fun copyFrom(other: SManga) {
|
fun copyFrom(other: SManga) {
|
||||||
if (other.author != null)
|
if (other.author != null) {
|
||||||
author = other.author
|
author = other.author
|
||||||
|
}
|
||||||
|
|
||||||
if (other.artist != null)
|
if (other.artist != null) {
|
||||||
artist = other.artist
|
artist = other.artist
|
||||||
|
}
|
||||||
|
|
||||||
if (other.description != null)
|
if (other.description != null) {
|
||||||
description = other.description
|
description = other.description
|
||||||
|
}
|
||||||
|
|
||||||
if (other.genre != null)
|
if (other.genre != null) {
|
||||||
genre = other.genre
|
genre = other.genre
|
||||||
|
}
|
||||||
|
|
||||||
if (other.thumbnail_url != null)
|
if (other.thumbnail_url != null) {
|
||||||
thumbnail_url = other.thumbnail_url
|
thumbnail_url = other.thumbnail_url
|
||||||
|
}
|
||||||
|
|
||||||
status = other.status
|
status = other.status
|
||||||
|
|
||||||
if (!initialized)
|
if (!initialized) {
|
||||||
initialized = other.initialized
|
initialized = other.initialized
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val UNKNOWN = 0
|
const val UNKNOWN = 0
|
||||||
|
@ -343,10 +343,12 @@ abstract class HttpSource : CatalogueSource {
|
|||||||
return try {
|
return try {
|
||||||
val uri = URI(orig)
|
val uri = URI(orig)
|
||||||
var out = uri.path
|
var out = uri.path
|
||||||
if (uri.query != null)
|
if (uri.query != null) {
|
||||||
out += "?" + uri.query
|
out += "?" + uri.query
|
||||||
if (uri.fragment != null)
|
}
|
||||||
|
if (uri.fragment != null) {
|
||||||
out += "#" + uri.fragment
|
out += "#" + uri.fragment
|
||||||
|
}
|
||||||
out
|
out
|
||||||
} catch (e: URISyntaxException) {
|
} catch (e: URISyntaxException) {
|
||||||
orig
|
orig
|
||||||
|
@ -59,7 +59,8 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
setTheme(when (preferences.themeMode().get()) {
|
setTheme(
|
||||||
|
when (preferences.themeMode().get()) {
|
||||||
Values.THEME_MODE_SYSTEM -> {
|
Values.THEME_MODE_SYSTEM -> {
|
||||||
if (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) {
|
if (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) {
|
||||||
darkTheme
|
darkTheme
|
||||||
@ -69,7 +70,8 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
Values.THEME_MODE_DARK -> darkTheme
|
Values.THEME_MODE_DARK -> darkTheme
|
||||||
else -> lightTheme
|
else -> lightTheme
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
@ -15,7 +15,8 @@ import kotlinx.android.extensions.LayoutContainer
|
|||||||
import kotlinx.android.synthetic.clearFindViewByIdCache
|
import kotlinx.android.synthetic.clearFindViewByIdCache
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) : RestoreViewOnCreateController(bundle),
|
abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
|
||||||
|
RestoreViewOnCreateController(bundle),
|
||||||
LayoutContainer {
|
LayoutContainer {
|
||||||
|
|
||||||
lateinit var binding: VB
|
lateinit var binding: VB
|
||||||
|
@ -87,10 +87,12 @@ abstract class DialogController : RestoreViewOnCreateController {
|
|||||||
*/
|
*/
|
||||||
fun showDialog(router: Router, tag: String?) {
|
fun showDialog(router: Router, tag: String?) {
|
||||||
dismissed = false
|
dismissed = false
|
||||||
router.pushController(RouterTransaction.with(this)
|
router.pushController(
|
||||||
|
RouterTransaction.with(this)
|
||||||
.pushChangeHandler(SimpleSwapChangeHandler(false))
|
.pushChangeHandler(SimpleSwapChangeHandler(false))
|
||||||
.popChangeHandler(SimpleSwapChangeHandler(false))
|
.popChangeHandler(SimpleSwapChangeHandler(false))
|
||||||
.tag(tag))
|
.tag(tag)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,12 +44,10 @@ abstract class RxController<VB : ViewBinding>(bundle: Bundle? = null) : BaseCont
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <T> Observable<T>.subscribeUntilDetach(): Subscription {
|
fun <T> Observable<T>.subscribeUntilDetach(): Subscription {
|
||||||
|
|
||||||
return subscribe().also { untilDetachSubscriptions.add(it) }
|
return subscribe().also { untilDetachSubscriptions.add(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> Observable<T>.subscribeUntilDetach(onNext: (T) -> Unit): Subscription {
|
fun <T> Observable<T>.subscribeUntilDetach(onNext: (T) -> Unit): Subscription {
|
||||||
|
|
||||||
return subscribe(onNext).also { untilDetachSubscriptions.add(it) }
|
return subscribe(onNext).also { untilDetachSubscriptions.add(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +55,6 @@ abstract class RxController<VB : ViewBinding>(bundle: Bundle? = null) : BaseCont
|
|||||||
onNext: (T) -> Unit,
|
onNext: (T) -> Unit,
|
||||||
onError: (Throwable) -> Unit
|
onError: (Throwable) -> Unit
|
||||||
): Subscription {
|
): Subscription {
|
||||||
|
|
||||||
return subscribe(onNext, onError).also { untilDetachSubscriptions.add(it) }
|
return subscribe(onNext, onError).also { untilDetachSubscriptions.add(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,17 +63,14 @@ abstract class RxController<VB : ViewBinding>(bundle: Bundle? = null) : BaseCont
|
|||||||
onError: (Throwable) -> Unit,
|
onError: (Throwable) -> Unit,
|
||||||
onCompleted: () -> Unit
|
onCompleted: () -> Unit
|
||||||
): Subscription {
|
): Subscription {
|
||||||
|
|
||||||
return subscribe(onNext, onError, onCompleted).also { untilDetachSubscriptions.add(it) }
|
return subscribe(onNext, onError, onCompleted).also { untilDetachSubscriptions.add(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> Observable<T>.subscribeUntilDestroy(): Subscription {
|
fun <T> Observable<T>.subscribeUntilDestroy(): Subscription {
|
||||||
|
|
||||||
return subscribe().also { untilDestroySubscriptions.add(it) }
|
return subscribe().also { untilDestroySubscriptions.add(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> Observable<T>.subscribeUntilDestroy(onNext: (T) -> Unit): Subscription {
|
fun <T> Observable<T>.subscribeUntilDestroy(onNext: (T) -> Unit): Subscription {
|
||||||
|
|
||||||
return subscribe(onNext).also { untilDestroySubscriptions.add(it) }
|
return subscribe(onNext).also { untilDestroySubscriptions.add(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +78,6 @@ abstract class RxController<VB : ViewBinding>(bundle: Bundle? = null) : BaseCont
|
|||||||
onNext: (T) -> Unit,
|
onNext: (T) -> Unit,
|
||||||
onError: (Throwable) -> Unit
|
onError: (Throwable) -> Unit
|
||||||
): Subscription {
|
): Subscription {
|
||||||
|
|
||||||
return subscribe(onNext, onError).also { untilDestroySubscriptions.add(it) }
|
return subscribe(onNext, onError).also { untilDestroySubscriptions.add(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +86,6 @@ abstract class RxController<VB : ViewBinding>(bundle: Bundle? = null) : BaseCont
|
|||||||
onError: (Throwable) -> Unit,
|
onError: (Throwable) -> Unit,
|
||||||
onCompleted: () -> Unit
|
onCompleted: () -> Unit
|
||||||
): Subscription {
|
): Subscription {
|
||||||
|
|
||||||
return subscribe(onNext, onError, onCompleted).also { untilDestroySubscriptions.add(it) }
|
return subscribe(onNext, onError, onCompleted).also { untilDestroySubscriptions.add(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,8 @@ import reactivecircus.flowbinding.android.view.clicks
|
|||||||
/**
|
/**
|
||||||
* Controller to manage the categories for the users' library.
|
* Controller to manage the categories for the users' library.
|
||||||
*/
|
*/
|
||||||
class CategoryController : NucleusController<CategoriesControllerBinding, CategoryPresenter>(),
|
class CategoryController :
|
||||||
|
NucleusController<CategoriesControllerBinding, CategoryPresenter>(),
|
||||||
ActionMode.Callback,
|
ActionMode.Callback,
|
||||||
FlexibleAdapter.OnItemClickListener,
|
FlexibleAdapter.OnItemClickListener,
|
||||||
FlexibleAdapter.OnItemLongClickListener,
|
FlexibleAdapter.OnItemLongClickListener,
|
||||||
@ -176,8 +177,10 @@ class CategoryController : NucleusController<CategoriesControllerBinding, Catego
|
|||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.action_delete -> {
|
R.id.action_delete -> {
|
||||||
undoHelper = UndoHelper(adapter, this)
|
undoHelper = UndoHelper(adapter, this)
|
||||||
undoHelper?.start(adapter.selectedPositions, view!!,
|
undoHelper?.start(
|
||||||
R.string.snack_categories_deleted, R.string.action_undo, 3000)
|
adapter.selectedPositions, view!!,
|
||||||
|
R.string.snack_categories_deleted, R.string.action_undo, 3000
|
||||||
|
)
|
||||||
|
|
||||||
mode.finish()
|
mode.finish()
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,6 @@ class CategoryItem(val category: Category) : AbstractFlexibleItem<CategoryHolder
|
|||||||
position: Int,
|
position: Int,
|
||||||
payloads: List<Any?>?
|
payloads: List<Any?>?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
holder.bind(category)
|
holder.bind(category)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,8 @@ import rx.android.schedulers.AndroidSchedulers
|
|||||||
* Controller that shows the currently active downloads.
|
* Controller that shows the currently active downloads.
|
||||||
* Uses R.layout.fragment_download_queue.
|
* Uses R.layout.fragment_download_queue.
|
||||||
*/
|
*/
|
||||||
class DownloadController : NucleusController<DownloadControllerBinding, DownloadPresenter>(),
|
class DownloadController :
|
||||||
|
NucleusController<DownloadControllerBinding, DownloadPresenter>(),
|
||||||
DownloadAdapter.DownloadItemListener {
|
DownloadAdapter.DownloadItemListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,8 +124,9 @@ class DownloadController : NucleusController<DownloadControllerBinding, Download
|
|||||||
val adapter = adapter ?: return false
|
val adapter = adapter ?: return false
|
||||||
val items = adapter.currentItems.sortedBy { it.download.chapter.date_upload }
|
val items = adapter.currentItems.sortedBy { it.download.chapter.date_upload }
|
||||||
.toMutableList()
|
.toMutableList()
|
||||||
if (item.itemId == R.id.newest)
|
if (item.itemId == R.id.newest) {
|
||||||
items.reverse()
|
items.reverse()
|
||||||
|
}
|
||||||
adapter.updateDataSet(items)
|
adapter.updateDataSet(items)
|
||||||
val downloads = items.mapNotNull { it.download }
|
val downloads = items.mapNotNull { it.download }
|
||||||
presenter.reorder(downloads)
|
presenter.reorder(downloads)
|
||||||
@ -279,10 +281,11 @@ class DownloadController : NucleusController<DownloadControllerBinding, Download
|
|||||||
val items = adapter?.currentItems?.toMutableList() ?: return
|
val items = adapter?.currentItems?.toMutableList() ?: return
|
||||||
val item = items[position]
|
val item = items[position]
|
||||||
items.remove(item)
|
items.remove(item)
|
||||||
if (menuItem.itemId == R.id.move_to_top)
|
if (menuItem.itemId == R.id.move_to_top) {
|
||||||
items.add(0, item)
|
items.add(0, item)
|
||||||
else
|
} else {
|
||||||
items.add(item)
|
items.add(item)
|
||||||
|
}
|
||||||
|
|
||||||
val adapter = adapter ?: return
|
val adapter = adapter ?: return
|
||||||
adapter.updateDataSet(items)
|
adapter.updateDataSet(items)
|
||||||
|
@ -80,13 +80,17 @@ class DownloadHolder(private val view: View, val adapter: DownloadAdapter) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun showPopupMenu(view: View) {
|
private fun showPopupMenu(view: View) {
|
||||||
view.popupMenu(R.menu.download_single, {
|
view.popupMenu(
|
||||||
|
R.menu.download_single,
|
||||||
|
{
|
||||||
findItem(R.id.move_to_top).isVisible = bindingAdapterPosition != 0
|
findItem(R.id.move_to_top).isVisible = bindingAdapterPosition != 0
|
||||||
findItem(R.id.move_to_bottom).isVisible =
|
findItem(R.id.move_to_bottom).isVisible =
|
||||||
bindingAdapterPosition != adapter.itemCount - 1
|
bindingAdapterPosition != adapter.itemCount - 1
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
adapter.downloadItemListener.onMenuItemClick(bindingAdapterPosition, this)
|
adapter.downloadItemListener.onMenuItemClick(bindingAdapterPosition, this)
|
||||||
true
|
true
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,8 @@ import uy.kohesive.injekt.api.get
|
|||||||
/**
|
/**
|
||||||
* Controller to manage the catalogues available in the app.
|
* Controller to manage the catalogues available in the app.
|
||||||
*/
|
*/
|
||||||
open class ExtensionController : NucleusController<ExtensionControllerBinding, ExtensionPresenter>(),
|
open class ExtensionController :
|
||||||
|
NucleusController<ExtensionControllerBinding, ExtensionPresenter>(),
|
||||||
ExtensionAdapter.OnButtonClickListener,
|
ExtensionAdapter.OnButtonClickListener,
|
||||||
FlexibleAdapter.OnItemClickListener,
|
FlexibleAdapter.OnItemClickListener,
|
||||||
FlexibleAdapter.OnItemLongClickListener,
|
FlexibleAdapter.OnItemLongClickListener,
|
||||||
@ -92,9 +93,11 @@ open class ExtensionController : NucleusController<ExtensionControllerBinding, E
|
|||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.action_search -> expandActionViewFromInteraction = true
|
R.id.action_search -> expandActionViewFromInteraction = true
|
||||||
R.id.action_settings -> {
|
R.id.action_settings -> {
|
||||||
router.pushController((RouterTransaction.with(ExtensionFilterController()))
|
router.pushController(
|
||||||
|
(RouterTransaction.with(ExtensionFilterController()))
|
||||||
.popChangeHandler(SettingsExtensionsFadeChangeHandler())
|
.popChangeHandler(SettingsExtensionsFadeChangeHandler())
|
||||||
.pushChangeHandler(FadeChangeHandler()))
|
.pushChangeHandler(FadeChangeHandler())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
R.id.action_auto_check -> {
|
R.id.action_auto_check -> {
|
||||||
item.isChecked = !item.isChecked
|
item.isChecked = !item.isChecked
|
||||||
@ -198,7 +201,8 @@ open class ExtensionController : NucleusController<ExtensionControllerBinding, E
|
|||||||
adapter?.updateDataSet(
|
adapter?.updateDataSet(
|
||||||
extensions.filter {
|
extensions.filter {
|
||||||
it.extension.name.contains(query, ignoreCase = true)
|
it.extension.name.contains(query, ignoreCase = true)
|
||||||
})
|
}
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
adapter?.updateDataSet(extensions)
|
adapter?.updateDataSet(extensions)
|
||||||
}
|
}
|
||||||
|
@ -46,9 +46,11 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
|||||||
|
|
||||||
private var preferenceScreen: PreferenceScreen? = null
|
private var preferenceScreen: PreferenceScreen? = null
|
||||||
|
|
||||||
constructor(pkgName: String) : this(Bundle().apply {
|
constructor(pkgName: String) : this(
|
||||||
|
Bundle().apply {
|
||||||
putString(PKGNAME_KEY, pkgName)
|
putString(PKGNAME_KEY, pkgName)
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||||
val themedInflater = inflater.cloneInContext(getPreferenceThemeContext())
|
val themedInflater = inflater.cloneInContext(getPreferenceThemeContext())
|
||||||
@ -137,7 +139,8 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
|||||||
source.preferences
|
source.preferences
|
||||||
} else {*/
|
} else {*/
|
||||||
context.getSharedPreferences("source_${source.id}", Context.MODE_PRIVATE)
|
context.getSharedPreferences("source_${source.id}", Context.MODE_PRIVATE)
|
||||||
/*}*/)
|
/*}*/
|
||||||
|
)
|
||||||
|
|
||||||
if (source is ConfigurableSource) {
|
if (source is ConfigurableSource) {
|
||||||
if (multiSource) {
|
if (multiSource) {
|
||||||
@ -178,14 +181,19 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
val f = when (preference) {
|
val f = when (preference) {
|
||||||
is EditTextPreference -> EditTextPreferenceDialogController
|
is EditTextPreference ->
|
||||||
|
EditTextPreferenceDialogController
|
||||||
.newInstance(preference.getKey())
|
.newInstance(preference.getKey())
|
||||||
is ListPreference -> ListPreferenceDialogController
|
is ListPreference ->
|
||||||
|
ListPreferenceDialogController
|
||||||
.newInstance(preference.getKey())
|
.newInstance(preference.getKey())
|
||||||
is MultiSelectListPreference -> MultiSelectListPreferenceDialogController
|
is MultiSelectListPreference ->
|
||||||
|
MultiSelectListPreferenceDialogController
|
||||||
.newInstance(preference.getKey())
|
.newInstance(preference.getKey())
|
||||||
else -> throw IllegalArgumentException("Tried to display dialog for unknown " +
|
else -> throw IllegalArgumentException(
|
||||||
"preference type. Did you forget to override onDisplayPreferenceDialog()?")
|
"Tried to display dialog for unknown " +
|
||||||
|
"preference type. Did you forget to override onDisplayPreferenceDialog()?"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
f.targetController = this
|
f.targetController = this
|
||||||
f.showDialog(router)
|
f.showDialog(router)
|
||||||
|
@ -23,7 +23,8 @@ class ExtensionDividerItemDecoration(context: Context) : RecyclerView.ItemDecora
|
|||||||
val child = parent.getChildAt(i)
|
val child = parent.getChildAt(i)
|
||||||
val holder = parent.getChildViewHolder(child)
|
val holder = parent.getChildViewHolder(child)
|
||||||
if (holder is ExtensionHolder &&
|
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 params = child.layoutParams as RecyclerView.LayoutParams
|
||||||
val top = child.bottom + params.bottomMargin
|
val top = child.bottom + params.bottomMargin
|
||||||
val bottom = top + divider.intrinsicHeight
|
val bottom = top + divider.intrinsicHeight
|
||||||
|
@ -38,7 +38,6 @@ data class ExtensionGroupItem(val name: String, val size: Int, val showSize: Boo
|
|||||||
position: Int,
|
position: Int,
|
||||||
payloads: List<Any?>?
|
payloads: List<Any?>?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
holder.bind(this)
|
holder.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,13 +69,15 @@ class ExtensionHolder(view: View, override val adapter: ExtensionAdapter) :
|
|||||||
|
|
||||||
val installStep = item.installStep
|
val installStep = item.installStep
|
||||||
if (installStep != null) {
|
if (installStep != null) {
|
||||||
setText(when (installStep) {
|
setText(
|
||||||
|
when (installStep) {
|
||||||
InstallStep.Pending -> R.string.ext_pending
|
InstallStep.Pending -> R.string.ext_pending
|
||||||
InstallStep.Downloading -> R.string.ext_downloading
|
InstallStep.Downloading -> R.string.ext_downloading
|
||||||
InstallStep.Installing -> R.string.ext_installing
|
InstallStep.Installing -> R.string.ext_installing
|
||||||
InstallStep.Installed -> R.string.ext_installed
|
InstallStep.Installed -> R.string.ext_installed
|
||||||
InstallStep.Error -> R.string.action_retry
|
InstallStep.Error -> R.string.action_retry
|
||||||
})
|
}
|
||||||
|
)
|
||||||
if (installStep != InstallStep.Error) {
|
if (installStep != InstallStep.Error) {
|
||||||
isEnabled = false
|
isEnabled = false
|
||||||
isClickable = false
|
isClickable = false
|
||||||
|
@ -46,7 +46,6 @@ data class ExtensionItem(
|
|||||||
position: Int,
|
position: Int,
|
||||||
payloads: List<Any?>?
|
payloads: List<Any?>?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
if (payloads == null || payloads.isEmpty()) {
|
if (payloads == null || payloads.isEmpty()) {
|
||||||
holder.bind(this)
|
holder.bind(this)
|
||||||
} else {
|
} else {
|
||||||
|
@ -10,10 +10,12 @@ import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
|||||||
class ExtensionTrustDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
|
class ExtensionTrustDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
|
||||||
where T : Controller, T : ExtensionTrustDialog.Listener {
|
where T : Controller, T : ExtensionTrustDialog.Listener {
|
||||||
|
|
||||||
constructor(target: T, signatureHash: String, pkgName: String) : this(Bundle().apply {
|
constructor(target: T, signatureHash: String, pkgName: String) : this(
|
||||||
|
Bundle().apply {
|
||||||
putString(SIGNATURE_KEY, signatureHash)
|
putString(SIGNATURE_KEY, signatureHash)
|
||||||
putString(PKGNAME_KEY, pkgName)
|
putString(PKGNAME_KEY, pkgName)
|
||||||
}) {
|
}
|
||||||
|
) {
|
||||||
targetController = target
|
targetController = target
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,9 +255,11 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
|||||||
controller.createActionModeIfNeeded()
|
controller.createActionModeIfNeeded()
|
||||||
when {
|
when {
|
||||||
lastClickPosition == -1 -> setSelection(position)
|
lastClickPosition == -1 -> setSelection(position)
|
||||||
lastClickPosition > position -> for (i in position until lastClickPosition)
|
lastClickPosition > position ->
|
||||||
|
for (i in position until lastClickPosition)
|
||||||
setSelection(i)
|
setSelection(i)
|
||||||
lastClickPosition < position -> for (i in lastClickPosition + 1..position)
|
lastClickPosition < position ->
|
||||||
|
for (i in lastClickPosition + 1..position)
|
||||||
setSelection(i)
|
setSelection(i)
|
||||||
else -> setSelection(position)
|
else -> setSelection(position)
|
||||||
}
|
}
|
||||||
|
@ -230,10 +230,11 @@ class LibraryController(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the current active category.
|
// Get the current active category.
|
||||||
val activeCat = if (adapter.categories.isNotEmpty())
|
val activeCat = if (adapter.categories.isNotEmpty()) {
|
||||||
binding.libraryPager.currentItem
|
binding.libraryPager.currentItem
|
||||||
else
|
} else {
|
||||||
activeCategory
|
activeCategory
|
||||||
|
}
|
||||||
|
|
||||||
// Set the categories
|
// Set the categories
|
||||||
adapter.categories = categories
|
adapter.categories = categories
|
||||||
@ -260,11 +261,12 @@ class LibraryController(
|
|||||||
* @return the preference.
|
* @return the preference.
|
||||||
*/
|
*/
|
||||||
private fun getColumnsPreferenceForCurrentOrientation(): Preference<Int> {
|
private fun getColumnsPreferenceForCurrentOrientation(): Preference<Int> {
|
||||||
return if (resources?.configuration?.orientation == Configuration.ORIENTATION_PORTRAIT)
|
return if (resources?.configuration?.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||||
preferences.portraitColumns()
|
preferences.portraitColumns()
|
||||||
else
|
} else {
|
||||||
preferences.landscapeColumns()
|
preferences.landscapeColumns()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a filter is changed.
|
* Called when a filter is changed.
|
||||||
@ -510,8 +512,13 @@ class LibraryController(
|
|||||||
if (manga.favorite) {
|
if (manga.favorite) {
|
||||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||||
intent.type = "image/*"
|
intent.type = "image/*"
|
||||||
startActivityForResult(Intent.createChooser(intent,
|
startActivityForResult(
|
||||||
resources?.getString(R.string.file_select_cover)), REQUEST_IMAGE_OPEN)
|
Intent.createChooser(
|
||||||
|
intent,
|
||||||
|
resources?.getString(R.string.file_select_cover)
|
||||||
|
),
|
||||||
|
REQUEST_IMAGE_OPEN
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
activity?.toast(R.string.notification_first_add_to_library)
|
activity?.toast(R.string.notification_first_add_to_library)
|
||||||
}
|
}
|
||||||
|
@ -27,11 +27,12 @@ class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference
|
|||||||
var downloadCount = -1
|
var downloadCount = -1
|
||||||
|
|
||||||
override fun getLayoutRes(): Int {
|
override fun getLayoutRes(): Int {
|
||||||
return if (libraryAsList.get())
|
return if (libraryAsList.get()) {
|
||||||
R.layout.source_list_item
|
R.layout.source_list_item
|
||||||
else
|
} else {
|
||||||
R.layout.source_grid_item
|
R.layout.source_grid_item
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): LibraryHolder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): LibraryHolder {
|
||||||
val parent = adapter.recyclerView
|
val parent = adapter.recyclerView
|
||||||
@ -40,7 +41,8 @@ class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference
|
|||||||
val coverHeight = parent.itemWidth / 3 * 4
|
val coverHeight = parent.itemWidth / 3 * 4
|
||||||
card.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, coverHeight)
|
card.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, coverHeight)
|
||||||
gradient.layoutParams = FrameLayout.LayoutParams(
|
gradient.layoutParams = FrameLayout.LayoutParams(
|
||||||
MATCH_PARENT, coverHeight / 2, Gravity.BOTTOM)
|
MATCH_PARENT, coverHeight / 2, Gravity.BOTTOM
|
||||||
|
)
|
||||||
}
|
}
|
||||||
LibraryGridHolder(view, adapter)
|
LibraryGridHolder(view, adapter)
|
||||||
} else {
|
} else {
|
||||||
@ -76,15 +78,16 @@ class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun containsGenre(tag: String, genres: List<String>?): Boolean {
|
private fun containsGenre(tag: String, genres: List<String>?): Boolean {
|
||||||
return if (tag.startsWith("-"))
|
return if (tag.startsWith("-")) {
|
||||||
genres?.find {
|
genres?.find {
|
||||||
it.trim().toLowerCase() == tag.substringAfter("-").toLowerCase()
|
it.trim().toLowerCase() == tag.substringAfter("-").toLowerCase()
|
||||||
} == null
|
} == null
|
||||||
else
|
} else {
|
||||||
genres?.find {
|
genres?.find {
|
||||||
it.trim().toLowerCase() == tag.toLowerCase()
|
it.trim().toLowerCase() == tag.toLowerCase()
|
||||||
} != null
|
} != null
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other is LibraryItem) {
|
if (other is LibraryItem) {
|
||||||
|
@ -214,10 +214,11 @@ class LibraryPresenter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val comparator = if (preferences.librarySortingAscending().get())
|
val comparator = if (preferences.librarySortingAscending().get()) {
|
||||||
Comparator(sortFn)
|
Comparator(sortFn)
|
||||||
else
|
} else {
|
||||||
Collections.reverseOrder(sortFn)
|
Collections.reverseOrder(sortFn)
|
||||||
|
}
|
||||||
|
|
||||||
return map.mapValues { entry -> entry.value.sortedWith(comparator) }
|
return map.mapValues { entry -> entry.value.sortedWith(comparator) }
|
||||||
}
|
}
|
||||||
@ -229,10 +230,11 @@ class LibraryPresenter(
|
|||||||
*/
|
*/
|
||||||
private fun getLibraryObservable(): Observable<Library> {
|
private fun getLibraryObservable(): Observable<Library> {
|
||||||
return Observable.combineLatest(getCategoriesObservable(), getLibraryMangasObservable()) { dbCategories, libraryManga ->
|
return Observable.combineLatest(getCategoriesObservable(), getLibraryMangasObservable()) { dbCategories, libraryManga ->
|
||||||
val categories = if (libraryManga.containsKey(0))
|
val categories = if (libraryManga.containsKey(0)) {
|
||||||
arrayListOf(Category.createDefault()) + dbCategories
|
arrayListOf(Category.createDefault()) + dbCategories
|
||||||
else
|
} else {
|
||||||
dbCategories
|
dbCategories
|
||||||
|
}
|
||||||
|
|
||||||
this.categories = categories
|
this.categories = categories
|
||||||
Library(categories, libraryManga)
|
Library(categories, libraryManga)
|
||||||
|
@ -129,8 +129,11 @@ class LibrarySettingsSheet(
|
|||||||
|
|
||||||
override fun initModels() {
|
override fun initModels() {
|
||||||
val sorting = preferences.librarySortingMode().get()
|
val sorting = preferences.librarySortingMode().get()
|
||||||
val order = if (preferences.librarySortingAscending().get())
|
val order = if (preferences.librarySortingAscending().get()) {
|
||||||
Item.MultiSort.SORT_ASC else Item.MultiSort.SORT_DESC
|
Item.MultiSort.SORT_ASC
|
||||||
|
} else {
|
||||||
|
Item.MultiSort.SORT_DESC
|
||||||
|
}
|
||||||
|
|
||||||
alphabetically.state =
|
alphabetically.state =
|
||||||
if (sorting == LibrarySort.ALPHA) order else Item.MultiSort.SORT_NONE
|
if (sorting == LibrarySort.ALPHA) order else Item.MultiSort.SORT_NONE
|
||||||
|
@ -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.history.HistoryController
|
||||||
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController
|
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController
|
||||||
import eu.kanade.tachiyomi.ui.source.SourceController
|
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.lang.launchUI
|
||||||
import eu.kanade.tachiyomi.util.system.WebViewUtil
|
import eu.kanade.tachiyomi.util.system.WebViewUtil
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
|
@ -35,10 +35,12 @@ import uy.kohesive.injekt.api.get
|
|||||||
|
|
||||||
class MangaController : RxController<MangaControllerBinding>, TabbedController {
|
class MangaController : RxController<MangaControllerBinding>, TabbedController {
|
||||||
|
|
||||||
constructor(manga: Manga?, fromSource: Boolean = false) : super(Bundle().apply {
|
constructor(manga: Manga?, fromSource: Boolean = false) : super(
|
||||||
|
Bundle().apply {
|
||||||
putLong(MANGA_EXTRA, manga?.id ?: 0)
|
putLong(MANGA_EXTRA, manga?.id ?: 0)
|
||||||
putBoolean(FROM_SOURCE_EXTRA, fromSource)
|
putBoolean(FROM_SOURCE_EXTRA, fromSource)
|
||||||
}) {
|
}
|
||||||
|
) {
|
||||||
this.manga = manga
|
this.manga = manga
|
||||||
if (manga != null) {
|
if (manga != null) {
|
||||||
source = Injekt.get<SourceManager>().getOrStub(manga.source)
|
source = Injekt.get<SourceManager>().getOrStub(manga.source)
|
||||||
@ -46,7 +48,8 @@ class MangaController : RxController<MangaControllerBinding>, TabbedController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(mangaId: Long) : this(
|
constructor(mangaId: Long) : this(
|
||||||
Injekt.get<DatabaseHelper>().getManga(mangaId).executeAsBlocking())
|
Injekt.get<DatabaseHelper>().getManga(mangaId).executeAsBlocking()
|
||||||
|
)
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
constructor(bundle: Bundle) : this(bundle.getLong(MANGA_EXTRA))
|
constructor(bundle: Bundle) : this(bundle.getLong(MANGA_EXTRA))
|
||||||
@ -87,9 +90,10 @@ class MangaController : RxController<MangaControllerBinding>, TabbedController {
|
|||||||
binding.mangaPager.offscreenPageLimit = 3
|
binding.mangaPager.offscreenPageLimit = 3
|
||||||
binding.mangaPager.adapter = adapter
|
binding.mangaPager.adapter = adapter
|
||||||
|
|
||||||
if (!fromSource)
|
if (!fromSource) {
|
||||||
binding.mangaPager.currentItem = CHAPTERS_CONTROLLER
|
binding.mangaPager.currentItem = CHAPTERS_CONTROLLER
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView(view: View) {
|
override fun onDestroyView(view: View) {
|
||||||
super.onDestroyView(view)
|
super.onDestroyView(view)
|
||||||
@ -130,9 +134,11 @@ class MangaController : RxController<MangaControllerBinding>, TabbedController {
|
|||||||
|
|
||||||
private fun setTrackingIconInternal(visible: Boolean) {
|
private fun setTrackingIconInternal(visible: Boolean) {
|
||||||
val tab = activity?.tabs?.getTabAt(TRACK_CONTROLLER) ?: return
|
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)
|
VectorDrawableCompat.create(resources!!, R.drawable.ic_done_white_18dp, null)
|
||||||
else null
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
tab.icon = drawable
|
tab.icon = drawable
|
||||||
}
|
}
|
||||||
@ -144,7 +150,8 @@ class MangaController : RxController<MangaControllerBinding>, TabbedController {
|
|||||||
private val tabTitles = listOf(
|
private val tabTitles = listOf(
|
||||||
R.string.manga_detail_tab,
|
R.string.manga_detail_tab,
|
||||||
R.string.manga_chapters_tab,
|
R.string.manga_chapters_tab,
|
||||||
R.string.manga_tracking_tab)
|
R.string.manga_tracking_tab
|
||||||
|
)
|
||||||
.map { resources!!.getString(it) }
|
.map { resources!!.getString(it) }
|
||||||
|
|
||||||
override fun getCount(): Int {
|
override fun getCount(): Int {
|
||||||
|
@ -10,7 +10,8 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
|
|
||||||
class ChapterItem(val chapter: Chapter, val manga: Manga) : AbstractFlexibleItem<ChapterHolder>(),
|
class ChapterItem(val chapter: Chapter, val manga: Manga) :
|
||||||
|
AbstractFlexibleItem<ChapterHolder>(),
|
||||||
Chapter by chapter {
|
Chapter by chapter {
|
||||||
|
|
||||||
private var _status: Int = 0
|
private var _status: Int = 0
|
||||||
|
@ -26,8 +26,11 @@ class ChaptersAdapter(
|
|||||||
|
|
||||||
val bookmarkedColor = context.getResourceColor(R.attr.colorAccent)
|
val bookmarkedColor = context.getResourceColor(R.attr.colorAccent)
|
||||||
|
|
||||||
val decimalFormat = DecimalFormat("#.###", DecimalFormatSymbols()
|
val decimalFormat = DecimalFormat(
|
||||||
.apply { decimalSeparator = '.' })
|
"#.###",
|
||||||
|
DecimalFormatSymbols()
|
||||||
|
.apply { decimalSeparator = '.' }
|
||||||
|
)
|
||||||
|
|
||||||
val dateFormat: DateFormat = preferences.dateFormat().getOrDefault()
|
val dateFormat: DateFormat = preferences.dateFormat().getOrDefault()
|
||||||
|
|
||||||
|
@ -39,7 +39,8 @@ import reactivecircus.flowbinding.android.view.clicks
|
|||||||
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
|
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
class ChaptersController : NucleusController<ChaptersControllerBinding, ChaptersPresenter>(),
|
class ChaptersController :
|
||||||
|
NucleusController<ChaptersControllerBinding, ChaptersPresenter>(),
|
||||||
ActionMode.Callback,
|
ActionMode.Callback,
|
||||||
FlexibleAdapter.OnItemClickListener,
|
FlexibleAdapter.OnItemClickListener,
|
||||||
FlexibleAdapter.OnItemLongClickListener,
|
FlexibleAdapter.OnItemLongClickListener,
|
||||||
@ -168,11 +169,13 @@ class ChaptersController : NucleusController<ChaptersControllerBinding, Chapters
|
|||||||
menuFilterEmpty.isVisible = filterSet
|
menuFilterEmpty.isVisible = filterSet
|
||||||
|
|
||||||
// Disable unread filter option if read filter is enabled.
|
// Disable unread filter option if read filter is enabled.
|
||||||
if (presenter.onlyRead())
|
if (presenter.onlyRead()) {
|
||||||
menuFilterUnread.isEnabled = false
|
menuFilterUnread.isEnabled = false
|
||||||
|
}
|
||||||
// Disable read filter option if unread filter is enabled.
|
// Disable read filter option if unread filter is enabled.
|
||||||
if (presenter.onlyUnread())
|
if (presenter.onlyUnread()) {
|
||||||
menuFilterRead.isEnabled = false
|
menuFilterRead.isEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
// Display mode submenu
|
// Display mode submenu
|
||||||
if (presenter.manga.displayMode == Manga.DISPLAY_NAME) {
|
if (presenter.manga.displayMode == Manga.DISPLAY_NAME) {
|
||||||
@ -320,9 +323,11 @@ class ChaptersController : NucleusController<ChaptersControllerBinding, Chapters
|
|||||||
createActionModeIfNeeded()
|
createActionModeIfNeeded()
|
||||||
when {
|
when {
|
||||||
lastClickPosition == -1 -> setSelection(position)
|
lastClickPosition == -1 -> setSelection(position)
|
||||||
lastClickPosition > position -> for (i in position until lastClickPosition)
|
lastClickPosition > position ->
|
||||||
|
for (i in position until lastClickPosition)
|
||||||
setSelection(i)
|
setSelection(i)
|
||||||
lastClickPosition < position -> for (i in lastClickPosition + 1..position)
|
lastClickPosition < position ->
|
||||||
|
for (i in lastClickPosition + 1..position)
|
||||||
setSelection(i)
|
setSelection(i)
|
||||||
else -> setSelection(position)
|
else -> setSelection(position)
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,8 @@ class ChaptersPresenter(
|
|||||||
|
|
||||||
// Add the subscription that retrieves the chapters from the database, keeps subscribed to
|
// Add the subscription that retrieves the chapters from the database, keeps subscribed to
|
||||||
// changes, and sends the list of chapters to the relay.
|
// changes, and sends the list of chapters to the relay.
|
||||||
add(db.getChapters(manga).asRxObservable()
|
add(
|
||||||
|
db.getChapters(manga).asRxObservable()
|
||||||
.map { chapters ->
|
.map { chapters ->
|
||||||
// Convert every chapter to a model.
|
// Convert every chapter to a model.
|
||||||
chapters.map { it.toModel() }
|
chapters.map { it.toModel() }
|
||||||
@ -86,7 +87,8 @@ class ChaptersPresenter(
|
|||||||
// Listen for download status changes
|
// Listen for download status changes
|
||||||
observeDownloads()
|
observeDownloads()
|
||||||
}
|
}
|
||||||
.subscribe { chaptersRelay.call(it) })
|
.subscribe { chaptersRelay.call(it) }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeDownloads() {
|
private fun observeDownloads() {
|
||||||
@ -141,9 +143,12 @@ class ChaptersPresenter(
|
|||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.map { syncChaptersWithSource(db, it, manga, source) }
|
.map { syncChaptersWithSource(db, it, manga, source) }
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribeFirst({ view, _ ->
|
.subscribeFirst(
|
||||||
|
{ view, _ ->
|
||||||
view.onFetchChaptersDone()
|
view.onFetchChaptersDone()
|
||||||
}, ChaptersController::onFetchChaptersError)
|
},
|
||||||
|
ChaptersController::onFetchChaptersError
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -200,9 +205,10 @@ class ChaptersPresenter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Force UI update if downloaded filter active and download finished.
|
// Force UI update if downloaded filter active and download finished.
|
||||||
if (onlyDownloaded() && download.status == Download.DOWNLOADED)
|
if (onlyDownloaded() && download.status == Download.DOWNLOADED) {
|
||||||
refreshChapters()
|
refreshChapters()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the next unread chapter or null if everything is read.
|
* Returns the next unread chapter or null if everything is read.
|
||||||
@ -263,9 +269,12 @@ class ChaptersPresenter(
|
|||||||
.doOnNext { if (onlyDownloaded()) refreshChapters() }
|
.doOnNext { if (onlyDownloaded()) refreshChapters() }
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribeFirst({ view, _ ->
|
.subscribeFirst(
|
||||||
|
{ view, _ ->
|
||||||
view.onChaptersDeleted(chapters)
|
view.onChaptersDeleted(chapters)
|
||||||
}, ChaptersController::onChaptersDeletedError)
|
},
|
||||||
|
ChaptersController::onChaptersDeletedError
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,10 +24,12 @@ class DownloadCustomChaptersDialog<T> : DialogController
|
|||||||
* Initialize dialog.
|
* Initialize dialog.
|
||||||
* @param maxChapters maximal number of chapters that user can download.
|
* @param maxChapters maximal number of chapters that user can download.
|
||||||
*/
|
*/
|
||||||
constructor(target: T, maxChapters: Int) : super(Bundle().apply {
|
constructor(target: T, maxChapters: Int) : super(
|
||||||
|
Bundle().apply {
|
||||||
// Add maximum number of chapters to download value to bundle.
|
// Add maximum number of chapters to download value to bundle.
|
||||||
putInt(KEY_ITEM_MAX, maxChapters)
|
putInt(KEY_ITEM_MAX, maxChapters)
|
||||||
}) {
|
}
|
||||||
|
) {
|
||||||
targetController = target
|
targetController = target
|
||||||
this.maxChapters = maxChapters
|
this.maxChapters = maxChapters
|
||||||
}
|
}
|
||||||
|
@ -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.history.HistoryController
|
||||||
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController
|
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController
|
||||||
import eu.kanade.tachiyomi.ui.source.browse.BrowseSourceController
|
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.ui.webview.WebViewActivity
|
||||||
import eu.kanade.tachiyomi.util.lang.truncateCenter
|
import eu.kanade.tachiyomi.util.lang.truncateCenter
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
@ -217,12 +217,14 @@ class MangaInfoController(private val fromSource: Boolean = false) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update status TextView.
|
// Update status TextView.
|
||||||
binding.mangaStatus.setText(when (manga.status) {
|
binding.mangaStatus.setText(
|
||||||
|
when (manga.status) {
|
||||||
SManga.ONGOING -> R.string.ongoing
|
SManga.ONGOING -> R.string.ongoing
|
||||||
SManga.COMPLETED -> R.string.completed
|
SManga.COMPLETED -> R.string.completed
|
||||||
SManga.LICENSED -> R.string.licensed
|
SManga.LICENSED -> R.string.licensed
|
||||||
else -> R.string.unknown
|
else -> R.string.unknown
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// Set the favorite drawable to the correct one.
|
// Set the favorite drawable to the correct one.
|
||||||
setFavoriteButtonState(manga.favorite)
|
setFavoriteButtonState(manga.favorite)
|
||||||
@ -291,24 +293,27 @@ class MangaInfoController(private val fromSource: Boolean = false) :
|
|||||||
val isExpanded = binding.mangaInfoToggle.text == context.getString(R.string.manga_info_collapse)
|
val isExpanded = binding.mangaInfoToggle.text == context.getString(R.string.manga_info_collapse)
|
||||||
|
|
||||||
binding.mangaInfoToggle.text =
|
binding.mangaInfoToggle.text =
|
||||||
if (isExpanded)
|
if (isExpanded) {
|
||||||
context.getString(R.string.manga_info_expand)
|
context.getString(R.string.manga_info_expand)
|
||||||
else
|
} else {
|
||||||
context.getString(R.string.manga_info_collapse)
|
context.getString(R.string.manga_info_collapse)
|
||||||
|
}
|
||||||
|
|
||||||
with(binding.mangaSummary) {
|
with(binding.mangaSummary) {
|
||||||
maxLines =
|
maxLines =
|
||||||
if (isExpanded)
|
if (isExpanded) {
|
||||||
3
|
3
|
||||||
else
|
} else {
|
||||||
Int.MAX_VALUE
|
Int.MAX_VALUE
|
||||||
|
}
|
||||||
|
|
||||||
ellipsize =
|
ellipsize =
|
||||||
if (isExpanded)
|
if (isExpanded) {
|
||||||
TextUtils.TruncateAt.END
|
TextUtils.TruncateAt.END
|
||||||
else
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.mangaGenresTagsCompact.visibleIf { isExpanded }
|
binding.mangaGenresTagsCompact.visibleIf { isExpanded }
|
||||||
binding.mangaGenresTagsFullChips.visibleIf { !isExpanded }
|
binding.mangaGenresTagsFullChips.visibleIf { !isExpanded }
|
||||||
@ -492,8 +497,10 @@ class MangaInfoController(private val fromSource: Boolean = false) :
|
|||||||
val clipboard = activity.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
val clipboard = activity.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
clipboard.setPrimaryClip(ClipData.newPlainText(label, content))
|
clipboard.setPrimaryClip(ClipData.newPlainText(label, content))
|
||||||
|
|
||||||
activity.toast(view.context.getString(R.string.copied_to_clipboard, content.truncateCenter(20)),
|
activity.toast(
|
||||||
Toast.LENGTH_SHORT)
|
view.context.getString(R.string.copied_to_clipboard, content.truncateCenter(20)),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,9 +76,12 @@ class MangaInfoPresenter(
|
|||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.doOnNext { sendMangaToView() }
|
.doOnNext { sendMangaToView() }
|
||||||
.subscribeFirst({ view, _ ->
|
.subscribeFirst(
|
||||||
|
{ view, _ ->
|
||||||
view.onFetchMangaDone()
|
view.onFetchMangaDone()
|
||||||
}, MangaInfoController::onFetchMangaError)
|
},
|
||||||
|
MangaInfoController::onFetchMangaError
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,9 +19,11 @@ class SetTrackChaptersDialog<T> : DialogController
|
|||||||
|
|
||||||
private val item: TrackItem
|
private val item: TrackItem
|
||||||
|
|
||||||
constructor(target: T, item: TrackItem) : super(Bundle().apply {
|
constructor(target: T, item: TrackItem) : super(
|
||||||
|
Bundle().apply {
|
||||||
putSerializable(KEY_ITEM_TRACK, item.track)
|
putSerializable(KEY_ITEM_TRACK, item.track)
|
||||||
}) {
|
}
|
||||||
|
) {
|
||||||
targetController = target
|
targetController = target
|
||||||
this.item = item
|
this.item = item
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,11 @@ class SetTrackReadingDatesDialog<T> : DialogController
|
|||||||
|
|
||||||
private val dateToUpdate: ReadingDate
|
private val dateToUpdate: ReadingDate
|
||||||
|
|
||||||
constructor(target: T, dateToUpdate: ReadingDate, item: TrackItem) : super(Bundle().apply {
|
constructor(target: T, dateToUpdate: ReadingDate, item: TrackItem) : super(
|
||||||
|
Bundle().apply {
|
||||||
putSerializable(SetTrackReadingDatesDialog.KEY_ITEM_TRACK, item.track)
|
putSerializable(SetTrackReadingDatesDialog.KEY_ITEM_TRACK, item.track)
|
||||||
}) {
|
}
|
||||||
|
) {
|
||||||
targetController = target
|
targetController = target
|
||||||
this.item = item
|
this.item = item
|
||||||
this.dateToUpdate = dateToUpdate
|
this.dateToUpdate = dateToUpdate
|
||||||
@ -40,10 +42,12 @@ class SetTrackReadingDatesDialog<T> : DialogController
|
|||||||
val listener = (targetController as? Listener)
|
val listener = (targetController as? Listener)
|
||||||
|
|
||||||
return MaterialDialog(activity!!)
|
return MaterialDialog(activity!!)
|
||||||
.title(when (dateToUpdate) {
|
.title(
|
||||||
|
when (dateToUpdate) {
|
||||||
ReadingDate.Start -> R.string.track_started_reading_date
|
ReadingDate.Start -> R.string.track_started_reading_date
|
||||||
ReadingDate.Finish -> R.string.track_finished_reading_date
|
ReadingDate.Finish -> R.string.track_finished_reading_date
|
||||||
})
|
}
|
||||||
|
)
|
||||||
.datePicker(currentDate = getCurrentDate()) { _, date ->
|
.datePicker(currentDate = getCurrentDate()) { _, date ->
|
||||||
listener?.setReadingDate(item, dateToUpdate, date.timeInMillis)
|
listener?.setReadingDate(item, dateToUpdate, date.timeInMillis)
|
||||||
}
|
}
|
||||||
@ -60,11 +64,12 @@ class SetTrackReadingDatesDialog<T> : DialogController
|
|||||||
ReadingDate.Start -> it.started_reading_date
|
ReadingDate.Start -> it.started_reading_date
|
||||||
ReadingDate.Finish -> it.finished_reading_date
|
ReadingDate.Finish -> it.finished_reading_date
|
||||||
}
|
}
|
||||||
if (date != 0L)
|
if (date != 0L) {
|
||||||
timeInMillis = date
|
timeInMillis = date
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface Listener {
|
interface Listener {
|
||||||
fun setReadingDate(item: TrackItem, type: ReadingDate, date: Long)
|
fun setReadingDate(item: TrackItem, type: ReadingDate, date: Long)
|
||||||
|
@ -19,9 +19,11 @@ class SetTrackScoreDialog<T> : DialogController
|
|||||||
|
|
||||||
private val item: TrackItem
|
private val item: TrackItem
|
||||||
|
|
||||||
constructor(target: T, item: TrackItem) : super(Bundle().apply {
|
constructor(target: T, item: TrackItem) : super(
|
||||||
|
Bundle().apply {
|
||||||
putSerializable(KEY_ITEM_TRACK, item.track)
|
putSerializable(KEY_ITEM_TRACK, item.track)
|
||||||
}) {
|
}
|
||||||
|
) {
|
||||||
targetController = target
|
targetController = target
|
||||||
this.item = item
|
this.item = item
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,11 @@ class SetTrackStatusDialog<T> : DialogController
|
|||||||
|
|
||||||
private val item: TrackItem
|
private val item: TrackItem
|
||||||
|
|
||||||
constructor(target: T, item: TrackItem) : super(Bundle().apply {
|
constructor(target: T, item: TrackItem) : super(
|
||||||
|
Bundle().apply {
|
||||||
putSerializable(KEY_ITEM_TRACK, item.track)
|
putSerializable(KEY_ITEM_TRACK, item.track)
|
||||||
}) {
|
}
|
||||||
|
) {
|
||||||
targetController = target
|
targetController = target
|
||||||
this.item = item
|
this.item = item
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@ import kotlinx.coroutines.flow.onEach
|
|||||||
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
|
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
class TrackController : NucleusController<TrackControllerBinding, TrackPresenter>(),
|
class TrackController :
|
||||||
|
NucleusController<TrackControllerBinding, TrackPresenter>(),
|
||||||
TrackAdapter.OnClickListener,
|
TrackAdapter.OnClickListener,
|
||||||
SetTrackStatusDialog.Listener,
|
SetTrackStatusDialog.Listener,
|
||||||
SetTrackChaptersDialog.Listener,
|
SetTrackChaptersDialog.Listener,
|
||||||
|
@ -67,8 +67,10 @@ class TrackPresenter(
|
|||||||
.toList()
|
.toList()
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribeFirst({ view, _ -> view.onRefreshDone() },
|
.subscribeFirst(
|
||||||
TrackController::onRefreshError)
|
{ view, _ -> view.onRefreshDone() },
|
||||||
|
TrackController::onRefreshError
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun search(query: String, service: TrackService) {
|
fun search(query: String, service: TrackService) {
|
||||||
@ -76,19 +78,25 @@ class TrackPresenter(
|
|||||||
searchSubscription = service.search(query)
|
searchSubscription = service.search(query)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribeLatestCache(TrackController::onSearchResults,
|
.subscribeLatestCache(
|
||||||
TrackController::onSearchResultsError)
|
TrackController::onSearchResults,
|
||||||
|
TrackController::onSearchResultsError
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun registerTracking(item: Track?, service: TrackService) {
|
fun registerTracking(item: Track?, service: TrackService) {
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
item.manga_id = manga.id!!
|
item.manga_id = manga.id!!
|
||||||
add(service.bind(item)
|
add(
|
||||||
|
service.bind(item)
|
||||||
.flatMap { db.insertTrack(item).asRxObservable() }
|
.flatMap { db.insertTrack(item).asRxObservable() }
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe({ },
|
.subscribe(
|
||||||
{ error -> context.toast(error.message) }))
|
{ },
|
||||||
|
{ error -> context.toast(error.message) }
|
||||||
|
)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
unregisterTracking(service)
|
unregisterTracking(service)
|
||||||
}
|
}
|
||||||
@ -103,13 +111,15 @@ class TrackPresenter(
|
|||||||
.flatMap { db.insertTrack(track).asRxObservable() }
|
.flatMap { db.insertTrack(track).asRxObservable() }
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribeFirst({ view, _ -> view.onRefreshDone() },
|
.subscribeFirst(
|
||||||
|
{ view, _ -> view.onRefreshDone() },
|
||||||
{ view, error ->
|
{ view, error ->
|
||||||
view.onRefreshError(error)
|
view.onRefreshError(error)
|
||||||
|
|
||||||
// Restart on error to set old values
|
// Restart on error to set old values
|
||||||
fetchTrackings()
|
fetchTrackings()
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setStatus(item: TrackItem, index: Int) {
|
fun setStatus(item: TrackItem, index: Int) {
|
||||||
|
@ -40,9 +40,11 @@ class TrackSearchDialog : DialogController {
|
|||||||
private val trackController
|
private val trackController
|
||||||
get() = targetController as TrackController
|
get() = targetController as TrackController
|
||||||
|
|
||||||
constructor(target: TrackController, service: TrackService) : super(Bundle().apply {
|
constructor(target: TrackController, service: TrackService) : super(
|
||||||
|
Bundle().apply {
|
||||||
putInt(KEY_SERVICE, service.id)
|
putInt(KEY_SERVICE, service.id)
|
||||||
}) {
|
}
|
||||||
|
) {
|
||||||
targetController = target
|
targetController = target
|
||||||
this.service = service
|
this.service = service
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ class MangaItem(val manga: Manga) : AbstractFlexibleItem<MangaHolder>() {
|
|||||||
position: Int,
|
position: Int,
|
||||||
payloads: List<Any?>?
|
payloads: List<Any?>?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
holder.bind(this)
|
holder.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,8 @@ import eu.kanade.tachiyomi.databinding.MigrationControllerBinding
|
|||||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
|
|
||||||
class MigrationController : NucleusController<MigrationControllerBinding, MigrationPresenter>(),
|
class MigrationController :
|
||||||
|
NucleusController<MigrationControllerBinding, MigrationPresenter>(),
|
||||||
FlexibleAdapter.OnItemClickListener,
|
FlexibleAdapter.OnItemClickListener,
|
||||||
SourceAdapter.OnSelectClickListener {
|
SourceAdapter.OnSelectClickListener {
|
||||||
|
|
||||||
|
@ -34,7 +34,8 @@ class MigrationPresenter(
|
|||||||
.asRxObservable()
|
.asRxObservable()
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.doOnNext { state = state.copy(sourcesWithManga = findSourcesWithManga(it)) }
|
.doOnNext { state = state.copy(sourcesWithManga = findSourcesWithManga(it)) }
|
||||||
.combineLatest(stateRelay.map { it.selectedSource }
|
.combineLatest(
|
||||||
|
stateRelay.map { it.selectedSource }
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
) { library, source -> library to source }
|
) { library, source -> library to source }
|
||||||
.filter { (_, source) -> source != null }
|
.filter { (_, source) -> source != null }
|
||||||
|
@ -8,8 +8,8 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchController
|
import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchController
|
||||||
import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchPresenter
|
import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchPresenter
|
||||||
import eu.kanade.tachiyomi.util.view.gone
|
import eu.kanade.tachiyomi.util.view.gone
|
||||||
import eu.kanade.tachiyomi.util.view.visible
|
import eu.kanade.tachiyomi.util.view.visible
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
@ -8,9 +8,9 @@ import eu.kanade.tachiyomi.source.CatalogueSource
|
|||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchCardItem
|
import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchCardItem
|
||||||
import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchItem
|
import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchItem
|
||||||
import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchPresenter
|
import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchPresenter
|
||||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
|
@ -40,7 +40,6 @@ data class SourceItem(val source: Source, val header: SelectionHeader? = null) :
|
|||||||
position: Int,
|
position: Int,
|
||||||
payloads: List<Any?>?
|
payloads: List<Any?>?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
holder.bind(this)
|
holder.bind(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,11 +50,12 @@ class AboutController : SettingsController() {
|
|||||||
|
|
||||||
preference {
|
preference {
|
||||||
titleRes = R.string.version
|
titleRes = R.string.version
|
||||||
summary = if (BuildConfig.DEBUG)
|
summary = if (BuildConfig.DEBUG) {
|
||||||
"Preview r${BuildConfig.COMMIT_COUNT} (${BuildConfig.COMMIT_SHA})"
|
"Preview r${BuildConfig.COMMIT_COUNT} (${BuildConfig.COMMIT_SHA})"
|
||||||
else
|
} else {
|
||||||
"Stable ${BuildConfig.VERSION_NAME}"
|
"Stable ${BuildConfig.VERSION_NAME}"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
preference {
|
preference {
|
||||||
titleRes = R.string.build_time
|
titleRes = R.string.build_time
|
||||||
summary = getFormattedBuildTime()
|
summary = getFormattedBuildTime()
|
||||||
@ -157,10 +158,12 @@ class AboutController : SettingsController() {
|
|||||||
|
|
||||||
class NewUpdateDialogController(bundle: Bundle? = null) : DialogController(bundle) {
|
class NewUpdateDialogController(bundle: Bundle? = null) : DialogController(bundle) {
|
||||||
|
|
||||||
constructor(body: String, url: String) : this(Bundle().apply {
|
constructor(body: String, url: String) : this(
|
||||||
|
Bundle().apply {
|
||||||
putString(BODY_KEY, body)
|
putString(BODY_KEY, body)
|
||||||
putString(URL_KEY, url)
|
putString(URL_KEY, url)
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||||
return MaterialDialog(activity!!)
|
return MaterialDialog(activity!!)
|
||||||
@ -190,7 +193,8 @@ class AboutController : SettingsController() {
|
|||||||
val buildTime = inputDf.parse(BuildConfig.BUILD_TIME)
|
val buildTime = inputDf.parse(BuildConfig.BUILD_TIME)
|
||||||
|
|
||||||
val outputDf = DateFormat.getDateTimeInstance(
|
val outputDf = DateFormat.getDateTimeInstance(
|
||||||
DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault())
|
DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault()
|
||||||
|
)
|
||||||
outputDf.timeZone = TimeZone.getDefault()
|
outputDf.timeZone = TimeZone.getDefault()
|
||||||
|
|
||||||
buildTime.toDateTimestampString(dateFormat)
|
buildTime.toDateTimestampString(dateFormat)
|
||||||
|
@ -26,7 +26,8 @@ class ChapterLoadByNumber {
|
|||||||
// If there is only one chapter for this number, use it
|
// If there is only one chapter for this number, use it
|
||||||
chaptersForNumber.size == 1 -> chaptersForNumber.first()
|
chaptersForNumber.size == 1 -> chaptersForNumber.first()
|
||||||
// Prefer a chapter of the same scanlator as the selected
|
// 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()
|
?: chaptersForNumber.first()
|
||||||
}
|
}
|
||||||
chapters.add(preferredChapter)
|
chapters.add(preferredChapter)
|
||||||
|
@ -127,10 +127,12 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||||||
* Called when the activity is created. Initializes the presenter and configuration.
|
* Called when the activity is created. Initializes the presenter and configuration.
|
||||||
*/
|
*/
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
setTheme(when (preferences.readerTheme().get()) {
|
setTheme(
|
||||||
|
when (preferences.readerTheme().get()) {
|
||||||
0 -> R.style.Theme_Reader_Light
|
0 -> R.style.Theme_Reader_Light
|
||||||
else -> R.style.Theme_Reader
|
else -> R.style.Theme_Reader
|
||||||
})
|
}
|
||||||
|
)
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
binding = ReaderActivityBinding.inflate(layoutInflater)
|
binding = ReaderActivityBinding.inflate(layoutInflater)
|
||||||
@ -278,7 +280,8 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||||||
insets.systemWindowInsetLeft,
|
insets.systemWindowInsetLeft,
|
||||||
insets.systemWindowInsetTop,
|
insets.systemWindowInsetTop,
|
||||||
insets.systemWindowInsetRight,
|
insets.systemWindowInsetRight,
|
||||||
insets.systemWindowInsetBottom)
|
insets.systemWindowInsetBottom
|
||||||
|
)
|
||||||
}
|
}
|
||||||
insets
|
insets
|
||||||
}
|
}
|
||||||
@ -293,20 +296,22 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||||||
})
|
})
|
||||||
binding.leftChapter.setOnClickListener {
|
binding.leftChapter.setOnClickListener {
|
||||||
if (viewer != null) {
|
if (viewer != null) {
|
||||||
if (viewer is R2LPagerViewer)
|
if (viewer is R2LPagerViewer) {
|
||||||
loadNextChapter()
|
loadNextChapter()
|
||||||
else
|
} else {
|
||||||
loadPreviousChapter()
|
loadPreviousChapter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
binding.rightChapter.setOnClickListener {
|
binding.rightChapter.setOnClickListener {
|
||||||
if (viewer != null) {
|
if (viewer != null) {
|
||||||
if (viewer is R2LPagerViewer)
|
if (viewer is R2LPagerViewer) {
|
||||||
loadPreviousChapter()
|
loadPreviousChapter()
|
||||||
else
|
} else {
|
||||||
loadNextChapter()
|
loadNextChapter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Set initial visibility
|
// Set initial visibility
|
||||||
setMenuVisibility(menuVisible)
|
setMenuVisibility(menuVisible)
|
||||||
@ -590,11 +595,13 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||||||
* depending on the [result].
|
* depending on the [result].
|
||||||
*/
|
*/
|
||||||
fun onSetAsCoverResult(result: ReaderPresenter.SetAsCoverResult) {
|
fun onSetAsCoverResult(result: ReaderPresenter.SetAsCoverResult) {
|
||||||
toast(when (result) {
|
toast(
|
||||||
|
when (result) {
|
||||||
Success -> R.string.cover_updated
|
Success -> R.string.cover_updated
|
||||||
AddToLibraryFirst -> R.string.notification_first_add_to_library
|
AddToLibraryFirst -> R.string.notification_first_add_to_library
|
||||||
Error -> R.string.notification_cover_update_failed
|
Error -> R.string.notification_cover_update_failed
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -700,11 +707,12 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
|||||||
* Sets the 32-bit color mode according to [enabled].
|
* Sets the 32-bit color mode according to [enabled].
|
||||||
*/
|
*/
|
||||||
private fun setTrueColor(enabled: Boolean) {
|
private fun setTrueColor(enabled: Boolean) {
|
||||||
if (enabled)
|
if (enabled) {
|
||||||
SubsamplingScaleImageView.setPreferredBitmapConfig(Bitmap.Config.ARGB_8888)
|
SubsamplingScaleImageView.setPreferredBitmapConfig(Bitmap.Config.ARGB_8888)
|
||||||
else
|
} else {
|
||||||
SubsamplingScaleImageView.setPreferredBitmapConfig(Bitmap.Config.RGB_565)
|
SubsamplingScaleImageView.setPreferredBitmapConfig(Bitmap.Config.RGB_565)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.P)
|
@TargetApi(Build.VERSION_CODES.P)
|
||||||
private fun setCutoutShort(enabled: Boolean) {
|
private fun setCutoutShort(enabled: Boolean) {
|
||||||
|
@ -214,9 +214,10 @@ class ReaderColorFilterSheet(private val activity: ReaderActivity) : BottomSheet
|
|||||||
brightness_overlay.gone()
|
brightness_overlay.gone()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isDisabled)
|
if (!isDisabled) {
|
||||||
txt_brightness_seekbar_value.text = value.toString()
|
txt_brightness_seekbar_value.text = value.toString()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the color filter value subscription
|
* Manages the color filter value subscription
|
||||||
|
@ -17,14 +17,16 @@ class ReaderColorFilterView(
|
|||||||
|
|
||||||
fun setFilterColor(color: Int, filterMode: Int) {
|
fun setFilterColor(color: Int, filterMode: Int) {
|
||||||
colorFilterPaint.color = color
|
colorFilterPaint.color = color
|
||||||
colorFilterPaint.xfermode = PorterDuffXfermode(when (filterMode) {
|
colorFilterPaint.xfermode = PorterDuffXfermode(
|
||||||
|
when (filterMode) {
|
||||||
1 -> PorterDuff.Mode.MULTIPLY
|
1 -> PorterDuff.Mode.MULTIPLY
|
||||||
2 -> PorterDuff.Mode.SCREEN
|
2 -> PorterDuff.Mode.SCREEN
|
||||||
3 -> PorterDuff.Mode.OVERLAY
|
3 -> PorterDuff.Mode.OVERLAY
|
||||||
4 -> PorterDuff.Mode.LIGHTEN
|
4 -> PorterDuff.Mode.LIGHTEN
|
||||||
5 -> PorterDuff.Mode.DARKEN
|
5 -> PorterDuff.Mode.DARKEN
|
||||||
else -> PorterDuff.Mode.SRC_OVER
|
else -> PorterDuff.Mode.SRC_OVER
|
||||||
})
|
}
|
||||||
|
)
|
||||||
invalidate()
|
invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,8 +100,10 @@ class ReaderPresenter(
|
|||||||
if (
|
if (
|
||||||
(manga.readFilter == Manga.SHOW_READ && !it.read) ||
|
(manga.readFilter == Manga.SHOW_READ && !it.read) ||
|
||||||
(manga.readFilter == Manga.SHOW_UNREAD && it.read) ||
|
(manga.readFilter == Manga.SHOW_UNREAD && it.read) ||
|
||||||
(manga.downloadedFilter == Manga.SHOW_DOWNLOADED &&
|
(
|
||||||
!downloadManager.isChapterDownloaded(it, manga)) ||
|
manga.downloadedFilter == Manga.SHOW_DOWNLOADED &&
|
||||||
|
!downloadManager.isChapterDownloaded(it, manga)
|
||||||
|
) ||
|
||||||
(manga.bookmarkedFilter == Manga.SHOW_BOOKMARKED && !it.bookmark)
|
(manga.bookmarkedFilter == Manga.SHOW_BOOKMARKED && !it.bookmark)
|
||||||
) {
|
) {
|
||||||
return@filter false
|
return@filter false
|
||||||
@ -201,9 +203,12 @@ class ReaderPresenter(
|
|||||||
.first()
|
.first()
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.doOnNext { init(it, initialChapterId) }
|
.doOnNext { init(it, initialChapterId) }
|
||||||
.subscribeFirst({ _, _ ->
|
.subscribeFirst(
|
||||||
|
{ _, _ ->
|
||||||
// Ignore onNext event
|
// Ignore onNext event
|
||||||
}, ReaderActivity::setInitialChapterError)
|
},
|
||||||
|
ReaderActivity::setInitialChapterError
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -245,9 +250,12 @@ class ReaderPresenter(
|
|||||||
.flatMap { getLoadObservable(loader!!, it) }
|
.flatMap { getLoadObservable(loader!!, it) }
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribeFirst({ _, _ ->
|
.subscribeFirst(
|
||||||
|
{ _, _ ->
|
||||||
// Ignore onNext event
|
// Ignore onNext event
|
||||||
}, ReaderActivity::setInitialChapterError)
|
},
|
||||||
|
ReaderActivity::setInitialChapterError
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -262,13 +270,17 @@ class ReaderPresenter(
|
|||||||
chapter: ReaderChapter
|
chapter: ReaderChapter
|
||||||
): Observable<ViewerChapters> {
|
): Observable<ViewerChapters> {
|
||||||
return loader.loadChapter(chapter)
|
return loader.loadChapter(chapter)
|
||||||
.andThen(Observable.fromCallable {
|
.andThen(
|
||||||
|
Observable.fromCallable {
|
||||||
val chapterPos = chapterList.indexOf(chapter)
|
val chapterPos = chapterList.indexOf(chapter)
|
||||||
|
|
||||||
ViewerChapters(chapter,
|
ViewerChapters(
|
||||||
|
chapter,
|
||||||
chapterList.getOrNull(chapterPos - 1),
|
chapterList.getOrNull(chapterPos - 1),
|
||||||
chapterList.getOrNull(chapterPos + 1))
|
chapterList.getOrNull(chapterPos + 1)
|
||||||
})
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.doOnNext { newChapters ->
|
.doOnNext { newChapters ->
|
||||||
val oldChapters = viewerChaptersRelay.value
|
val oldChapters = viewerChaptersRelay.value
|
||||||
@ -312,11 +324,14 @@ class ReaderPresenter(
|
|||||||
activeChapterSubscription = getLoadObservable(loader, chapter)
|
activeChapterSubscription = getLoadObservable(loader, chapter)
|
||||||
.doOnSubscribe { isLoadingAdjacentChapterRelay.call(true) }
|
.doOnSubscribe { isLoadingAdjacentChapterRelay.call(true) }
|
||||||
.doOnUnsubscribe { isLoadingAdjacentChapterRelay.call(false) }
|
.doOnUnsubscribe { isLoadingAdjacentChapterRelay.call(false) }
|
||||||
.subscribeFirst({ view, _ ->
|
.subscribeFirst(
|
||||||
|
{ view, _ ->
|
||||||
view.moveToPageIndex(0)
|
view.moveToPageIndex(0)
|
||||||
}, { _, _ ->
|
},
|
||||||
|
{ _, _ ->
|
||||||
// Ignore onError event, viewers handle that state
|
// Ignore onError event, viewers handle that state
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -509,9 +524,11 @@ class ReaderPresenter(
|
|||||||
notifier.onClear()
|
notifier.onClear()
|
||||||
|
|
||||||
// Pictures directory.
|
// Pictures directory.
|
||||||
val destDir = File(Environment.getExternalStorageDirectory().absolutePath +
|
val destDir = File(
|
||||||
|
Environment.getExternalStorageDirectory().absolutePath +
|
||||||
File.separator + Environment.DIRECTORY_PICTURES +
|
File.separator + Environment.DIRECTORY_PICTURES +
|
||||||
File.separator + "Tachiyomi")
|
File.separator + "Tachiyomi"
|
||||||
|
)
|
||||||
|
|
||||||
// Copy file in background.
|
// Copy file in background.
|
||||||
Observable.fromCallable { saveImage(page, destDir, manga) }
|
Observable.fromCallable { saveImage(page, destDir, manga) }
|
||||||
@ -614,7 +631,8 @@ class ReaderPresenter(
|
|||||||
|
|
||||||
db.getTracks(manga).asRxSingle()
|
db.getTracks(manga).asRxSingle()
|
||||||
.flatMapCompletable { trackList ->
|
.flatMapCompletable { trackList ->
|
||||||
Completable.concat(trackList.map { track ->
|
Completable.concat(
|
||||||
|
trackList.map { track ->
|
||||||
val service = trackManager.getService(track.sync_id)
|
val service = trackManager.getService(track.sync_id)
|
||||||
if (service != null && service.isLogged && chapterRead > track.last_chapter_read) {
|
if (service != null && service.isLogged && chapterRead > track.last_chapter_read) {
|
||||||
track.last_chapter_read = chapterRead
|
track.last_chapter_read = chapterRead
|
||||||
@ -628,7 +646,8 @@ class ReaderPresenter(
|
|||||||
} else {
|
} else {
|
||||||
Completable.complete()
|
Completable.complete()
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.onErrorComplete()
|
.onErrorComplete()
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
|
@ -66,13 +66,17 @@ class SaveImageNotifier(private val context: Context) {
|
|||||||
|
|
||||||
setContentIntent(NotificationHandler.openImagePendingActivity(context, file))
|
setContentIntent(NotificationHandler.openImagePendingActivity(context, file))
|
||||||
// Share action
|
// Share action
|
||||||
addAction(R.drawable.ic_share_24dp,
|
addAction(
|
||||||
|
R.drawable.ic_share_24dp,
|
||||||
context.getString(R.string.action_share),
|
context.getString(R.string.action_share),
|
||||||
NotificationReceiver.shareImagePendingBroadcast(context, file.absolutePath, notificationId))
|
NotificationReceiver.shareImagePendingBroadcast(context, file.absolutePath, notificationId)
|
||||||
|
)
|
||||||
// Delete action
|
// Delete action
|
||||||
addAction(R.drawable.ic_delete_24dp,
|
addAction(
|
||||||
|
R.drawable.ic_delete_24dp,
|
||||||
context.getString(R.string.action_delete),
|
context.getString(R.string.action_delete),
|
||||||
NotificationReceiver.deleteImagePendingBroadcast(context, file.absolutePath, notificationId))
|
NotificationReceiver.deleteImagePendingBroadcast(context, file.absolutePath, notificationId)
|
||||||
|
)
|
||||||
|
|
||||||
updateNotification()
|
updateNotification()
|
||||||
}
|
}
|
||||||
|
@ -44,10 +44,12 @@ class EpubPageLoader(file: File) : PageLoader() {
|
|||||||
* Returns an observable that emits a ready state unless the loader was recycled.
|
* Returns an observable that emits a ready state unless the loader was recycled.
|
||||||
*/
|
*/
|
||||||
override fun getPage(page: ReaderPage): Observable<Int> {
|
override fun getPage(page: ReaderPage): Observable<Int> {
|
||||||
return Observable.just(if (isRecycled) {
|
return Observable.just(
|
||||||
|
if (isRecycled) {
|
||||||
Page.ERROR
|
Page.ERROR
|
||||||
} else {
|
} else {
|
||||||
Page.READY
|
Page.READY
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,12 +46,15 @@ class HttpPageLoader(
|
|||||||
.concatMap { source.fetchImageFromCacheThenNet(it) }
|
.concatMap { source.fetchImageFromCacheThenNet(it) }
|
||||||
.repeat()
|
.repeat()
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.subscribe({
|
.subscribe(
|
||||||
}, { error ->
|
{
|
||||||
|
},
|
||||||
|
{ error ->
|
||||||
if (error !is InterruptedException) {
|
if (error !is InterruptedException) {
|
||||||
Timber.e(error)
|
Timber.e(error)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -186,11 +189,12 @@ class HttpPageLoader(
|
|||||||
* @param page the page whose source image has to be downloaded.
|
* @param page the page whose source image has to be downloaded.
|
||||||
*/
|
*/
|
||||||
private fun HttpSource.fetchImageFromCacheThenNet(page: ReaderPage): Observable<ReaderPage> {
|
private fun HttpSource.fetchImageFromCacheThenNet(page: ReaderPage): Observable<ReaderPage> {
|
||||||
return if (page.imageUrl.isNullOrEmpty())
|
return if (page.imageUrl.isNullOrEmpty()) {
|
||||||
getImageUrl(page).flatMap { getCachedImage(it) }
|
getImageUrl(page).flatMap { getCachedImage(it) }
|
||||||
else
|
} else {
|
||||||
getCachedImage(page)
|
getCachedImage(page)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun HttpSource.getImageUrl(page: ReaderPage): Observable<ReaderPage> {
|
private fun HttpSource.getImageUrl(page: ReaderPage): Observable<ReaderPage> {
|
||||||
page.status = Page.LOAD_PAGE
|
page.status = Page.LOAD_PAGE
|
||||||
|
@ -60,11 +60,13 @@ class RarPageLoader(file: File) : PageLoader() {
|
|||||||
* Returns an observable that emits a ready state unless the loader was recycled.
|
* Returns an observable that emits a ready state unless the loader was recycled.
|
||||||
*/
|
*/
|
||||||
override fun getPage(page: ReaderPage): Observable<Int> {
|
override fun getPage(page: ReaderPage): Observable<Int> {
|
||||||
return Observable.just(if (isRecycled) {
|
return Observable.just(
|
||||||
|
if (isRecycled) {
|
||||||
Page.ERROR
|
Page.ERROR
|
||||||
} else {
|
} else {
|
||||||
Page.READY
|
Page.READY
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,10 +49,12 @@ class ZipPageLoader(file: File) : PageLoader() {
|
|||||||
* Returns an observable that emits a ready state unless the loader was recycled.
|
* Returns an observable that emits a ready state unless the loader was recycled.
|
||||||
*/
|
*/
|
||||||
override fun getPage(page: ReaderPage): Observable<Int> {
|
override fun getPage(page: ReaderPage): Observable<Int> {
|
||||||
return Observable.just(if (isRecycled) {
|
return Observable.just(
|
||||||
|
if (isRecycled) {
|
||||||
Page.ERROR
|
Page.ERROR
|
||||||
} else {
|
} else {
|
||||||
Page.READY
|
Page.READY
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,8 @@ class ReaderProgressBar @JvmOverloads constructor(
|
|||||||
* The rotation animation to use while the progress bar is visible.
|
* The rotation animation to use while the progress bar is visible.
|
||||||
*/
|
*/
|
||||||
private val rotationAnimation by lazy {
|
private val rotationAnimation by lazy {
|
||||||
RotateAnimation(0f, 360f,
|
RotateAnimation(
|
||||||
|
0f, 360f,
|
||||||
Animation.RELATIVE_TO_SELF, 0.5f,
|
Animation.RELATIVE_TO_SELF, 0.5f,
|
||||||
Animation.RELATIVE_TO_SELF, 0.5f
|
Animation.RELATIVE_TO_SELF, 0.5f
|
||||||
).apply {
|
).apply {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user