mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-23 16:11:51 +01:00
Update to Kotlin 1.4.10, coroutines 1.3.9, Kotlinter 3.0.2 (#594)
This commit is contained in:
parent
f10f8c6b64
commit
9f15f25f43
@ -75,7 +75,8 @@ class BackupCreateService : Service() {
|
||||
startForeground(Notifications.ID_BACKUP_PROGRESS, notifier.showBackupProgress().build())
|
||||
|
||||
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
|
||||
PowerManager.PARTIAL_WAKE_LOCK, "${javaClass.name}:WakeLock"
|
||||
PowerManager.PARTIAL_WAKE_LOCK,
|
||||
"${javaClass.name}:WakeLock"
|
||||
)
|
||||
wakeLock.acquire()
|
||||
}
|
||||
|
@ -37,8 +37,11 @@ class BackupCreatorJob(private val context: Context, workerParams: WorkerParamet
|
||||
val interval = prefInterval ?: preferences.backupInterval().getOrDefault()
|
||||
if (interval > 0) {
|
||||
val request = PeriodicWorkRequestBuilder<BackupCreatorJob>(
|
||||
interval.toLong(), TimeUnit.HOURS,
|
||||
10, TimeUnit.MINUTES)
|
||||
interval.toLong(),
|
||||
TimeUnit.HOURS,
|
||||
10,
|
||||
TimeUnit.MINUTES
|
||||
)
|
||||
.addTag(TAG)
|
||||
.build()
|
||||
|
||||
|
@ -103,7 +103,8 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
|
||||
|
||||
private fun initParser(): Gson = when (version) {
|
||||
1 -> GsonBuilder().create()
|
||||
2 -> GsonBuilder()
|
||||
2 ->
|
||||
GsonBuilder()
|
||||
.registerTypeAdapter<MangaImpl>(MangaTypeAdapter.build())
|
||||
.registerTypeHierarchyAdapter<ChapterImpl>(ChapterTypeAdapter.build())
|
||||
.registerTypeAdapter<CategoryImpl>(CategoryTypeAdapter.build())
|
||||
|
@ -121,7 +121,9 @@ class BackupRestoreService : Service() {
|
||||
super.onCreate()
|
||||
startForeground(Notifications.ID_RESTORE_PROGRESS, progressNotification.build())
|
||||
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
|
||||
PowerManager.PARTIAL_WAKE_LOCK, "BackupRestoreService:WakeLock")
|
||||
PowerManager.PARTIAL_WAKE_LOCK,
|
||||
"BackupRestoreService:WakeLock"
|
||||
)
|
||||
wakeLock.acquire(TimeUnit.HOURS.toMillis(3))
|
||||
}
|
||||
|
||||
@ -382,12 +384,20 @@ class BackupRestoreService : Service() {
|
||||
* @param total the total progress.
|
||||
*/
|
||||
private fun showProgressNotification(current: Int, total: Int, title: String) {
|
||||
notificationManager.notify(Notifications.ID_RESTORE_PROGRESS, progressNotification
|
||||
notificationManager.notify(
|
||||
Notifications.ID_RESTORE_PROGRESS,
|
||||
progressNotification
|
||||
.setContentTitle(title.chop(30))
|
||||
.setContentText(getString(R.string.restoring_progress, restoreProgress,
|
||||
totalAmount))
|
||||
.setContentText(
|
||||
getString(
|
||||
R.string.restoring_progress,
|
||||
restoreProgress,
|
||||
totalAmount
|
||||
)
|
||||
)
|
||||
.setProgress(total, current, false)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -395,8 +405,14 @@ class BackupRestoreService : Service() {
|
||||
*/
|
||||
private fun showResultNotification(path: String?, file: String?) {
|
||||
|
||||
val content = mutableListOf(getString(R.string.restore_completed_content, restoreProgress
|
||||
.toString(), errors.size.toString()))
|
||||
val content = mutableListOf(
|
||||
getString(
|
||||
R.string.restore_completed_content,
|
||||
restoreProgress
|
||||
.toString(),
|
||||
errors.size.toString()
|
||||
)
|
||||
)
|
||||
val sourceMissingCount = sourcesMissing.distinct().size
|
||||
if (sourceMissingCount > 0) {
|
||||
val sources = sourcesMissing.distinct().filter { it.toLongOrNull() == null }
|
||||
@ -408,20 +424,29 @@ class BackupRestoreService : Service() {
|
||||
if (sources.isEmpty()) {
|
||||
content.add(
|
||||
resources.getQuantityString(
|
||||
R.plurals.sources_missing, sourceMissingCount, sourceMissingCount
|
||||
R.plurals.sources_missing,
|
||||
sourceMissingCount,
|
||||
sourceMissingCount
|
||||
)
|
||||
)
|
||||
} else {
|
||||
content.add(
|
||||
resources.getQuantityString(
|
||||
R.plurals.sources_missing, sourceMissingCount, sourceMissingCount
|
||||
R.plurals.sources_missing,
|
||||
sourceMissingCount,
|
||||
sourceMissingCount
|
||||
) + ": " + missingSourcesString
|
||||
)
|
||||
}
|
||||
}
|
||||
if (lincensedManga > 0)
|
||||
content.add(resources.getQuantityString(R.plurals.licensed_manga, lincensedManga,
|
||||
lincensedManga))
|
||||
content.add(
|
||||
resources.getQuantityString(
|
||||
R.plurals.licensed_manga,
|
||||
lincensedManga,
|
||||
lincensedManga
|
||||
)
|
||||
)
|
||||
val trackingErrors = trackingErrors.distinct()
|
||||
if (trackingErrors.isNotEmpty()) {
|
||||
val trackingErrorsString = trackingErrors.distinct().joinToString("\n")
|
||||
@ -440,8 +465,14 @@ class BackupRestoreService : Service() {
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setColor(ContextCompat.getColor(this, R.color.colorAccent))
|
||||
if (errors.size > 0 && !path.isNullOrEmpty() && !file.isNullOrEmpty()) {
|
||||
resultNotification.addAction(R.drawable.ic_close_24dp, getString(R.string
|
||||
.view_all_errors), getErrorLogIntent(path, file))
|
||||
resultNotification.addAction(
|
||||
R.drawable.ic_close_24dp,
|
||||
getString(
|
||||
R.string
|
||||
.view_all_errors
|
||||
),
|
||||
getErrorLogIntent(path, file)
|
||||
)
|
||||
}
|
||||
notificationManager.notify(Notifications.ID_RESTORE_COMPLETE, resultNotification.build())
|
||||
}
|
||||
|
@ -46,10 +46,12 @@ class ChapterCache(private val context: Context) {
|
||||
private val gson: Gson by injectLazy()
|
||||
|
||||
/** Cache class used for cache management. */
|
||||
private val diskCache = DiskLruCache.open(File(context.cacheDir, PARAMETER_CACHE_DIRECTORY),
|
||||
private val diskCache = DiskLruCache.open(
|
||||
File(context.cacheDir, PARAMETER_CACHE_DIRECTORY),
|
||||
PARAMETER_APP_VERSION,
|
||||
PARAMETER_VALUE_COUNT,
|
||||
PARAMETER_CACHE_SIZE)
|
||||
PARAMETER_CACHE_SIZE
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns directory of cache.
|
||||
|
@ -83,7 +83,8 @@ class CoverCache(val context: Context) {
|
||||
withContext(Dispatchers.Main) {
|
||||
context.toast(
|
||||
context.getString(
|
||||
R.string.deleted_, Formatter.formatFileSize(context, deletedSize)
|
||||
R.string.deleted_,
|
||||
Formatter.formatFileSize(context, deletedSize)
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -111,7 +112,8 @@ class CoverCache(val context: Context) {
|
||||
withContext(Dispatchers.Main) {
|
||||
context.toast(
|
||||
context.getString(
|
||||
R.string.deleted_, Formatter.formatFileSize(context, deletedSize)
|
||||
R.string.deleted_,
|
||||
Formatter.formatFileSize(context, deletedSize)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -30,8 +30,13 @@ import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory
|
||||
* This class provides operations to manage the database through its interfaces.
|
||||
*/
|
||||
open class DatabaseHelper(context: Context) :
|
||||
MangaQueries, ChapterQueries, TrackQueries, CategoryQueries, MangaCategoryQueries,
|
||||
HistoryQueries, SearchMetadataQueries {
|
||||
MangaQueries,
|
||||
ChapterQueries,
|
||||
TrackQueries,
|
||||
CategoryQueries,
|
||||
MangaCategoryQueries,
|
||||
HistoryQueries,
|
||||
SearchMetadataQueries {
|
||||
|
||||
private val configuration = SupportSQLiteOpenHelper.Configuration.builder(context)
|
||||
.name(DbOpenCallback.DATABASE_NAME)
|
||||
|
@ -44,8 +44,10 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
|
||||
db.execSQL(ChapterTable.sourceOrderUpdateQuery)
|
||||
|
||||
// Fix kissmanga covers after supporting cloudflare
|
||||
db.execSQL("""UPDATE mangas SET thumbnail_url =
|
||||
REPLACE(thumbnail_url, '93.174.95.110', 'kissmanga.com') WHERE source = 4""")
|
||||
db.execSQL(
|
||||
"""UPDATE mangas SET thumbnail_url =
|
||||
REPLACE(thumbnail_url, '93.174.95.110', 'kissmanga.com') WHERE source = 4"""
|
||||
)
|
||||
}
|
||||
if (oldVersion < 3) {
|
||||
// Initialize history tables
|
||||
|
@ -73,13 +73,14 @@ interface Manga : SManga {
|
||||
genre?.split(",")?.map { it.trim().toLowerCase(Locale.US) } ?: emptyList()
|
||||
return if (currentTags.any { tag -> tag.startsWith("japanese") || isMangaTag(tag) }) {
|
||||
TYPE_MANGA
|
||||
} else if (currentTags.any { tag -> tag.startsWith("english") || isComicTag(tag) } || isComicSource(
|
||||
sourceName
|
||||
)) {
|
||||
} else if (currentTags.any { tag -> tag.startsWith("english") || isComicTag(tag) } ||
|
||||
isComicSource(sourceName)
|
||||
) {
|
||||
TYPE_COMIC
|
||||
} else if (currentTags.any { tag ->
|
||||
tag.startsWith("chinese") || isManhuaTag(tag)
|
||||
} || sourceName.contains("manhua", true)) {
|
||||
} || sourceName.contains("manhua", true)
|
||||
) {
|
||||
TYPE_MANHUA
|
||||
} else if (currentTags.any { tag -> isManhwaTag(tag) } || isWebtoonSource(sourceName)) {
|
||||
TYPE_MANHWA
|
||||
|
@ -74,7 +74,8 @@ open class MangaImpl : Manga {
|
||||
|
||||
override fun copyFrom(other: SManga) {
|
||||
if (other is MangaImpl && other::ogTitle.isInitialized &&
|
||||
!other.title.isBlank() && other.ogTitle != ogTitle) {
|
||||
!other.title.isBlank() && other.ogTitle != ogTitle
|
||||
) {
|
||||
val oldTitle = ogTitle
|
||||
title = other.ogTitle
|
||||
val db: DownloadManager by injectLazy()
|
||||
|
@ -11,18 +11,22 @@ interface CategoryQueries : DbProvider {
|
||||
|
||||
fun getCategories() = db.get()
|
||||
.listOfObjects(Category::class.java)
|
||||
.withQuery(Query.builder()
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(CategoryTable.TABLE)
|
||||
.orderBy(CategoryTable.COL_ORDER)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getCategoriesForManga(manga: Manga) = db.get()
|
||||
.listOfObjects(Category::class.java)
|
||||
.withQuery(RawQuery.builder()
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(getCategoriesForMangaQuery())
|
||||
.args(manga.id)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun insertCategory(category: Category) = db.put().`object`(category).prepare()
|
||||
|
@ -20,67 +20,81 @@ interface ChapterQueries : DbProvider {
|
||||
|
||||
fun getChapters(manga: Manga) = db.get()
|
||||
.listOfObjects(Chapter::class.java)
|
||||
.withQuery(Query.builder()
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(ChapterTable.TABLE)
|
||||
.where("${ChapterTable.COL_MANGA_ID} = ?")
|
||||
.whereArgs(manga.id)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getRecentChapters(date: Date) = db.get()
|
||||
.listOfObjects(MangaChapter::class.java)
|
||||
.withQuery(RawQuery.builder()
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(getRecentsQuery())
|
||||
.args(date.time)
|
||||
.observesTables(ChapterTable.TABLE)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.withGetResolver(MangaChapterGetResolver.INSTANCE)
|
||||
.prepare()
|
||||
|
||||
fun getUpdatedManga(date: Date, search: String = "", endless: Boolean) = db.get()
|
||||
.listOfObjects(MangaChapterHistory::class.java)
|
||||
.withQuery(RawQuery.builder()
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(getRecentsQueryDistinct(search.sqLite, endless))
|
||||
.args(date.time)
|
||||
.observesTables(ChapterTable.TABLE)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
|
||||
.prepare()
|
||||
|
||||
fun getChapter(id: Long) = db.get()
|
||||
.`object`(Chapter::class.java)
|
||||
.withQuery(Query.builder()
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(ChapterTable.TABLE)
|
||||
.where("${ChapterTable.COL_ID} = ?")
|
||||
.whereArgs(id)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getChapter(url: String) = db.get()
|
||||
.`object`(Chapter::class.java)
|
||||
.withQuery(Query.builder()
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(ChapterTable.TABLE)
|
||||
.where("${ChapterTable.COL_URL} = ?")
|
||||
.whereArgs(url)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getChapters(url: String) = db.get()
|
||||
.listOfObjects(Chapter::class.java)
|
||||
.withQuery(Query.builder()
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(ChapterTable.TABLE)
|
||||
.where("${ChapterTable.COL_URL} = ?")
|
||||
.whereArgs(url)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getChapter(url: String, mangaId: Long) = db.get()
|
||||
.`object`(Chapter::class.java)
|
||||
.withQuery(Query.builder()
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(ChapterTable.TABLE)
|
||||
.where("${ChapterTable.COL_URL} = ? AND ${ChapterTable.COL_MANGA_ID} = ?")
|
||||
.whereArgs(url, mangaId)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun insertChapter(chapter: Chapter) = db.put().`object`(chapter).prepare()
|
||||
|
@ -27,11 +27,13 @@ interface HistoryQueries : DbProvider {
|
||||
*/
|
||||
fun getRecentManga(date: Date, offset: Int = 0, search: String = "") = db.get()
|
||||
.listOfObjects(MangaChapterHistory::class.java)
|
||||
.withQuery(RawQuery.builder()
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(getRecentMangasQuery(offset, search.sqLite))
|
||||
.args(date.time)
|
||||
.observesTables(HistoryTable.TABLE)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
|
||||
.prepare()
|
||||
|
||||
@ -42,11 +44,13 @@ interface HistoryQueries : DbProvider {
|
||||
*/
|
||||
fun getRecentlyAdded(date: Date, search: String = "", endless: Boolean) = db.get()
|
||||
.listOfObjects(MangaChapterHistory::class.java)
|
||||
.withQuery(RawQuery.builder()
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(getRecentAdditionsQuery(search.sqLite, endless))
|
||||
.args(date.time)
|
||||
.observesTables(MangaTable.TABLE)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
|
||||
.prepare()
|
||||
|
||||
@ -57,11 +61,13 @@ interface HistoryQueries : DbProvider {
|
||||
*/
|
||||
fun getRecentMangaLimit(date: Date, limit: Int = 0, search: String = "") = db.get()
|
||||
.listOfObjects(MangaChapterHistory::class.java)
|
||||
.withQuery(RawQuery.builder()
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(getRecentMangasLimitQuery(limit, search.sqLite))
|
||||
.args(date.time)
|
||||
.observesTables(HistoryTable.TABLE)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
|
||||
.prepare()
|
||||
|
||||
@ -72,30 +78,36 @@ interface HistoryQueries : DbProvider {
|
||||
*/
|
||||
fun getRecentsWithUnread(date: Date, search: String = "", endless: Boolean) = db.get()
|
||||
.listOfObjects(MangaChapterHistory::class.java)
|
||||
.withQuery(RawQuery.builder()
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(getRecentReadWithUnreadChapters(search.sqLite, endless))
|
||||
.args(date.time)
|
||||
.observesTables(HistoryTable.TABLE)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
|
||||
.prepare()
|
||||
|
||||
fun getHistoryByMangaId(mangaId: Long) = db.get()
|
||||
.listOfObjects(History::class.java)
|
||||
.withQuery(RawQuery.builder()
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(getHistoryByMangaId())
|
||||
.args(mangaId)
|
||||
.observesTables(HistoryTable.TABLE)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getHistoryByChapterUrl(chapterUrl: String) = db.get()
|
||||
.`object`(History::class.java)
|
||||
.withQuery(RawQuery.builder()
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(getHistoryByChapterUrl())
|
||||
.args(chapterUrl)
|
||||
.observesTables(HistoryTable.TABLE)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
/**
|
||||
@ -119,16 +131,20 @@ interface HistoryQueries : DbProvider {
|
||||
.prepare()
|
||||
|
||||
fun deleteHistory() = db.delete()
|
||||
.byQuery(DeleteQuery.builder()
|
||||
.byQuery(
|
||||
DeleteQuery.builder()
|
||||
.table(HistoryTable.TABLE)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun deleteHistoryNoLastRead() = db.delete()
|
||||
.byQuery(DeleteQuery.builder()
|
||||
.byQuery(
|
||||
DeleteQuery.builder()
|
||||
.table(HistoryTable.TABLE)
|
||||
.where("${HistoryTable.COL_LAST_READ} = ?")
|
||||
.whereArgs(0)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
}
|
||||
|
@ -15,11 +15,13 @@ interface MangaCategoryQueries : DbProvider {
|
||||
fun insertMangasCategories(mangasCategories: List<MangaCategory>) = db.put().objects(mangasCategories).prepare()
|
||||
|
||||
fun deleteOldMangasCategories(mangas: List<Manga>) = db.delete()
|
||||
.byQuery(DeleteQuery.builder()
|
||||
.byQuery(
|
||||
DeleteQuery.builder()
|
||||
.table(MangaCategoryTable.TABLE)
|
||||
.where("${MangaCategoryTable.COL_MANGA_ID} IN (${Queries.placeholders(mangas.size)})")
|
||||
.whereArgs(*mangas.map { it.id }.toTypedArray())
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun setMangaCategories(mangasCategories: List<MangaCategory>, mangas: List<Manga>) {
|
||||
|
@ -23,46 +23,56 @@ interface MangaQueries : DbProvider {
|
||||
|
||||
fun getMangas() = db.get()
|
||||
.listOfObjects(Manga::class.java)
|
||||
.withQuery(Query.builder()
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getLibraryMangas() = db.get()
|
||||
.listOfObjects(LibraryManga::class.java)
|
||||
.withQuery(RawQuery.builder()
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(libraryQuery)
|
||||
.observesTables(MangaTable.TABLE, ChapterTable.TABLE, MangaCategoryTable.TABLE, CategoryTable.TABLE)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.withGetResolver(LibraryMangaGetResolver.INSTANCE)
|
||||
.prepare()
|
||||
|
||||
fun getFavoriteMangas() = db.get()
|
||||
.listOfObjects(Manga::class.java)
|
||||
.withQuery(Query.builder()
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_FAVORITE} = ?")
|
||||
.whereArgs(1)
|
||||
.orderBy(MangaTable.COL_TITLE)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getManga(url: String, sourceId: Long) = db.get()
|
||||
.`object`(Manga::class.java)
|
||||
.withQuery(Query.builder()
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_URL} = ? AND ${MangaTable.COL_SOURCE} = ?")
|
||||
.whereArgs(url, sourceId)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getManga(id: Long) = db.get()
|
||||
.`object`(Manga::class.java)
|
||||
.withQuery(Query.builder()
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_ID} = ?")
|
||||
.whereArgs(id)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun insertManga(manga: Manga) = db.put().`object`(manga).prepare()
|
||||
@ -114,25 +124,31 @@ interface MangaQueries : DbProvider {
|
||||
fun deleteMangas(mangas: List<Manga>) = db.delete().objects(mangas).prepare()
|
||||
|
||||
fun deleteMangasNotInLibrary() = db.delete()
|
||||
.byQuery(DeleteQuery.builder()
|
||||
.byQuery(
|
||||
DeleteQuery.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_FAVORITE} = ?")
|
||||
.whereArgs(0)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun deleteMangas() = db.delete()
|
||||
.byQuery(DeleteQuery.builder()
|
||||
.byQuery(
|
||||
DeleteQuery.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getLastReadManga() = db.get()
|
||||
.listOfObjects(Manga::class.java)
|
||||
.withQuery(RawQuery.builder()
|
||||
.withQuery(
|
||||
RawQuery.builder()
|
||||
.query(getLastReadMangaQuery())
|
||||
.observesTables(MangaTable.TABLE)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getTotalChapterManga() = db.get().listOfObjects(Manga::class.java)
|
||||
|
@ -9,7 +9,8 @@ import eu.kanade.tachiyomi.data.database.tables.MangaTable as Manga
|
||||
/**
|
||||
* Query to get the manga from the library, with their categories and unread count.
|
||||
*/
|
||||
val libraryQuery = """
|
||||
val libraryQuery =
|
||||
"""
|
||||
SELECT M.*, COALESCE(MC.${MangaCategory.COL_CATEGORY_ID}, 0) AS ${Manga.COL_CATEGORY}
|
||||
FROM (
|
||||
SELECT ${Manga.TABLE}.*, COALESCE(C.unread, 0) AS ${Manga.COL_UNREAD}, COALESCE(R.hasread, 0) AS ${Manga.COL_HAS_READ}
|
||||
@ -40,7 +41,8 @@ val libraryQuery = """
|
||||
/**
|
||||
* Query to get the recent chapters of manga from the library up to a date.
|
||||
*/
|
||||
fun getRecentsQuery() = """
|
||||
fun getRecentsQuery() =
|
||||
"""
|
||||
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, * FROM ${Manga.TABLE} JOIN ${Chapter.TABLE}
|
||||
ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}
|
||||
WHERE ${Manga.COL_FAVORITE} = 1
|
||||
@ -52,7 +54,8 @@ fun getRecentsQuery() = """
|
||||
/**
|
||||
* Query to get the recently added manga
|
||||
*/
|
||||
fun getRecentAdditionsQuery(search: String, endless: Boolean) = """
|
||||
fun getRecentAdditionsQuery(search: String, endless: Boolean) =
|
||||
"""
|
||||
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, * FROM ${Manga.TABLE}
|
||||
WHERE ${Manga.COL_FAVORITE} = 1
|
||||
AND ${Manga.COL_DATE_ADDED} > ?
|
||||
@ -64,7 +67,8 @@ fun getRecentAdditionsQuery(search: String, endless: Boolean) = """
|
||||
/**
|
||||
* Query to get the manga with recently uploaded chapters
|
||||
*/
|
||||
fun getRecentsQueryDistinct(search: String, endless: Boolean) = """
|
||||
fun getRecentsQueryDistinct(search: String, endless: Boolean) =
|
||||
"""
|
||||
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*
|
||||
FROM ${Manga.TABLE}
|
||||
JOIN ${Chapter.TABLE}
|
||||
@ -92,7 +96,8 @@ fun getRecentsQueryDistinct(search: String, endless: Boolean) = """
|
||||
* and are read after the given time period
|
||||
* @return return limit is 25
|
||||
*/
|
||||
fun getRecentMangasQuery(offset: Int = 0, search: String = "") = """
|
||||
fun getRecentMangasQuery(offset: Int = 0, search: String = "") =
|
||||
"""
|
||||
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.*
|
||||
FROM ${Manga.TABLE}
|
||||
JOIN ${Chapter.TABLE}
|
||||
@ -118,7 +123,8 @@ fun getRecentMangasQuery(offset: Int = 0, search: String = "") = """
|
||||
* The select statement returns all information of chapters that have the same id as the chapter in max_last_read
|
||||
* and are read after the given time period
|
||||
*/
|
||||
fun getRecentMangasLimitQuery(limit: Int = 25, search: String = "") = """
|
||||
fun getRecentMangasLimitQuery(limit: Int = 25, search: String = "") =
|
||||
"""
|
||||
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.*
|
||||
FROM ${Manga.TABLE}
|
||||
JOIN ${Chapter.TABLE}
|
||||
@ -145,7 +151,8 @@ fun getRecentMangasLimitQuery(limit: Int = 25, search: String = "") = """
|
||||
* The select statement returns all information of chapters that have the same id as the chapter in max_last_read
|
||||
* and are read after the given time period
|
||||
*/
|
||||
fun getRecentReadWithUnreadChapters(search: String = "", endless: Boolean) = """
|
||||
fun getRecentReadWithUnreadChapters(search: String = "", endless: Boolean) =
|
||||
"""
|
||||
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.*
|
||||
FROM (
|
||||
SELECT ${Manga.TABLE}.*
|
||||
@ -178,7 +185,8 @@ fun getRecentReadWithUnreadChapters(search: String = "", endless: Boolean) = """
|
||||
${if (endless) "" else "LIMIT 8"}
|
||||
"""
|
||||
|
||||
fun getHistoryByMangaId() = """
|
||||
fun getHistoryByMangaId() =
|
||||
"""
|
||||
SELECT ${History.TABLE}.*
|
||||
FROM ${History.TABLE}
|
||||
JOIN ${Chapter.TABLE}
|
||||
@ -186,7 +194,8 @@ fun getHistoryByMangaId() = """
|
||||
WHERE ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = ? AND ${History.TABLE}.${History.COL_CHAPTER_ID} = ${Chapter.TABLE}.${Chapter.COL_ID}
|
||||
"""
|
||||
|
||||
fun getHistoryByChapterUrl() = """
|
||||
fun getHistoryByChapterUrl() =
|
||||
"""
|
||||
SELECT ${History.TABLE}.*
|
||||
FROM ${History.TABLE}
|
||||
JOIN ${Chapter.TABLE}
|
||||
@ -194,7 +203,8 @@ fun getHistoryByChapterUrl() = """
|
||||
WHERE ${Chapter.TABLE}.${Chapter.COL_URL} = ? AND ${History.TABLE}.${History.COL_CHAPTER_ID} = ${Chapter.TABLE}.${Chapter.COL_ID}
|
||||
"""
|
||||
|
||||
fun getLastReadMangaQuery() = """
|
||||
fun getLastReadMangaQuery() =
|
||||
"""
|
||||
SELECT ${Manga.TABLE}.*, MAX(${History.TABLE}.${History.COL_LAST_READ}) AS max
|
||||
FROM ${Manga.TABLE}
|
||||
JOIN ${Chapter.TABLE}
|
||||
@ -206,7 +216,8 @@ fun getLastReadMangaQuery() = """
|
||||
ORDER BY max DESC
|
||||
"""
|
||||
|
||||
fun getTotalChapterMangaQuery() = """
|
||||
fun getTotalChapterMangaQuery() =
|
||||
"""
|
||||
SELECT ${Manga.TABLE}.*
|
||||
FROM ${Manga.TABLE}
|
||||
JOIN ${Chapter.TABLE}
|
||||
@ -218,7 +229,8 @@ fun getTotalChapterMangaQuery() = """
|
||||
/**
|
||||
* Query to get the categories for a manga.
|
||||
*/
|
||||
fun getCategoriesForMangaQuery() = """
|
||||
fun getCategoriesForMangaQuery() =
|
||||
"""
|
||||
SELECT ${Category.TABLE}.* FROM ${Category.TABLE}
|
||||
JOIN ${MangaCategory.TABLE} ON ${Category.TABLE}.${Category.COL_ID} =
|
||||
${MangaCategory.TABLE}.${MangaCategory.COL_CATEGORY_ID}
|
||||
|
@ -10,35 +10,43 @@ interface SearchMetadataQueries : DbProvider {
|
||||
|
||||
fun getSearchMetadataForManga(mangaId: Long) = db.get()
|
||||
.`object`(SearchMetadata::class.java)
|
||||
.withQuery(Query.builder()
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(SearchMetadataTable.TABLE)
|
||||
.where("${SearchMetadataTable.COL_MANGA_ID} = ?")
|
||||
.whereArgs(mangaId)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getSearchMetadata() = db.get()
|
||||
.listOfObjects(SearchMetadata::class.java)
|
||||
.withQuery(Query.builder()
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(SearchMetadataTable.TABLE)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getSearchMetadataByIndexedExtra(extra: String) = db.get()
|
||||
.listOfObjects(SearchMetadata::class.java)
|
||||
.withQuery(Query.builder()
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(SearchMetadataTable.TABLE)
|
||||
.where("${SearchMetadataTable.COL_INDEXED_EXTRA} = ?")
|
||||
.whereArgs(extra)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun insertSearchMetadata(metadata: SearchMetadata) = db.put().`object`(metadata).prepare()
|
||||
|
||||
fun deleteSearchMetadata(metadata: SearchMetadata) = db.delete().`object`(metadata).prepare()
|
||||
|
||||
fun deleteAllSearchMetadata() = db.delete().byQuery(DeleteQuery.builder()
|
||||
fun deleteAllSearchMetadata() = db.delete().byQuery(
|
||||
DeleteQuery.builder()
|
||||
.table(SearchMetadataTable.TABLE)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
}
|
||||
|
@ -12,11 +12,13 @@ interface TrackQueries : DbProvider {
|
||||
|
||||
fun getTracks(manga: Manga) = db.get()
|
||||
.listOfObjects(Track::class.java)
|
||||
.withQuery(Query.builder()
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(TrackTable.TABLE)
|
||||
.where("${TrackTable.COL_MANGA_ID} = ?")
|
||||
.whereArgs(manga.id)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.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 deleteTrackForManga(manga: Manga, sync: TrackService) = db.delete()
|
||||
.byQuery(DeleteQuery.builder()
|
||||
.byQuery(
|
||||
DeleteQuery.builder()
|
||||
.table(TrackTable.TABLE)
|
||||
.where("${TrackTable.COL_MANGA_ID} = ? AND ${TrackTable.COL_SYNC_ID} = ?")
|
||||
.whereArgs(manga.id, sync.id)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
}
|
||||
|
@ -19,11 +19,13 @@ class HistoryLastReadPutResolver : HistoryPutResolver() {
|
||||
override fun performPut(@NonNull db: StorIOSQLite, @NonNull history: History): PutResult = db.inTransactionReturn {
|
||||
val updateQuery = mapToUpdateQuery(history)
|
||||
|
||||
val cursor = db.lowLevel().query(Query.builder()
|
||||
val cursor = db.lowLevel().query(
|
||||
Query.builder()
|
||||
.table(updateQuery.table())
|
||||
.where(updateQuery.where())
|
||||
.whereArgs(updateQuery.whereArgs())
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
|
||||
val putResult: PutResult
|
||||
|
||||
|
@ -15,7 +15,8 @@ object CategoryTable {
|
||||
const val COL_MANGA_ORDER = "manga_order"
|
||||
|
||||
val createTableQuery: String
|
||||
get() = """CREATE TABLE $TABLE(
|
||||
get() =
|
||||
"""CREATE TABLE $TABLE(
|
||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
$COL_NAME TEXT NOT NULL,
|
||||
$COL_ORDER INTEGER NOT NULL,
|
||||
|
@ -31,7 +31,8 @@ object ChapterTable {
|
||||
const val COL_SOURCE_ORDER = "source_order"
|
||||
|
||||
val createTableQuery: String
|
||||
get() = """CREATE TABLE $TABLE(
|
||||
get() =
|
||||
"""CREATE TABLE $TABLE(
|
||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
$COL_MANGA_ID INTEGER NOT NULL,
|
||||
$COL_URL TEXT NOT NULL,
|
||||
|
@ -31,7 +31,8 @@ object HistoryTable {
|
||||
* query to create history table
|
||||
*/
|
||||
val createTableQuery: String
|
||||
get() = """CREATE TABLE $TABLE(
|
||||
get() =
|
||||
"""CREATE TABLE $TABLE(
|
||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
$COL_CHAPTER_ID INTEGER NOT NULL UNIQUE,
|
||||
$COL_LAST_READ LONG,
|
||||
|
@ -11,7 +11,8 @@ object MangaCategoryTable {
|
||||
const val COL_CATEGORY_ID = "category_id"
|
||||
|
||||
val createTableQuery: String
|
||||
get() = """CREATE TABLE $TABLE(
|
||||
get() =
|
||||
"""CREATE TABLE $TABLE(
|
||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
$COL_MANGA_ID INTEGER NOT NULL,
|
||||
$COL_CATEGORY_ID INTEGER NOT NULL,
|
||||
|
@ -45,7 +45,8 @@ object MangaTable {
|
||||
const val COL_DATE_ADDED = "date_added"
|
||||
|
||||
val createTableQuery: String
|
||||
get() = """CREATE TABLE $TABLE(
|
||||
get() =
|
||||
"""CREATE TABLE $TABLE(
|
||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
$COL_SOURCE INTEGER NOT NULL,
|
||||
$COL_URL TEXT NOT NULL,
|
||||
|
@ -15,7 +15,8 @@ object SearchMetadataTable {
|
||||
|
||||
// Insane foreign, primary key to avoid touch manga table
|
||||
val createTableQuery: String
|
||||
get() = """CREATE TABLE $TABLE(
|
||||
get() =
|
||||
"""CREATE TABLE $TABLE(
|
||||
$COL_MANGA_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
$COL_UPLOADER TEXT,
|
||||
$COL_EXTRA TEXT NOT NULL,
|
||||
|
@ -27,7 +27,8 @@ object TrackTable {
|
||||
const val COL_TRACKING_URL = "remote_url"
|
||||
|
||||
val createTableQuery: String
|
||||
get() = """CREATE TABLE $TABLE(
|
||||
get() =
|
||||
"""CREATE TABLE $TABLE(
|
||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
$COL_MANGA_ID INTEGER NOT NULL,
|
||||
$COL_SYNC_ID INTEGER NOT NULL,
|
||||
|
@ -251,7 +251,9 @@ class DownloadManager(val context: Context) {
|
||||
queue.remove(chapters)
|
||||
val chapterDirs =
|
||||
provider.findChapterDirs(chapters, manga, source) + provider.findTempChapterDirs(
|
||||
chapters, manga, source
|
||||
chapters,
|
||||
manga,
|
||||
source
|
||||
)
|
||||
chapterDirs.forEach { it.delete() }
|
||||
cache.removeChapters(chapters, manga)
|
||||
|
@ -78,16 +78,21 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
|
||||
isDownloading = true
|
||||
// Pause action
|
||||
addAction(R.drawable.ic_pause_24dp,
|
||||
addAction(
|
||||
R.drawable.ic_pause_24dp,
|
||||
context.getString(R.string.pause),
|
||||
NotificationReceiver.pauseDownloadsPendingBroadcast(context))
|
||||
NotificationReceiver.pauseDownloadsPendingBroadcast(context)
|
||||
)
|
||||
}
|
||||
|
||||
if (download != null) {
|
||||
val title = download.manga.title.chop(15)
|
||||
val quotedTitle = Pattern.quote(title)
|
||||
val chapter = download.chapter.name.replaceFirst("$quotedTitle[\\s]*[-]*[\\s]*"
|
||||
.toRegex(RegexOption.IGNORE_CASE), "")
|
||||
val chapter = download.chapter.name.replaceFirst(
|
||||
"$quotedTitle[\\s]*[-]*[\\s]*"
|
||||
.toRegex(RegexOption.IGNORE_CASE),
|
||||
""
|
||||
)
|
||||
setContentTitle("$title - $chapter".chop(30))
|
||||
setContentText(
|
||||
context.getString(R.string.downloading)
|
||||
@ -124,17 +129,21 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
|
||||
isDownloading = true
|
||||
// Pause action
|
||||
addAction(R.drawable.ic_pause_24dp,
|
||||
addAction(
|
||||
R.drawable.ic_pause_24dp,
|
||||
context.getString(R.string.pause),
|
||||
NotificationReceiver.pauseDownloadsPendingBroadcast(context))
|
||||
NotificationReceiver.pauseDownloadsPendingBroadcast(context)
|
||||
)
|
||||
}
|
||||
|
||||
val title = download.manga.title.chop(15)
|
||||
val quotedTitle = Pattern.quote(title)
|
||||
val chapter = download.chapter.name.replaceFirst("$quotedTitle[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE), "")
|
||||
setContentTitle("$title - $chapter".chop(30))
|
||||
setContentText(context.getString(R.string.downloading_progress)
|
||||
.format(download.downloadedImages, download.pages!!.size))
|
||||
setContentText(
|
||||
context.getString(R.string.downloading_progress)
|
||||
.format(download.downloadedImages, download.pages!!.size)
|
||||
)
|
||||
setStyle(null)
|
||||
setProgress(download.pages!!.size, download.downloadedImages, false)
|
||||
}
|
||||
|
@ -163,11 +163,15 @@ class DownloadService : Service() {
|
||||
subscriptions += ReactiveNetwork.observeNetworkConnectivity(applicationContext)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ state -> onNetworkStateChanged(state)
|
||||
}, {
|
||||
.subscribe(
|
||||
{ state ->
|
||||
onNetworkStateChanged(state)
|
||||
},
|
||||
{
|
||||
toast(R.string.could_not_download_chapter_can_try_again)
|
||||
stopSelf()
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,7 +20,9 @@ class CoverViewTarget(
|
||||
progress?.gone()
|
||||
view.scaleType = ImageView.ScaleType.CENTER
|
||||
val vector = VectorDrawableCompat.create(
|
||||
view.context.resources, R.drawable.ic_broken_image_24dp, null
|
||||
view.context.resources,
|
||||
R.drawable.ic_broken_image_24dp,
|
||||
null
|
||||
)
|
||||
vector?.setTint(view.context.getResourceColor(android.R.attr.textColorSecondary))
|
||||
view.setImageDrawable(vector)
|
||||
|
@ -70,7 +70,8 @@ class MangaFetcher : Fetcher<Manga> {
|
||||
return fileLoader(coverFile)
|
||||
}
|
||||
val (_, body) = awaitGetCall(
|
||||
manga, if (manga.favorite) {
|
||||
manga,
|
||||
if (manga.favorite) {
|
||||
!options.networkCachePolicy.readEnabled
|
||||
} else {
|
||||
false
|
||||
|
@ -29,7 +29,8 @@ class CustomMangaManager(val context: Context) {
|
||||
|
||||
val json = try {
|
||||
Gson().fromJson(
|
||||
Scanner(editJson).useDelimiter("\\Z").next(), JsonObject::class.java
|
||||
Scanner(editJson).useDelimiter("\\Z").next(),
|
||||
JsonObject::class.java
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
@ -83,7 +84,12 @@ class CustomMangaManager(val context: Context) {
|
||||
|
||||
fun Manga.toJson(): MangaJson {
|
||||
return MangaJson(
|
||||
id!!, title, author, artist, description, genre?.split(", ")?.toTypedArray()
|
||||
id!!,
|
||||
title,
|
||||
author,
|
||||
artist,
|
||||
description,
|
||||
genre?.split(", ")?.toTypedArray()
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -42,8 +42,11 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||
.build()
|
||||
|
||||
val request = PeriodicWorkRequestBuilder<LibraryUpdateJob>(
|
||||
interval.toLong(), TimeUnit.HOURS,
|
||||
10, TimeUnit.MINUTES)
|
||||
interval.toLong(),
|
||||
TimeUnit.HOURS,
|
||||
10,
|
||||
TimeUnit.MINUTES
|
||||
)
|
||||
.addTag(TAG)
|
||||
.setConstraints(constraints)
|
||||
.build()
|
||||
|
@ -131,7 +131,9 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
val manga = it.key
|
||||
val chapters = it.value
|
||||
val chapterNames = chapters.map { chapter -> chapter.name }
|
||||
notifications.add(Pair(context.notification(Notifications.CHANNEL_NEW_CHAPTERS) {
|
||||
notifications.add(
|
||||
Pair(
|
||||
context.notification(Notifications.CHANNEL_NEW_CHAPTERS) {
|
||||
setSmallIcon(R.drawable.ic_tachi)
|
||||
try {
|
||||
val request = GetRequest.Builder(context).data(manga)
|
||||
@ -148,8 +150,8 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
setContentTitle(manga.title)
|
||||
color = ContextCompat.getColor(context, R.color.colorAccent)
|
||||
val chaptersNames = if (chapterNames.size > MAX_CHAPTERS) {
|
||||
"${chapterNames.take(MAX_CHAPTERS - 1)
|
||||
.joinToString(", ")}, " + context.resources.getQuantityString(
|
||||
"${chapterNames.take(MAX_CHAPTERS - 1).joinToString(", ")}, " +
|
||||
context.resources.getQuantityString(
|
||||
R.plurals.notification_and_n_more,
|
||||
(chapterNames.size - (MAX_CHAPTERS - 1)),
|
||||
(chapterNames.size - (MAX_CHAPTERS - 1))
|
||||
@ -161,30 +163,41 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
setGroup(Notifications.GROUP_NEW_CHAPTERS)
|
||||
setContentIntent(
|
||||
NotificationReceiver.openChapterPendingActivity(
|
||||
context, manga, chapters.first()
|
||||
context,
|
||||
manga,
|
||||
chapters.first()
|
||||
)
|
||||
)
|
||||
addAction(
|
||||
R.drawable.ic_eye_24dp,
|
||||
context.getString(R.string.mark_as_read),
|
||||
NotificationReceiver.markAsReadPendingBroadcast(
|
||||
context, manga, chapters, Notifications.ID_NEW_CHAPTERS
|
||||
context,
|
||||
manga,
|
||||
chapters,
|
||||
Notifications.ID_NEW_CHAPTERS
|
||||
)
|
||||
)
|
||||
addAction(
|
||||
R.drawable.ic_book_24dp,
|
||||
context.getString(R.string.view_chapters),
|
||||
NotificationReceiver.openChapterPendingActivity(
|
||||
context, manga, Notifications.ID_NEW_CHAPTERS
|
||||
context,
|
||||
manga,
|
||||
Notifications.ID_NEW_CHAPTERS
|
||||
)
|
||||
)
|
||||
setAutoCancel(true)
|
||||
}, manga.id.hashCode()))
|
||||
},
|
||||
manga.id.hashCode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
NotificationManagerCompat.from(context).apply {
|
||||
|
||||
notify(Notifications.ID_NEW_CHAPTERS,
|
||||
notify(
|
||||
Notifications.ID_NEW_CHAPTERS,
|
||||
context.notification(Notifications.CHANNEL_NEW_CHAPTERS) {
|
||||
setSmallIcon(R.drawable.ic_tachi)
|
||||
setLargeIcon(notificationBitmap)
|
||||
@ -193,14 +206,18 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
if (updates.size > 1) {
|
||||
setContentText(
|
||||
context.resources.getQuantityString(
|
||||
R.plurals.for_n_titles, updates.size, updates.size
|
||||
R.plurals.for_n_titles,
|
||||
updates.size,
|
||||
updates.size
|
||||
)
|
||||
)
|
||||
setStyle(
|
||||
NotificationCompat.BigTextStyle()
|
||||
.bigText(updates.keys.joinToString("\n") {
|
||||
.bigText(
|
||||
updates.keys.joinToString("\n") {
|
||||
it.title.chop(45)
|
||||
})
|
||||
}
|
||||
)
|
||||
)
|
||||
} else {
|
||||
setContentText(updates.keys.first().title.chop(45))
|
||||
@ -211,7 +228,8 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
setGroupSummary(true)
|
||||
setContentIntent(getNotificationIntent())
|
||||
setAutoCancel(true)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
notifications.forEach {
|
||||
notify(it.second, it.first)
|
||||
|
@ -9,7 +9,8 @@ object LibraryUpdateRanker {
|
||||
|
||||
val rankingScheme = listOf(
|
||||
(this::lexicographicRanking)(),
|
||||
(this::latestFirstRanking)())
|
||||
(this::latestFirstRanking)()
|
||||
)
|
||||
|
||||
/**
|
||||
* Provides a total ordering over all the Mangas.
|
||||
|
@ -134,7 +134,8 @@ class LibraryUpdateService(
|
||||
val selectedScheme = preferences.libraryUpdatePrioritization().getOrDefault()
|
||||
val savedMangasList = intent.getLongArrayExtra(KEY_MANGAS)?.asList()
|
||||
|
||||
val mangaList = (if (savedMangasList != null) {
|
||||
val mangaList = (
|
||||
if (savedMangasList != null) {
|
||||
val mangas = db.getLibraryMangas().executeAsBlocking().filter {
|
||||
it.id in savedMangasList
|
||||
}.distinctBy { it.id }
|
||||
@ -143,7 +144,8 @@ class LibraryUpdateService(
|
||||
mangas
|
||||
} else {
|
||||
getMangaToUpdate(intent, target)
|
||||
}).sortedWith(rankingScheme[selectedScheme])
|
||||
}
|
||||
).sortedWith(rankingScheme[selectedScheme])
|
||||
// Update favorite manga. Destroy service when completed or in case of an error.
|
||||
launchTarget(target, mangaList, startId)
|
||||
return START_REDELIVER_INTENT
|
||||
@ -157,7 +159,8 @@ class LibraryUpdateService(
|
||||
super.onCreate()
|
||||
notifier = LibraryUpdateNotifier(this)
|
||||
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
|
||||
PowerManager.PARTIAL_WAKE_LOCK, "LibraryUpdateService:WakeLock"
|
||||
PowerManager.PARTIAL_WAKE_LOCK,
|
||||
"LibraryUpdateService:WakeLock"
|
||||
)
|
||||
wakeLock.acquire(TimeUnit.MINUTES.toMillis(30))
|
||||
startForeground(Notifications.ID_LIBRARY_PROGRESS, notifier.progressNotificationBuilder.build())
|
||||
@ -247,7 +250,9 @@ class LibraryUpdateService(
|
||||
val hasDLs = try {
|
||||
requestSemaphore.withPermit {
|
||||
updateMangaInSource(
|
||||
it.key, downloadNew, categoriesToDownload
|
||||
it.key,
|
||||
downloadNew,
|
||||
categoriesToDownload
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
@ -351,13 +356,15 @@ class LibraryUpdateService(
|
||||
var hasDownloads = false
|
||||
while (count < mangaToUpdateMap[source]!!.size) {
|
||||
val shouldDownload =
|
||||
(downloadNew && (categoriesToDownload.isEmpty() || mangaToUpdateMap[source]!![count].category in categoriesToDownload || db.getCategoriesForManga(
|
||||
mangaToUpdateMap[source]!![count]
|
||||
).executeOnIO().any { (it.id ?: -1) in categoriesToDownload }))
|
||||
if (updateMangaChapters(
|
||||
mangaToUpdateMap[source]!![count], this.count.andIncrement, shouldDownload
|
||||
(
|
||||
downloadNew && (
|
||||
categoriesToDownload.isEmpty() ||
|
||||
mangaToUpdateMap[source]!![count].category in categoriesToDownload ||
|
||||
db.getCategoriesForManga(mangaToUpdateMap[source]!![count])
|
||||
.executeOnIO().any { (it.id ?: -1) in categoriesToDownload }
|
||||
)
|
||||
) {
|
||||
)
|
||||
if (updateMangaChapters(mangaToUpdateMap[source]!![count], this.count.andIncrement, shouldDownload)) {
|
||||
hasDownloads = true
|
||||
}
|
||||
count++
|
||||
|
@ -58,29 +58,41 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
// Clear the download queue
|
||||
ACTION_CLEAR_DOWNLOADS -> downloadManager.clearQueue(true)
|
||||
// Launch share activity and dismiss notification
|
||||
ACTION_SHARE_IMAGE -> shareImage(context, intent.getStringExtra(EXTRA_FILE_LOCATION),
|
||||
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
|
||||
ACTION_SHARE_IMAGE -> shareImage(
|
||||
context,
|
||||
intent.getStringExtra(EXTRA_FILE_LOCATION),
|
||||
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
|
||||
)
|
||||
// Delete image from path and dismiss notification
|
||||
ACTION_DELETE_IMAGE -> deleteImage(context, intent.getStringExtra(EXTRA_FILE_LOCATION),
|
||||
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
|
||||
ACTION_DELETE_IMAGE -> deleteImage(
|
||||
context,
|
||||
intent.getStringExtra(EXTRA_FILE_LOCATION),
|
||||
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
|
||||
)
|
||||
// Cancel library update and dismiss notification
|
||||
ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context)
|
||||
ACTION_CANCEL_RESTORE -> cancelRestoreUpdate(context)
|
||||
// Share backup file
|
||||
ACTION_SHARE_BACKUP ->
|
||||
shareBackup(
|
||||
context, intent.getParcelableExtra(EXTRA_URI),
|
||||
context,
|
||||
intent.getParcelableExtra(EXTRA_URI),
|
||||
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
|
||||
)
|
||||
// Open reader activity
|
||||
ACTION_OPEN_CHAPTER -> {
|
||||
openChapter(context, intent.getLongExtra(EXTRA_MANGA_ID, -1),
|
||||
intent.getLongExtra(EXTRA_CHAPTER_ID, -1))
|
||||
openChapter(
|
||||
context,
|
||||
intent.getLongExtra(EXTRA_MANGA_ID, -1),
|
||||
intent.getLongExtra(EXTRA_CHAPTER_ID, -1)
|
||||
)
|
||||
}
|
||||
ACTION_MARK_AS_READ -> {
|
||||
val notificationId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
|
||||
if (notificationId > -1) dismissNotification(
|
||||
context, notificationId, intent.getIntExtra(EXTRA_GROUP_ID, 0)
|
||||
context,
|
||||
notificationId,
|
||||
intent.getIntExtra(EXTRA_GROUP_ID, 0)
|
||||
)
|
||||
val urls = intent.getStringArrayExtra(EXTRA_CHAPTER_URL) ?: return
|
||||
val mangaId = intent.getLongExtra(EXTRA_MANGA_ID, -1)
|
||||
@ -377,8 +389,13 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
clipData = ClipData.newRawUri(null, uri)
|
||||
type = "image/*"
|
||||
}
|
||||
return PendingIntent.getActivity(context, 0, shareIntent, PendingIntent
|
||||
.FLAG_CANCEL_CURRENT)
|
||||
return PendingIntent.getActivity(
|
||||
context,
|
||||
0,
|
||||
shareIntent,
|
||||
PendingIntent
|
||||
.FLAG_CANCEL_CURRENT
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -412,8 +429,13 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
Chapter
|
||||
): PendingIntent {
|
||||
val newIntent = ReaderActivity.newIntent(context, manga, chapter)
|
||||
return PendingIntent.getActivity(context, manga.id.hashCode(), newIntent, PendingIntent
|
||||
.FLAG_UPDATE_CURRENT)
|
||||
return PendingIntent.getActivity(
|
||||
context,
|
||||
manga.id.hashCode(),
|
||||
newIntent,
|
||||
PendingIntent
|
||||
.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -431,7 +453,10 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
.putExtra("notificationId", manga.id.hashCode())
|
||||
.putExtra("groupId", groupId)
|
||||
return PendingIntent.getActivity(
|
||||
context, manga.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT
|
||||
context,
|
||||
manga.id.hashCode(),
|
||||
newIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
}
|
||||
|
||||
@ -462,7 +487,10 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
Intent(context, MainActivity::class.java).setAction(MainActivity.SHORTCUT_EXTENSIONS)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
return PendingIntent.getActivity(
|
||||
context, 0, newIntent, PendingIntent.FLAG_UPDATE_CURRENT
|
||||
context,
|
||||
0,
|
||||
newIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -61,37 +61,44 @@ object Notifications {
|
||||
fun createChannels(context: Context) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
|
||||
|
||||
val channels = listOf(NotificationChannel(
|
||||
val channels = listOf(
|
||||
NotificationChannel(
|
||||
CHANNEL_COMMON,
|
||||
context.getString(R.string.common),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
), NotificationChannel(
|
||||
),
|
||||
NotificationChannel(
|
||||
CHANNEL_LIBRARY,
|
||||
context.getString(R.string.updating_library),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
).apply {
|
||||
setShowBadge(false)
|
||||
}, NotificationChannel(
|
||||
},
|
||||
NotificationChannel(
|
||||
CHANNEL_DOWNLOADER,
|
||||
context.getString(R.string.downloads),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
).apply {
|
||||
setShowBadge(false)
|
||||
}, NotificationChannel(
|
||||
},
|
||||
NotificationChannel(
|
||||
CHANNEL_UPDATES_TO_EXTS,
|
||||
context.getString(R.string.extension_updates),
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
), NotificationChannel(
|
||||
),
|
||||
NotificationChannel(
|
||||
CHANNEL_NEW_CHAPTERS,
|
||||
context.getString(R.string.new_chapters),
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
), NotificationChannel(
|
||||
),
|
||||
NotificationChannel(
|
||||
CHANNEL_BACKUP_RESTORE,
|
||||
context.getString(R.string.restoring_backup),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
).apply {
|
||||
setShowBadge(false)
|
||||
})
|
||||
}
|
||||
)
|
||||
context.notificationManager.createNotificationChannels(channels)
|
||||
}
|
||||
}
|
||||
|
@ -43,12 +43,20 @@ class PreferencesHelper(val context: Context) {
|
||||
private val flowPrefs = FlowSharedPreferences(prefs)
|
||||
|
||||
private val defaultDownloadsDir = Uri.fromFile(
|
||||
File(Environment.getExternalStorageDirectory().absolutePath + File.separator +
|
||||
context.getString(R.string.app_name), "downloads"))
|
||||
File(
|
||||
Environment.getExternalStorageDirectory().absolutePath + File.separator +
|
||||
context.getString(R.string.app_name),
|
||||
"downloads"
|
||||
)
|
||||
)
|
||||
|
||||
private val defaultBackupDir = Uri.fromFile(
|
||||
File(Environment.getExternalStorageDirectory().absolutePath + File.separator +
|
||||
context.getString(R.string.app_name), "backup"))
|
||||
File(
|
||||
Environment.getExternalStorageDirectory().absolutePath + File.separator +
|
||||
context.getString(R.string.app_name),
|
||||
"backup"
|
||||
)
|
||||
)
|
||||
|
||||
fun getInt(key: String, default: Int?) = rxPrefs.getInteger(key, default)
|
||||
fun getStringPref(key: String, default: String?) = rxPrefs.getString(key, default)
|
||||
|
@ -237,7 +237,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
.appendQueryParameter("response_type", "token")
|
||||
.build()!!
|
||||
|
||||
fun addToLibraryQuery() = """
|
||||
fun addToLibraryQuery() =
|
||||
"""
|
||||
|mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) {
|
||||
|SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status) {
|
||||
| id
|
||||
@ -246,7 +247,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
|}
|
||||
|""".trimMargin()
|
||||
|
||||
fun deleteFromLibraryQuery() = """
|
||||
fun deleteFromLibraryQuery() =
|
||||
"""
|
||||
|mutation DeleteManga(${'$'}listId: Int) {
|
||||
|DeleteMediaListEntry (id: ${'$'}listId) {
|
||||
|deleted
|
||||
@ -254,7 +256,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
|}
|
||||
|}""".trimMargin()
|
||||
|
||||
fun updateInLibraryQuery() = """
|
||||
fun updateInLibraryQuery() =
|
||||
"""
|
||||
|mutation UpdateManga(${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}score: Int) {
|
||||
|SaveMediaListEntry (id: ${'$'}listId, progress: ${'$'}progress, status: ${'$'}status, scoreRaw: ${'$'}score) {
|
||||
|id
|
||||
@ -264,7 +267,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
|}
|
||||
|""".trimMargin()
|
||||
|
||||
fun searchQuery() = """
|
||||
fun searchQuery() =
|
||||
"""
|
||||
|query Search(${'$'}query: String) {
|
||||
|Page (perPage: 50) {
|
||||
|media(search: ${'$'}query, type: MANGA, format_not_in: [NOVEL]) {
|
||||
@ -289,7 +293,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
|}
|
||||
|""".trimMargin()
|
||||
|
||||
fun findLibraryMangaQuery() = """
|
||||
fun findLibraryMangaQuery() =
|
||||
"""
|
||||
|query (${'$'}id: Int!, ${'$'}manga_id: Int!) {
|
||||
|Page {
|
||||
|mediaList(userId: ${'$'}id, type: MANGA, mediaId: ${'$'}manga_id) {
|
||||
@ -320,7 +325,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
|}
|
||||
|""".trimMargin()
|
||||
|
||||
fun currentUserQuery() = """
|
||||
fun currentUserQuery() =
|
||||
"""
|
||||
|query User {
|
||||
|Viewer {
|
||||
|id
|
||||
|
@ -37,8 +37,10 @@ class BangumiInterceptor(val bangumi: Bangumi, val gson: Gson) : Interceptor {
|
||||
|
||||
val authRequest = if (originalRequest.method == "GET") originalRequest.newBuilder()
|
||||
.header("User-Agent", "Tachiyomi")
|
||||
.url(originalRequest.url.newBuilder()
|
||||
.addQueryParameter("access_token", currAuth.access_token).build())
|
||||
.url(
|
||||
originalRequest.url.newBuilder()
|
||||
.addQueryParameter("access_token", currAuth.access_token).build()
|
||||
)
|
||||
.build() else originalRequest.newBuilder()
|
||||
.post(addTocken(currAuth.access_token, originalRequest.body as FormBody))
|
||||
.header("User-Agent", "Tachiyomi")
|
||||
@ -54,7 +56,8 @@ class BangumiInterceptor(val bangumi: Bangumi, val gson: Gson) : Interceptor {
|
||||
System.currentTimeMillis() / 1000,
|
||||
oauth.expires_in,
|
||||
oauth.refresh_token,
|
||||
this.oauth?.user_id)
|
||||
this.oauth?.user_id
|
||||
)
|
||||
|
||||
bangumi.saveToken(oauth)
|
||||
}
|
||||
|
@ -44,7 +44,10 @@ class UpdaterJob(private val context: Context, workerParams: WorkerParameters) :
|
||||
android.R.drawable.stat_sys_download_done,
|
||||
context.getString(R.string.download),
|
||||
PendingIntent.getService(
|
||||
context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
|
||||
context,
|
||||
0,
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -66,8 +69,11 @@ class UpdaterJob(private val context: Context, workerParams: WorkerParameters) :
|
||||
.build()
|
||||
|
||||
val request = PeriodicWorkRequestBuilder<UpdaterJob>(
|
||||
1, TimeUnit.DAYS,
|
||||
1, TimeUnit.HOURS)
|
||||
1,
|
||||
TimeUnit.DAYS,
|
||||
1,
|
||||
TimeUnit.HOURS
|
||||
)
|
||||
.addTag(TAG)
|
||||
.setConstraints(constraints)
|
||||
.build()
|
||||
|
@ -75,13 +75,17 @@ internal class UpdaterNotifier(private val context: Context) {
|
||||
setProgress(0, 0, false)
|
||||
// Install action
|
||||
setContentIntent(NotificationHandler.installApkPendingActivity(context, uri))
|
||||
addAction(R.drawable.ic_system_update_24dp,
|
||||
addAction(
|
||||
R.drawable.ic_system_update_24dp,
|
||||
context.getString(R.string.install),
|
||||
NotificationHandler.installApkPendingActivity(context, uri))
|
||||
NotificationHandler.installApkPendingActivity(context, uri)
|
||||
)
|
||||
// Cancel action
|
||||
addAction(R.drawable.ic_close_24dp,
|
||||
addAction(
|
||||
R.drawable.ic_close_24dp,
|
||||
context.getString(R.string.cancel),
|
||||
NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER))
|
||||
NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER)
|
||||
)
|
||||
}
|
||||
notification.show()
|
||||
}
|
||||
@ -99,13 +103,17 @@ internal class UpdaterNotifier(private val context: Context) {
|
||||
setProgress(0, 0, false)
|
||||
color = ContextCompat.getColor(context, R.color.colorAccent)
|
||||
// Retry action
|
||||
addAction(R.drawable.ic_refresh_24dp,
|
||||
addAction(
|
||||
R.drawable.ic_refresh_24dp,
|
||||
context.getString(R.string.retry),
|
||||
UpdaterService.downloadApkPendingService(context, url))
|
||||
UpdaterService.downloadApkPendingService(context, url)
|
||||
)
|
||||
// Cancel action
|
||||
addAction(R.drawable.ic_close_24dp,
|
||||
addAction(
|
||||
R.drawable.ic_close_24dp,
|
||||
context.getString(R.string.cancel),
|
||||
NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER))
|
||||
NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER)
|
||||
)
|
||||
}
|
||||
notification.show(Notifications.ID_UPDATER)
|
||||
}
|
||||
|
@ -43,7 +43,8 @@ class UpdaterService : Service() {
|
||||
startForeground(Notifications.ID_UPDATER, notifier.onDownloadStarted(getString(R.string.app_name)).build())
|
||||
|
||||
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
|
||||
PowerManager.PARTIAL_WAKE_LOCK, "${javaClass.name}:WakeLock"
|
||||
PowerManager.PARTIAL_WAKE_LOCK,
|
||||
"${javaClass.name}:WakeLock"
|
||||
)
|
||||
wakeLock.acquire()
|
||||
}
|
||||
|
@ -80,8 +80,7 @@ class ExtensionManager(
|
||||
context.packageManager.getApplicationIcon(pkgName)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
else null
|
||||
} else null
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,12 +45,15 @@ class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParam
|
||||
val preferences: PreferencesHelper by injectLazy()
|
||||
preferences.extensionUpdatesCount().set(names.size)
|
||||
NotificationManagerCompat.from(context).apply {
|
||||
notify(Notifications.ID_UPDATES_TO_EXTS,
|
||||
notify(
|
||||
Notifications.ID_UPDATES_TO_EXTS,
|
||||
context.notification(Notifications.CHANNEL_UPDATES_TO_EXTS) {
|
||||
setContentTitle(
|
||||
context.resources.getQuantityString(
|
||||
R.plurals.extension_updates_available, names
|
||||
.size, names.size
|
||||
R.plurals.extension_updates_available,
|
||||
names
|
||||
.size,
|
||||
names.size
|
||||
)
|
||||
)
|
||||
val extNames = names.joinToString(", ")
|
||||
@ -64,7 +67,8 @@ class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParam
|
||||
)
|
||||
)
|
||||
setAutoCancel(true)
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,8 +84,11 @@ class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParam
|
||||
.build()
|
||||
|
||||
val request = PeriodicWorkRequestBuilder<ExtensionUpdateJob>(
|
||||
12, TimeUnit.HOURS,
|
||||
1, TimeUnit.HOURS)
|
||||
12,
|
||||
TimeUnit.HOURS,
|
||||
1,
|
||||
TimeUnit.HOURS
|
||||
)
|
||||
.addTag(TAG)
|
||||
.setConstraints(constraints)
|
||||
.build()
|
||||
|
@ -103,8 +103,10 @@ internal object ExtensionLoader {
|
||||
// Validate lib version
|
||||
val majorLibVersion = versionName.substringBefore('.').toInt()
|
||||
if (majorLibVersion < LIB_VERSION_MIN || majorLibVersion > LIB_VERSION_MAX) {
|
||||
val exception = Exception("Lib version is $majorLibVersion, while only versions " +
|
||||
"$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed")
|
||||
val exception = Exception(
|
||||
"Lib version is $majorLibVersion, while only versions " +
|
||||
"$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed"
|
||||
)
|
||||
Timber.w(exception)
|
||||
return LoadResult.Error(exception)
|
||||
}
|
||||
|
@ -58,7 +58,8 @@ fun Call.asObservable(): Observable<Response> {
|
||||
// Based on https://github.com/gildor/kotlin-coroutines-okhttp
|
||||
suspend fun Call.await(): Response {
|
||||
return suspendCancellableCoroutine { continuation ->
|
||||
enqueue(object : Callback {
|
||||
enqueue(
|
||||
object : Callback {
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
continuation.resume(response)
|
||||
}
|
||||
@ -68,7 +69,8 @@ suspend fun Call.await(): Response {
|
||||
if (continuation.isCancelled) return
|
||||
continuation.resumeWithException(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
continuation.invokeOnCancellation {
|
||||
try {
|
||||
|
@ -241,10 +241,12 @@ class LocalSource(private val context: Context) : CatalogueSource {
|
||||
date_upload = chapterFile.lastModified()
|
||||
ChapterRecognition.parseChapterNumber(this, manga)
|
||||
}
|
||||
}.sortedWith(Comparator { c1, c2 ->
|
||||
}.sortedWith(
|
||||
Comparator { c1, c2 ->
|
||||
val c = c2.chapter_number.compareTo(c1.chapter_number)
|
||||
if (c == 0) c2.name.compareToCaseInsensitiveNaturalOrder(c1.name) else c
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
return Observable.just(chapters)
|
||||
}
|
||||
@ -289,18 +291,22 @@ class LocalSource(private val context: Context) : CatalogueSource {
|
||||
return when (format) {
|
||||
is Format.Directory -> {
|
||||
val entry = format.file.listFiles()
|
||||
?.sortedWith(Comparator<File> { f1, f2 ->
|
||||
?.sortedWith(
|
||||
Comparator<File> { f1, f2 ->
|
||||
f1.name.compareToCaseInsensitiveNaturalOrder(f2.name)
|
||||
})
|
||||
}
|
||||
)
|
||||
?.find { !it.isDirectory && ImageUtil.isImage(it.name) { FileInputStream(it) } }
|
||||
|
||||
entry?.let { updateCover(context, manga, it.inputStream()) }
|
||||
}
|
||||
is Format.Zip -> {
|
||||
ZipFile(format.file).use { zip ->
|
||||
val entry = zip.entries().toList().sortedWith(Comparator<ZipEntry> { f1, f2 ->
|
||||
val entry = zip.entries().toList().sortedWith(
|
||||
Comparator<ZipEntry> { f1, f2 ->
|
||||
f1.name.compareToCaseInsensitiveNaturalOrder(f2.name)
|
||||
}).find {
|
||||
}
|
||||
).find {
|
||||
!it.isDirectory && ImageUtil.isImage(it.name) {
|
||||
zip.getInputStream(it)
|
||||
}
|
||||
@ -311,9 +317,11 @@ class LocalSource(private val context: Context) : CatalogueSource {
|
||||
}
|
||||
is Format.Rar -> {
|
||||
Archive(format.file).use { archive ->
|
||||
val entry = archive.fileHeaders.sortedWith(Comparator<FileHeader> { f1, f2 ->
|
||||
val entry = archive.fileHeaders.sortedWith(
|
||||
Comparator<FileHeader> { f1, f2 ->
|
||||
f1.fileNameString.compareToCaseInsensitiveNaturalOrder(f2.fileNameString)
|
||||
}).find {
|
||||
}
|
||||
).find {
|
||||
!it.isDirectory && ImageUtil.isImage(it.fileNameString) {
|
||||
archive.getInputStream(it)
|
||||
}
|
||||
|
@ -21,13 +21,24 @@ open class SourceManager(private val context: Context) {
|
||||
|
||||
private val delegatedSources = listOf(
|
||||
DelegatedSource(
|
||||
"reader.kireicake.com", 5509224355268673176, KireiCake()
|
||||
), DelegatedSource(
|
||||
"jaiminisbox.com", 9064882169246918586, FoolSlide("jaiminis", "/reader")
|
||||
), DelegatedSource(
|
||||
"mangadex.org", 2499283573021220255, MangaDex()
|
||||
), DelegatedSource(
|
||||
"mangaplus.shueisha.co.jp", 1998944621602463790, MangaPlus()
|
||||
"reader.kireicake.com",
|
||||
5509224355268673176,
|
||||
KireiCake()
|
||||
),
|
||||
DelegatedSource(
|
||||
"jaiminisbox.com",
|
||||
9064882169246918586,
|
||||
FoolSlide("jaiminis", "/reader")
|
||||
),
|
||||
DelegatedSource(
|
||||
"mangadex.org",
|
||||
2499283573021220255,
|
||||
MangaDex()
|
||||
),
|
||||
DelegatedSource(
|
||||
"mangaplus.shueisha.co.jp",
|
||||
1998944621602463790,
|
||||
MangaPlus()
|
||||
)
|
||||
).associateBy { it.sourceId }
|
||||
|
||||
@ -92,8 +103,10 @@ open class SourceManager(private val context: Context) {
|
||||
private fun getSourceNotInstalledException(): Exception {
|
||||
return SourceNotFoundException(
|
||||
context.getString(
|
||||
R.string.source_not_installed_, id.toString()
|
||||
), id
|
||||
R.string.source_not_installed_,
|
||||
id.toString()
|
||||
),
|
||||
id
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,11 @@ DelegatedHttpSource
|
||||
val chapterNumber = uri.pathSegments.getOrNull(4 + offset) ?: return null
|
||||
val subChapterNumber = uri.pathSegments.getOrNull(5 + offset)?.toIntOrNull()?.toString()
|
||||
return "$urlModifier/read/" + listOfNotNull(
|
||||
mangaName, lang, volume, chapterNumber, subChapterNumber
|
||||
mangaName,
|
||||
lang,
|
||||
volume,
|
||||
chapterNumber,
|
||||
subChapterNumber
|
||||
).joinToString("/") + "/"
|
||||
}
|
||||
|
||||
@ -95,8 +99,11 @@ DelegatedHttpSource
|
||||
private fun allowAdult(request: Request) = allowAdult(request.url.toString())
|
||||
|
||||
private fun allowAdult(url: String): Request {
|
||||
return POST(url, body = FormBody.Builder()
|
||||
return POST(
|
||||
url,
|
||||
body = FormBody.Builder()
|
||||
.add("adult", "true")
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -17,9 +17,8 @@ class KireiCake : FoolSlide("kireicake") {
|
||||
this.url = url
|
||||
source = delegate?.id ?: -1
|
||||
title = document.select("$mangaDetailsInfoSelector li:has(b:contains(title))").first()
|
||||
?.ownText()?.substringAfter(":")?.trim() ?: url.split("/").last().replace(
|
||||
"_", " " + ""
|
||||
).capitalizeWords()
|
||||
?.ownText()?.substringAfter(":")?.trim()
|
||||
?: url.split("/").last().replace("_", " " + "").capitalizeWords()
|
||||
description =
|
||||
document.select("$mangaDetailsInfoSelector li:has(b:contains(description))").first()
|
||||
?.ownText()?.substringAfter(":")
|
||||
|
@ -61,9 +61,13 @@ class MangaPlus : DelegatedHttpSource() {
|
||||
context.getString(R.string.chapter_not_found)
|
||||
)
|
||||
if (manga != null) {
|
||||
Triple(trueChapter, manga.apply {
|
||||
Triple(
|
||||
trueChapter,
|
||||
manga.apply {
|
||||
this.title = trimmedTitle
|
||||
}, chapters.orEmpty())
|
||||
},
|
||||
chapters.orEmpty()
|
||||
)
|
||||
} else null
|
||||
}
|
||||
}
|
||||
|
@ -33,12 +33,16 @@ class CenteredToolbar@JvmOverloads constructor(context: Context, attrs: Attribut
|
||||
}
|
||||
|
||||
fun showDropdown(down: Boolean = true) {
|
||||
toolbar_title.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_blank_24dp, 0,
|
||||
toolbar_title.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
R.drawable.ic_blank_24dp,
|
||||
0,
|
||||
if (down) {
|
||||
R.drawable.ic_arrow_drop_down_24dp
|
||||
} else {
|
||||
R.drawable.ic_arrow_drop_up_24dp
|
||||
}, 0)
|
||||
},
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
fun hideDropdown() {
|
||||
|
@ -21,7 +21,9 @@ class MaterialFastScroll @JvmOverloads constructor(context: Context, attrs: Attr
|
||||
var scrollOffset = 0
|
||||
init {
|
||||
setViewsToUse(
|
||||
R.layout.material_fastscroll, R.id.fast_scroller_bubble, R.id.fast_scroller_handle
|
||||
R.layout.material_fastscroll,
|
||||
R.id.fast_scroller_bubble,
|
||||
R.id.fast_scroller_handle
|
||||
)
|
||||
autoHideEnabled = true
|
||||
ignoreTouchesOutsideHandle = false
|
||||
@ -85,7 +87,8 @@ class MaterialFastScroll @JvmOverloads constructor(context: Context, attrs: Attr
|
||||
val targetPos = getTargetPos(y)
|
||||
if (layoutManager is StaggeredGridLayoutManager) {
|
||||
(layoutManager as StaggeredGridLayoutManager).scrollToPositionWithOffset(
|
||||
targetPos, scrollOffset
|
||||
targetPos,
|
||||
scrollOffset
|
||||
)
|
||||
} else {
|
||||
(layoutManager as LinearLayoutManager).scrollToPositionWithOffset(targetPos, scrollOffset)
|
||||
|
@ -119,7 +119,10 @@ class MaterialMenuSheet(
|
||||
isElevated = elevate
|
||||
elevationAnimator?.cancel()
|
||||
elevationAnimator = ObjectAnimator.ofFloat(
|
||||
title_layout, "elevation", title_layout.elevation, if (elevate) 10f else 0f
|
||||
title_layout,
|
||||
"elevation",
|
||||
title_layout.elevation,
|
||||
if (elevate) 10f else 0f
|
||||
)
|
||||
elevationAnimator?.start()
|
||||
}
|
||||
|
@ -14,11 +14,13 @@ import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.*
|
||||
import timber.log.Timber
|
||||
|
||||
abstract class BaseController(bundle: Bundle? = null) : RestoreViewOnCreateController(bundle),
|
||||
abstract class BaseController(bundle: Bundle? = null) :
|
||||
RestoreViewOnCreateController(bundle),
|
||||
LayoutContainer {
|
||||
|
||||
init {
|
||||
addLifecycleListener(object : LifecycleListener() {
|
||||
addLifecycleListener(
|
||||
object : LifecycleListener() {
|
||||
override fun postCreateView(controller: Controller, view: View) {
|
||||
onViewCreated(view)
|
||||
}
|
||||
@ -38,7 +40,8 @@ abstract class BaseController(bundle: Bundle? = null) : RestoreViewOnCreateContr
|
||||
override fun preDestroyView(controller: Controller, view: View) {
|
||||
Timber.d("Destroy view for ${controller.instance()}")
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override val containerView: View?
|
||||
@ -96,7 +99,8 @@ abstract class BaseController(bundle: Bundle? = null) : RestoreViewOnCreateContr
|
||||
*/
|
||||
var expandActionViewFromInteraction = false
|
||||
fun MenuItem.fixExpand(onExpand: ((MenuItem) -> Boolean)? = null, onCollapse: ((MenuItem) -> Boolean)? = null) {
|
||||
setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
|
||||
setOnActionExpandListener(
|
||||
object : MenuItem.OnActionExpandListener {
|
||||
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
||||
return onExpand?.invoke(item) ?: true
|
||||
}
|
||||
@ -106,7 +110,8 @@ abstract class BaseController(bundle: Bundle? = null) : RestoreViewOnCreateContr
|
||||
|
||||
return onCollapse?.invoke(item) ?: true
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
if (expandActionViewFromInteraction) {
|
||||
expandActionViewFromInteraction = false
|
||||
|
@ -87,10 +87,12 @@ abstract class DialogController : RestoreViewOnCreateController {
|
||||
*/
|
||||
fun showDialog(router: Router, tag: String?) {
|
||||
dismissed = false
|
||||
router.pushController(RouterTransaction.with(this)
|
||||
router.pushController(
|
||||
RouterTransaction.with(this)
|
||||
.pushChangeHandler(SimpleSwapChangeHandler(false))
|
||||
.popChangeHandler(SimpleSwapChangeHandler(false))
|
||||
.tag(tag))
|
||||
.tag(tag)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7,7 +7,8 @@ import nucleus.factory.PresenterFactory
|
||||
import nucleus.presenter.Presenter
|
||||
|
||||
@Suppress("LeakingThis")
|
||||
abstract class NucleusController<P : Presenter<*>>(val bundle: Bundle? = null) : RxController(bundle),
|
||||
abstract class NucleusController<P : Presenter<*>>(val bundle: Bundle? = null) :
|
||||
RxController(bundle),
|
||||
PresenterFactory<P> {
|
||||
|
||||
private val delegate = NucleusConductorDelegate(this)
|
||||
|
@ -22,7 +22,8 @@ import kotlinx.android.synthetic.main.categories_controller.*
|
||||
/**
|
||||
* Controller to manage the categories for the users' library.
|
||||
*/
|
||||
class CategoryController(bundle: Bundle? = null) : BaseController(bundle),
|
||||
class CategoryController(bundle: Bundle? = null) :
|
||||
BaseController(bundle),
|
||||
FlexibleAdapter.OnItemClickListener,
|
||||
FlexibleAdapter.OnItemMoveListener,
|
||||
CategoryAdapter.CategoryItemListener {
|
||||
@ -147,12 +148,14 @@ class CategoryController(bundle: Bundle? = null) : BaseController(bundle),
|
||||
adapter?.restoreDeletedItems()
|
||||
undoing = true
|
||||
}
|
||||
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||
addCallback(
|
||||
object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||
super.onDismissed(transientBottomBar, event)
|
||||
if (!undoing) confirmDelete()
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
(activity as? MainActivity)?.setUndoSnackBar(snack)
|
||||
}
|
||||
|
@ -51,16 +51,22 @@ class CategoryHolder(view: View, val adapter: CategoryAdapter) : BaseFlexibleVie
|
||||
createCategory = category.order == CREATE_CATEGORY_ORDER
|
||||
if (createCategory) {
|
||||
title.setTextColor(ContextCompat.getColor(itemView.context, R.color.text_color_hint))
|
||||
regularDrawable = ContextCompat.getDrawable(itemView.context, R.drawable
|
||||
.ic_add_24dp)
|
||||
regularDrawable = ContextCompat.getDrawable(
|
||||
itemView.context,
|
||||
R.drawable
|
||||
.ic_add_24dp
|
||||
)
|
||||
image.gone()
|
||||
edit_button.setImageDrawable(null)
|
||||
edit_text.setText("")
|
||||
edit_text.hint = title.text
|
||||
} else {
|
||||
title.setTextColor(ContextCompat.getColor(itemView.context, R.color.textColorPrimary))
|
||||
regularDrawable = ContextCompat.getDrawable(itemView.context, R.drawable
|
||||
.ic_drag_handle_24dp)
|
||||
regularDrawable = ContextCompat.getDrawable(
|
||||
itemView.context,
|
||||
R.drawable
|
||||
.ic_drag_handle_24dp
|
||||
)
|
||||
image.visible()
|
||||
edit_text.setText(title.text)
|
||||
}
|
||||
@ -80,7 +86,8 @@ class CategoryHolder(view: View, val adapter: CategoryAdapter) : BaseFlexibleVie
|
||||
if (!createCategory) {
|
||||
reorder.setImageDrawable(
|
||||
ContextCompat.getDrawable(
|
||||
itemView.context, R.drawable.ic_delete_24dp
|
||||
itemView.context,
|
||||
R.drawable.ic_delete_24dp
|
||||
)
|
||||
)
|
||||
reorder.setOnClickListener {
|
||||
@ -96,8 +103,13 @@ class CategoryHolder(view: View, val adapter: CategoryAdapter) : BaseFlexibleVie
|
||||
reorder.setOnTouchListener { _, _ -> true }
|
||||
}
|
||||
edit_text.clearFocus()
|
||||
edit_button.drawable?.mutate()?.setTint(ContextCompat.getColor(itemView.context, R
|
||||
.color.gray_button))
|
||||
edit_button.drawable?.mutate()?.setTint(
|
||||
ContextCompat.getColor(
|
||||
itemView.context,
|
||||
R
|
||||
.color.gray_button
|
||||
)
|
||||
)
|
||||
reorder.setImageDrawable(regularDrawable)
|
||||
}
|
||||
}
|
||||
@ -105,7 +117,8 @@ class CategoryHolder(view: View, val adapter: CategoryAdapter) : BaseFlexibleVie
|
||||
private fun submitChanges() {
|
||||
if (edit_text.visibility == View.VISIBLE) {
|
||||
if (adapter.categoryItemListener
|
||||
.onCategoryRename(adapterPosition, edit_text.text.toString())) {
|
||||
.onCategoryRename(adapterPosition, edit_text.text.toString())
|
||||
) {
|
||||
isEditing(false)
|
||||
edit_text.inputType = InputType.TYPE_NULL
|
||||
if (!createCategory)
|
||||
@ -119,8 +132,11 @@ class CategoryHolder(view: View, val adapter: CategoryAdapter) : BaseFlexibleVie
|
||||
private fun showKeyboard() {
|
||||
val inputMethodManager: InputMethodManager =
|
||||
itemView.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.showSoftInput(edit_text, WindowManager.LayoutParams
|
||||
.SOFT_INPUT_ADJUST_PAN)
|
||||
inputMethodManager.showSoftInput(
|
||||
edit_text,
|
||||
WindowManager.LayoutParams
|
||||
.SOFT_INPUT_ADJUST_PAN
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,7 +70,8 @@ class ManageCategoryDialog(bundle: Bundle? = null) :
|
||||
preferences.downloadNew().set(true)
|
||||
}
|
||||
if (preferences.libraryUpdateInterval().getOrDefault() > 0 &&
|
||||
!updatePref(preferences.libraryUpdateCategories(), view.include_global)) {
|
||||
!updatePref(preferences.libraryUpdateCategories(), view.include_global)
|
||||
) {
|
||||
preferences.libraryUpdateInterval().set(0)
|
||||
LibraryUpdateJob.setupTask(0)
|
||||
}
|
||||
@ -99,9 +100,11 @@ class ManageCategoryDialog(bundle: Bundle? = null) :
|
||||
view.title.hint = category.name
|
||||
view.title.append(category.name)
|
||||
val downloadNew = preferences.downloadNew().getOrDefault()
|
||||
setCheckbox(view.download_new,
|
||||
setCheckbox(
|
||||
view.download_new,
|
||||
preferences.downloadNewCategories(),
|
||||
true)
|
||||
true
|
||||
)
|
||||
if (downloadNew && preferences.downloadNewCategories().getOrDefault().isEmpty())
|
||||
view.download_new.gone()
|
||||
else if (!downloadNew)
|
||||
|
@ -8,8 +8,11 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
*
|
||||
* @param context the context of the fragment containing this adapter.
|
||||
*/
|
||||
class DownloadAdapter(controller: DownloadItemListener) : FlexibleAdapter<DownloadItem>(null, controller,
|
||||
true) {
|
||||
class DownloadAdapter(controller: DownloadItemListener) : FlexibleAdapter<DownloadItem>(
|
||||
null,
|
||||
controller,
|
||||
true
|
||||
) {
|
||||
|
||||
/**
|
||||
* Listener called when an item of the list is released.
|
||||
|
@ -94,7 +94,8 @@ class DownloadBottomSheet @JvmOverloads constructor(
|
||||
private fun updateDLTitle() {
|
||||
val extCount = presenter.downloadQueue.firstOrNull()
|
||||
title_text.text = if (extCount != null) resources.getString(
|
||||
R.string.downloading_, extCount.chapter.name
|
||||
R.string.downloading_,
|
||||
extCount.chapter.name
|
||||
)
|
||||
else ""
|
||||
}
|
||||
@ -164,7 +165,8 @@ class DownloadBottomSheet @JvmOverloads constructor(
|
||||
if (presenter.downloadQueue.isEmpty()) {
|
||||
empty_view?.show(
|
||||
R.drawable.ic_download_off_24dp,
|
||||
R.string.nothing_is_downloading)
|
||||
R.string.nothing_is_downloading
|
||||
)
|
||||
} else {
|
||||
empty_view?.hide()
|
||||
}
|
||||
|
@ -17,22 +17,38 @@ class DownloadButton @JvmOverloads constructor(context: Context, attrs: Attribut
|
||||
FrameLayout(context, attrs) {
|
||||
|
||||
private val activeColor = context.getResourceColor(R.attr.colorAccent)
|
||||
private val progressBGColor = ContextCompat.getColor(context,
|
||||
R.color.divider)
|
||||
private val disabledColor = ContextCompat.getColor(context,
|
||||
R.color.material_on_surface_disabled)
|
||||
private val downloadedColor = ContextCompat.getColor(context,
|
||||
R.color.download)
|
||||
private val errorColor = ContextCompat.getColor(context,
|
||||
R.color.material_red_500)
|
||||
private val filledCircle = ContextCompat.getDrawable(context,
|
||||
R.drawable.filled_circle)?.mutate()
|
||||
private val borderCircle = ContextCompat.getDrawable(context,
|
||||
R.drawable.border_circle)?.mutate()
|
||||
private val downloadDrawable = ContextCompat.getDrawable(context,
|
||||
R.drawable.ic_arrow_downward_24dp)?.mutate()
|
||||
private val checkDrawable = ContextCompat.getDrawable(context,
|
||||
R.drawable.ic_check_24dp)?.mutate()
|
||||
private val progressBGColor = ContextCompat.getColor(
|
||||
context,
|
||||
R.color.divider
|
||||
)
|
||||
private val disabledColor = ContextCompat.getColor(
|
||||
context,
|
||||
R.color.material_on_surface_disabled
|
||||
)
|
||||
private val downloadedColor = ContextCompat.getColor(
|
||||
context,
|
||||
R.color.download
|
||||
)
|
||||
private val errorColor = ContextCompat.getColor(
|
||||
context,
|
||||
R.color.material_red_500
|
||||
)
|
||||
private val filledCircle = ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.filled_circle
|
||||
)?.mutate()
|
||||
private val borderCircle = ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.border_circle
|
||||
)?.mutate()
|
||||
private val downloadDrawable = ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.ic_arrow_downward_24dp
|
||||
)?.mutate()
|
||||
private val checkDrawable = ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.ic_check_24dp
|
||||
)?.mutate()
|
||||
private var isAnimating = false
|
||||
private var iconAnimation: ObjectAnimator? = null
|
||||
|
||||
@ -42,8 +58,10 @@ class DownloadButton @JvmOverloads constructor(context: Context, attrs: Attribut
|
||||
download_icon.alpha = 1f
|
||||
isAnimating = false
|
||||
}
|
||||
download_icon.setImageDrawable(if (state == Download.CHECKED)
|
||||
checkDrawable else downloadDrawable)
|
||||
download_icon.setImageDrawable(
|
||||
if (state == Download.CHECKED)
|
||||
checkDrawable else downloadDrawable
|
||||
)
|
||||
when (state) {
|
||||
Download.CHECKED -> {
|
||||
download_progress.gone()
|
||||
|
@ -54,8 +54,10 @@ class DownloadHolder(private val view: View, val adapter: DownloadAdapter) :
|
||||
|
||||
migration_menu.visibleIf(adapterPosition != 0 || adapterPosition != adapter.itemCount - 1)
|
||||
migration_menu.setVectorCompat(
|
||||
R.drawable.ic_more_vert_24dp, view.context
|
||||
.getResourceColor(android.R.attr.textColorPrimary))
|
||||
R.drawable.ic_more_vert_24dp,
|
||||
view.context
|
||||
.getResourceColor(android.R.attr.textColorPrimary)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -83,9 +83,11 @@ class ExtensionBottomPresenter(
|
||||
val untrustedSorted = untrusted.sortedBy { it.pkgName }
|
||||
val availableSorted = available
|
||||
// Filter out already installed extensions and disabled languages
|
||||
.filter { avail -> installed.none { it.pkgName == avail.pkgName } &&
|
||||
.filter { avail ->
|
||||
installed.none { it.pkgName == avail.pkgName } &&
|
||||
untrusted.none { it.pkgName == avail.pkgName } &&
|
||||
(avail.lang in activeLangs || avail.lang == "all") }
|
||||
(avail.lang in activeLangs || avail.lang == "all")
|
||||
}
|
||||
.sortedBy { it.pkgName }
|
||||
|
||||
if (installedSorted.isNotEmpty() || untrustedSorted.isNotEmpty()) {
|
||||
|
@ -88,11 +88,17 @@ ExtensionAdapter.OnButtonClickListener,
|
||||
fun updateExtTitle() {
|
||||
val extCount = presenter.getExtensionUpdateCount()
|
||||
title_text.text = if (extCount == 0) context.getString(R.string.extensions)
|
||||
else resources.getQuantityString(R.plurals.extension_updates_available, extCount,
|
||||
extCount)
|
||||
else resources.getQuantityString(
|
||||
R.plurals.extension_updates_available,
|
||||
extCount,
|
||||
extCount
|
||||
)
|
||||
|
||||
title_text.setTextColor(context.getResourceColor(
|
||||
if (extCount == 0) R.attr.actionBarTintColor else R.attr.colorAccent))
|
||||
title_text.setTextColor(
|
||||
context.getResourceColor(
|
||||
if (extCount == 0) R.attr.actionBarTintColor else R.attr.colorAccent
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onButtonClick(position: Int) {
|
||||
@ -153,7 +159,8 @@ ExtensionAdapter.OnButtonClickListener,
|
||||
adapter?.updateDataSet(
|
||||
extensions.filter {
|
||||
it.extension.name.contains(controller.extQuery, ignoreCase = true)
|
||||
})
|
||||
}
|
||||
)
|
||||
} else {
|
||||
adapter?.updateDataSet(extensions)
|
||||
}
|
||||
|
@ -44,9 +44,11 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
||||
|
||||
private var preferenceScreen: PreferenceScreen? = null
|
||||
|
||||
constructor(pkgName: String) : this(Bundle().apply {
|
||||
constructor(pkgName: String) : this(
|
||||
Bundle().apply {
|
||||
putString(PKGNAME_KEY, pkgName)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
val themedInflater = inflater.cloneInContext(getPreferenceThemeContext())
|
||||
@ -107,8 +109,10 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
||||
extension_prefs_recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
|
||||
|
||||
if (screen.preferenceCount == 0) {
|
||||
extension_prefs_empty_view.show(R.drawable.ic_no_settings_24dp,
|
||||
R.string.empty_preferences_for_extension)
|
||||
extension_prefs_empty_view.show(
|
||||
R.drawable.ic_no_settings_24dp,
|
||||
R.string.empty_preferences_for_extension
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,7 +143,8 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
||||
source.preferences
|
||||
} else {*/
|
||||
context.getSharedPreferences("source_${source.id}", Context.MODE_PRIVATE)
|
||||
/*}*/)
|
||||
/*}*/
|
||||
)
|
||||
|
||||
if (source is ConfigurableSource) {
|
||||
if (multiSource) {
|
||||
@ -193,14 +198,19 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
||||
}
|
||||
|
||||
val f = when (preference) {
|
||||
is EditTextPreference -> EditTextPreferenceDialogController
|
||||
is EditTextPreference ->
|
||||
EditTextPreferenceDialogController
|
||||
.newInstance(preference.getKey())
|
||||
is ListPreference -> ListPreferenceDialogController
|
||||
is ListPreference ->
|
||||
ListPreferenceDialogController
|
||||
.newInstance(preference.getKey())
|
||||
is MultiSelectListPreference -> MultiSelectListPreferenceDialogController
|
||||
is MultiSelectListPreference ->
|
||||
MultiSelectListPreferenceDialogController
|
||||
.newInstance(preference.getKey())
|
||||
else -> throw IllegalArgumentException("Tried to display dialog for unknown " +
|
||||
"preference type. Did you forget to override onDisplayPreferenceDialog()?")
|
||||
else -> throw IllegalArgumentException(
|
||||
"Tried to display dialog for unknown " +
|
||||
"preference type. Did you forget to override onDisplayPreferenceDialog()?"
|
||||
)
|
||||
}
|
||||
f.targetController = this
|
||||
f.showDialog(router)
|
||||
|
@ -24,7 +24,8 @@ class ExtensionDividerItemDecoration(context: Context) : androidx.recyclerview.w
|
||||
val child = parent.getChildAt(i)
|
||||
val holder = parent.getChildViewHolder(child)
|
||||
if (holder is ExtensionHolder &&
|
||||
parent.getChildViewHolder(parent.getChildAt(i + 1)) is ExtensionHolder) {
|
||||
parent.getChildViewHolder(parent.getChildAt(i + 1)) is ExtensionHolder
|
||||
) {
|
||||
val params = child.layoutParams as androidx.recyclerview.widget.RecyclerView.LayoutParams
|
||||
val top = child.bottom + params.bottomMargin
|
||||
val bottom = top + divider.intrinsicHeight
|
||||
|
@ -63,13 +63,15 @@ class ExtensionHolder(view: View, val adapter: ExtensionAdapter) :
|
||||
val extension = item.extension
|
||||
val installStep = item.installStep
|
||||
if (installStep != null) {
|
||||
setText(when (installStep) {
|
||||
setText(
|
||||
when (installStep) {
|
||||
InstallStep.Pending -> R.string.pending
|
||||
InstallStep.Downloading -> R.string.downloading
|
||||
InstallStep.Installing -> R.string.installing
|
||||
InstallStep.Installed -> R.string.installed
|
||||
InstallStep.Error -> R.string.retry
|
||||
})
|
||||
}
|
||||
)
|
||||
if (installStep != InstallStep.Error) {
|
||||
isEnabled = false
|
||||
isClickable = false
|
||||
@ -79,7 +81,8 @@ class ExtensionHolder(view: View, val adapter: ExtensionAdapter) :
|
||||
extension.hasUpdate -> {
|
||||
isActivated = true
|
||||
backgroundTintList = ColorStateList.valueOf(
|
||||
context.getResourceColor(R.attr.colorAccent))
|
||||
context.getResourceColor(R.attr.colorAccent)
|
||||
)
|
||||
strokeColor = ColorStateList.valueOf(Color.TRANSPARENT)
|
||||
setText(R.string.update)
|
||||
}
|
||||
|
@ -10,10 +10,12 @@ class ExtensionTrustDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
|
||||
where T : ExtensionTrustDialog.Listener {
|
||||
|
||||
lateinit var listener: 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(PKGNAME_KEY, pkgName)
|
||||
}) {
|
||||
}
|
||||
) {
|
||||
listener = target
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,8 @@ class DisplayBottomSheet(private val controller: LibraryController) : BottomShee
|
||||
val height = activity.window.decorView.rootWindowInsets.systemWindowInsetBottom
|
||||
sheetBehavior.peekHeight = 220.dpToPx + height
|
||||
|
||||
sheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
|
||||
sheetBehavior.addBottomSheetCallback(
|
||||
object : BottomSheetBehavior.BottomSheetCallback() {
|
||||
override fun onSlide(bottomSheet: View, progress: Float) { }
|
||||
|
||||
override fun onStateChanged(p0: View, state: Int) {
|
||||
@ -53,7 +54,8 @@ class DisplayBottomSheet(private val controller: LibraryController) : BottomShee
|
||||
sheetBehavior.skipCollapsed = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
|
@ -59,7 +59,8 @@ class LibraryCategoryAdapter(val controller: LibraryController) :
|
||||
fun indexOf(categoryOrder: Int): Int {
|
||||
return currentItems.indexOfFirst {
|
||||
if (it is LibraryHeaderItem) it.category.order == categoryOrder
|
||||
else false }
|
||||
else false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,13 +71,15 @@ class LibraryCategoryAdapter(val controller: LibraryController) :
|
||||
fun indexOf(manga: Manga): Int {
|
||||
return currentItems.indexOfFirst {
|
||||
if (it is LibraryItem) it.manga.id == manga.id
|
||||
else false }
|
||||
else false
|
||||
}
|
||||
}
|
||||
|
||||
fun getHeaderPositions(): List<Int> {
|
||||
return currentItems.mapIndexedNotNull { index, it ->
|
||||
if (it is LibraryHeaderItem) index
|
||||
else null }
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -87,7 +90,8 @@ class LibraryCategoryAdapter(val controller: LibraryController) :
|
||||
fun allIndexOf(manga: Manga): List<Int> {
|
||||
return currentItems.mapIndexedNotNull { index, it ->
|
||||
if (it is LibraryItem && it.manga.id == manga.id) index
|
||||
else null }
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
fun performFilter() {
|
||||
@ -140,7 +144,8 @@ class LibraryCategoryAdapter(val controller: LibraryController) :
|
||||
val last = history.maxBy { it.last_read }
|
||||
if (last != null && last.last_read > 100) {
|
||||
recyclerView.context.getString(
|
||||
R.string.read_, last.last_read.timeSpanFromNow
|
||||
R.string.read_,
|
||||
last.last_read.timeSpanFromNow
|
||||
)
|
||||
} else {
|
||||
"N/A"
|
||||
@ -154,7 +159,9 @@ class LibraryCategoryAdapter(val controller: LibraryController) :
|
||||
LibrarySort.TOTAL -> {
|
||||
val total = item.manga.totalChapters
|
||||
if (total > 0) recyclerView.resources.getQuantityString(
|
||||
R.plurals.chapters, total, total
|
||||
R.plurals.chapters,
|
||||
total,
|
||||
total
|
||||
)
|
||||
else {
|
||||
"N/A"
|
||||
@ -164,7 +171,8 @@ class LibraryCategoryAdapter(val controller: LibraryController) :
|
||||
val lastUpdate = item.manga.last_update
|
||||
if (lastUpdate > 0) {
|
||||
recyclerView.context.getString(
|
||||
R.string.updated_, lastUpdate.timeSpanFromNow
|
||||
R.string.updated_,
|
||||
lastUpdate.timeSpanFromNow
|
||||
)
|
||||
} else {
|
||||
"N/A"
|
||||
|
@ -108,10 +108,13 @@ class LibraryController(
|
||||
) : BaseController(bundle),
|
||||
ActionMode.Callback,
|
||||
ChangeMangaCategoriesDialog.Listener,
|
||||
FlexibleAdapter.OnItemClickListener, FlexibleAdapter.OnItemLongClickListener,
|
||||
FlexibleAdapter.OnItemMoveListener, LibraryCategoryAdapter.LibraryListener,
|
||||
FlexibleAdapter.OnItemClickListener,
|
||||
FlexibleAdapter.OnItemLongClickListener,
|
||||
FlexibleAdapter.OnItemMoveListener,
|
||||
LibraryCategoryAdapter.LibraryListener,
|
||||
BottomSheetController,
|
||||
RootSearchInterface, LibraryServiceListener {
|
||||
RootSearchInterface,
|
||||
LibraryServiceListener {
|
||||
|
||||
init {
|
||||
setHasOptionsMenu(true)
|
||||
@ -325,7 +328,8 @@ class LibraryController(
|
||||
adapter = LibraryCategoryAdapter(this)
|
||||
setRecyclerLayout()
|
||||
|
||||
recycler.manager.spanSizeLookup = (object : GridLayoutManager.SpanSizeLookup() {
|
||||
recycler.manager.spanSizeLookup = (
|
||||
object : GridLayoutManager.SpanSizeLookup() {
|
||||
override fun getSpanSize(position: Int): Int {
|
||||
if (libraryLayout == 0) return 1
|
||||
val item = this@LibraryController.adapter.getItem(position)
|
||||
@ -335,7 +339,8 @@ class LibraryController(
|
||||
1
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
recycler.setHasFixedSize(true)
|
||||
recycler.adapter = adapter
|
||||
|
||||
@ -360,7 +365,10 @@ class LibraryController(
|
||||
setUpHopper()
|
||||
|
||||
elevateAppBar =
|
||||
scrollViewWith(recycler, swipeRefreshLayout = swipe_refresh, afterInsets = { insets ->
|
||||
scrollViewWith(
|
||||
recycler,
|
||||
swipeRefreshLayout = swipe_refresh,
|
||||
afterInsets = { insets ->
|
||||
category_recycler?.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
topMargin = recycler?.paddingTop ?: 0
|
||||
}
|
||||
@ -368,9 +376,11 @@ class LibraryController(
|
||||
topMargin = recycler?.paddingTop ?: 0
|
||||
}
|
||||
header_title?.updatePaddingRelative(top = insets.systemWindowInsetTop + 2.dpToPx)
|
||||
}, onLeavingController = {
|
||||
},
|
||||
onLeavingController = {
|
||||
header_title?.gone()
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
swipe_refresh.setOnRefreshListener {
|
||||
swipe_refresh.isRefreshing = false
|
||||
@ -387,19 +397,24 @@ class LibraryController(
|
||||
preferences.updateOnRefresh().getOrDefault() == -1 -> {
|
||||
MaterialDialog(activity!!).title(R.string.what_should_update)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.listItemsSingleChoice(items = listOf(
|
||||
.listItemsSingleChoice(
|
||||
items = listOf(
|
||||
view.context.getString(
|
||||
R.string.top_category,
|
||||
presenter.allCategories.first().name
|
||||
),
|
||||
view.context.getString(
|
||||
R.string.top_category, presenter.allCategories.first().name
|
||||
), view.context.getString(
|
||||
R.string.categories_in_global_update
|
||||
)
|
||||
), selection = { _, index, _ ->
|
||||
),
|
||||
selection = { _, index, _ ->
|
||||
preferences.updateOnRefresh().set(index)
|
||||
when (index) {
|
||||
0 -> updateLibrary(presenter.allCategories.first())
|
||||
else -> updateLibrary()
|
||||
}
|
||||
}).positiveButton(R.string.update).show()
|
||||
}
|
||||
).positiveButton(R.string.update).show()
|
||||
}
|
||||
else -> {
|
||||
when (preferences.updateOnRefresh().getOrDefault()) {
|
||||
@ -632,7 +647,8 @@ class LibraryController(
|
||||
if (libraryLayout == 0) {
|
||||
recycler.spanCount = 1
|
||||
recycler.updatePaddingRelative(
|
||||
start = 0, end = 0
|
||||
start = 0,
|
||||
end = 0
|
||||
)
|
||||
} else {
|
||||
recycler.columnWidth = when (preferences.gridSize().getOrDefault()) {
|
||||
@ -733,7 +749,8 @@ class LibraryController(
|
||||
|
||||
category_hopper_frame.visibleIf(!singleCategory && !preferences.hideHopper().get())
|
||||
filter_bottom_sheet.updateButtons(
|
||||
showExpand = !singleCategory && presenter.showAllCategories, groupType = presenter.groupType
|
||||
showExpand = !singleCategory && presenter.showAllCategories,
|
||||
groupType = presenter.groupType
|
||||
)
|
||||
adapter.isLongPressDragEnabled = canDrag()
|
||||
category_recycler.setCategories(presenter.categories)
|
||||
@ -783,9 +800,11 @@ class LibraryController(
|
||||
)
|
||||
animatorSet.playSequentially(animations)
|
||||
animatorSet.startDelay = 1250
|
||||
animatorSet.addListener(EndAnimatorListener {
|
||||
animatorSet.addListener(
|
||||
EndAnimatorListener {
|
||||
isAnimatingHopper = false
|
||||
})
|
||||
}
|
||||
)
|
||||
animatorSet.start()
|
||||
}
|
||||
|
||||
@ -836,16 +855,21 @@ class LibraryController(
|
||||
if (headerPosition > -1) {
|
||||
val appbar = activity?.appbar
|
||||
recycler.suppressLayout(true)
|
||||
val appbarOffset = if (appbar?.y ?: 0f > -20) 0 else (appbar?.y?.plus(
|
||||
val appbarOffset = if (appbar?.y ?: 0f > -20) 0 else (
|
||||
appbar?.y?.plus(
|
||||
view?.rootWindowInsets?.systemWindowInsetTop ?: 0
|
||||
) ?: 0f).roundToInt() + 30.dpToPx
|
||||
) ?: 0f
|
||||
).roundToInt() + 30.dpToPx
|
||||
val previousHeader = adapter.getItem(adapter.indexOf(pos - 1)) as? LibraryHeaderItem
|
||||
(recycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
|
||||
headerPosition, (when {
|
||||
headerPosition,
|
||||
(
|
||||
when {
|
||||
headerPosition == 0 -> 0
|
||||
previousHeader?.category?.isHidden == true -> (-3).dpToPx
|
||||
else -> (-30).dpToPx
|
||||
}) + appbarOffset
|
||||
}
|
||||
) + appbarOffset
|
||||
)
|
||||
(adapter.getItem(headerPosition) as? LibraryHeaderItem)?.category?.let {
|
||||
saveActiveCategory(it)
|
||||
@ -1033,9 +1057,9 @@ class LibraryController(
|
||||
val position = viewHolder?.adapterPosition ?: return
|
||||
swipe_refresh.isEnabled = actionState != ItemTouchHelper.ACTION_STATE_DRAG
|
||||
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
|
||||
if (lastItemPosition != null && position != lastItemPosition && lastItem == adapter.getItem(
|
||||
position
|
||||
)
|
||||
if (lastItemPosition != null &&
|
||||
position != lastItemPosition &&
|
||||
lastItem == adapter.getItem(position)
|
||||
) {
|
||||
// because for whatever reason you can repeatedly tap on a currently dragging manga
|
||||
adapter.removeSelection(position)
|
||||
@ -1063,10 +1087,11 @@ class LibraryController(
|
||||
|
||||
override fun onItemMove(fromPosition: Int, toPosition: Int) {
|
||||
// Because padding a recycler causes it to scroll up we have to scroll it back down... wild
|
||||
if ((adapter.getItem(fromPosition) is LibraryItem && adapter.getItem(fromPosition) is
|
||||
LibraryItem) || adapter.getItem(
|
||||
fromPosition
|
||||
) == null
|
||||
if ((
|
||||
adapter.getItem(fromPosition) is LibraryItem &&
|
||||
adapter.getItem(fromPosition) is LibraryItem
|
||||
) ||
|
||||
adapter.getItem(fromPosition) == null
|
||||
) {
|
||||
recycler.scrollBy(0, recycler.paddingTop)
|
||||
}
|
||||
@ -1079,9 +1104,12 @@ class LibraryController(
|
||||
val item = adapter.getItem(fromPosition) as? LibraryItem ?: return false
|
||||
val newHeader = adapter.getSectionHeader(toPosition) as? LibraryHeaderItem
|
||||
if (toPosition < 1) return false
|
||||
return (adapter.getItem(toPosition) !is LibraryHeaderItem) && (newHeader?.category?.id == item.manga.category || !presenter.mangaIsInCategory(
|
||||
item.manga, newHeader?.category?.id
|
||||
))
|
||||
return (adapter.getItem(toPosition) !is LibraryHeaderItem) && (
|
||||
newHeader?.category?.id == item.manga.category || !presenter.mangaIsInCategory(
|
||||
item.manga,
|
||||
newHeader?.category?.id
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onItemReleased(position: Int) {
|
||||
@ -1110,7 +1138,9 @@ class LibraryController(
|
||||
return
|
||||
}
|
||||
if (newHeader?.category != null) moveMangaToCategory(
|
||||
item.manga, newHeader.category, mangaIds
|
||||
item.manga,
|
||||
newHeader.category,
|
||||
mangaIds
|
||||
)
|
||||
}
|
||||
lastItemPosition = null
|
||||
@ -1147,8 +1177,10 @@ class LibraryController(
|
||||
inQueue -> R.string._already_in_queue
|
||||
LibraryUpdateService.isRunning() -> R.string.adding_category_to_queue
|
||||
else -> R.string.updating_
|
||||
}, category.name
|
||||
), Snackbar.LENGTH_LONG
|
||||
},
|
||||
category.name
|
||||
),
|
||||
Snackbar.LENGTH_LONG
|
||||
) {
|
||||
anchorView = anchorView()
|
||||
view.elevation = 15f.dpToPx
|
||||
@ -1163,7 +1195,9 @@ class LibraryController(
|
||||
}
|
||||
}
|
||||
if (!inQueue) LibraryUpdateService.start(
|
||||
view!!.context, category, mangaToUse = if (category.isDynamic) {
|
||||
view!!.context,
|
||||
category,
|
||||
mangaToUse = if (category.isDynamic) {
|
||||
presenter.getMangaInCategories(category.id)
|
||||
} else null
|
||||
)
|
||||
@ -1327,9 +1361,11 @@ class LibraryController(
|
||||
}
|
||||
R.id.action_migrate -> {
|
||||
val skipPre = preferences.skipPreMigration().getOrDefault()
|
||||
PreMigrationController.navigateToMigration(skipPre,
|
||||
PreMigrationController.navigateToMigration(
|
||||
skipPre,
|
||||
router,
|
||||
selectedMangas.filter { it.id != LocalSource.ID }.mapNotNull { it.id })
|
||||
selectedMangas.filter { it.id != LocalSource.ID }.mapNotNull { it.id }
|
||||
)
|
||||
destroyActionModeIfNeeded()
|
||||
}
|
||||
else -> return false
|
||||
@ -1356,7 +1392,8 @@ class LibraryController(
|
||||
destroyActionModeIfNeeded()
|
||||
snack?.dismiss()
|
||||
snack = view?.snack(
|
||||
activity?.getString(R.string.removed_from_library) ?: "", Snackbar.LENGTH_INDEFINITE
|
||||
activity?.getString(R.string.removed_from_library) ?: "",
|
||||
Snackbar.LENGTH_INDEFINITE
|
||||
) {
|
||||
anchorView = anchorView()
|
||||
view.elevation = 15f.dpToPx
|
||||
@ -1365,12 +1402,14 @@ class LibraryController(
|
||||
presenter.reAddMangas(mangas)
|
||||
undoing = true
|
||||
}
|
||||
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||
addCallback(
|
||||
object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||
super.onDismissed(transientBottomBar, event)
|
||||
if (!undoing) presenter.confirmDeletion(mangas)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
(activity as? MainActivity)?.setUndoSnackBar(snack)
|
||||
}
|
||||
|
@ -26,38 +26,45 @@ class LibraryGestureDetector(private val controller: LibraryController) : Gestur
|
||||
var result = false
|
||||
val diffY = e2.y - e1.y
|
||||
val diffX = e2.x - e1.x
|
||||
if (abs(diffX) <= abs(diffY) && abs(diffY) > MainActivity.SWIPE_THRESHOLD && abs(velocityY) > MainActivity.SWIPE_VELOCITY_THRESHOLD) {
|
||||
if (abs(diffX) <= abs(diffY) &&
|
||||
abs(diffY) > MainActivity.SWIPE_THRESHOLD &&
|
||||
abs(velocityY) > MainActivity.SWIPE_VELOCITY_THRESHOLD
|
||||
) {
|
||||
if (diffY <= 0) {
|
||||
controller.showSheet()
|
||||
} else {
|
||||
controller.filter_bottom_sheet.sheetBehavior?.hide()
|
||||
}
|
||||
result = true
|
||||
} else if (abs(diffX) >= abs(diffY) && abs(diffX) > MainActivity.SWIPE_THRESHOLD * 3 && abs(
|
||||
velocityX
|
||||
) > MainActivity.SWIPE_VELOCITY_THRESHOLD
|
||||
} else if (abs(diffX) >= abs(diffY) &&
|
||||
abs(diffX) > MainActivity.SWIPE_THRESHOLD * 3 &&
|
||||
abs(velocityX) > MainActivity.SWIPE_VELOCITY_THRESHOLD
|
||||
) {
|
||||
if (diffX <= 0) {
|
||||
controller.category_hopper_frame.updateLayoutParams<CoordinatorLayout.LayoutParams> {
|
||||
anchorGravity =
|
||||
Gravity.TOP or (if (anchorGravity == Gravity.TOP or Gravity.RIGHT) {
|
||||
Gravity.TOP or (
|
||||
if (anchorGravity == Gravity.TOP or Gravity.RIGHT) {
|
||||
controller.preferences.hopperGravity().set(1)
|
||||
Gravity.CENTER
|
||||
} else {
|
||||
controller.preferences.hopperGravity().set(0)
|
||||
Gravity.LEFT
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
controller.category_hopper_frame.updateLayoutParams<CoordinatorLayout.LayoutParams> {
|
||||
anchorGravity =
|
||||
Gravity.TOP or Gravity.TOP or (if (anchorGravity == Gravity.TOP or Gravity.LEFT) {
|
||||
Gravity.TOP or Gravity.TOP or (
|
||||
if (anchorGravity == Gravity.TOP or Gravity.LEFT) {
|
||||
controller.preferences.hopperGravity().set(1)
|
||||
Gravity.CENTER
|
||||
} else {
|
||||
controller.preferences.hopperGravity().set(2)
|
||||
Gravity.RIGHT
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
if (!controller.hasMovedHopper) {
|
||||
|
@ -79,11 +79,13 @@ class LibraryHeaderHolder(val view: View, private val adapter: LibraryCategoryAd
|
||||
}
|
||||
val shorterMargin = adapter.headerItems.firstOrNull() == item
|
||||
sectionText.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
topMargin = (when {
|
||||
topMargin = (
|
||||
when {
|
||||
shorterMargin -> 2
|
||||
previousIsCollapsed -> 5
|
||||
else -> 32
|
||||
}).dpToPx
|
||||
}
|
||||
).dpToPx
|
||||
}
|
||||
val category = item.category
|
||||
|
||||
@ -117,7 +119,8 @@ class LibraryHeaderHolder(val view: View, private val adapter: LibraryCategoryAd
|
||||
sortText.setText(category.sortRes())
|
||||
expandImage.setImageResource(
|
||||
if (category.isHidden) R.drawable.ic_expand_more_24dp
|
||||
else R.drawable.ic_expand_less_24dp)
|
||||
else R.drawable.ic_expand_less_24dp
|
||||
)
|
||||
when {
|
||||
adapter.mode == SelectableAdapter.Mode.MULTI -> {
|
||||
checkboxImage.visibleIf(!category.isHidden)
|
||||
@ -160,22 +163,31 @@ class LibraryHeaderHolder(val view: View, private val adapter: LibraryCategoryAd
|
||||
adapter.controller.activity?.let { activity ->
|
||||
val items = mutableListOf(
|
||||
MaterialMenuSheet.MenuSheetItem(
|
||||
LibrarySort.ALPHA, R.drawable.ic_sort_by_alpha_24dp, R.string.title
|
||||
), MaterialMenuSheet.MenuSheetItem(
|
||||
LibrarySort.ALPHA,
|
||||
R.drawable.ic_sort_by_alpha_24dp,
|
||||
R.string.title
|
||||
),
|
||||
MaterialMenuSheet.MenuSheetItem(
|
||||
LibrarySort.LAST_READ,
|
||||
R.drawable.ic_recent_read_outline_24dp,
|
||||
R.string.last_read
|
||||
), MaterialMenuSheet.MenuSheetItem(
|
||||
),
|
||||
MaterialMenuSheet.MenuSheetItem(
|
||||
LibrarySort.LATEST_CHAPTER,
|
||||
R.drawable.ic_new_releases_24dp,
|
||||
R.string.latest_chapter
|
||||
), MaterialMenuSheet.MenuSheetItem(
|
||||
LibrarySort.UNREAD, R.drawable.ic_eye_24dp, R.string.unread
|
||||
), MaterialMenuSheet.MenuSheetItem(
|
||||
),
|
||||
MaterialMenuSheet.MenuSheetItem(
|
||||
LibrarySort.UNREAD,
|
||||
R.drawable.ic_eye_24dp,
|
||||
R.string.unread
|
||||
),
|
||||
MaterialMenuSheet.MenuSheetItem(
|
||||
LibrarySort.TOTAL,
|
||||
R.drawable.ic_sort_by_numeric_24dp,
|
||||
R.string.total_chapters
|
||||
), MaterialMenuSheet.MenuSheetItem(
|
||||
),
|
||||
MaterialMenuSheet.MenuSheetItem(
|
||||
LibrarySort.DATE_ADDED,
|
||||
R.drawable.ic_heart_outline_24dp,
|
||||
R.string.date_added
|
||||
@ -192,7 +204,10 @@ class LibraryHeaderHolder(val view: View, private val adapter: LibraryCategoryAd
|
||||
}
|
||||
val sortingMode = category.sortingMode()
|
||||
val sheet = MaterialMenuSheet(
|
||||
activity, items, activity.getString(R.string.sort_by), sortingMode
|
||||
activity,
|
||||
items,
|
||||
activity.getString(R.string.sort_by),
|
||||
sortingMode
|
||||
) { sheet, item ->
|
||||
onCatSortClicked(category, item)
|
||||
val nCategory = (adapter.getItem(adapterPosition) as? LibraryHeaderItem)?.category
|
||||
@ -212,7 +227,8 @@ class LibraryHeaderHolder(val view: View, private val adapter: LibraryCategoryAd
|
||||
sortingMode == LibrarySort.DRAG_AND_DROP -> R.drawable.ic_check_24dp
|
||||
if (sortingMode == LibrarySort.DATE_ADDED ||
|
||||
sortingMode == LibrarySort.LATEST_CHAPTER ||
|
||||
sortingMode == LibrarySort.LAST_READ) !isAscending else isAscending ->
|
||||
sortingMode == LibrarySort.LAST_READ
|
||||
) !isAscending else isAscending ->
|
||||
R.drawable.ic_arrow_downward_24dp
|
||||
else -> R.drawable.ic_arrow_upward_24dp
|
||||
}
|
||||
@ -257,7 +273,8 @@ class LibraryHeaderHolder(val view: View, private val adapter: LibraryCategoryAd
|
||||
val tintedDrawable = drawable?.mutate()
|
||||
tintedDrawable?.setTint(
|
||||
ContextCompat.getColor(
|
||||
contentView.context, if (allSelected) R.color.colorAccent
|
||||
contentView.context,
|
||||
if (allSelected) R.color.colorAccent
|
||||
else R.color.gray_button
|
||||
)
|
||||
)
|
||||
|
@ -39,7 +39,8 @@ abstract class LibraryHolder(
|
||||
item.manga.source == LocalSource.ID -> -2
|
||||
else -> item.downloadCount
|
||||
},
|
||||
showTotal)
|
||||
showTotal
|
||||
)
|
||||
}
|
||||
|
||||
fun setReadingButton(item: LibraryItem) {
|
||||
|
@ -66,18 +66,21 @@ class LibraryItem(
|
||||
gradient.layoutParams = FrameLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||
(coverHeight * 0.66f).toInt(),
|
||||
Gravity.BOTTOM)
|
||||
Gravity.BOTTOM
|
||||
)
|
||||
card.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
bottomMargin = 6.dpToPx
|
||||
}
|
||||
} else if (libraryLayout == 2) {
|
||||
constraint_layout.background = ContextCompat.getDrawable(
|
||||
context, R.drawable.library_item_selector
|
||||
context,
|
||||
R.drawable.library_item_selector
|
||||
)
|
||||
}
|
||||
if (isFixedSize) {
|
||||
constraint_layout.layoutParams = FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
cover_thumbnail.maxHeight = Int.MAX_VALUE
|
||||
cover_thumbnail.minimumHeight = 0
|
||||
@ -162,7 +165,8 @@ class LibraryItem(
|
||||
} == null
|
||||
else
|
||||
genres?.find {
|
||||
it.trim().toLowerCase() == tag.toLowerCase() } != null
|
||||
it.trim().toLowerCase() == tag.toLowerCase()
|
||||
} != null
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
|
@ -129,7 +129,8 @@ class LibraryPresenter(
|
||||
private fun blankItem(id: Int = currentCategory): List<LibraryItem> {
|
||||
return listOf(
|
||||
LibraryItem(
|
||||
LibraryManga.createBlank(id), LibraryHeaderItem({ getCategory(id) }, id)
|
||||
LibraryManga.createBlank(id),
|
||||
LibraryHeaderItem({ getCategory(id) }, id)
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -146,7 +147,8 @@ class LibraryPresenter(
|
||||
view.onNextLibraryUpdate(
|
||||
if (!show) sectionedLibraryItems[currentCategory]
|
||||
?: sectionedLibraryItems[categories.first().id] ?: blankItem()
|
||||
else libraryItems, true
|
||||
else libraryItems,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
@ -169,7 +171,8 @@ class LibraryPresenter(
|
||||
view.onNextLibraryUpdate(
|
||||
if (!showAll) sectionedLibraryItems[currentCategory]
|
||||
?: sectionedLibraryItems[categories.first().id] ?: blankItem()
|
||||
else libraryItems, freshStart
|
||||
else libraryItems,
|
||||
freshStart
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -454,15 +457,19 @@ class LibraryPresenter(
|
||||
)
|
||||
val catItemAll = LibraryHeaderItem({ categoryAll }, -1)
|
||||
val categorySet = mutableSetOf<Int>()
|
||||
val headerItems = (categories.mapNotNull { category ->
|
||||
val headerItems = (
|
||||
categories.mapNotNull { category ->
|
||||
val id = category.id
|
||||
if (id == null) null
|
||||
else id to LibraryHeaderItem({ getCategory(id) }, id)
|
||||
} + (-1 to catItemAll) + (0 to LibraryHeaderItem({ getCategory(0) }, 0))).toMap()
|
||||
} + (-1 to catItemAll) + (0 to LibraryHeaderItem({ getCategory(0) }, 0))
|
||||
).toMap()
|
||||
|
||||
val items = libraryManga.mapNotNull {
|
||||
val headerItem = (if (!libraryIsGrouped) catItemAll
|
||||
else headerItems[it.category]) ?: return@mapNotNull null
|
||||
val headerItem = (
|
||||
if (!libraryIsGrouped) catItemAll
|
||||
else headerItems[it.category]
|
||||
) ?: return@mapNotNull null
|
||||
categorySet.add(it.category)
|
||||
LibraryItem(it, headerItem)
|
||||
}.toMutableList()
|
||||
@ -475,8 +482,11 @@ class LibraryPresenter(
|
||||
if (libraryIsGrouped) {
|
||||
categories.forEach { category ->
|
||||
val catId = category.id ?: return@forEach
|
||||
if (catId > 0 && !categorySet.contains(catId) && (catId !in categoriesHidden ||
|
||||
!showAll)) {
|
||||
if (catId > 0 && !categorySet.contains(catId) && (
|
||||
catId !in categoriesHidden ||
|
||||
!showAll
|
||||
)
|
||||
) {
|
||||
val headerItem = headerItems[catId]
|
||||
if (headerItem != null) items.add(
|
||||
LibraryItem(LibraryManga.createBlank(catId), headerItem)
|
||||
@ -592,18 +602,21 @@ class LibraryPresenter(
|
||||
mapTrackingOrder(it.name)
|
||||
} else {
|
||||
it.name
|
||||
} }
|
||||
}
|
||||
}
|
||||
headers.forEachIndexed { index, category -> category.order = index }
|
||||
return items to headers
|
||||
}
|
||||
|
||||
private fun mapStatus(status: Int): String {
|
||||
return context.getString(when (status) {
|
||||
return context.getString(
|
||||
when (status) {
|
||||
SManga.LICENSED -> R.string.licensed
|
||||
SManga.ONGOING -> R.string.ongoing
|
||||
SManga.COMPLETED -> R.string.completed
|
||||
else -> R.string.unknown
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun mapTrackingOrder(status: String): String {
|
||||
|
@ -33,7 +33,8 @@ class CategoryRecyclerView @JvmOverloads constructor(
|
||||
fun setCategories(items: List<Category>) {
|
||||
itemAdapter.set(items.map(::CategoryItem))
|
||||
fastAdapter.onBindViewHolderListener =
|
||||
(object : OnBindViewHolderListenerImpl<CategoryItem>() {
|
||||
(
|
||||
object : OnBindViewHolderListenerImpl<CategoryItem>() {
|
||||
override fun onBindViewHolder(
|
||||
viewHolder: ViewHolder,
|
||||
position: Int,
|
||||
@ -43,7 +44,8 @@ class CategoryRecyclerView @JvmOverloads constructor(
|
||||
(viewHolder as? CategoryItem.ViewHolder)?.categoryTitle?.isSelected =
|
||||
selectedCategory == position
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
fastAdapter.onClickListener = { _, _, item, _ ->
|
||||
if (item.category.id != -1)
|
||||
onCategoryClicked(item.category.order)
|
||||
|
@ -104,7 +104,8 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
|
||||
pager = controller.recycler
|
||||
val shadow2: View = controller.shadow2
|
||||
val shadow: View = controller.shadow
|
||||
sheetBehavior?.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
|
||||
sheetBehavior?.addBottomSheetCallback(
|
||||
object : BottomSheetBehavior.BottomSheetCallback() {
|
||||
override fun onSlide(bottomSheet: View, progress: Float) {
|
||||
pill.alpha = (1 - max(0f, progress)) * 0.25f
|
||||
shadow2.alpha = (1 - max(0f, progress)) * 0.25f
|
||||
@ -115,7 +116,8 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
|
||||
override fun onStateChanged(p0: View, state: Int) {
|
||||
stateChanged(state)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
if (context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
second_layout.removeView(view_options)
|
||||
@ -284,13 +286,15 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
|
||||
unreadProgress.state = unreadP - 3
|
||||
}
|
||||
tracked?.setState(preferences.filterTracked())
|
||||
mangaType?.setState(when (preferences.filterMangaType().getOrDefault()) {
|
||||
mangaType?.setState(
|
||||
when (preferences.filterMangaType().getOrDefault()) {
|
||||
Manga.TYPE_MANGA -> context.getString(R.string.manga)
|
||||
Manga.TYPE_MANHUA -> context.getString(R.string.manhua)
|
||||
Manga.TYPE_MANHWA -> context.getString(R.string.manhwa)
|
||||
Manga.TYPE_COMIC -> context.getString(R.string.comic)
|
||||
else -> ""
|
||||
})
|
||||
}
|
||||
)
|
||||
reorderFilters()
|
||||
reSortViews()
|
||||
}
|
||||
@ -361,8 +365,11 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
|
||||
val recycler = RecyclerView(context)
|
||||
if (filterOrder.count() != 6)
|
||||
filterOrder = "urdcmt"
|
||||
val adapter = FlexibleAdapter(filterOrder.toCharArray().map(::ManageFilterItem),
|
||||
this, true)
|
||||
val adapter = FlexibleAdapter(
|
||||
filterOrder.toCharArray().map(::ManageFilterItem),
|
||||
this,
|
||||
true
|
||||
)
|
||||
recycler.layoutManager = LinearLayoutManager(context)
|
||||
recycler.adapter = adapter
|
||||
adapter.isHandleDragEnabled = true
|
||||
|
@ -83,19 +83,23 @@ class FilterTagGroup@JvmOverloads constructor(context: Context, attrs: Attribute
|
||||
|
||||
private fun toggleButton(index: Int, callBack: Boolean = true) {
|
||||
if (index < 0 || itemCount == 0 ||
|
||||
(isActivated && index != buttons.indexOfFirst { it.isActivated }))
|
||||
(isActivated && index != buttons.indexOfFirst { it.isActivated })
|
||||
)
|
||||
return
|
||||
if (callBack) {
|
||||
val transition = androidx.transition.AutoTransition()
|
||||
transition.duration = 150
|
||||
androidx.transition.TransitionManager.beginDelayedTransition(
|
||||
parent.parent as ViewGroup, transition
|
||||
parent.parent as ViewGroup,
|
||||
transition
|
||||
)
|
||||
}
|
||||
if (itemCount == 1) {
|
||||
firstButton.isActivated = !firstButton.isActivated
|
||||
firstButton.setTextColor(if (firstButton.isActivated) Color.WHITE else context
|
||||
.getResourceColor(android.R.attr.textColorPrimary))
|
||||
firstButton.setTextColor(
|
||||
if (firstButton.isActivated) Color.WHITE else context
|
||||
.getResourceColor(android.R.attr.textColorPrimary)
|
||||
)
|
||||
listener?.onFilterClicked(this, if (firstButton.isActivated) index else -1, callBack)
|
||||
return
|
||||
}
|
||||
@ -118,8 +122,10 @@ class FilterTagGroup@JvmOverloads constructor(context: Context, attrs: Attribute
|
||||
buttons.forEach { if (it != mainButton) it.gone() }
|
||||
separators.forEach { it.gone() }
|
||||
}
|
||||
mainButton.setTextColor(if (mainButton.isActivated) Color.WHITE else context
|
||||
.getResourceColor(android.R.attr.textColorPrimary))
|
||||
mainButton.setTextColor(
|
||||
if (mainButton.isActivated) Color.WHITE else context
|
||||
.getResourceColor(android.R.attr.textColorPrimary)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,10 +144,12 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
||||
drawerArrow = DrawerArrowDrawable(this)
|
||||
drawerArrow?.color = getResourceColor(R.attr.actionBarTintColor)
|
||||
searchDrawable = ContextCompat.getDrawable(
|
||||
this, R.drawable.ic_search_24dp
|
||||
this,
|
||||
R.drawable.ic_search_24dp
|
||||
)
|
||||
dismissDrawable = ContextCompat.getDrawable(
|
||||
this, R.drawable.ic_close_24dp
|
||||
this,
|
||||
R.drawable.ic_close_24dp
|
||||
)
|
||||
|
||||
var continueSwitchingTabs = false
|
||||
@ -182,18 +184,22 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
||||
if (!currentController.canChangeTabs {
|
||||
continueSwitchingTabs = true
|
||||
this@MainActivity.bottom_nav.selectedItemId = id
|
||||
}) return@setOnNavigationItemSelectedListener false
|
||||
}
|
||||
) return@setOnNavigationItemSelectedListener false
|
||||
}
|
||||
continueSwitchingTabs = false
|
||||
if (item.itemId != R.id.nav_browse)
|
||||
preferences.lastTab().set(item.itemId)
|
||||
val currentRoot = router.backstack.firstOrNull()
|
||||
if (currentRoot?.tag()?.toIntOrNull() != id) {
|
||||
setRoot(when (id) {
|
||||
setRoot(
|
||||
when (id) {
|
||||
R.id.nav_library -> LibraryController()
|
||||
R.id.nav_recents -> RecentsController()
|
||||
else -> SourceController()
|
||||
}, id)
|
||||
},
|
||||
id
|
||||
)
|
||||
} else if (currentRoot.tag()?.toIntOrNull() == id) {
|
||||
if (router.backstackSize == 1) {
|
||||
val controller =
|
||||
@ -225,7 +231,8 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
||||
// Consume any horizontal insets and pad all content in. There's not much we can do
|
||||
// with horizontal insets
|
||||
v.updatePadding(
|
||||
left = insets.systemWindowInsetLeft, right = insets.systemWindowInsetRight
|
||||
left = insets.systemWindowInsetLeft,
|
||||
right = insets.systemWindowInsetRight
|
||||
)
|
||||
appbar.updatePadding(
|
||||
top = insets.systemWindowInsetTop
|
||||
@ -251,7 +258,8 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
||||
|
||||
bottom_nav.visibleIf(!hideBottomNav)
|
||||
bottom_nav.alpha = if (hideBottomNav) 0f else 1f
|
||||
router.addChangeListener(object : ControllerChangeHandler.ControllerChangeListener {
|
||||
router.addChangeListener(
|
||||
object : ControllerChangeHandler.ControllerChangeListener {
|
||||
override fun onChangeStarted(
|
||||
to: Controller?,
|
||||
from: Controller?,
|
||||
@ -275,7 +283,8 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
||||
appbar.y = 0f
|
||||
showDLQueueTutorial()
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
syncActivityViewWithController(router.backstack.lastOrNull()?.controller())
|
||||
|
||||
@ -322,7 +331,8 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
||||
// if in portrait with 2/3 button mode, translucent nav bar
|
||||
else {
|
||||
ColorUtils.setAlphaComponent(
|
||||
getResourceColor(R.attr.colorPrimaryVariant), 179
|
||||
getResourceColor(R.attr.colorPrimaryVariant),
|
||||
179
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -335,7 +345,9 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
||||
override fun onSupportActionModeFinished(mode: androidx.appcompat.view.ActionMode) {
|
||||
launchUI {
|
||||
val scale = Settings.Global.getFloat(
|
||||
contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f
|
||||
contentResolver,
|
||||
Settings.Global.ANIMATOR_DURATION_SCALE,
|
||||
1.0f
|
||||
)
|
||||
val duration = resources.getInteger(android.R.integer.config_mediumAnimTime) * scale
|
||||
delay(duration.toLong())
|
||||
@ -372,7 +384,8 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
||||
) {
|
||||
val recentsItem = bottom_nav.getItemView(R.id.nav_recents) ?: return
|
||||
preferences.shownDownloadQueueTutorial().set(true)
|
||||
TapTargetView.showFor(this,
|
||||
TapTargetView.showFor(
|
||||
this,
|
||||
TapTarget.forView(
|
||||
recentsItem,
|
||||
getString(R.string.manage_whats_downloading),
|
||||
@ -387,7 +400,8 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
||||
super.onTargetClick(view)
|
||||
bottom_nav.selectedItemId = R.id.nav_recents
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -398,7 +412,8 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
||||
|
||||
private fun getAppUpdates() {
|
||||
if (isUpdaterEnabled &&
|
||||
Date().time >= preferences.lastAppCheck().get() + TimeUnit.DAYS.toMillis(1)) {
|
||||
Date().time >= preferences.lastAppCheck().get() + TimeUnit.DAYS.toMillis(1)
|
||||
) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val result = updateChecker.checkForUpdate()
|
||||
@ -441,7 +456,9 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
||||
protected open fun handleIntentAction(intent: Intent): Boolean {
|
||||
val notificationId = intent.getIntExtra("notificationId", -1)
|
||||
if (notificationId > -1) NotificationReceiver.dismissNotification(
|
||||
applicationContext, notificationId, intent.getIntExtra("groupId", 0)
|
||||
applicationContext,
|
||||
notificationId,
|
||||
intent.getIntExtra("groupId", 0)
|
||||
)
|
||||
when (intent.action) {
|
||||
SHORTCUT_LIBRARY -> bottom_nav.selectedItemId = R.id.nav_library
|
||||
@ -528,10 +545,9 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
||||
extraViewForUndo?.getGlobalVisibleRect(extRect)
|
||||
// This way the snackbar will only be dismissed if
|
||||
// the user clicks outside it.
|
||||
if (canDismissSnackBar && !sRect.contains(
|
||||
ev.x.toInt(),
|
||||
ev.y.toInt()
|
||||
) && (extRect == null || !extRect.contains(ev.x.toInt(), ev.y.toInt()))
|
||||
if (canDismissSnackBar &&
|
||||
!sRect.contains(ev.x.toInt(), ev.y.toInt()) &&
|
||||
(extRect == null || !extRect.contains(ev.x.toInt(), ev.y.toInt()))
|
||||
) {
|
||||
snackBar?.dismiss()
|
||||
snackBar = null
|
||||
@ -567,14 +583,17 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
||||
animationSet?.cancel()
|
||||
animationSet = AnimatorSet()
|
||||
val alphaAnimation = ValueAnimator.ofFloat(
|
||||
bottom_nav.alpha, if (hideBottomNav) 0f else 1f
|
||||
bottom_nav.alpha,
|
||||
if (hideBottomNav) 0f else 1f
|
||||
)
|
||||
alphaAnimation.addUpdateListener { valueAnimator ->
|
||||
bottom_nav.alpha = valueAnimator.animatedValue as Float
|
||||
}
|
||||
alphaAnimation.addListener(EndAnimatorListener {
|
||||
alphaAnimation.addListener(
|
||||
EndAnimatorListener {
|
||||
bottom_nav.visibility = if (hideBottomNav) View.GONE else View.VISIBLE
|
||||
})
|
||||
}
|
||||
)
|
||||
alphaAnimation.duration = 200
|
||||
alphaAnimation.startDelay = 50
|
||||
animationSet?.playTogether(alphaAnimation)
|
||||
@ -610,9 +629,10 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
|
||||
if (abs(diffX) <= abs(diffY)) {
|
||||
val sheetRect = Rect()
|
||||
bottom_nav.getGlobalVisibleRect(sheetRect)
|
||||
if (sheetRect.contains(
|
||||
e1.x.toInt(), e1.y.toInt()
|
||||
) && abs(diffY) > Companion.SWIPE_THRESHOLD && abs(velocityY) > Companion.SWIPE_VELOCITY_THRESHOLD && diffY <= 0
|
||||
if (sheetRect.contains(e1.x.toInt(), e1.y.toInt()) &&
|
||||
abs(diffY) > Companion.SWIPE_THRESHOLD &&
|
||||
abs(velocityY) > Companion.SWIPE_VELOCITY_THRESHOLD &&
|
||||
diffY <= 0
|
||||
) {
|
||||
val bottomSheetController =
|
||||
router.backstack.lastOrNull()?.controller() as? BottomSheetController
|
||||
|
@ -64,7 +64,9 @@ class SearchActivity : MainActivity() {
|
||||
override fun handleIntentAction(intent: Intent): Boolean {
|
||||
val notificationId = intent.getIntExtra("notificationId", -1)
|
||||
if (notificationId > -1) NotificationReceiver.dismissNotification(
|
||||
applicationContext, notificationId, intent.getIntExtra("groupId", 0)
|
||||
applicationContext,
|
||||
notificationId,
|
||||
intent.getIntExtra("groupId", 0)
|
||||
)
|
||||
when (intent.action) {
|
||||
Intent.ACTION_SEARCH, "com.google.android.gms.actions.SEARCH_ACTION" -> {
|
||||
@ -92,7 +94,8 @@ class SearchActivity : MainActivity() {
|
||||
router.replaceTopController(
|
||||
RouterTransaction.with(MangaDetailsController(extras))
|
||||
.pushChangeHandler(SimpleSwapChangeHandler())
|
||||
.popChangeHandler(FadeChangeHandler()))
|
||||
.popChangeHandler(FadeChangeHandler())
|
||||
)
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
@ -100,8 +103,11 @@ class SearchActivity : MainActivity() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun openMangaIntent(context: Context, id: Long) = Intent(context, SearchActivity::class
|
||||
.java)
|
||||
fun openMangaIntent(context: Context, id: Long) = Intent(
|
||||
context,
|
||||
SearchActivity::class
|
||||
.java
|
||||
)
|
||||
.apply {
|
||||
action = SHORTCUT_MANGA
|
||||
putExtra(MangaDetailsController.MANGA_EXTRA, id)
|
||||
|
@ -33,10 +33,12 @@ class EditMangaDialog : DialogController {
|
||||
private val infoController
|
||||
get() = targetController as MangaDetailsController
|
||||
|
||||
constructor(target: MangaDetailsController, manga: Manga) : super(Bundle()
|
||||
constructor(target: MangaDetailsController, manga: Manga) : super(
|
||||
Bundle()
|
||||
.apply {
|
||||
putLong(KEY_MANGA, manga.id!!)
|
||||
}) {
|
||||
}
|
||||
) {
|
||||
targetController = target
|
||||
this.manga = manga
|
||||
}
|
||||
@ -99,7 +101,8 @@ class EditMangaDialog : DialogController {
|
||||
if (manga.originalDescription != null) {
|
||||
view.manga_description.hint =
|
||||
"${resources?.getString(R.string.description)}: ${manga.originalDescription?.replace(
|
||||
"\n", " "
|
||||
"\n",
|
||||
" "
|
||||
)?.chop(20)}"
|
||||
}
|
||||
}
|
||||
@ -110,9 +113,12 @@ class EditMangaDialog : DialogController {
|
||||
view.reset_tags.setOnClickListener { resetTags() }
|
||||
view.reset_cover.visibleIf(!isLocal)
|
||||
view.reset_cover.setOnClickListener {
|
||||
view.manga_cover.loadAny(manga, builder = {
|
||||
view.manga_cover.loadAny(
|
||||
manga,
|
||||
builder = {
|
||||
parameters(Parameters.Builder().set(MangaFetcher.realCover, true).build())
|
||||
})
|
||||
}
|
||||
)
|
||||
willResetCover = true
|
||||
}
|
||||
}
|
||||
@ -136,10 +142,15 @@ class EditMangaDialog : DialogController {
|
||||
}
|
||||
|
||||
private fun onPositiveButtonClick() {
|
||||
infoController.presenter.updateManga(dialogView?.title?.text.toString(),
|
||||
dialogView?.manga_author?.text.toString(), dialogView?.manga_artist?.text.toString(),
|
||||
customCoverUri, dialogView?.manga_description?.text.toString(),
|
||||
dialogView?.manga_genres_tags?.tags, willResetCover)
|
||||
infoController.presenter.updateManga(
|
||||
dialogView?.title?.text.toString(),
|
||||
dialogView?.manga_author?.text.toString(),
|
||||
dialogView?.manga_artist?.text.toString(),
|
||||
customCoverUri,
|
||||
dialogView?.manga_description?.text.toString(),
|
||||
dialogView?.manga_genres_tags?.tags,
|
||||
willResetCover
|
||||
)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
@ -26,8 +26,11 @@ class MangaDetailsAdapter(
|
||||
val delegate: MangaDetailsInterface = controller
|
||||
val presenter = controller.presenter
|
||||
|
||||
val decimalFormat = DecimalFormat("#.###", DecimalFormatSymbols()
|
||||
.apply { decimalSeparator = '.' })
|
||||
val decimalFormat = DecimalFormat(
|
||||
"#.###",
|
||||
DecimalFormatSymbols()
|
||||
.apply { decimalSeparator = '.' }
|
||||
)
|
||||
|
||||
fun setChapters(items: List<ChapterItem>?) {
|
||||
this.items = items ?: emptyList()
|
||||
@ -47,10 +50,12 @@ class MangaDetailsAdapter(
|
||||
if (s.isNullOrBlank()) {
|
||||
updateDataSet(items)
|
||||
} else {
|
||||
updateDataSet(items.filter {
|
||||
updateDataSet(
|
||||
items.filter {
|
||||
it.name.contains(s, true) ||
|
||||
it.scanlator?.contains(s, true) == true
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,14 +76,16 @@ class MangaDetailsAdapter(
|
||||
if (volume != null) {
|
||||
recyclerView.context.getString(
|
||||
if (scrollType == MangaDetailsPresenter.MULTIPLE_SEASONS) R.string.season_
|
||||
else R.string.volume_, volume
|
||||
else R.string.volume_,
|
||||
volume
|
||||
)
|
||||
} else {
|
||||
getChapterName(chapter)
|
||||
}
|
||||
}
|
||||
MangaDetailsPresenter.TENS_OF_CHAPTERS -> recyclerView.context.getString(
|
||||
R.string.chapters_, get10sRange(
|
||||
R.string.chapters_,
|
||||
get10sRange(
|
||||
chapter.chapter_number
|
||||
)
|
||||
)
|
||||
@ -89,7 +96,8 @@ class MangaDetailsAdapter(
|
||||
private fun getChapterName(item: ChapterItem): String {
|
||||
return if (item.chapter_number > 0) {
|
||||
recyclerView.context.getString(
|
||||
R.string.chapter_, decimalFormat.format(item.chapter_number)
|
||||
R.string.chapter_,
|
||||
decimalFormat.format(item.chapter_number)
|
||||
)
|
||||
} else {
|
||||
item.name
|
||||
|
@ -110,7 +110,8 @@ import java.io.IOException
|
||||
import java.util.Locale
|
||||
import kotlin.math.max
|
||||
|
||||
class MangaDetailsController : BaseController,
|
||||
class MangaDetailsController :
|
||||
BaseController,
|
||||
FlexibleAdapter.OnItemClickListener,
|
||||
FlexibleAdapter.OnItemLongClickListener,
|
||||
ActionMode.Callback,
|
||||
@ -124,12 +125,14 @@ class MangaDetailsController : BaseController,
|
||||
fromCatalogue: Boolean = false,
|
||||
smartSearchConfig: SourceController.SmartSearchConfig? = null,
|
||||
update: Boolean = false
|
||||
) : super(Bundle().apply {
|
||||
) : super(
|
||||
Bundle().apply {
|
||||
putLong(MANGA_EXTRA, manga?.id ?: 0)
|
||||
putBoolean(FROM_CATALOGUE_EXTRA, fromCatalogue)
|
||||
putParcelable(SMART_SEARCH_CONFIG_EXTRA, smartSearchConfig)
|
||||
putBoolean(UPDATE_EXTRA, update)
|
||||
}) {
|
||||
}
|
||||
) {
|
||||
this.manga = manga
|
||||
if (manga != null) {
|
||||
source = Injekt.get<SourceManager>().getOrStub(manga.source)
|
||||
@ -145,7 +148,9 @@ class MangaDetailsController : BaseController,
|
||||
val notificationId = bundle.getInt("notificationId", -1)
|
||||
val context = applicationContext ?: return
|
||||
if (notificationId > -1) NotificationReceiver.dismissNotification(
|
||||
context, notificationId, bundle.getInt("groupId", 0)
|
||||
context,
|
||||
notificationId,
|
||||
bundle.getInt("groupId", 0)
|
||||
)
|
||||
}
|
||||
|
||||
@ -227,13 +232,20 @@ class MangaDetailsController : BaseController,
|
||||
swipe_refresh.setDistanceToTriggerSync(70.dpToPx)
|
||||
activity!!.appbar.elevation = 0f
|
||||
|
||||
scrollViewWith(recycler, padBottom = true, customPadding = true, afterInsets = { insets ->
|
||||
scrollViewWith(
|
||||
recycler,
|
||||
padBottom = true,
|
||||
customPadding = true,
|
||||
afterInsets = { insets ->
|
||||
setInsets(insets, appbarHeight, offset)
|
||||
}, liftOnScroll = {
|
||||
},
|
||||
liftOnScroll = {
|
||||
colorToolbar(it)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
recycler.addOnScrollListener(
|
||||
object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
val atTop = !recyclerView.canScrollVertically(-1)
|
||||
@ -246,7 +258,8 @@ class MangaDetailsController : BaseController,
|
||||
val atTop = !recyclerView.canScrollVertically(-1)
|
||||
if (atTop) getHeader()?.backdrop?.translationY = 0f
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun setInsets(insets: WindowInsets, appbarHeight: Int, offset: Int) {
|
||||
@ -280,15 +293,19 @@ class MangaDetailsController : BaseController,
|
||||
if (colorAnimator?.isRunning == true) activity?.window?.statusBarColor
|
||||
?: color
|
||||
else ColorUtils.setAlphaComponent(
|
||||
color, if (toolbarIsColored) 0 else 175
|
||||
color,
|
||||
if (toolbarIsColored) 0 else 175
|
||||
)
|
||||
val colorTo = ColorUtils.setAlphaComponent(
|
||||
color, if (toolbarIsColored) 175 else 0
|
||||
color,
|
||||
if (toolbarIsColored) 175 else 0
|
||||
)
|
||||
colorAnimator?.cancel()
|
||||
if (animate) {
|
||||
colorAnimator = ValueAnimator.ofObject(
|
||||
android.animation.ArgbEvaluator(), colorFrom, colorTo
|
||||
android.animation.ArgbEvaluator(),
|
||||
colorFrom,
|
||||
colorTo
|
||||
)
|
||||
colorAnimator?.duration = 250 // milliseconds
|
||||
colorAnimator?.addUpdateListener { animator ->
|
||||
@ -307,7 +324,8 @@ class MangaDetailsController : BaseController,
|
||||
val view = view ?: return
|
||||
|
||||
val request = LoadRequest.Builder(view.context).data(presenter.manga).allowHardware(false)
|
||||
.target(onSuccess = { drawable ->
|
||||
.target(
|
||||
onSuccess = { drawable ->
|
||||
val bitmap = (drawable as BitmapDrawable).bitmap
|
||||
// Generate the Palette on a background thread.
|
||||
Palette.from(bitmap).generate {
|
||||
@ -329,13 +347,15 @@ class MangaDetailsController : BaseController,
|
||||
}
|
||||
manga_cover_full.setImageDrawable(drawable)
|
||||
getHeader()?.updateCover(manga!!)
|
||||
}, onError = {
|
||||
},
|
||||
onError = {
|
||||
val file = presenter.coverCache.getCoverFile(manga!!)
|
||||
if (file.exists()) {
|
||||
file.delete()
|
||||
setPaletteColor()
|
||||
}
|
||||
}).build()
|
||||
}
|
||||
).build()
|
||||
Coil.imageLoader(view.context).execute(request)
|
||||
}
|
||||
|
||||
@ -343,10 +363,7 @@ class MangaDetailsController : BaseController,
|
||||
private fun setActionBar(forThis: Boolean) {
|
||||
val activity = activity ?: return
|
||||
// if the theme is using inverted toolbar color
|
||||
if (!activity.isInNightMode() && ThemeUtil.isBlueTheme(
|
||||
presenter.preferences.theme()
|
||||
)
|
||||
) {
|
||||
if (!activity.isInNightMode() && ThemeUtil.isBlueTheme(presenter.preferences.theme())) {
|
||||
if (forThis) (activity as MainActivity).appbar.context.setTheme(
|
||||
R.style.ThemeOverlay_AppCompat_DayNight_ActionBar
|
||||
)
|
||||
@ -481,10 +498,12 @@ class MangaDetailsController : BaseController,
|
||||
1 -> return
|
||||
else -> {
|
||||
MaterialDialog(context).title(R.string.chapters_removed).message(
|
||||
text = context.resources.getQuantityString(R.plurals.deleted_chapters,
|
||||
text = context.resources.getQuantityString(
|
||||
R.plurals.deleted_chapters,
|
||||
deletedChapters.size,
|
||||
deletedChapters.size,
|
||||
deletedChapters.joinToString("\n") { "${it.name}" })
|
||||
deletedChapters.joinToString("\n") { "${it.name}" }
|
||||
)
|
||||
).positiveButton(R.string.delete) {
|
||||
presenter.deleteChapters(deletedChapters, false)
|
||||
if (it.isCheckPromptChecked()) deleteRemovedPref.set(2)
|
||||
@ -502,7 +521,8 @@ class MangaDetailsController : BaseController,
|
||||
//region Recycler methods
|
||||
fun updateChapterDownload(download: Download) {
|
||||
getHolder(download.chapter)?.notifyStatus(
|
||||
download.status, presenter.isLockedFromSearch,
|
||||
download.status,
|
||||
presenter.isLockedFromSearch,
|
||||
download.progress
|
||||
)
|
||||
}
|
||||
@ -638,7 +658,8 @@ class MangaDetailsController : BaseController,
|
||||
snack?.dismiss()
|
||||
snack = view?.snack(
|
||||
if (bookmarked) R.string.removed_bookmark
|
||||
else R.string.bookmarked, Snackbar.LENGTH_INDEFINITE
|
||||
else R.string.bookmarked,
|
||||
Snackbar.LENGTH_INDEFINITE
|
||||
) {
|
||||
setAction(R.string.undo) {
|
||||
bookmarkChapters(listOf(item), bookmarked)
|
||||
@ -657,21 +678,24 @@ class MangaDetailsController : BaseController,
|
||||
snack?.dismiss()
|
||||
snack = view?.snack(
|
||||
if (read) R.string.marked_as_unread
|
||||
else R.string.marked_as_read, Snackbar.LENGTH_INDEFINITE
|
||||
else R.string.marked_as_read,
|
||||
Snackbar.LENGTH_INDEFINITE
|
||||
) {
|
||||
var undoing = false
|
||||
setAction(R.string.undo) {
|
||||
presenter.markChaptersRead(listOf(item), read, true, lastRead, pagesLeft)
|
||||
undoing = true
|
||||
}
|
||||
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||
addCallback(
|
||||
object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||
super.onDismissed(transientBottomBar, event)
|
||||
if (!undoing && !read && presenter.preferences.removeAfterMarkedAsRead()) {
|
||||
presenter.deleteChapters(listOf(item))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
(activity as? MainActivity)?.setUndoSnackBar(snack)
|
||||
}
|
||||
@ -748,7 +772,8 @@ class MangaDetailsController : BaseController,
|
||||
when (item.itemId) {
|
||||
R.id.action_edit -> {
|
||||
editMangaDialog = EditMangaDialog(
|
||||
this, presenter.manga
|
||||
this,
|
||||
presenter.manga
|
||||
)
|
||||
editMangaDialog?.showDialog(router)
|
||||
}
|
||||
@ -781,11 +806,14 @@ class MangaDetailsController : BaseController,
|
||||
|
||||
override fun prepareToShareManga() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val request = LoadRequest.Builder(activity!!).data(manga).target(onError = {
|
||||
val request = LoadRequest.Builder(activity!!).data(manga).target(
|
||||
onError = {
|
||||
shareManga()
|
||||
}, onSuccess = {
|
||||
},
|
||||
onSuccess = {
|
||||
presenter.shareManga((it as BitmapDrawable).bitmap)
|
||||
}).build()
|
||||
}
|
||||
).build()
|
||||
Coil.imageLoader(activity!!).execute(request)
|
||||
} else {
|
||||
shareManga()
|
||||
@ -825,7 +853,10 @@ class MangaDetailsController : BaseController,
|
||||
|
||||
val activity = activity ?: return
|
||||
val intent = WebViewActivity.newIntent(
|
||||
activity.applicationContext, source.id, url, presenter.manga
|
||||
activity.applicationContext,
|
||||
source.id,
|
||||
url,
|
||||
presenter.manga
|
||||
.title
|
||||
)
|
||||
startActivity(intent)
|
||||
@ -847,7 +878,9 @@ class MangaDetailsController : BaseController,
|
||||
val context = view?.context ?: return
|
||||
MaterialDialog(context).message(
|
||||
text = context.resources.getQuantityString(
|
||||
R.plurals.remove_n_chapters, chapters.size, chapters.size
|
||||
R.plurals.remove_n_chapters,
|
||||
chapters.size,
|
||||
chapters.size
|
||||
)
|
||||
).positiveButton(R.string.remove) {
|
||||
presenter.deleteChapters(chapters)
|
||||
@ -901,22 +934,27 @@ class MangaDetailsController : BaseController,
|
||||
val view = view ?: return
|
||||
presenter.downloadChapters(chapters)
|
||||
val text = view.context.getString(
|
||||
R.string.add_x_to_library, presenter.manga.mangaType
|
||||
R.string.add_x_to_library,
|
||||
presenter.manga.mangaType
|
||||
(view.context).toLowerCase(Locale.ROOT)
|
||||
)
|
||||
if (!presenter.manga.favorite && (snack == null ||
|
||||
snack?.getText() != text)
|
||||
if (!presenter.manga.favorite && (
|
||||
snack == null ||
|
||||
snack?.getText() != text
|
||||
)
|
||||
) {
|
||||
snack = view.snack(text, Snackbar.LENGTH_INDEFINITE) {
|
||||
setAction(R.string.add) {
|
||||
presenter.setFavorite(true)
|
||||
}
|
||||
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||
addCallback(
|
||||
object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||
super.onDismissed(transientBottomBar, event)
|
||||
if (snack == transientBottomBar) snack = null
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
(activity as? MainActivity)?.setUndoSnackBar(snack)
|
||||
}
|
||||
@ -935,17 +973,18 @@ class MangaDetailsController : BaseController,
|
||||
val item = presenter.getNextUnreadChapter()
|
||||
if (item != null) {
|
||||
openChapter(item.chapter)
|
||||
} else if (snack == null || snack?.getText() != view?.context?.getString(
|
||||
R.string.next_chapter_not_found
|
||||
)
|
||||
} else if (snack == null ||
|
||||
snack?.getText() != view?.context?.getString(R.string.next_chapter_not_found)
|
||||
) {
|
||||
snack = view?.snack(R.string.next_chapter_not_found, Snackbar.LENGTH_LONG) {
|
||||
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||
addCallback(
|
||||
object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||
super.onDismissed(transientBottomBar, event)
|
||||
if (snack == transientBottomBar) snack = null
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1023,7 +1062,10 @@ class MangaDetailsController : BaseController,
|
||||
categories.indexOfFirst { it.id == id }.takeIf { it != -1 }
|
||||
}.toTypedArray()
|
||||
ChangeMangaCategoriesDialog(
|
||||
this, listOf(manga), categories, preselected
|
||||
this,
|
||||
listOf(manga),
|
||||
categories,
|
||||
preselected
|
||||
).showDialog(
|
||||
router
|
||||
)
|
||||
@ -1080,12 +1122,14 @@ class MangaDetailsController : BaseController,
|
||||
setAction(R.string.undo) {
|
||||
presenter.setFavorite(true)
|
||||
}
|
||||
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||
addCallback(
|
||||
object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||
super.onDismissed(transientBottomBar, event)
|
||||
if (!presenter.manga.favorite) presenter.confirmDeletion()
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
val favButton = getHeader()?.favorite_button
|
||||
(activity as? MainActivity)?.setUndoSnackBar(snack, favButton)
|
||||
@ -1204,7 +1248,9 @@ class MangaDetailsController : BaseController,
|
||||
if (startingDLChapterPos != null) {
|
||||
val item = adapter?.getItem(startingDLChapterPos!!) as? ChapterItem
|
||||
(recycler.findViewHolderForAdapterPosition(startingDLChapterPos!!) as? ChapterHolder)?.notifyStatus(
|
||||
item?.status ?: Download.NOT_DOWNLOADED, false, 0
|
||||
item?.status ?: Download.NOT_DOWNLOADED,
|
||||
false,
|
||||
0
|
||||
)
|
||||
}
|
||||
startingDLChapterPos = null
|
||||
@ -1308,7 +1354,8 @@ class MangaDetailsController : BaseController,
|
||||
)
|
||||
duration = shortAnimationDuration.toLong()
|
||||
interpolator = DecelerateInterpolator()
|
||||
addListener(object : AnimatorListenerAdapter() {
|
||||
addListener(
|
||||
object : AnimatorListenerAdapter() {
|
||||
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
TransitionManager.endTransitions(frame_layout)
|
||||
@ -1319,7 +1366,8 @@ class MangaDetailsController : BaseController,
|
||||
TransitionManager.endTransitions(frame_layout)
|
||||
currentAnimator = null
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
start()
|
||||
}
|
||||
|
||||
@ -1351,7 +1399,8 @@ class MangaDetailsController : BaseController,
|
||||
play(ObjectAnimator.ofFloat(fullBackdrop, View.ALPHA, 0f))
|
||||
duration = shortAnimationDuration.toLong()
|
||||
interpolator = DecelerateInterpolator()
|
||||
addListener(object : AnimatorListenerAdapter() {
|
||||
addListener(
|
||||
object : AnimatorListenerAdapter() {
|
||||
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
thumbView.alpha = 1f
|
||||
@ -1368,7 +1417,8 @@ class MangaDetailsController : BaseController,
|
||||
swipe_refresh.isEnabled = true
|
||||
currentAnimator = null
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
@ -353,8 +353,10 @@ class MangaDetailsPresenter(
|
||||
val categoriesToDownload = preferences.downloadNewCategories().getOrDefault().map(String::toInt)
|
||||
val shouldDownload = categoriesToDownload.isEmpty() || getMangaCategoryIds().any { it in categoriesToDownload }
|
||||
if (shouldDownload) {
|
||||
downloadChapters(newChapters.first.sortedBy { it.chapter_number }
|
||||
.map { it.toModel() })
|
||||
downloadChapters(
|
||||
newChapters.first.sortedBy { it.chapter_number }
|
||||
.map { it.toModel() }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -419,9 +421,11 @@ class MangaDetailsPresenter(
|
||||
}
|
||||
|
||||
private fun trimException(e: java.lang.Exception): String {
|
||||
return (if (e.message?.contains(": ") == true) e.message?.split(": ")?.drop(1)
|
||||
return (
|
||||
if (e.message?.contains(": ") == true) e.message?.split(": ")?.drop(1)
|
||||
?.joinToString(": ")
|
||||
else e.message) ?: preferences.context.getString(R.string.unknown_error)
|
||||
else e.message
|
||||
) ?: preferences.context.getString(R.string.unknown_error)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -160,11 +160,13 @@ class MangaHeaderHolder(
|
||||
else expand()
|
||||
}
|
||||
manga_summary_label.text = itemView.context.getString(
|
||||
R.string.about_this_, manga.mangaType(itemView.context)
|
||||
R.string.about_this_,
|
||||
manga.mangaType(itemView.context)
|
||||
)
|
||||
with(favorite_button) {
|
||||
icon = ContextCompat.getDrawable(
|
||||
itemView.context, when {
|
||||
itemView.context,
|
||||
when {
|
||||
item.isLocked -> R.drawable.ic_lock_24dp
|
||||
manga.favorite -> R.drawable.ic_heart_24dp
|
||||
else -> R.drawable.ic_heart_outline_24dp
|
||||
@ -210,7 +212,8 @@ class MangaHeaderHolder(
|
||||
val number = adapter.decimalFormat.format(nextChapter.chapter_number.toDouble())
|
||||
if (nextChapter.chapter_number > 0) resources.getString(
|
||||
if (nextChapter.last_page_read > 0) R.string.continue_reading_chapter_
|
||||
else R.string.start_reading_chapter_, number
|
||||
else R.string.start_reading_chapter_,
|
||||
number
|
||||
)
|
||||
else {
|
||||
resources.getString(
|
||||
@ -231,14 +234,16 @@ class MangaHeaderHolder(
|
||||
}
|
||||
|
||||
manga_status.visibleIf(manga.status != 0)
|
||||
manga_status.text = (itemView.context.getString(
|
||||
manga_status.text = (
|
||||
itemView.context.getString(
|
||||
when (manga.status) {
|
||||
SManga.ONGOING -> R.string.ongoing
|
||||
SManga.COMPLETED -> R.string.completed
|
||||
SManga.LICENSED -> R.string.licensed
|
||||
else -> R.string.unknown_status
|
||||
}
|
||||
))
|
||||
)
|
||||
)
|
||||
manga_source.text = presenter.source.toString()
|
||||
|
||||
filters_text.text = presenter.currentFilters()
|
||||
@ -256,7 +261,8 @@ class MangaHeaderHolder(
|
||||
if (checked) {
|
||||
backgroundTintList = ColorStateList.valueOf(
|
||||
ColorUtils.setAlphaComponent(
|
||||
context.getResourceColor(R.attr.colorAccent), 75
|
||||
context.getResourceColor(R.attr.colorAccent),
|
||||
75
|
||||
)
|
||||
)
|
||||
strokeColor = ColorStateList.valueOf(Color.TRANSPARENT)
|
||||
@ -287,7 +293,8 @@ class MangaHeaderHolder(
|
||||
)
|
||||
|
||||
icon = ContextCompat.getDrawable(
|
||||
itemView.context, if (tracked) R.drawable
|
||||
itemView.context,
|
||||
if (tracked) R.drawable
|
||||
.ic_check_24dp else R.drawable.ic_sync_24dp
|
||||
)
|
||||
checked(tracked)
|
||||
@ -308,16 +315,22 @@ class MangaHeaderHolder(
|
||||
fun updateCover(manga: Manga) {
|
||||
if (!manga.initialized) return
|
||||
val drawable = adapter.controller.manga_cover_full?.drawable
|
||||
manga_cover.loadAny(manga, builder = {
|
||||
manga_cover.loadAny(
|
||||
manga,
|
||||
builder = {
|
||||
placeholder(drawable)
|
||||
error(drawable)
|
||||
if (manga.favorite) networkCachePolicy(CachePolicy.DISABLED)
|
||||
})
|
||||
backdrop.loadAny(manga, builder = {
|
||||
}
|
||||
)
|
||||
backdrop.loadAny(
|
||||
manga,
|
||||
builder = {
|
||||
placeholder(drawable)
|
||||
error(drawable)
|
||||
if (manga.favorite) networkCachePolicy(CachePolicy.DISABLED)
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun expand() {
|
||||
|
@ -44,7 +44,9 @@ class ChapterFilterLayout @JvmOverloads constructor(context: Context, attrs: Att
|
||||
show_download.isChecked = manga.downloadedFilter == Manga.SHOW_DOWNLOADED
|
||||
show_bookmark.isChecked = manga.bookmarkedFilter == Manga.SHOW_BOOKMARKED
|
||||
|
||||
show_all.isChecked = !(show_read.isChecked || show_unread.isChecked ||
|
||||
show_download.isChecked || show_bookmark.isChecked)
|
||||
show_all.isChecked = !(
|
||||
show_read.isChecked || show_unread.isChecked ||
|
||||
show_download.isChecked || show_bookmark.isChecked
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -58,13 +58,16 @@ class ChapterHolder(
|
||||
if (showPagesLeft && chapter.pages_left > 0) {
|
||||
statuses.add(
|
||||
itemView.resources.getQuantityString(
|
||||
R.plurals.pages_left, chapter.pages_left, chapter.pages_left
|
||||
R.plurals.pages_left,
|
||||
chapter.pages_left,
|
||||
chapter.pages_left
|
||||
)
|
||||
)
|
||||
} else if (showPagesLeft) {
|
||||
statuses.add(
|
||||
itemView.context.getString(
|
||||
R.string.page_, chapter.last_page_read + 1
|
||||
R.string.page_,
|
||||
chapter.last_page_read + 1
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -81,7 +84,10 @@ class ChapterHolder(
|
||||
}
|
||||
// this will color the scanlator the same bookmarks
|
||||
ChapterUtil.setTextViewForChapter(
|
||||
chapter_scanlator, item, showBookmark = false, hideStatus = isLocked
|
||||
chapter_scanlator,
|
||||
item,
|
||||
showBookmark = false,
|
||||
hideStatus = isLocked
|
||||
)
|
||||
chapter_scanlator.text = statuses.joinToString(" • ")
|
||||
|
||||
@ -115,9 +121,11 @@ class ChapterHolder(
|
||||
val anim3 = slideAnimation(-slide, 0f)
|
||||
anim3.startDelay = 750
|
||||
animatorSet.playSequentially(anim1, anim2, anim3)
|
||||
animatorSet.addListener(EndAnimatorListener {
|
||||
animatorSet.addListener(
|
||||
EndAnimatorListener {
|
||||
adapter.hasShownSwipeTut.set(true)
|
||||
})
|
||||
}
|
||||
)
|
||||
animatorSet.start()
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,8 @@ class ChaptersSortBottomSheet(controller: MangaDetailsController) : BottomSheetD
|
||||
val height = activity.window.decorView.rootWindowInsets.systemWindowInsetBottom
|
||||
sheetBehavior.peekHeight = 415.dpToPx + height
|
||||
|
||||
sheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
|
||||
sheetBehavior.addBottomSheetCallback(
|
||||
object : BottomSheetBehavior.BottomSheetCallback() {
|
||||
override fun onSlide(bottomSheet: View, progress: Float) {
|
||||
if (progress.isNaN())
|
||||
pill.alpha = 0f
|
||||
@ -50,7 +51,8 @@ class ChaptersSortBottomSheet(controller: MangaDetailsController) : BottomSheetD
|
||||
sheetBehavior.skipCollapsed = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
@ -89,19 +91,27 @@ class ChaptersSortBottomSheet(controller: MangaDetailsController) : BottomSheetD
|
||||
chapter_filter_layout.setCheckboxes(presenter.manga)
|
||||
|
||||
var defPref = presenter.globalSort()
|
||||
sort_group.check(if (presenter.manga.sortDescending(defPref)) R.id.sort_newest else
|
||||
R.id.sort_oldest)
|
||||
sort_group.check(
|
||||
if (presenter.manga.sortDescending(defPref)) R.id.sort_newest else
|
||||
R.id.sort_oldest
|
||||
)
|
||||
|
||||
hide_titles.isChecked = presenter.manga.displayMode != Manga.DISPLAY_NAME
|
||||
sort_method_group.check(if (presenter.manga.sorting == Manga.SORTING_SOURCE) R.id.sort_by_source else
|
||||
R.id.sort_by_number)
|
||||
sort_method_group.check(
|
||||
if (presenter.manga.sorting == Manga.SORTING_SOURCE) R.id.sort_by_source else
|
||||
R.id.sort_by_number
|
||||
)
|
||||
|
||||
set_as_default_sort.visInvisIf(defPref != presenter.manga.sortDescending() &&
|
||||
presenter.manga.usesLocalSort())
|
||||
set_as_default_sort.visInvisIf(
|
||||
defPref != presenter.manga.sortDescending() &&
|
||||
presenter.manga.usesLocalSort()
|
||||
)
|
||||
sort_group.setOnCheckedChangeListener { _, checkedId ->
|
||||
presenter.setSortOrder(checkedId == R.id.sort_newest)
|
||||
set_as_default_sort.visInvisIf(defPref != presenter.manga.sortDescending() &&
|
||||
presenter.manga.usesLocalSort())
|
||||
set_as_default_sort.visInvisIf(
|
||||
defPref != presenter.manga.sortDescending() &&
|
||||
presenter.manga.usesLocalSort()
|
||||
)
|
||||
}
|
||||
|
||||
set_as_default_sort.setOnClickListener {
|
||||
|
@ -19,9 +19,11 @@ class SetTrackChaptersDialog<T> : DialogController
|
||||
private val item: TrackItem
|
||||
private lateinit var listener: Listener
|
||||
|
||||
constructor(target: T, item: TrackItem) : super(Bundle().apply {
|
||||
constructor(target: T, item: TrackItem) : super(
|
||||
Bundle().apply {
|
||||
putSerializable(KEY_ITEM_TRACK, item.track)
|
||||
}) {
|
||||
}
|
||||
) {
|
||||
listener = target
|
||||
this.item = item
|
||||
}
|
||||
|
@ -18,9 +18,11 @@ class SetTrackScoreDialog<T> : DialogController where T : SetTrackScoreDialog.Li
|
||||
private val item: TrackItem
|
||||
private lateinit var listener: Listener
|
||||
|
||||
constructor(target: T, item: TrackItem) : super(Bundle().apply {
|
||||
constructor(target: T, item: TrackItem) : super(
|
||||
Bundle().apply {
|
||||
putSerializable(KEY_ITEM_TRACK, item.track)
|
||||
}) {
|
||||
}
|
||||
) {
|
||||
listener = target
|
||||
this.item = item
|
||||
}
|
||||
|
@ -17,9 +17,11 @@ class SetTrackStatusDialog<T> : DialogController
|
||||
private val item: TrackItem
|
||||
private lateinit var listener: Listener
|
||||
|
||||
constructor(target: T, item: TrackItem) : super(Bundle().apply {
|
||||
constructor(target: T, item: TrackItem) : super(
|
||||
Bundle().apply {
|
||||
putSerializable(KEY_ITEM_TRACK, item.track)
|
||||
}) {
|
||||
}
|
||||
) {
|
||||
listener = target
|
||||
this.item = item
|
||||
}
|
||||
@ -40,8 +42,11 @@ class SetTrackStatusDialog<T> : DialogController
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.status)
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.listItemsSingleChoice(items = statusString, initialSelection = selectedIndex,
|
||||
waitForPositiveButton = false) { dialog, position, _ ->
|
||||
.listItemsSingleChoice(
|
||||
items = statusString,
|
||||
initialSelection = selectedIndex,
|
||||
waitForPositiveButton = false
|
||||
) { dialog, position, _ ->
|
||||
listener.setStatus(item, position)
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
@ -42,10 +42,13 @@ class TrackHolder(view: View, adapter: TrackAdapter) : BaseViewHolder(view) {
|
||||
R.string.all_chapters_read
|
||||
)
|
||||
track.total_chapters > 0 -> context.getString(
|
||||
R.string.chapter_x_of_y, track.last_chapter_read, track.total_chapters
|
||||
R.string.chapter_x_of_y,
|
||||
track.last_chapter_read,
|
||||
track.total_chapters
|
||||
)
|
||||
track.last_chapter_read > 0 -> context.getString(
|
||||
R.string.chapter_, track.last_chapter_read.toString()
|
||||
R.string.chapter_,
|
||||
track.last_chapter_read.toString()
|
||||
)
|
||||
else -> context.getString(R.string.not_started)
|
||||
}
|
||||
|
@ -19,9 +19,11 @@ class TrackRemoveDialog<T> : DialogController
|
||||
private val item: TrackItem
|
||||
private lateinit var listener: Listener
|
||||
|
||||
constructor(target: T, item: TrackItem) : super(Bundle().apply {
|
||||
constructor(target: T, item: TrackItem) : super(
|
||||
Bundle().apply {
|
||||
putSerializable(KEY_ITEM_TRACK, item.track)
|
||||
}) {
|
||||
}
|
||||
) {
|
||||
listener = target
|
||||
this.item = item
|
||||
}
|
||||
@ -42,11 +44,15 @@ class TrackRemoveDialog<T> : DialogController
|
||||
if (item.service.canRemoveFromService()) {
|
||||
dialog.checkBoxPrompt(
|
||||
text = activity!!.getString(
|
||||
R.string.remove_tracking_from_, item.service.name
|
||||
), isCheckedDefault = true, onToggle = null
|
||||
R.string.remove_tracking_from_,
|
||||
item.service.name
|
||||
),
|
||||
isCheckedDefault = true,
|
||||
onToggle = null
|
||||
).positiveButton(R.string.remove) {
|
||||
listener.removeTracker(
|
||||
item, it.isCheckPromptChecked()
|
||||
item,
|
||||
it.isCheckPromptChecked()
|
||||
)
|
||||
}
|
||||
dialog.getCheckBoxPrompt().textSize = 16f
|
||||
|
@ -43,10 +43,12 @@ class TrackSearchDialog : DialogController {
|
||||
|
||||
private lateinit var presenter: MangaDetailsPresenter
|
||||
|
||||
constructor(target: TrackingBottomSheet, service: TrackService, wasTracked: Boolean) : super(Bundle()
|
||||
constructor(target: TrackingBottomSheet, service: TrackService, wasTracked: Boolean) : super(
|
||||
Bundle()
|
||||
.apply {
|
||||
putInt(KEY_SERVICE, service.id)
|
||||
}) {
|
||||
}
|
||||
) {
|
||||
wasPreviouslyTracked = wasTracked
|
||||
bottomSheet = target
|
||||
presenter = target.presenter
|
||||
|
@ -19,7 +19,8 @@ import eu.kanade.tachiyomi.util.view.setEdgeToEdge
|
||||
import kotlinx.android.synthetic.main.tracking_bottom_sheet.*
|
||||
import timber.log.Timber
|
||||
|
||||
class TrackingBottomSheet(private val controller: MangaDetailsController) : BottomSheetDialog
|
||||
class TrackingBottomSheet(private val controller: MangaDetailsController) :
|
||||
BottomSheetDialog
|
||||
(controller.activity!!, R.style.BottomSheetDialogTheme),
|
||||
TrackAdapter.OnClickListener,
|
||||
SetTrackStatusDialog.Listener,
|
||||
@ -45,7 +46,8 @@ class TrackingBottomSheet(private val controller: MangaDetailsController) : Bott
|
||||
val height = activity.window.decorView.rootWindowInsets.systemWindowInsetBottom
|
||||
sheetBehavior.peekHeight = 380.dpToPx + height
|
||||
|
||||
sheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
|
||||
sheetBehavior.addBottomSheetCallback(
|
||||
object : BottomSheetBehavior.BottomSheetCallback() {
|
||||
override fun onSlide(bottomSheet: View, progress: Float) { }
|
||||
|
||||
override fun onStateChanged(p0: View, state: Int) {
|
||||
@ -53,7 +55,8 @@ class TrackingBottomSheet(private val controller: MangaDetailsController) : Bott
|
||||
sheetBehavior.skipCollapsed = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user