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