Cleanup resources and put comments where SY code is different from preview code
This commit is contained in:
parent
7e5d095f8d
commit
4ef72194bb
@ -46,9 +46,11 @@ class AppModule(val app: Application) : InjektModule {
|
||||
|
||||
addSingletonFactory { Gson() }
|
||||
|
||||
// SY -->
|
||||
addSingletonFactory { EHentaiUpdateHelper(app) }
|
||||
|
||||
addSingletonFactory { Markwon.create(app) }
|
||||
// SY <--
|
||||
|
||||
// Asynchronously init expensive components for a faster cold start
|
||||
|
||||
|
@ -151,9 +151,10 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
|
||||
|
||||
// Backup extension ID/name mapping
|
||||
backupExtensionInfo(extensionEntries, extensions)
|
||||
|
||||
// SY -->
|
||||
root[SAVEDSEARCHES] =
|
||||
Injekt.get<PreferencesHelper>().eh_savedSearches().get().joinToString(separator = "***")
|
||||
// SY <--
|
||||
}
|
||||
|
||||
try {
|
||||
@ -306,6 +307,7 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
|
||||
* @return [Observable] that contains manga
|
||||
*/
|
||||
fun restoreChapterFetchObservable(source: Source, manga: Manga, chapters: List<Chapter>, throttleManager: EHentaiThrottleManager): Observable<Pair<List<Chapter>, List<Chapter>>> {
|
||||
// SY -->
|
||||
return (
|
||||
if (source is EHentai) {
|
||||
source.fetchChapterList(manga, throttleManager::throttle)
|
||||
@ -322,6 +324,7 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
|
||||
syncChaptersWithSource(databaseHelper, it, manga, source)
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
.doOnNext { pair ->
|
||||
if (pair.first.isNotEmpty()) {
|
||||
chapters.forEach { it.manga_id = manga.id }
|
||||
@ -496,6 +499,7 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
|
||||
return true
|
||||
}
|
||||
|
||||
// SY -->
|
||||
internal fun restoreSavedSearches(jsonSavedSearches: JsonElement) {
|
||||
val backupSavedSearches = jsonSavedSearches.asString.split("***").toSet()
|
||||
backupSavedSearches.forEach {
|
||||
@ -505,6 +509,7 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Returns manga
|
||||
|
@ -103,7 +103,9 @@ class BackupRestoreService : Service() {
|
||||
|
||||
private var job: Job? = null
|
||||
|
||||
// SY -->
|
||||
private val throttleManager = EHentaiThrottleManager()
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* The progress of a backup restore
|
||||
@ -115,9 +117,11 @@ class BackupRestoreService : Service() {
|
||||
*/
|
||||
private var restoreAmount = 0
|
||||
|
||||
// SY -->
|
||||
private var skippedAmount = 0
|
||||
|
||||
private var totalAmount = 0
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Mapping of source ID to source name from backup data
|
||||
@ -178,7 +182,9 @@ class BackupRestoreService : Service() {
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
val uri = intent?.getParcelableExtra<Uri>(BackupConst.EXTRA_URI) ?: return START_NOT_STICKY
|
||||
|
||||
// SY -->
|
||||
throttleManager.resetThrottle()
|
||||
// SY <--
|
||||
|
||||
// Cancel any previous job if needed.
|
||||
job?.cancel()
|
||||
@ -221,6 +227,7 @@ class BackupRestoreService : Service() {
|
||||
|
||||
val mangasJson = json.get(MANGAS).asJsonArray
|
||||
|
||||
// SY -->
|
||||
val validManga = mangasJson.filter {
|
||||
var manga = backupManager.parser.fromJson<MangaImpl>(it.asJsonObject.get(MANGA))
|
||||
// EXH -->
|
||||
@ -235,13 +242,16 @@ class BackupRestoreService : Service() {
|
||||
totalAmount = mangasJson.size()
|
||||
restoreAmount = validManga.count() + 1 // +1 for categories
|
||||
skippedAmount = mangasJson.size() - validManga.count()
|
||||
// SY <--
|
||||
restoreProgress = 0
|
||||
errors.clear()
|
||||
|
||||
// Restore categories
|
||||
json.get(CATEGORIES)?.let { restoreCategories(it) }
|
||||
|
||||
// SY -->
|
||||
json.get(SAVEDSEARCHES)?.let { restoreSavedSearches(it) }
|
||||
// SY <--
|
||||
|
||||
// Store source mapping for error messages
|
||||
sourceMapping = BackupRestoreValidator.getSourceMapping(json)
|
||||
@ -273,15 +283,19 @@ class BackupRestoreService : Service() {
|
||||
showRestoreProgress(restoreProgress, restoreAmount, getString(R.string.categories))
|
||||
}
|
||||
|
||||
// SY -->
|
||||
private fun restoreSavedSearches(savedSearchesJson: JsonElement) {
|
||||
backupManager.restoreSavedSearches(savedSearchesJson)
|
||||
|
||||
restoreProgress += 1
|
||||
showRestoreProgress(restoreProgress, restoreAmount, getString(R.string.eh_saved_searches))
|
||||
}
|
||||
// SY <--
|
||||
|
||||
private fun restoreManga(mangaJson: JsonObject) {
|
||||
// SY -->
|
||||
var manga = backupManager.parser.fromJson<MangaImpl>(mangaJson.get(MANGA))
|
||||
// SY <--
|
||||
val chapters = backupManager.parser.fromJson<List<ChapterImpl>>(
|
||||
mangaJson.get(CHAPTERS)
|
||||
?: JsonArray()
|
||||
@ -437,7 +451,9 @@ class BackupRestoreService : Service() {
|
||||
* @return [Observable] that contains manga
|
||||
*/
|
||||
private fun chapterFetchObservable(source: Source, manga: Manga, chapters: List<Chapter>): Observable<Pair<List<Chapter>, List<Chapter>>> {
|
||||
// SY -->
|
||||
return backupManager.restoreChapterFetchObservable(source, manga, chapters, throttleManager)
|
||||
// SY <--
|
||||
// If there's any error, return empty update and continue.
|
||||
.onErrorReturn {
|
||||
errors.add(Date() to "${manga.title} - ${it.message}")
|
||||
|
@ -17,7 +17,9 @@ object Backup {
|
||||
const val EXTENSIONS = "extensions"
|
||||
const val HISTORY = "history"
|
||||
const val VERSION = "version"
|
||||
// SY -->
|
||||
const val SAVEDSEARCHES = "savedsearches"
|
||||
// SY <--
|
||||
|
||||
fun getDefaultFilename(): String {
|
||||
val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date())
|
||||
|
@ -60,5 +60,7 @@ open class DatabaseHelper(context: Context) :
|
||||
|
||||
inline fun inTransaction(block: () -> Unit) = db.inTransaction(block)
|
||||
|
||||
// SY -->
|
||||
fun lowLevel() = db.lowLevel()
|
||||
// SY <--
|
||||
}
|
||||
|
@ -41,8 +41,10 @@ class CategoryPutResolver : DefaultPutResolver<Category>() {
|
||||
put(COL_NAME, obj.name)
|
||||
put(COL_ORDER, obj.order)
|
||||
put(COL_FLAGS, obj.flags)
|
||||
// SY -->
|
||||
val orderString = obj.mangaOrder.joinToString("/")
|
||||
put(COL_MANGA_ORDER, orderString)
|
||||
// SY <--
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,8 +56,10 @@ class CategoryGetResolver : DefaultGetResolver<Category>() {
|
||||
order = cursor.getInt(cursor.getColumnIndex(COL_ORDER))
|
||||
flags = cursor.getInt(cursor.getColumnIndex(COL_FLAGS))
|
||||
|
||||
// SY -->
|
||||
val orderString = cursor.getString(cursor.getColumnIndex(COL_MANGA_ORDER))
|
||||
mangaOrder = orderString?.split("/")?.mapNotNull { it.toLongOrNull() } ?: emptyList()
|
||||
// SY <--
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,9 @@ interface Category : Serializable {
|
||||
|
||||
var flags: Int
|
||||
|
||||
// SY -->
|
||||
var mangaOrder: List<Long>
|
||||
// SY <--
|
||||
|
||||
val nameLower: String
|
||||
get() = name.toLowerCase()
|
||||
|
@ -10,7 +10,9 @@ class CategoryImpl : Category {
|
||||
|
||||
override var flags: Int = 0
|
||||
|
||||
// SY -->
|
||||
override var mangaOrder: List<Long> = emptyList()
|
||||
// SY <--
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
|
@ -8,7 +8,9 @@ open class MangaImpl : Manga {
|
||||
|
||||
override lateinit var url: String
|
||||
|
||||
// SY -->
|
||||
override var title: String = ""
|
||||
// SY <--
|
||||
|
||||
override var artist: String? = null
|
||||
|
||||
|
@ -14,7 +14,7 @@ import eu.kanade.tachiyomi.data.database.tables.ChapterTable
|
||||
import java.util.Date
|
||||
|
||||
interface ChapterQueries : DbProvider {
|
||||
|
||||
// SY -->
|
||||
fun getChapters(manga: Manga) = getChaptersByMangaId(manga.id)
|
||||
|
||||
fun getChaptersByMangaId(mangaId: Long?) = db.get()
|
||||
@ -36,6 +36,7 @@ interface ChapterQueries : DbProvider {
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
// SY <--
|
||||
|
||||
fun getRecentChapters(date: Date) = db.get()
|
||||
.listOfObjects(MangaChapter::class.java)
|
||||
@ -82,6 +83,7 @@ interface ChapterQueries : DbProvider {
|
||||
)
|
||||
.prepare()
|
||||
|
||||
// SY -->
|
||||
fun getChapters(url: String) = db.get()
|
||||
.listOfObjects(Chapter::class.java)
|
||||
.withQuery(
|
||||
@ -92,6 +94,7 @@ interface ChapterQueries : DbProvider {
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
// SY <--
|
||||
|
||||
fun insertChapter(chapter: Chapter) = db.put().`object`(chapter).prepare()
|
||||
|
||||
|
@ -18,6 +18,7 @@ interface HistoryQueries : DbProvider {
|
||||
*/
|
||||
fun insertHistory(history: History) = db.put().`object`(history).prepare()
|
||||
|
||||
// SY -->
|
||||
/**
|
||||
* Returns history of recent manga containing last read chapter
|
||||
* @param date recent date range
|
||||
@ -50,6 +51,7 @@ interface HistoryQueries : DbProvider {
|
||||
)
|
||||
.withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
|
||||
.prepare()
|
||||
// SY <--
|
||||
|
||||
fun getHistoryByMangaId(mangaId: Long) = db.get()
|
||||
.listOfObjects(History::class.java)
|
||||
|
@ -26,12 +26,14 @@ interface MangaCategoryQueries : DbProvider {
|
||||
|
||||
fun setMangaCategories(mangasCategories: List<MangaCategory>, mangas: List<Manga>) {
|
||||
db.inTransaction {
|
||||
// SY -->
|
||||
mangas.chunked(100) { chunk ->
|
||||
deleteOldMangasCategories(chunk).executeAsBlocking()
|
||||
}
|
||||
mangasCategories.chunked(100) { chunk ->
|
||||
insertMangasCategories(chunk).executeAsBlocking()
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ interface MangaQueries : DbProvider {
|
||||
)
|
||||
.prepare()
|
||||
|
||||
// SY -->
|
||||
fun getMergedMangas(id: Long) = db.get()
|
||||
.listOfObjects(Manga::class.java)
|
||||
.withQuery(
|
||||
@ -83,6 +84,7 @@ interface MangaQueries : DbProvider {
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
// SY <--
|
||||
|
||||
fun insertManga(manga: Manga) = db.put().`object`(manga).prepare()
|
||||
|
||||
@ -170,6 +172,7 @@ interface MangaQueries : DbProvider {
|
||||
)
|
||||
.prepare()
|
||||
|
||||
// SY -->
|
||||
fun getMangaWithMetadata() = db.get()
|
||||
.listOfObjects(Manga::class.java)
|
||||
.withQuery(
|
||||
@ -219,4 +222,5 @@ interface MangaQueries : DbProvider {
|
||||
.build()
|
||||
)
|
||||
.prepare()
|
||||
// SY <--
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable as MangaCateg
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable as Manga
|
||||
import eu.kanade.tachiyomi.data.database.tables.MergedTable as Merged
|
||||
|
||||
// SY -->
|
||||
/**
|
||||
* Query to get the manga merged into a merged manga
|
||||
*/
|
||||
@ -32,6 +33,7 @@ fun getMergedChaptersQuery(id: Long) =
|
||||
JOIN ${Chapter.TABLE}
|
||||
ON ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = M.${Merged.COL_MANGA_ID}
|
||||
"""
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Query to get the manga from the library, with their categories and unread count.
|
||||
@ -76,6 +78,7 @@ fun getRecentsQuery() =
|
||||
* and are read after the given time period
|
||||
* @return return limit is 25
|
||||
*/
|
||||
// SY -->
|
||||
fun getRecentMangasQuery(offset: Int = 0, search: String = "") =
|
||||
"""
|
||||
SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.*
|
||||
@ -122,6 +125,7 @@ fun getRecentMangasLimitQuery(limit: Int = 25, search: String = "") =
|
||||
ORDER BY max_last_read.${History.COL_LAST_READ} DESC
|
||||
LIMIT $limit
|
||||
"""
|
||||
// SY <--
|
||||
|
||||
fun getHistoryByMangaId() =
|
||||
"""
|
||||
|
@ -1,32 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.database.resolvers
|
||||
|
||||
import android.content.ContentValues
|
||||
import com.pushtorefresh.storio.sqlite.StorIOSQLite
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.PutResolver
|
||||
import com.pushtorefresh.storio.sqlite.operations.put.PutResult
|
||||
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
|
||||
import eu.kanade.tachiyomi.data.database.inTransactionReturn
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
|
||||
// [EXH]
|
||||
class MangaUrlPutResolver : PutResolver<Manga>() {
|
||||
|
||||
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
|
||||
val updateQuery = mapToUpdateQuery(manga)
|
||||
val contentValues = mapToContentValues(manga)
|
||||
|
||||
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
|
||||
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
|
||||
}
|
||||
|
||||
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_ID} = ?")
|
||||
.whereArgs(manga.id)
|
||||
.build()
|
||||
|
||||
fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
|
||||
put(MangaTable.COL_URL, manga.url)
|
||||
}
|
||||
}
|
@ -12,7 +12,9 @@ object CategoryTable {
|
||||
|
||||
const val COL_FLAGS = "flags"
|
||||
|
||||
// SY -->
|
||||
const val COL_MANGA_ORDER = "manga_order"
|
||||
// SY <--
|
||||
|
||||
val createTableQuery: String
|
||||
get() =
|
||||
@ -21,9 +23,12 @@ object CategoryTable {
|
||||
$COL_NAME TEXT NOT NULL,
|
||||
$COL_ORDER INTEGER NOT NULL,
|
||||
$COL_FLAGS INTEGER NOT NULL,
|
||||
// SY -->
|
||||
$COL_MANGA_ORDER TEXT NOT NULL
|
||||
// SY <--
|
||||
)"""
|
||||
|
||||
// SY -->
|
||||
val addMangaOrder: String
|
||||
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_MANGA_ORDER TEXT"
|
||||
// SY <--
|
||||
}
|
||||
|
@ -6,7 +6,9 @@ abstract class UpdateChecker {
|
||||
|
||||
companion object {
|
||||
fun getUpdateChecker(): UpdateChecker {
|
||||
// SY -->
|
||||
return GithubUpdateChecker()
|
||||
// SY <--
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,9 +24,11 @@ interface GithubService {
|
||||
}
|
||||
}
|
||||
|
||||
// SY -->
|
||||
@GET("/repos/jobobby04/tachiyomiSY/releases/latest")
|
||||
suspend fun getLatestVersion(): GithubRelease
|
||||
|
||||
@GET("/repos/jobobby04/TachiyomiSYPreview/releases/latest")
|
||||
suspend fun getLatestDebugVersion(): GithubRelease
|
||||
// SY <--
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.data.updater.UpdateChecker
|
||||
import eu.kanade.tachiyomi.data.updater.UpdateResult
|
||||
import exh.syDebugVersion
|
||||
|
||||
// SY -->
|
||||
class GithubUpdateChecker(val debug: Boolean = false) : UpdateChecker() {
|
||||
|
||||
private val service: GithubService = GithubService.create()
|
||||
@ -25,3 +25,4 @@ class GithubUpdateChecker(val debug: Boolean = false) : UpdateChecker() {
|
||||
}
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
@ -79,6 +79,7 @@ class ExtensionManager(
|
||||
return iconMap[pkgName] ?: iconMap.getOrPut(pkgName) { context.packageManager.getApplicationIcon(pkgName) }
|
||||
}
|
||||
|
||||
// SY -->
|
||||
return when (source.id) {
|
||||
EH_SOURCE_ID -> context.getDrawable(R.mipmap.ic_ehentai_source)
|
||||
EXH_SOURCE_ID -> context.getDrawable(R.mipmap.ic_ehentai_source)
|
||||
@ -91,6 +92,7 @@ class ExtensionManager(
|
||||
MERGED_SOURCE_ID -> context.getDrawable(R.mipmap.ic_merged_source)
|
||||
else -> null
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,7 +110,9 @@ class ExtensionManager(
|
||||
updatedInstalledExtensionsStatuses(value)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
var unalteredAvailableExtensions = emptyList<Extension.Available>()
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Relay used to notify the untrusted extensions.
|
||||
@ -155,7 +159,9 @@ class ExtensionManager(
|
||||
untrustedExtensions = extensions
|
||||
.filterIsInstance<LoadResult.Untrusted>()
|
||||
.map { it.extension }
|
||||
// SY -->
|
||||
.filterNotBlacklisted()
|
||||
// SY <--
|
||||
}
|
||||
|
||||
// EXH -->
|
||||
@ -210,8 +216,10 @@ class ExtensionManager(
|
||||
emptyList()
|
||||
}
|
||||
|
||||
// SY -->
|
||||
unalteredAvailableExtensions = extensions
|
||||
availableExtensions = extensions.filterNotBlacklisted()
|
||||
// SY <--
|
||||
}
|
||||
}
|
||||
|
||||
@ -231,14 +239,18 @@ class ExtensionManager(
|
||||
|
||||
for ((index, installedExt) in mutInstalledExtensions.withIndex()) {
|
||||
val pkgName = installedExt.pkgName
|
||||
// SY -->
|
||||
val availableExt = unalteredAvailableExtensions.find { it.pkgName == pkgName }
|
||||
// SY <--
|
||||
|
||||
if (availableExt == null && !installedExt.isObsolete) {
|
||||
mutInstalledExtensions[index] = installedExt.copy(isObsolete = true)
|
||||
changed = true
|
||||
// SY -->
|
||||
} else if (installedExt.isBlacklisted() && !installedExt.isRedundant) {
|
||||
mutInstalledExtensions[index] = installedExt.copy(isRedundant = true)
|
||||
changed = true
|
||||
// SY <--
|
||||
} else if (availableExt != null) {
|
||||
val hasUpdate = availableExt.versionCode > installedExt.versionCode
|
||||
if (installedExt.hasUpdate != hasUpdate) {
|
||||
@ -334,10 +346,12 @@ class ExtensionManager(
|
||||
* @param extension The extension to be registered.
|
||||
*/
|
||||
private fun registerNewExtension(extension: Extension.Installed) {
|
||||
// SY -->
|
||||
if (extension.isBlacklisted()) {
|
||||
XLog.d("[EXH] Removing blacklisted extension: (name: String, pkgName: %s)!", extension.name, extension.pkgName)
|
||||
return
|
||||
}
|
||||
// SY <--
|
||||
|
||||
installedExtensions += extension
|
||||
extension.sources.forEach { sourceManager.registerSource(it) }
|
||||
@ -350,10 +364,12 @@ class ExtensionManager(
|
||||
* @param extension The extension to be registered.
|
||||
*/
|
||||
private fun registerUpdatedExtension(extension: Extension.Installed) {
|
||||
// SY -->
|
||||
if (extension.isBlacklisted()) {
|
||||
XLog.d("[EXH] Removing blacklisted extension: (name: String, pkgName: %s)!", extension.name, extension.pkgName)
|
||||
return
|
||||
}
|
||||
// SY <--
|
||||
|
||||
val mutInstalledExtensions = installedExtensions.toMutableList()
|
||||
val oldExtension = mutInstalledExtensions.find { it.pkgName == extension.pkgName }
|
||||
|
@ -47,12 +47,16 @@ internal class ExtensionGithubApi {
|
||||
|
||||
preferences.lastExtCheck().set(Date().time)
|
||||
|
||||
// SY -->
|
||||
val blacklistEnabled = preferences.eh_enableSourceBlacklist().get()
|
||||
// SY <--
|
||||
|
||||
val installedExtensions = ExtensionLoader.loadExtensions(context)
|
||||
.filterIsInstance<LoadResult.Success>()
|
||||
.map { it.extension }
|
||||
// SY -->
|
||||
.filterNot { it.isBlacklisted(blacklistEnabled) }
|
||||
// SY <--
|
||||
|
||||
val extensionsWithUpdate = mutableListOf<Extension.Installed>()
|
||||
for (installedExt in installedExtensions) {
|
||||
@ -96,12 +100,14 @@ internal class ExtensionGithubApi {
|
||||
return "$REPO_URL/apk/${extension.apkName}"
|
||||
}
|
||||
|
||||
// SY -->
|
||||
fun Extension.isBlacklisted(
|
||||
blacklistEnabled: Boolean =
|
||||
preferences.eh_enableSourceBlacklist().get()
|
||||
): Boolean {
|
||||
return pkgName in BlacklistedSources.BLACKLISTED_EXTENSIONS && blacklistEnabled
|
||||
}
|
||||
// SY <--
|
||||
|
||||
companion object {
|
||||
private const val REPO_URL = "https://raw.githubusercontent.com/inorichi/tachiyomi-extensions/repo"
|
||||
|
@ -20,7 +20,9 @@ sealed class Extension {
|
||||
val hasUpdate: Boolean = false,
|
||||
val isObsolete: Boolean = false,
|
||||
val isUnofficial: Boolean = false,
|
||||
// SY -->
|
||||
val isRedundant: Boolean = false
|
||||
// SY <--
|
||||
) : Extension()
|
||||
|
||||
data class Available(
|
||||
|
@ -6,6 +6,7 @@ import java.util.concurrent.TimeUnit
|
||||
import okhttp3.Cache
|
||||
import okhttp3.OkHttpClient
|
||||
|
||||
// SY -->
|
||||
open class NetworkHelper(context: Context) {
|
||||
|
||||
private val cacheDir = File(context.cacheDir, "network_cache")
|
||||
@ -26,3 +27,4 @@ open class NetworkHelper(context: Context) {
|
||||
.addInterceptor(CloudflareInterceptor(context))
|
||||
.build()
|
||||
}
|
||||
// SY <--
|
||||
|
@ -47,3 +47,5 @@ interface Source {
|
||||
}
|
||||
|
||||
fun Source.icon(): Drawable? = Injekt.get<ExtensionManager>().getAppIconForSource(this)
|
||||
|
||||
fun Source.getPreferenceKey(): String = "source_$id"
|
||||
|
@ -37,23 +37,27 @@ import uy.kohesive.injekt.injectLazy
|
||||
|
||||
open class SourceManager(private val context: Context) {
|
||||
|
||||
private val prefs: PreferencesHelper by injectLazy()
|
||||
|
||||
private val sourcesMap = mutableMapOf<Long, Source>()
|
||||
|
||||
private val stubSourcesMap = mutableMapOf<Long, StubSource>()
|
||||
|
||||
// SY -->
|
||||
private val prefs: PreferencesHelper by injectLazy()
|
||||
|
||||
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
// SY <--
|
||||
|
||||
init {
|
||||
createInternalSources().forEach { registerSource(it) }
|
||||
|
||||
// SY -->
|
||||
// Recreate sources when they change
|
||||
prefs.enableExhentai().asFlow().onEach {
|
||||
createEHSources().forEach { registerSource(it) }
|
||||
}.launchIn(scope)
|
||||
|
||||
registerSource(MergedSource())
|
||||
// SY <--
|
||||
}
|
||||
|
||||
open fun get(sourceKey: Long): Source? {
|
||||
@ -70,9 +74,11 @@ open class SourceManager(private val context: Context) {
|
||||
|
||||
fun getCatalogueSources() = sourcesMap.values.filterIsInstance<CatalogueSource>()
|
||||
|
||||
// SY -->
|
||||
fun getVisibleCatalogueSources() = sourcesMap.values.filterIsInstance<CatalogueSource>().filter {
|
||||
it.id !in BlacklistedSources.HIDDEN_SOURCES
|
||||
}
|
||||
// SY <--
|
||||
|
||||
internal fun registerSource(source: Source, overwrite: Boolean = false) {
|
||||
// EXH -->
|
||||
@ -105,6 +111,7 @@ open class SourceManager(private val context: Context) {
|
||||
LocalSource(context)
|
||||
)
|
||||
|
||||
// SY -->
|
||||
private fun createEHSources(): List<Source> {
|
||||
val exSrcs = mutableListOf<HttpSource>(
|
||||
EHentai(EH_SOURCE_ID, false, context)
|
||||
@ -120,6 +127,7 @@ open class SourceManager(private val context: Context) {
|
||||
exSrcs += HBrowse()
|
||||
return exSrcs
|
||||
}
|
||||
// SY <--
|
||||
|
||||
private inner class StubSource(override val id: Long) : Source {
|
||||
|
||||
@ -147,6 +155,7 @@ open class SourceManager(private val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// SY -->
|
||||
companion object {
|
||||
val DELEGATED_SOURCES = listOf(
|
||||
DelegatedSource(
|
||||
@ -176,6 +185,7 @@ open class SourceManager(private val context: Context) {
|
||||
val newSourceClass: KClass<out DelegatedHttpSource>
|
||||
)
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
class SourceNotFoundException(message: String, val id: Long) : Exception(message)
|
||||
|
@ -6,7 +6,9 @@ import rx.subjects.Subject
|
||||
|
||||
open class Page(
|
||||
val index: Int,
|
||||
// SY -->
|
||||
var url: String = "",
|
||||
// SY <--
|
||||
var imageUrl: String? = null,
|
||||
@Transient var uri: Uri? = null // Deprecated but can't be deleted due to extensions
|
||||
) : ProgressListener {
|
||||
|
@ -61,7 +61,9 @@ interface SManga : Serializable {
|
||||
const val ONGOING = 1
|
||||
const val COMPLETED = 2
|
||||
const val LICENSED = 3
|
||||
// SY -->
|
||||
const val RECOMMENDS = 69 // nice
|
||||
// SY <--
|
||||
|
||||
fun create(): SManga {
|
||||
return SMangaImpl()
|
||||
|
@ -4,7 +4,9 @@ class SMangaImpl : SManga {
|
||||
|
||||
override lateinit var url: String
|
||||
|
||||
// SY -->
|
||||
override var title: String = ""
|
||||
// SY <--
|
||||
|
||||
override var artist: String? = null
|
||||
|
||||
|
@ -34,6 +34,7 @@ abstract class HttpSource : CatalogueSource {
|
||||
/**
|
||||
* Network service.
|
||||
*/
|
||||
// SY -->
|
||||
protected val network: NetworkHelper by lazy {
|
||||
val original = Injekt.get<NetworkHelper>()
|
||||
object : NetworkHelper(Injekt.get<Application>()) {
|
||||
@ -53,12 +54,13 @@ abstract class HttpSource : CatalogueSource {
|
||||
get() = original.cookieManager
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
// /**
|
||||
// * Preferences that a source may need.
|
||||
// */
|
||||
// val preferences: SharedPreferences by lazy {
|
||||
// Injekt.get<Application>().getSharedPreferences("source_$id", Context.MODE_PRIVATE)
|
||||
// Injekt.get<Application>().getSharedPreferences(source.getPreferenceKey(), Context.MODE_PRIVATE)
|
||||
// }
|
||||
|
||||
/**
|
||||
@ -92,7 +94,9 @@ abstract class HttpSource : CatalogueSource {
|
||||
* Default network client for doing requests.
|
||||
*/
|
||||
open val client: OkHttpClient
|
||||
// SY -->
|
||||
get() = delegate?.baseHttpClient ?: network.client
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Headers builder for requests. Implementations can override this method for custom headers.
|
||||
@ -323,7 +327,7 @@ abstract class HttpSource : CatalogueSource {
|
||||
*
|
||||
* @param page the page whose source image has to be downloaded.
|
||||
*/
|
||||
open fun fetchImage(page: Page): Observable<Response> {
|
||||
/* SY --> */ open /* SY <-- */ fun fetchImage(page: Page): Observable<Response> {
|
||||
return client.newCallWithProgress(imageRequest(page), page)
|
||||
.asObservableSuccess()
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
|
||||
abstract class BaseViewHolder(view: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(view), LayoutContainer {
|
||||
abstract class BaseViewHolder(view: View) : RecyclerView.ViewHolder(view), LayoutContainer {
|
||||
|
||||
override val containerView: View?
|
||||
get() = itemView
|
||||
|
@ -101,7 +101,9 @@ class BrowseController :
|
||||
activity?.tabs?.apply {
|
||||
val updates = preferences.extensionUpdatesCount().get()
|
||||
if (updates > 0) {
|
||||
// SY -->
|
||||
val badge: BadgeDrawable? = getTabAt(EXTENSIONS_CONTROLLER)?.orCreateBadge
|
||||
// SY <--
|
||||
badge?.isVisible = true
|
||||
} else {
|
||||
getTabAt(EXTENSIONS_CONTROLLER)?.removeBadge()
|
||||
@ -111,6 +113,7 @@ class BrowseController :
|
||||
|
||||
private inner class BrowseAdapter : RouterPagerAdapter(this@BrowseController) {
|
||||
|
||||
// SY -->
|
||||
private val tabTitles = (
|
||||
if (preferences.latestTabInFront().get()) {
|
||||
listOf(
|
||||
@ -129,6 +132,7 @@ class BrowseController :
|
||||
)
|
||||
}
|
||||
)
|
||||
// SY <--
|
||||
.map { resources!!.getString(it) }
|
||||
|
||||
override fun getCount(): Int {
|
||||
@ -138,8 +142,10 @@ class BrowseController :
|
||||
override fun configureRouter(router: Router, position: Int) {
|
||||
if (!router.hasRootController()) {
|
||||
val controller: Controller = when (position) {
|
||||
// SY -->
|
||||
SOURCES_CONTROLLER -> if (preferences.latestTabInFront().get()) LatestController() else SourceController()
|
||||
LATEST_CONTROLLER -> if (!preferences.latestTabInFront().get()) LatestController() else SourceController()
|
||||
// SY <--
|
||||
EXTENSIONS_CONTROLLER -> ExtensionController()
|
||||
MIGRATION_CONTROLLER -> MigrationSourcesController()
|
||||
else -> error("Wrong position $position")
|
||||
@ -157,8 +163,10 @@ class BrowseController :
|
||||
const val TO_EXTENSIONS_EXTRA = "to_extensions"
|
||||
|
||||
const val SOURCES_CONTROLLER = 0
|
||||
// SY -->
|
||||
const val LATEST_CONTROLLER = 1
|
||||
const val EXTENSIONS_CONTROLLER = 2
|
||||
const val MIGRATION_CONTROLLER = 3
|
||||
// SY <--
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ open class ExtensionPresenter(
|
||||
val items = mutableListOf<ExtensionItem>()
|
||||
|
||||
val updatesSorted = installed.filter { it.hasUpdate }.sortedBy { it.pkgName }
|
||||
val installedSorted = installed.filter { !it.hasUpdate }.sortedWith(compareBy({ !it.isObsolete && !it.isRedundant }, { it.pkgName }))
|
||||
val installedSorted = installed.filter { !it.hasUpdate }.sortedWith(compareBy({ !it.isObsolete /* SY --> */ && !it.isRedundant /* SY <-- */ }, { it.pkgName }))
|
||||
val untrustedSorted = untrusted.sortedBy { it.pkgName }
|
||||
val availableSorted = available
|
||||
// Filter out already installed extensions and disabled languages
|
||||
|
@ -4,7 +4,7 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.util.DeferredField
|
||||
import exh.util.DeferredField
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
@ -23,7 +23,7 @@ class MigratingManga(
|
||||
|
||||
val migrationJob = parentContext + SupervisorJob() + Dispatchers.Default
|
||||
|
||||
var migrationStatus: Int = MigrationStatus.RUNNUNG
|
||||
var migrationStatus: Int = MigrationStatus.RUNNING
|
||||
|
||||
@Volatile
|
||||
private var manga: Manga? = null
|
||||
@ -44,8 +44,8 @@ class MigratingManga(
|
||||
|
||||
class MigrationStatus {
|
||||
companion object {
|
||||
val RUNNUNG = 0
|
||||
val MANGA_FOUND = 1
|
||||
val MANGA_NOT_FOUND = 2
|
||||
const val RUNNING = 0
|
||||
const val MANGA_FOUND = 1
|
||||
const val MANGA_NOT_FOUND = 2
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ class MigrationListController(bundle: Bundle? = null) :
|
||||
|
||||
override fun getTitle(): String? {
|
||||
return resources?.getString(R.string.migration) + " (${adapter?.items?.count {
|
||||
it.manga.migrationStatus != MigrationStatus.RUNNUNG
|
||||
it.manga.migrationStatus != MigrationStatus.RUNNING
|
||||
}}/${adapter?.itemCount ?: 0})"
|
||||
}
|
||||
|
||||
@ -369,7 +369,7 @@ class MigrationListController(bundle: Bundle? = null) :
|
||||
fun useMangaForMigration(manga: Manga, source: Source) {
|
||||
val firstIndex = selectedPosition ?: return
|
||||
val migratingManga = adapter?.getItem(firstIndex) ?: return
|
||||
migratingManga.manga.migrationStatus = MigrationStatus.RUNNUNG
|
||||
migratingManga.manga.migrationStatus = MigrationStatus.RUNNING
|
||||
adapter?.notifyItemChanged(firstIndex)
|
||||
launchUI {
|
||||
val result = CoroutineScope(migratingManga.manga.migrationJob).async {
|
||||
|
@ -45,7 +45,7 @@ class MigrationProcessAdapter(
|
||||
fun allMangasDone() = (
|
||||
items.all {
|
||||
it.manga.migrationStatus != MigrationStatus
|
||||
.RUNNUNG
|
||||
.RUNNING
|
||||
} && items.any { it.manga.migrationStatus == MigrationStatus.MANGA_FOUND }
|
||||
)
|
||||
|
||||
|
@ -122,7 +122,7 @@ class MigrationProcessHolder(
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
if (item.manga.mangaId != this@MigrationProcessHolder.item?.manga?.mangaId ||
|
||||
item.manga.migrationStatus == MigrationStatus.RUNNUNG
|
||||
item.manga.migrationStatus == MigrationStatus.RUNNING
|
||||
) {
|
||||
return@withContext
|
||||
}
|
||||
|
@ -18,7 +18,10 @@ class MangaItem(val manga: Manga) : AbstractFlexibleItem<MangaHolder>(), Parcela
|
||||
}
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): MangaHolder {
|
||||
return MangaHolder(view, adapter)
|
||||
return MangaHolder(
|
||||
view,
|
||||
adapter
|
||||
)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(
|
||||
|
@ -19,7 +19,9 @@ import uy.kohesive.injekt.api.get
|
||||
class MigrationMangaController :
|
||||
NucleusController<MigrationMangaControllerBinding, MigrationMangaPresenter>,
|
||||
FlexibleAdapter.OnItemClickListener,
|
||||
// SY -->
|
||||
MigrationInterface {
|
||||
// SY <--
|
||||
|
||||
private var adapter: FlexibleAdapter<IFlexible<*>>? = null
|
||||
|
||||
@ -72,20 +74,23 @@ class MigrationMangaController :
|
||||
}
|
||||
|
||||
override fun onItemClick(view: View, position: Int): Boolean {
|
||||
val item = adapter?.getItem(position) as? MangaItem
|
||||
?: return false
|
||||
val item = adapter?.getItem(position) as? MangaItem ?: return false
|
||||
// SY -->
|
||||
PreMigrationController.navigateToMigration(
|
||||
Injekt.get<PreferencesHelper>().skipPreMigration().get(),
|
||||
router,
|
||||
listOf(item.manga.id!!)
|
||||
)
|
||||
// SY <--
|
||||
return false
|
||||
}
|
||||
|
||||
// SY -->
|
||||
override fun migrateManga(prevManga: Manga, manga: Manga, replace: Boolean): Manga? {
|
||||
presenter.migrateManga(prevManga, manga, replace)
|
||||
return null
|
||||
}
|
||||
// SY <--
|
||||
|
||||
companion object {
|
||||
const val SOURCE_ID_EXTRA = "source_id_extra"
|
||||
@ -93,6 +98,8 @@ class MigrationMangaController :
|
||||
}
|
||||
}
|
||||
|
||||
// SY -->
|
||||
interface MigrationInterface {
|
||||
fun migrateManga(prevManga: Manga, manga: Manga, replace: Boolean): Manga?
|
||||
}
|
||||
// SY <--
|
||||
|
@ -38,6 +38,7 @@ class MigrationMangaPresenter(
|
||||
.map { MangaItem(it) }
|
||||
}
|
||||
|
||||
// SY -->
|
||||
fun migrateManga(prevManga: Manga, manga: Manga, replace: Boolean) {
|
||||
val source = sourceManager.get(manga.source) ?: return
|
||||
|
||||
@ -109,4 +110,5 @@ class MigrationMangaPresenter(
|
||||
db.updateMangaTitle(manga).executeAsBlocking()
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
@ -26,7 +26,9 @@ import uy.kohesive.injekt.api.get
|
||||
class MigrationSourcesController :
|
||||
NucleusController<MigrationSourcesControllerBinding, MigrationSourcesPresenter>(),
|
||||
FlexibleAdapter.OnItemClickListener,
|
||||
// SY -->
|
||||
SourceAdapter.OnAllClickListener {
|
||||
// SY <--
|
||||
|
||||
private var adapter: SourceAdapter? = null
|
||||
|
||||
@ -58,6 +60,7 @@ class MigrationSourcesController :
|
||||
adapter?.updateDataSet(sourcesWithManga)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
override fun getTitle(): String? {
|
||||
return resources?.getString(R.string.source_migration)
|
||||
}
|
||||
@ -93,4 +96,5 @@ class MigrationSourcesController :
|
||||
}
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
@ -28,16 +28,12 @@ class MigrationSourcesPresenter(
|
||||
}
|
||||
|
||||
private fun findSourcesWithManga(library: List<Manga>): List<SourceItem> {
|
||||
val header =
|
||||
SelectionHeader()
|
||||
val header = SelectionHeader()
|
||||
return library.map { it.source }.toSet()
|
||||
// SY -->
|
||||
.mapNotNull { if (it != LocalSource.ID && it != MERGED_SOURCE_ID) sourceManager.getOrStub(it) else null }
|
||||
.sortedBy { it.name.toLowerCase(Locale.ROOT) }
|
||||
.map {
|
||||
SourceItem(
|
||||
it,
|
||||
header
|
||||
)
|
||||
}
|
||||
// SY <--
|
||||
.map { SourceItem(it, header) }
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,10 @@ class SelectionHeader : AbstractHeaderItem<SelectionHeader.Holder>() {
|
||||
* Creates a new view holder for this item.
|
||||
*/
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||
return Holder(view, adapter)
|
||||
return Holder(
|
||||
view,
|
||||
adapter
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -35,14 +38,16 @@ class SelectionHeader : AbstractHeaderItem<SelectionHeader.Holder>() {
|
||||
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>,
|
||||
holder: Holder,
|
||||
position: Int,
|
||||
// SY -->
|
||||
payloads: MutableList<Any?>?
|
||||
// SY <--
|
||||
) {
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
class Holder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) : BaseFlexibleViewHolder(view, adapter) {
|
||||
class Holder(view: View, adapter: FlexibleAdapter</* SY --> */ IFlexible<RecyclerView.ViewHolder> /* SY <-- */ >) : BaseFlexibleViewHolder(view, adapter) {
|
||||
init {
|
||||
title.text = view.context.getString(R.string.select_a_source_to_migrate_from)
|
||||
title.text = view.context.getString(/* SY --> */ R.string.select_a_source_to_migrate_from /* SY <-- */)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ class SourceAdapter(val controller: MigrationSourcesController) :
|
||||
setDisplayHeadersAtStartUp(true)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
/**
|
||||
* Listener for auto item clicks.
|
||||
*/
|
||||
@ -30,4 +31,5 @@ class SourceAdapter(val controller: MigrationSourcesController) :
|
||||
interface OnAllClickListener {
|
||||
fun onAllClick(position: Int)
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
@ -24,11 +24,13 @@ class SourceHolder(view: View, override val adapter: SourceAdapter) :
|
||||
get() = card
|
||||
|
||||
init {
|
||||
source_browse.gone()
|
||||
source_latest.text = "All"
|
||||
source_latest.setOnClickListener {
|
||||
source_latest.gone()
|
||||
// SY -->
|
||||
source_browse.text = "All"
|
||||
source_browse.setOnClickListener {
|
||||
adapter.allClickListener?.onAllClick(bindingAdapterPosition)
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
fun bind(item: SourceItem) {
|
||||
|
@ -28,7 +28,10 @@ data class SourceItem(val source: Source, val header: SelectionHeader) :
|
||||
* Creates a new view holder for this item.
|
||||
*/
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): SourceHolder {
|
||||
return SourceHolder(view, adapter as SourceAdapter)
|
||||
return SourceHolder(
|
||||
view,
|
||||
adapter as SourceAdapter
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,18 +70,22 @@ class SourceController(bundle: Bundle? = null) :
|
||||
// EXH <--
|
||||
|
||||
init {
|
||||
// Enable the option menu
|
||||
// SY -->
|
||||
setHasOptionsMenu(mode == Mode.CATALOGUE)
|
||||
// SY <--
|
||||
}
|
||||
|
||||
override fun getTitle(): String? {
|
||||
// SY -->
|
||||
return when (mode) {
|
||||
Mode.CATALOGUE -> applicationContext?.getString(R.string.label_sources)
|
||||
Mode.SMART_SEARCH -> "Find in another source"
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
override fun createPresenter(): SourcePresenter {
|
||||
return SourcePresenter(controllerMode = mode)
|
||||
return SourcePresenter(/* SY --> */ controllerMode = mode /* SY <-- */)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,6 +113,7 @@ class SourceController(bundle: Bundle? = null) :
|
||||
|
||||
requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 301)
|
||||
|
||||
// SY -->
|
||||
if (mode == Mode.CATALOGUE) {
|
||||
// Update list on extension changes (e.g. new installation)
|
||||
(parentController as BrowseController).extensionListUpdateRelay
|
||||
@ -116,6 +121,7 @@ class SourceController(bundle: Bundle? = null) :
|
||||
presenter.updateSources()
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
override fun onDestroyView(view: View) {
|
||||
@ -138,6 +144,7 @@ class SourceController(bundle: Bundle? = null) :
|
||||
private fun onItemClick(position: Int) {
|
||||
val item = adapter?.getItem(position) as? SourceItem ?: return
|
||||
val source = item.source
|
||||
// SY -->
|
||||
when (mode) {
|
||||
Mode.CATALOGUE -> {
|
||||
// Open the catalogue view.
|
||||
@ -152,6 +159,7 @@ class SourceController(bundle: Bundle? = null) :
|
||||
).withFadeTransaction()
|
||||
)
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
override fun onItemLongClick(position: Int) {
|
||||
@ -170,6 +178,7 @@ class SourceController(bundle: Bundle? = null) :
|
||||
items.add(Pair(activity.getString(R.string.action_hide), { hideCatalogue(item.source) }))
|
||||
}
|
||||
|
||||
// SY -->
|
||||
val isWatched = preferences.latestTabSources().get().contains(item.source.id.toString())
|
||||
|
||||
if (item.source.supportsLatest) {
|
||||
@ -187,6 +196,7 @@ class SourceController(bundle: Bundle? = null) :
|
||||
{ addToCategories(item.source) }
|
||||
)
|
||||
)
|
||||
// SY <--
|
||||
|
||||
MaterialDialog(activity)
|
||||
.title(text = item.source.name)
|
||||
@ -218,6 +228,7 @@ class SourceController(bundle: Bundle? = null) :
|
||||
presenter.updateSources()
|
||||
}
|
||||
|
||||
// SY -->
|
||||
private fun watchCatalogue(source: Source, isWatched: Boolean) {
|
||||
val current = preferences.latestTabSources().get()
|
||||
|
||||
@ -278,6 +289,7 @@ class SourceController(bundle: Bundle? = null) :
|
||||
)
|
||||
presenter.updateSources()
|
||||
}
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Called when browse is clicked in [SourceAdapter]
|
||||
@ -312,10 +324,12 @@ class SourceController(bundle: Bundle? = null) :
|
||||
// Inflate menu
|
||||
inflater.inflate(R.menu.source_main, menu)
|
||||
|
||||
// SY -->
|
||||
if (mode == Mode.SMART_SEARCH) {
|
||||
menu.findItem(R.id.action_search).isVisible = false
|
||||
menu.findItem(R.id.action_settings).isVisible = false
|
||||
}
|
||||
// SY <--
|
||||
|
||||
// Initialize search option.
|
||||
val searchItem = menu.findItem(R.id.action_search)
|
||||
@ -375,6 +389,7 @@ class SourceController(bundle: Bundle? = null) :
|
||||
}
|
||||
}
|
||||
|
||||
// SY -->
|
||||
@Parcelize
|
||||
data class SmartSearchConfig(val origTitle: String, val origMangaId: Long? = null) : Parcelable
|
||||
|
||||
@ -386,4 +401,5 @@ class SourceController(bundle: Bundle? = null) :
|
||||
companion object {
|
||||
const val SMART_SEARCH_CONFIG = "SMART_SEARCH_CONFIG"
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import kotlinx.android.synthetic.main.source_main_controller_card_item.source_br
|
||||
import kotlinx.android.synthetic.main.source_main_controller_card_item.source_latest
|
||||
import kotlinx.android.synthetic.main.source_main_controller_card_item.title
|
||||
|
||||
class SourceHolder(view: View, override val adapter: SourceAdapter, val showButtons: Boolean) :
|
||||
class SourceHolder(view: View, override val adapter: SourceAdapter /* SY --> */, val showButtons: Boolean /* SY <-- */) :
|
||||
BaseFlexibleViewHolder(view, adapter),
|
||||
SlicedHolder {
|
||||
|
||||
@ -35,10 +35,12 @@ class SourceHolder(view: View, override val adapter: SourceAdapter, val showButt
|
||||
adapter.latestClickListener.onLatestClick(bindingAdapterPosition)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
if (!showButtons) {
|
||||
source_browse.gone()
|
||||
source_latest.gone()
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
fun bind(item: SourceItem) {
|
||||
@ -58,7 +60,7 @@ class SourceHolder(view: View, override val adapter: SourceAdapter, val showButt
|
||||
}
|
||||
|
||||
source_browse.setText(R.string.browse)
|
||||
if (source.supportsLatest && showButtons) {
|
||||
if (source.supportsLatest /* SY --> */ && showButtons /* SY <-- */) {
|
||||
source_latest.visible()
|
||||
} else {
|
||||
source_latest.gone()
|
||||
|
@ -14,7 +14,7 @@ import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
* @param source Instance of [CatalogueSource] containing source information.
|
||||
* @param header The header for this item.
|
||||
*/
|
||||
data class SourceItem(val source: CatalogueSource, val header: LangItem? = null, val showButtons: Boolean) :
|
||||
data class SourceItem(val source: CatalogueSource, val header: LangItem? = null /* SY --> */, val showButtons: Boolean /* SY <-- */) :
|
||||
AbstractSectionableItem<SourceHolder, LangItem>(header) {
|
||||
|
||||
/**
|
||||
@ -28,7 +28,7 @@ data class SourceItem(val source: CatalogueSource, val header: LangItem? = null,
|
||||
* Creates a new view holder for this item.
|
||||
*/
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): SourceHolder {
|
||||
return SourceHolder(view, adapter as SourceAdapter, showButtons)
|
||||
return SourceHolder(view, adapter as SourceAdapter /* SY --> */, showButtons /* SY <-- */)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -32,7 +32,9 @@ import uy.kohesive.injekt.api.get
|
||||
class SourcePresenter(
|
||||
val sourceManager: SourceManager = Injekt.get(),
|
||||
private val preferences: PreferencesHelper = Injekt.get(),
|
||||
// SY -->
|
||||
private val controllerMode: SourceController.Mode
|
||||
// SY <--
|
||||
) : BasePresenter<SourceController>() {
|
||||
|
||||
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
@ -60,6 +62,8 @@ class SourcePresenter(
|
||||
|
||||
val pinnedSources = mutableListOf<SourceItem>()
|
||||
val pinnedCatalogues = preferences.pinnedCatalogues().get()
|
||||
|
||||
// SY -->
|
||||
val categories = mutableListOf<SourceCategory>()
|
||||
|
||||
preferences.sourcesTabCategories().get().sortedByDescending { it.toLowerCase() }.forEach {
|
||||
@ -73,6 +77,7 @@ class SourcePresenter(
|
||||
} else null
|
||||
|
||||
val sourcesInCategories = sourcesAndCategories?.map { it.first }
|
||||
// SY <--
|
||||
|
||||
val map = TreeMap<String, MutableList<CatalogueSource>> { d1, d2 ->
|
||||
// Catalogues without a lang defined will be placed at the end
|
||||
@ -90,6 +95,7 @@ class SourcePresenter(
|
||||
pinnedSources.add(SourceItem(source, LangItem(PINNED_KEY), controllerMode == SourceController.Mode.CATALOGUE))
|
||||
}
|
||||
|
||||
// SY -->
|
||||
if (sourcesInCategories != null && source.id.toString() in sourcesInCategories) {
|
||||
sourcesAndCategories
|
||||
.filter { SourcesAndCategory -> SourcesAndCategory.first == source.id.toString() }
|
||||
@ -107,14 +113,17 @@ class SourcePresenter(
|
||||
}
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
SourceItem(source, langItem, controllerMode == SourceController.Mode.CATALOGUE)
|
||||
}
|
||||
}
|
||||
|
||||
// SY -->
|
||||
categories.forEach {
|
||||
sourceItems = it.sources.sortedBy { sourceItem -> sourceItem.source.name.toLowerCase() } + sourceItems
|
||||
}
|
||||
// SY <--
|
||||
|
||||
if (pinnedSources.isNotEmpty()) {
|
||||
sourceItems = pinnedSources + sourceItems
|
||||
@ -170,4 +179,6 @@ class SourcePresenter(
|
||||
}
|
||||
}
|
||||
|
||||
// SY -->
|
||||
data class SourceCategory(val category: String, var sources: MutableList<SourceItem> = mutableListOf())
|
||||
// SY <--
|
||||
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.ui.browse.source.browse
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
@ -81,7 +80,9 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
constructor(
|
||||
source: CatalogueSource,
|
||||
searchQuery: String? = null,
|
||||
// SY -->
|
||||
smartSearchConfig: SourceController.SmartSearchConfig? = null
|
||||
// SY <--
|
||||
) : this(
|
||||
Bundle().apply {
|
||||
putLong(SOURCE_ID_KEY, source.id)
|
||||
@ -90,15 +91,19 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
putString(SEARCH_QUERY_KEY, searchQuery)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
if (smartSearchConfig != null) {
|
||||
putParcelable(SMART_SEARCH_CONFIG_KEY, smartSearchConfig)
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
)
|
||||
|
||||
private val preferences: PreferencesHelper by injectLazy()
|
||||
|
||||
// SY -->
|
||||
private val recommendsConfig: RecommendsConfig? = args.getParcelable(RECOMMENDS_CONFIG)
|
||||
// SY <--
|
||||
|
||||
// AZ -->
|
||||
private val mode = if (recommendsConfig == null) Mode.CATALOGUE else Mode.RECOMMENDS
|
||||
@ -138,19 +143,23 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
}
|
||||
|
||||
override fun getTitle(): String? {
|
||||
// SY -->
|
||||
return when (mode) {
|
||||
Mode.CATALOGUE -> presenter.source.name
|
||||
Mode.RECOMMENDS -> recommendsConfig!!.manga.title
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
override fun createPresenter(): BrowseSourcePresenter {
|
||||
// SY -->
|
||||
return BrowseSourcePresenter(
|
||||
args.getLong(SOURCE_ID_KEY),
|
||||
args.getString(SEARCH_QUERY_KEY),
|
||||
searchManga = if (mode == Mode.RECOMMENDS) recommendsConfig?.manga else null,
|
||||
recommends = (mode == Mode.RECOMMENDS)
|
||||
)
|
||||
// SY <--
|
||||
}
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
@ -172,12 +181,16 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
}
|
||||
|
||||
open fun initFilterSheet() {
|
||||
// SY -->
|
||||
if (mode == Mode.RECOMMENDS) {
|
||||
return
|
||||
}
|
||||
// SY <--
|
||||
|
||||
if (presenter.sourceFilters.isEmpty()) {
|
||||
// SY -->
|
||||
binding.fabFilter.text = activity!!.getString(R.string.eh_saved_searches)
|
||||
// SY <--
|
||||
}
|
||||
|
||||
filterSheet = SourceFilterSheet(
|
||||
@ -373,9 +386,11 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.source_browse, menu)
|
||||
|
||||
// SY -->
|
||||
if (mode == Mode.RECOMMENDS) {
|
||||
menu.findItem(R.id.action_search).isVisible = false
|
||||
}
|
||||
// SY <--
|
||||
|
||||
// Initialize search menu
|
||||
val searchItem = menu.findItem(R.id.action_search)
|
||||
@ -418,9 +433,11 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
menu.findItem(R.id.action_open_in_web_view).isVisible = isHttpSource
|
||||
|
||||
val isLocalSource = presenter.source is LocalSource
|
||||
// SY -->
|
||||
menu.findItem(R.id.action_local_source_help).isVisible = isLocalSource && mode == Mode.CATALOGUE
|
||||
|
||||
menu.findItem(R.id.action_settings).isVisible = presenter.source is ConfigurableSource
|
||||
// SY <--
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
@ -430,7 +447,9 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
R.id.action_comfortable_grid -> setDisplayMode(DisplayMode.COMFORTABLE_GRID)
|
||||
R.id.action_list -> setDisplayMode(DisplayMode.LIST)
|
||||
R.id.action_open_in_web_view -> openInWebView()
|
||||
// SY -->
|
||||
R.id.action_settings -> openSourceSettings()
|
||||
// SY <--
|
||||
R.id.action_local_source_help -> openLocalSourceHelpGuide()
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
@ -448,11 +467,13 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
activity?.openInBrowser(LocalSource.HELP_URL)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
private fun openSourceSettings() {
|
||||
router.pushController(
|
||||
SourcePreferencesController(presenter.source.id).withFadeTransaction()
|
||||
)
|
||||
}
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Restarts the request with a new query.
|
||||
@ -493,6 +514,7 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
* @param error the error received.
|
||||
*/
|
||||
fun onAddPageError(error: Throwable) {
|
||||
// SY -->
|
||||
XLog.w("> Failed to load next catalogue page!", error)
|
||||
|
||||
if (mode == Mode.CATALOGUE) {
|
||||
@ -504,6 +526,7 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
} else {
|
||||
XLog.w("> Recommendations")
|
||||
}
|
||||
// SY <--
|
||||
|
||||
val adapter = adapter ?: return
|
||||
adapter.onLoadMoreComplete(null)
|
||||
@ -523,10 +546,9 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
}
|
||||
|
||||
if (adapter.isEmpty) {
|
||||
Log.d("Adapter", "empty")
|
||||
val actions = emptyList<EmptyView.Action>().toMutableList()
|
||||
|
||||
if (presenter.source is LocalSource && mode == Mode.CATALOGUE) {
|
||||
if (presenter.source is LocalSource /* SY --> */ && mode == Mode.CATALOGUE /* SY <-- */) {
|
||||
actions += EmptyView.Action(R.string.local_source_help_guide, View.OnClickListener { openLocalSourceHelpGuide() })
|
||||
} else {
|
||||
actions += EmptyView.Action(R.string.action_retry, retryAction)
|
||||
@ -669,7 +691,7 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
*/
|
||||
override fun onItemClick(view: View, position: Int): Boolean {
|
||||
val item = adapter?.getItem(position) as? SourceItem ?: return false
|
||||
|
||||
// SY -->
|
||||
when (mode) {
|
||||
Mode.CATALOGUE -> {
|
||||
if (preferences.eh_useNewMangaInterface().get()) {
|
||||
@ -692,6 +714,7 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
}
|
||||
Mode.RECOMMENDS -> openSmartSearch(item.manga.title)
|
||||
}
|
||||
// SY <--
|
||||
return false
|
||||
}
|
||||
|
||||
@ -718,7 +741,9 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
* @param position the position of the element clicked.
|
||||
*/
|
||||
override fun onItemLongClick(position: Int) {
|
||||
if (mode == Mode.RECOMMENDS) { return }
|
||||
// SY -->
|
||||
if (mode == Mode.RECOMMENDS) return
|
||||
// SY <--
|
||||
val activity = activity ?: return
|
||||
val manga = (adapter?.getItem(position) as? SourceItem?)?.manga ?: return
|
||||
|
||||
@ -794,6 +819,7 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
activity?.toast(activity?.getString(R.string.manga_added_library))
|
||||
}
|
||||
|
||||
// SY -->
|
||||
@Parcelize
|
||||
data class RecommendsConfig(val manga: Manga) : Parcelable
|
||||
|
||||
@ -801,13 +827,15 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
CATALOGUE,
|
||||
RECOMMENDS
|
||||
}
|
||||
// SY <--
|
||||
|
||||
companion object {
|
||||
const val SOURCE_ID_KEY = "sourceId"
|
||||
|
||||
const val SEARCH_QUERY_KEY = "searchQuery"
|
||||
const val SMART_SEARCH_CONFIG_KEY = "smartSearchConfig"
|
||||
|
||||
// SY -->
|
||||
const val SMART_SEARCH_CONFIG_KEY = "smartSearchConfig"
|
||||
const val RECOMMENDS_CONFIG = "RECOMMENDS_CONFIG"
|
||||
// SY <--
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,9 @@ open class BrowseSourcePresenter(
|
||||
private val db: DatabaseHelper = Injekt.get(),
|
||||
private val prefs: PreferencesHelper = Injekt.get(),
|
||||
private val coverCache: CoverCache = Injekt.get(),
|
||||
// SY -->
|
||||
private val recommends: Boolean = false
|
||||
// SY <--
|
||||
) : BasePresenter<BrowseSourceController>() {
|
||||
|
||||
/**
|
||||
@ -70,7 +72,7 @@ open class BrowseSourcePresenter(
|
||||
/**
|
||||
* Query from the view.
|
||||
*/
|
||||
var query = if (recommends) "" else searchQuery ?: ""
|
||||
var query = /* SY --> */ if (recommends) "" else /* SY <-- */ searchQuery ?: ""
|
||||
private set
|
||||
|
||||
/**
|
||||
@ -146,9 +148,11 @@ open class BrowseSourcePresenter(
|
||||
subscribeToMangaInitializer()
|
||||
|
||||
// Create a new pager.
|
||||
// SY -->
|
||||
pager = if (recommends && searchManga != null) RecommendsPager(
|
||||
searchManga
|
||||
) else createPager(query, filters)
|
||||
// SY <--
|
||||
|
||||
val sourceId = source.id
|
||||
|
||||
|
@ -45,13 +45,9 @@ class SourceFilterSheet(
|
||||
|
||||
// EXH -->
|
||||
filterNavView.onSaveClicked = onSaveClicked
|
||||
// EXH <--
|
||||
|
||||
// EXH -->
|
||||
filterNavView.onSavedSearchClicked = onSavedSearchClicked
|
||||
// EXH <--
|
||||
|
||||
// EXH -->
|
||||
filterNavView.onSavedSearchDeleteClicked = onSavedSearchDeleteClicked
|
||||
// EXH <--
|
||||
|
||||
@ -62,6 +58,7 @@ class SourceFilterSheet(
|
||||
filterNavView.adapter.updateDataSet(items)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
fun setSavedSearches(searches: List<EXHSavedSearch>) {
|
||||
filterNavView.setSavedSearches(searches)
|
||||
}
|
||||
@ -69,19 +66,16 @@ class SourceFilterSheet(
|
||||
fun hideFilterButton() {
|
||||
filterNavView.hideFilterButton()
|
||||
}
|
||||
// SY <--
|
||||
|
||||
class FilterNavigationView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
SimpleNavigationView(context, attrs) {
|
||||
|
||||
// EXH -->
|
||||
var onSaveClicked = {}
|
||||
// EXH <--
|
||||
|
||||
// EXH -->
|
||||
var onSavedSearchClicked: (Int) -> Unit = {}
|
||||
// EXH <--
|
||||
|
||||
// EXH -->
|
||||
var onSavedSearchDeleteClicked: (Int, String) -> Unit = { _, _ -> }
|
||||
// EXH <--
|
||||
|
||||
@ -96,9 +90,13 @@ class SourceFilterSheet(
|
||||
recycler.adapter = adapter
|
||||
recycler.setHasFixedSize(true)
|
||||
val view = inflate(R.layout.source_filter_sheet)
|
||||
// SY -->
|
||||
((view as ViewGroup).findViewById(R.id.source_filter_content) as ViewGroup).addView(recycler)
|
||||
// SY <--
|
||||
addView(view)
|
||||
// SY -->
|
||||
save_search_btn.setOnClickListener { onSaveClicked() }
|
||||
// SY <--
|
||||
filter_btn.setOnClickListener { onFilterClicked() }
|
||||
reset_btn.setOnClickListener { onResetClicked() }
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.browse.source.filter
|
||||
|
||||
import android.view.View
|
||||
import android.widget.CheckBox
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
@ -15,11 +16,11 @@ open class CheckboxItem(val filter: Filter.CheckBox) : AbstractFlexibleItem<Chec
|
||||
return R.layout.navigation_view_checkbox
|
||||
}
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<androidx.recyclerview.widget.RecyclerView.ViewHolder>>): Holder {
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||
return Holder(view, adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<androidx.recyclerview.widget.RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
val view = holder.check
|
||||
view.text = filter.name
|
||||
view.isChecked = filter.state
|
||||
|
@ -4,6 +4,7 @@ import android.view.View
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Spinner
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
@ -18,11 +19,11 @@ open class SelectItem(val filter: Filter.Select<*>) : AbstractFlexibleItem<Selec
|
||||
return R.layout.navigation_view_spinner
|
||||
}
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<androidx.recyclerview.widget.RecyclerView.ViewHolder>>): Holder {
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||
return Holder(view, adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<androidx.recyclerview.widget.RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
holder.text.text = filter.name + ": "
|
||||
|
||||
val spinner = holder.spinner
|
||||
|
@ -15,10 +15,12 @@ import uy.kohesive.injekt.api.get
|
||||
class GlobalSearchCardItem(val manga: Manga) : AbstractFlexibleItem<GlobalSearchCardHolder>() {
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
// SY -->
|
||||
return when (Injekt.get<PreferencesHelper>().catalogueDisplayMode().get()) {
|
||||
PreferenceValues.DisplayMode.COMPACT_GRID -> R.layout.global_search_controller_compact_card_item
|
||||
else -> R.layout.global_search_controller_comfortable_card_item
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): GlobalSearchCardHolder {
|
||||
|
@ -77,11 +77,13 @@ open class GlobalSearchController(
|
||||
*/
|
||||
override fun onMangaClick(manga: Manga) {
|
||||
// Open MangaController.
|
||||
// SY -->
|
||||
if (presenter.preferences.eh_useNewMangaInterface().get()) {
|
||||
router.pushController(MangaAllInOneController(manga, true).withFadeTransaction())
|
||||
} else {
|
||||
router.pushController(MangaController(manga, true).withFadeTransaction())
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -49,7 +49,9 @@ class LibraryCategoryAdapter(view: LibraryCategoryView) :
|
||||
*/
|
||||
private var mangas: List<LibraryItem> = emptyList()
|
||||
|
||||
// SY -->
|
||||
val onItemReleaseListener: CategoryAdapter.OnItemReleaseListener = view
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Sets a list of manga in the adapter.
|
||||
|
@ -47,8 +47,10 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
FrameLayout(context, attrs),
|
||||
FlexibleAdapter.OnItemClickListener,
|
||||
FlexibleAdapter.OnItemLongClickListener,
|
||||
// SY -->
|
||||
FlexibleAdapter.OnItemMoveListener,
|
||||
CategoryAdapter.OnItemReleaseListener {
|
||||
// SY <--
|
||||
|
||||
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
|
||||
@ -142,8 +144,10 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
} else {
|
||||
SelectableAdapter.Mode.SINGLE
|
||||
}
|
||||
// SY -->
|
||||
val sortingMode = preferences.librarySortingMode().get()
|
||||
adapter.isLongPressDragEnabled = sortingMode == LibrarySort.DRAG_AND_DROP
|
||||
// SY <--
|
||||
|
||||
// EXH -->
|
||||
scope2 = newScope()
|
||||
@ -206,6 +210,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
controller.invalidateActionMode()
|
||||
}
|
||||
|
||||
// SY -->
|
||||
subscriptions += controller.reorganizeRelay
|
||||
.subscribe {
|
||||
if (it.first == category.id) {
|
||||
@ -230,10 +235,13 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
controller.invalidateActionMode()
|
||||
}
|
||||
// }
|
||||
// SY <--
|
||||
}
|
||||
|
||||
fun onRecycle() {
|
||||
// SY -->
|
||||
runBlocking { adapter.setItems(this, emptyList()) }
|
||||
// SY <--
|
||||
adapter.clearSelection()
|
||||
unsubscribe()
|
||||
}
|
||||
@ -254,7 +262,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
*/
|
||||
suspend fun onNextLibraryManga(cScope: CoroutineScope, event: LibraryMangaEvent) {
|
||||
// Get the manga list for this category.
|
||||
|
||||
// SY -->
|
||||
val sortingMode = preferences.librarySortingMode().get()
|
||||
adapter.isLongPressDragEnabled = sortingMode == LibrarySort.DRAG_AND_DROP
|
||||
var mangaForCategory = event.getMangaForCategory(category).orEmpty()
|
||||
@ -270,6 +278,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
)
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
// Update the category with its manga.
|
||||
// EXH -->
|
||||
adapter.setItems(cScope, mangaForCategory)
|
||||
@ -297,7 +306,9 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
is LibrarySelectionEvent.Selected -> {
|
||||
if (adapter.mode != SelectableAdapter.Mode.MULTI) {
|
||||
adapter.mode = SelectableAdapter.Mode.MULTI
|
||||
// SY -->
|
||||
adapter.isLongPressDragEnabled = false
|
||||
// SY <--
|
||||
}
|
||||
findAndToggleSelection(event.manga)
|
||||
}
|
||||
@ -306,16 +317,20 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
if (adapter.indexOf(event.manga) != -1) lastClickPosition = -1
|
||||
if (controller.selectedMangas.isEmpty()) {
|
||||
adapter.mode = SelectableAdapter.Mode.SINGLE
|
||||
// SY -->
|
||||
adapter.isLongPressDragEnabled = preferences.librarySortingMode()
|
||||
.get() == LibrarySort.DRAG_AND_DROP
|
||||
// SY <--
|
||||
}
|
||||
}
|
||||
is LibrarySelectionEvent.Cleared -> {
|
||||
adapter.mode = SelectableAdapter.Mode.SINGLE
|
||||
adapter.clearSelection()
|
||||
lastClickPosition = -1
|
||||
// SY -->
|
||||
adapter.isLongPressDragEnabled = preferences.librarySortingMode()
|
||||
.get() == LibrarySort.DRAG_AND_DROP
|
||||
// SY <--
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -359,7 +374,9 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
*/
|
||||
override fun onItemLongClick(position: Int) {
|
||||
controller.createActionModeIfNeeded()
|
||||
// SY -->
|
||||
adapter.isLongPressDragEnabled = false
|
||||
// SY <--
|
||||
when {
|
||||
lastClickPosition == -1 -> setSelection(position)
|
||||
lastClickPosition > position ->
|
||||
@ -372,7 +389,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
}
|
||||
lastClickPosition = position
|
||||
}
|
||||
|
||||
// SY -->
|
||||
override fun onItemMove(fromPosition: Int, toPosition: Int) {
|
||||
}
|
||||
|
||||
@ -405,6 +422,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
|
||||
onItemLongClick(position)
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Opens a manga.
|
||||
|
@ -28,7 +28,9 @@ import kotlinx.android.synthetic.main.source_compact_grid_item.unread_text
|
||||
*/
|
||||
open class LibraryCompactGridHolder(
|
||||
private val view: View,
|
||||
// SY -->
|
||||
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
|
||||
// SY <--
|
||||
) : LibraryHolder(view, adapter) {
|
||||
|
||||
/**
|
||||
|
@ -125,10 +125,12 @@ class LibraryController(
|
||||
*/
|
||||
val selectInverseRelay: PublishRelay<Int> = PublishRelay.create()
|
||||
|
||||
// SY -->
|
||||
/**
|
||||
* Relay to notify the library's viewpager to reotagnize all
|
||||
*/
|
||||
val reorganizeRelay: PublishRelay<Pair<Int, Int>> = PublishRelay.create()
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Number of manga per row in grid mode.
|
||||
@ -349,7 +351,9 @@ class LibraryController(
|
||||
* Called when the sorting mode is changed.
|
||||
*/
|
||||
private fun onSortChanged() {
|
||||
// SY -->
|
||||
activity?.invalidateOptionsMenu()
|
||||
// SY <--
|
||||
presenter.requestSortUpdate()
|
||||
}
|
||||
|
||||
@ -391,8 +395,10 @@ class LibraryController(
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.library, menu)
|
||||
|
||||
// SY -->
|
||||
val reorganizeItem = menu.findItem(R.id.action_reorganize)
|
||||
reorganizeItem.isVisible = preferences.librarySortingMode().get() == LibrarySort.DRAG_AND_DROP
|
||||
// SY <--
|
||||
|
||||
val searchItem = menu.findItem(R.id.action_search)
|
||||
val searchView = searchItem.actionView as SearchView
|
||||
@ -421,7 +427,9 @@ class LibraryController(
|
||||
// Mutate the filter icon because it needs to be tinted and the resource is shared.
|
||||
menu.findItem(R.id.action_filter).icon.mutate()
|
||||
|
||||
// SY -->
|
||||
menu.findItem(R.id.action_sync_favorites).isVisible = preferences.eh_isHentaiEnabled().get()
|
||||
// SY <--
|
||||
}
|
||||
|
||||
fun search(query: String) {
|
||||
@ -451,10 +459,10 @@ class LibraryController(
|
||||
}
|
||||
}
|
||||
}
|
||||
// SY -->
|
||||
R.id.action_source_migration -> {
|
||||
router.pushController(MigrationSourcesController().withFadeTransaction())
|
||||
}
|
||||
// --> EXH
|
||||
R.id.action_sync_favorites -> {
|
||||
if (preferences.eh_showSyncIntro().get()) {
|
||||
activity?.let { FavoritesIntroDialog().show(it) }
|
||||
@ -462,21 +470,23 @@ class LibraryController(
|
||||
presenter.favoritesSync.runSync()
|
||||
}
|
||||
}
|
||||
// <-- EXH
|
||||
R.id.action_alpha_asc -> reOrder(1)
|
||||
R.id.action_alpha_dsc -> reOrder(2)
|
||||
R.id.action_update_asc -> reOrder(3)
|
||||
R.id.action_update_dsc -> reOrder(4)
|
||||
// SY <--
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
private fun reOrder(type: Int) {
|
||||
adapter?.categories?.getOrNull(binding.libraryPager.currentItem)?.id?.let {
|
||||
reorganizeRelay.call(it to type)
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Invalidates the action mode, forcing it to refresh its content.
|
||||
@ -514,11 +524,13 @@ class LibraryController(
|
||||
R.id.action_delete -> showDeleteMangaDialog()
|
||||
R.id.action_select_all -> selectAllCategoryManga()
|
||||
R.id.action_select_inverse -> selectInverseCategoryManga()
|
||||
// SY -->
|
||||
R.id.action_migrate -> {
|
||||
val skipPre = preferences.skipPreMigration().get()
|
||||
PreMigrationController.navigateToMigration(skipPre, router, selectedMangas.mapNotNull { it.id })
|
||||
destroyActionModeIfNeeded()
|
||||
}
|
||||
// SY <--
|
||||
else -> return false
|
||||
}
|
||||
return true
|
||||
@ -539,11 +551,13 @@ class LibraryController(
|
||||
// Notify the presenter a manga is being opened.
|
||||
presenter.onOpenManga()
|
||||
|
||||
// SY -->
|
||||
if (preferences.eh_useNewMangaInterface().get()) {
|
||||
router.pushController(MangaAllInOneController(manga).withFadeTransaction())
|
||||
} else {
|
||||
router.pushController(MangaController(manga).withFadeTransaction())
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
/**
|
||||
@ -652,6 +666,7 @@ class LibraryController(
|
||||
destroyActionModeIfNeeded()
|
||||
}
|
||||
|
||||
// SY -->
|
||||
override fun onAttach(view: View) {
|
||||
super.onAttach(view)
|
||||
|
||||
@ -673,6 +688,7 @@ class LibraryController(
|
||||
// EXH
|
||||
cleanupSyncState()
|
||||
}
|
||||
// SY <--
|
||||
|
||||
private fun selectAllCategoryManga() {
|
||||
adapter?.categories?.getOrNull(binding.libraryPager.currentItem)?.id?.let {
|
||||
|
@ -15,7 +15,9 @@ import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
||||
|
||||
abstract class LibraryHolder(
|
||||
view: View,
|
||||
// SY -->
|
||||
val adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
|
||||
// SY <--
|
||||
) : BaseFlexibleViewHolder(view, adapter) {
|
||||
|
||||
/**
|
||||
@ -26,6 +28,7 @@ abstract class LibraryHolder(
|
||||
*/
|
||||
abstract fun onSetValues(item: LibraryItem)
|
||||
|
||||
// SY -->
|
||||
/**
|
||||
* Called when an item is released.
|
||||
*
|
||||
@ -35,4 +38,5 @@ abstract class LibraryHolder(
|
||||
super.onItemReleased(position)
|
||||
(adapter as? LibraryCategoryAdapter)?.onItemReleaseListener?.onItemReleased(position)
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
@ -28,8 +28,10 @@ class LibraryItem(val manga: LibraryManga, private val libraryDisplayMode: Prefe
|
||||
AbstractFlexibleItem<LibraryHolder>(), IFilterable<String> {
|
||||
|
||||
private val sourceManager: SourceManager = Injekt.get()
|
||||
// SY -->
|
||||
private val trackManager: TrackManager = Injekt.get()
|
||||
private val db: DatabaseHelper = Injekt.get()
|
||||
// SY <--
|
||||
|
||||
var downloadCount = -1
|
||||
var unreadCount = -1
|
||||
@ -80,6 +82,7 @@ class LibraryItem(val manga: LibraryManga, private val libraryDisplayMode: Prefe
|
||||
holder.onSetValues(this)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
/**
|
||||
* Returns true if this item is draggable.
|
||||
*/
|
||||
@ -138,6 +141,7 @@ class LibraryItem(val manga: LibraryManga, private val libraryDisplayMode: Prefe
|
||||
return@any false
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
private fun containsGenre(tag: String, genres: List<String>?): Boolean {
|
||||
return if (tag.startsWith("-")) {
|
||||
|
@ -32,7 +32,9 @@ import kotlinx.android.synthetic.main.source_list_item.unread_text
|
||||
|
||||
class LibraryListHolder(
|
||||
private val view: View,
|
||||
// SY -->
|
||||
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
|
||||
// SY <--
|
||||
) : LibraryHolder(view, adapter) {
|
||||
|
||||
/**
|
||||
|
@ -120,6 +120,7 @@ class LibraryPresenter(
|
||||
}
|
||||
}
|
||||
|
||||
// SY -->
|
||||
/**
|
||||
* Applies library filters to the given map of manga.
|
||||
*
|
||||
@ -171,6 +172,7 @@ class LibraryPresenter(
|
||||
|
||||
return map.mapValues { entry -> entry.value.filter(filterFn) }
|
||||
}
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Sets downloaded chapter count to each manga.
|
||||
@ -244,9 +246,11 @@ class LibraryPresenter(
|
||||
?: latestChapterManga.size
|
||||
manga1latestChapter.compareTo(manga2latestChapter)
|
||||
}
|
||||
// SY -->
|
||||
LibrarySort.DRAG_AND_DROP -> {
|
||||
0
|
||||
}
|
||||
// SY <--
|
||||
else -> throw Exception("Unknown sorting mode")
|
||||
}
|
||||
}
|
||||
@ -393,6 +397,7 @@ class LibraryPresenter(
|
||||
db.setMangaCategories(mc, mangas)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
fun migrateManga(prevManga: Manga, manga: Manga, replace: Boolean) {
|
||||
val source = sourceManager.get(manga.source) ?: return
|
||||
|
||||
@ -469,6 +474,7 @@ class LibraryPresenter(
|
||||
db.updateMangaTitle(manga).executeAsBlocking()
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Update cover with local file.
|
||||
|
@ -65,18 +65,23 @@ class LibrarySettingsSheet(
|
||||
* Returns true if there's at least one filter from [FilterGroup] active.
|
||||
*/
|
||||
fun hasActiveFilters(): Boolean {
|
||||
// SY -->
|
||||
return filterGroup.items.any { it.state != STATE_IGNORE }
|
||||
// SY <--
|
||||
}
|
||||
|
||||
inner class FilterGroup : Group {
|
||||
|
||||
// SY -->
|
||||
private val downloaded = Item.TriStateGroup(R.string.action_filter_downloaded, this)
|
||||
private val unread = Item.TriStateGroup(R.string.action_filter_unread, this)
|
||||
private val completed = Item.TriStateGroup(R.string.completed, this)
|
||||
private val tracked = Item.TriStateGroup(R.string.tracked, this)
|
||||
private val lewd = Item.TriStateGroup(R.string.lewd, this)
|
||||
// SY <--
|
||||
|
||||
override val header = null
|
||||
// SY -->
|
||||
override val items = (
|
||||
if (Injekt.get<TrackManager>().hasLoggedServices()) {
|
||||
listOf(downloaded, unread, completed, tracked, lewd)
|
||||
@ -84,8 +89,10 @@ class LibrarySettingsSheet(
|
||||
listOf(downloaded, unread, completed, lewd)
|
||||
}
|
||||
)
|
||||
// SY <--
|
||||
override val footer = null
|
||||
|
||||
// SY -->
|
||||
override fun initModels() { // j2k changes
|
||||
try {
|
||||
downloaded.state = preferences.filterDownloaded().get()
|
||||
@ -120,6 +127,7 @@ class LibrarySettingsSheet(
|
||||
|
||||
adapter.notifyItemChanged(item)
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,11 +149,13 @@ class LibrarySettingsSheet(
|
||||
private val lastChecked = Item.MultiSort(R.string.action_sort_last_checked, this)
|
||||
private val unread = Item.MultiSort(R.string.action_filter_unread, this)
|
||||
private val latestChapter = Item.MultiSort(R.string.action_sort_latest_chapter, this)
|
||||
// SY -->
|
||||
private val dragAndDrop = Item.MultiSort(R.string.action_sort_drag_and_drop, this)
|
||||
// SY <--
|
||||
|
||||
override val header = null
|
||||
override val items =
|
||||
listOf(alphabetically, lastRead, lastChecked, unread, total, latestChapter, dragAndDrop)
|
||||
listOf(alphabetically, lastRead, lastChecked, unread, total, latestChapter /* SY --> */, dragAndDrop /* SY <-- */)
|
||||
override val footer = null
|
||||
|
||||
override fun initModels() {
|
||||
@ -167,7 +177,9 @@ class LibrarySettingsSheet(
|
||||
total.state = if (sorting == LibrarySort.TOTAL) order else Item.MultiSort.SORT_NONE
|
||||
latestChapter.state =
|
||||
if (sorting == LibrarySort.LATEST_CHAPTER) order else Item.MultiSort.SORT_NONE
|
||||
// SY -->
|
||||
dragAndDrop.state = if (sorting == LibrarySort.DRAG_AND_DROP) order else Item.MultiSort.SORT_NONE
|
||||
// SY <--
|
||||
}
|
||||
|
||||
override fun onItemClicked(item: Item) {
|
||||
@ -178,6 +190,7 @@ class LibrarySettingsSheet(
|
||||
(it as Item.MultiStateGroup).state =
|
||||
Item.MultiSort.SORT_NONE
|
||||
}
|
||||
// SY -->
|
||||
if (item == dragAndDrop) {
|
||||
item.state = Item.MultiSort.SORT_ASC
|
||||
} else {
|
||||
@ -188,6 +201,7 @@ class LibrarySettingsSheet(
|
||||
else -> throw Exception("Unknown state")
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
preferences.librarySortingMode().set(
|
||||
when (item) {
|
||||
@ -197,7 +211,9 @@ class LibrarySettingsSheet(
|
||||
unread -> LibrarySort.UNREAD
|
||||
total -> LibrarySort.TOTAL
|
||||
latestChapter -> LibrarySort.LATEST_CHAPTER
|
||||
// SY -->
|
||||
dragAndDrop -> LibrarySort.DRAG_AND_DROP
|
||||
// SY <--
|
||||
else -> throw Exception("Unknown sorting")
|
||||
}
|
||||
)
|
||||
|
@ -8,7 +8,9 @@ object LibrarySort {
|
||||
const val UNREAD = 3
|
||||
const val TOTAL = 4
|
||||
const val LATEST_CHAPTER = 6
|
||||
// SY -->
|
||||
const val DRAG_AND_DROP = 7
|
||||
// SY <--
|
||||
|
||||
@Deprecated("Removed in favor of searching by source")
|
||||
const val SOURCE = 5
|
||||
|
@ -18,7 +18,7 @@ class ChangelogDialogController : DialogController() {
|
||||
val activity = activity!!
|
||||
val view = WhatsNewRecyclerView(activity)
|
||||
return MaterialDialog(activity)
|
||||
.title(res = if (BuildConfig.DEBUG || syDebugVersion != "0") R.string.notices else R.string.changelog)
|
||||
.title(res = if (BuildConfig.DEBUG /* SY --> */ || syDebugVersion != "0" /* SY <-- */) R.string.notices else R.string.changelog)
|
||||
.customView(view = view)
|
||||
.positiveButton(R.string.action_close)
|
||||
}
|
||||
@ -27,7 +27,7 @@ class ChangelogDialogController : DialogController() {
|
||||
override fun initAttrs(attrs: AttributeSet?, defStyle: Int) {
|
||||
mRowLayoutId = R.layout.changelog_row_layout
|
||||
mRowHeaderLayoutId = R.layout.changelog_header_layout
|
||||
mChangeLogFileResourceId = if (BuildConfig.DEBUG || syDebugVersion != "0") R.raw.changelog_debug else R.raw.changelog_release
|
||||
mChangeLogFileResourceId = if (BuildConfig.DEBUG /* SY --> */ || syDebugVersion != "0"/* SY <-- */) R.raw.changelog_debug else R.raw.changelog_release
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ import eu.kanade.tachiyomi.ui.recent.history.HistoryController
|
||||
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import exh.EH_SOURCE_ID
|
||||
import exh.EIGHTMUSES_SOURCE_ID
|
||||
import exh.EXHMigrations
|
||||
@ -78,6 +77,7 @@ class MainActivity : BaseActivity<MainActivityBinding>() {
|
||||
private var isConfirmingExit: Boolean = false
|
||||
private var isHandlingShortcut: Boolean = false
|
||||
|
||||
// SY -->
|
||||
// Idle-until-urgent
|
||||
private var firstPaint = false
|
||||
private val iuuQueue = LinkedList<() -> Unit>()
|
||||
@ -94,6 +94,7 @@ class MainActivity : BaseActivity<MainActivityBinding>() {
|
||||
iuuQueue += task
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -186,7 +187,9 @@ class MainActivity : BaseActivity<MainActivityBinding>() {
|
||||
if (EXHMigrations.upgrade(preferences)) {
|
||||
ChangelogDialogController().showDialog(router)
|
||||
}
|
||||
// EXH <--
|
||||
|
||||
// SY -->
|
||||
initWhenIdle {
|
||||
// Upload settings
|
||||
if (preferences.enableExhentai().get() &&
|
||||
@ -198,7 +201,9 @@ class MainActivity : BaseActivity<MainActivityBinding>() {
|
||||
|
||||
EHentaiUpdateWorker.scheduleBackground(this)
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
// SY -->
|
||||
if (!preferences.eh_isHentaiEnabled().get()) {
|
||||
if (EH_SOURCE_ID !in BlacklistedSources.HIDDEN_SOURCES) {
|
||||
BlacklistedSources.HIDDEN_SOURCES += EH_SOURCE_ID
|
||||
@ -225,7 +230,7 @@ class MainActivity : BaseActivity<MainActivityBinding>() {
|
||||
BlacklistedSources.HIDDEN_SOURCES += HBROWSE_SOURCE_ID
|
||||
}
|
||||
}
|
||||
// EXH <--
|
||||
// SY -->
|
||||
|
||||
setExtensionsBadge()
|
||||
preferences.extensionUpdatesCount().asFlow()
|
||||
@ -295,11 +300,13 @@ class MainActivity : BaseActivity<MainActivityBinding>() {
|
||||
router.popToRoot()
|
||||
}
|
||||
setSelectedNavItem(R.id.nav_library)
|
||||
// SY -->
|
||||
if (preferences.eh_useNewMangaInterface().get()) {
|
||||
router.pushController(RouterTransaction.with(MangaAllInOneController(extras)))
|
||||
} else {
|
||||
router.pushController(RouterTransaction.with(MangaController(extras)))
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
SHORTCUT_DOWNLOADS -> {
|
||||
if (router.backstackSize > 1) {
|
||||
|
@ -401,7 +401,7 @@ class MangaAllInOneHolder(
|
||||
|
||||
fun setTrackingIcon(tracked: Boolean) {
|
||||
if (tracked) {
|
||||
binding.btnTracking.setIconResource(R.drawable.ic_cloud_white_24dp)
|
||||
binding.btnTracking.setIconResource(R.drawable.ic_cloud_24dp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ class TrackController(val fromAllInOne: Boolean = false, val manga: Manga? = nul
|
||||
}
|
||||
|
||||
override fun createPresenter(): TrackPresenter {
|
||||
// SY -->
|
||||
return (
|
||||
if (fromAllInOne && manga != null) {
|
||||
TrackPresenter(manga)
|
||||
@ -44,6 +45,7 @@ class TrackController(val fromAllInOne: Boolean = false, val manga: Manga? = nul
|
||||
TrackPresenter((parentController as MangaController).manga!!)
|
||||
}
|
||||
)
|
||||
// SY <--
|
||||
}
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
@ -72,11 +74,13 @@ class TrackController(val fromAllInOne: Boolean = false, val manga: Manga? = nul
|
||||
val atLeastOneLink = trackings.any { it.track != null }
|
||||
adapter?.items = trackings
|
||||
binding.swipeRefresh.isEnabled = atLeastOneLink
|
||||
// SY -->
|
||||
if (!fromAllInOne) {
|
||||
(parentController as? MangaController)?.setTrackingIcon(atLeastOneLink)
|
||||
} else {
|
||||
(parentController as? MangaAllInOneController)?.setTrackingIcon(atLeastOneLink)
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
fun onSearchResults(results: List<TrackSearch>) {
|
||||
|
@ -48,7 +48,7 @@ class AboutController : SettingsController() {
|
||||
|
||||
preference {
|
||||
titleRes = R.string.version
|
||||
summary = if (syDebugVersion != "0") {
|
||||
summary = if (BuildConfig.DEBUG /* SY --> */ || syDebugVersion != "0" /* SY --> */) {
|
||||
"Preview r$syDebugVersion (${BuildConfig.COMMIT_SHA})"
|
||||
} else {
|
||||
"Stable ${BuildConfig.VERSION_NAME}"
|
||||
@ -71,7 +71,9 @@ class AboutController : SettingsController() {
|
||||
titleRes = R.string.changelog
|
||||
|
||||
onClick {
|
||||
// SY -->
|
||||
ChangelogDialogController().showDialog(router)
|
||||
// SY <--
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,13 +98,16 @@ class AboutController : SettingsController() {
|
||||
}
|
||||
preference {
|
||||
title = "GitHub"
|
||||
// SY -->
|
||||
val url = "https://github.com/jobobby04/TachiyomiSY"
|
||||
// SY <--
|
||||
summary = url
|
||||
onClick {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
// SY -->
|
||||
preference {
|
||||
title = "Original Tachiyomi GitHub "
|
||||
val url = "https://github.com/inorichi/tachiyomi"
|
||||
@ -112,6 +117,7 @@ class AboutController : SettingsController() {
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
preference {
|
||||
titleRes = R.string.label_extensions
|
||||
val url = "https://github.com/inorichi/tachiyomi-extensions"
|
||||
|
@ -67,6 +67,7 @@ class MoreController :
|
||||
router.pushController(DownloadController().withFadeTransaction())
|
||||
}
|
||||
}
|
||||
// SY -->
|
||||
if (preferences.eh_isHentaiEnabled().get()) {
|
||||
preference {
|
||||
titleRes = R.string.eh_batch_add
|
||||
@ -77,6 +78,7 @@ class MoreController :
|
||||
}
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
preferenceCategory {
|
||||
|
@ -647,10 +647,12 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
|
||||
viewer = newViewer
|
||||
binding.viewerContainer.addView(newViewer.getView())
|
||||
|
||||
// SY -->
|
||||
val defaultReaderType = manga.defaultReaderType()
|
||||
if (preferences.eh_useAutoWebtoon().get() && manga.viewer == 0 && defaultReaderType != null && defaultReaderType == WEBTOON) {
|
||||
binding.root.snack(resources.getString(R.string.eh_auto_webtoon_snack), Snackbar.LENGTH_LONG)
|
||||
} else if (preferences.showReadingMode()) {
|
||||
// SY <--
|
||||
showReadingModeSnackbar(presenter.getMangaViewer())
|
||||
}
|
||||
|
||||
|
@ -466,6 +466,7 @@ class ReaderPresenter(
|
||||
*/
|
||||
fun getMangaViewer(): Int {
|
||||
val manga = manga ?: return preferences.defaultViewer()
|
||||
// SY -->
|
||||
return if (manga.viewer == 0 && preferences.eh_useAutoWebtoon().get()) {
|
||||
manga.defaultReaderType() ?: if (manga.viewer == 0) preferences.defaultViewer() else manga.viewer
|
||||
} else if (manga.viewer == 0) {
|
||||
@ -473,6 +474,7 @@ class ReaderPresenter(
|
||||
} else {
|
||||
manga.viewer
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,7 +89,9 @@ class ReaderSettingsSheet(private val activity: ReaderActivity) : BottomSheetDia
|
||||
keepscreen.bindToPreference(preferences.keepScreenOn())
|
||||
long_tap.bindToPreference(preferences.readWithLongTap())
|
||||
always_show_chapter_transition.bindToPreference(preferences.alwaysShowChapterTransition())
|
||||
// SY -->
|
||||
auto_webtoon_mode.bindToPreference(preferences.eh_useAutoWebtoon())
|
||||
// SY <--
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
true_color.visible()
|
||||
|
@ -45,7 +45,7 @@ class HttpPageLoader(
|
||||
*/
|
||||
private val subscriptions = CompositeSubscription()
|
||||
|
||||
private val preloadSize = prefs.eh_preload_size().get()
|
||||
private val preloadSize = /* SY --> */ prefs.eh_preload_size().get() /* SY <-- */
|
||||
|
||||
init {
|
||||
// EXH -->
|
||||
@ -102,6 +102,7 @@ class HttpPageLoader(
|
||||
.getPageListFromCache(chapter.chapter)
|
||||
.onErrorResumeNext { source.fetchPageList(chapter.chapter) }
|
||||
.map { pages ->
|
||||
// SY -->
|
||||
val rp = pages.mapIndexed { index, page ->
|
||||
// Don't trust sources and use our own indexing
|
||||
ReaderPage(index, page.url, page.imageUrl)
|
||||
@ -114,6 +115,7 @@ class HttpPageLoader(
|
||||
}.forEach { queue.offer(it) }
|
||||
}
|
||||
rp
|
||||
// SY <--
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.recent
|
||||
import android.text.format.DateUtils
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
@ -16,11 +17,11 @@ class DateSectionItem(val date: Date) : AbstractHeaderItem<DateSectionItem.Holde
|
||||
return R.layout.recent_section_item
|
||||
}
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<androidx.recyclerview.widget.RecyclerView.ViewHolder>>): Holder {
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||
return Holder(view, adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<androidx.recyclerview.widget.RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
holder.bind(this)
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ class HistoryController :
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.recently_read, menu)
|
||||
inflater.inflate(R.menu.history, menu)
|
||||
val searchItem = menu.findItem(R.id.action_search)
|
||||
val searchView = searchItem.actionView as SearchView
|
||||
searchView.maxWidth = Int.MAX_VALUE
|
||||
|
@ -287,11 +287,13 @@ class UpdatesController :
|
||||
}
|
||||
|
||||
private fun openManga(chapter: UpdatesItem) {
|
||||
// SY -->
|
||||
if (Injekt.get<PreferencesHelper>().eh_useNewMangaInterface().get()) {
|
||||
router.pushController(MangaAllInOneController(chapter.manga).withFadeTransaction())
|
||||
} else {
|
||||
router.pushController(MangaController(chapter.manga).withFadeTransaction())
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,7 +133,7 @@ class SettingsAdvancedController : SettingsController() {
|
||||
}
|
||||
}
|
||||
|
||||
// <-- EXH
|
||||
// --> EXH
|
||||
preferenceCategory {
|
||||
title = "Developer tools"
|
||||
isPersistent = false
|
||||
|
@ -20,6 +20,7 @@ class SettingsBrowseController : SettingsController() {
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
|
||||
titleRes = R.string.browse
|
||||
|
||||
// SY -->
|
||||
preferenceCategory {
|
||||
titleRes = R.string.label_sources
|
||||
|
||||
@ -51,6 +52,7 @@ class SettingsBrowseController : SettingsController() {
|
||||
defaultValue = false
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
preferenceCategory {
|
||||
titleRes = R.string.label_extensions
|
||||
|
@ -209,6 +209,7 @@ class SettingsLibraryController : SettingsController() {
|
||||
}
|
||||
}
|
||||
|
||||
// SY -->
|
||||
if (preferences.skipPreMigration().get() || preferences.migrationSources().get()
|
||||
.isNotEmpty()
|
||||
) {
|
||||
@ -223,6 +224,7 @@ class SettingsLibraryController : SettingsController() {
|
||||
}
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
class LibraryColumnsDialog : DialogController() {
|
||||
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.ui.setting
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
import eu.kanade.tachiyomi.ui.more.AboutController
|
||||
import eu.kanade.tachiyomi.util.preference.iconRes
|
||||
import eu.kanade.tachiyomi.util.preference.iconTint
|
||||
import eu.kanade.tachiyomi.util.preference.onClick
|
||||
@ -66,6 +65,7 @@ class SettingsMainController : SettingsController() {
|
||||
titleRes = R.string.pref_category_security
|
||||
onClick { navigateTo(SettingsSecurityController()) }
|
||||
}
|
||||
// SY -->
|
||||
if (preferences.eh_isHentaiEnabled().get()) {
|
||||
preference {
|
||||
iconRes = R.drawable.eh_ic_ehlogo_red_24dp
|
||||
@ -86,18 +86,13 @@ class SettingsMainController : SettingsController() {
|
||||
onClick { navigateTo(SettingsHlController()) }
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
preference {
|
||||
iconRes = R.drawable.ic_code_24dp
|
||||
iconTint = tintColor
|
||||
titleRes = R.string.pref_category_advanced
|
||||
onClick { navigateTo(SettingsAdvancedController()) }
|
||||
}
|
||||
preference {
|
||||
iconRes = R.drawable.ic_info_24dp
|
||||
iconTint = tintColor
|
||||
titleRes = R.string.pref_category_about
|
||||
onClick { navigateTo(AboutController()) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateTo(controller: SettingsController) {
|
||||
|
@ -12,6 +12,7 @@ import eu.kanade.tachiyomi.util.preference.preferenceCategory
|
||||
import eu.kanade.tachiyomi.util.preference.summaryRes
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.util.system.hasDisplayCutout
|
||||
|
||||
class SettingsReaderController : SettingsController() {
|
||||
|
||||
@ -29,7 +30,7 @@ class SettingsReaderController : SettingsController() {
|
||||
R.string.vertical_viewer, R.string.webtoon_viewer, R.string.vertical_plus_viewer
|
||||
)
|
||||
entryValues = arrayOf("1", "2", "3", "4", "5")
|
||||
defaultValue = "1"
|
||||
defaultValue = "2"
|
||||
summary = "%s"
|
||||
}
|
||||
intListPreference {
|
||||
@ -64,6 +65,15 @@ class SettingsReaderController : SettingsController() {
|
||||
titleRes = R.string.pref_fullscreen
|
||||
defaultValue = true
|
||||
}
|
||||
|
||||
if (activity?.hasDisplayCutout() == true) {
|
||||
switchPreference {
|
||||
key = Keys.cutoutShort
|
||||
titleRes = R.string.pref_cutout_short
|
||||
defaultValue = true
|
||||
}
|
||||
}
|
||||
|
||||
switchPreference {
|
||||
key = Keys.keepScreenOn
|
||||
titleRes = R.string.pref_keep_screen_on
|
||||
@ -223,6 +233,7 @@ class SettingsReaderController : SettingsController() {
|
||||
defaultValue = true
|
||||
}
|
||||
}
|
||||
// EXH <--
|
||||
|
||||
preferenceCategory {
|
||||
titleRes = R.string.pager_viewer
|
||||
|
@ -79,6 +79,7 @@ class WebViewActivity : BaseActivity<WebviewActivityBinding>() {
|
||||
}
|
||||
|
||||
binding.webview.settings.javaScriptEnabled = true
|
||||
binding.webview.settings.domStorageEnabled = true
|
||||
|
||||
binding.webview.webChromeClient = object : WebChromeClient() {
|
||||
override fun onProgressChanged(view: WebView?, newProgress: Int) {
|
||||
|
@ -1,55 +0,0 @@
|
||||
package eu.kanade.tachiyomi.util
|
||||
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
/**
|
||||
* Field that can be initialized later. Users can suspend while waiting for the field to initialize.
|
||||
*
|
||||
* @author nulldev
|
||||
*/
|
||||
class DeferredField<T> {
|
||||
|
||||
@Volatile
|
||||
var content: T? = null
|
||||
|
||||
@Volatile
|
||||
var initialized = false
|
||||
private set
|
||||
|
||||
private val mutex = Mutex(true)
|
||||
|
||||
/**
|
||||
* Initialize the field
|
||||
*/
|
||||
fun initialize(content: T) {
|
||||
// Fast-path new listeners
|
||||
this.content = content
|
||||
initialized = true
|
||||
|
||||
// Notify current listeners
|
||||
mutex.unlock()
|
||||
}
|
||||
|
||||
fun set(content: T) {
|
||||
mutex.tryLock()
|
||||
this.content = content
|
||||
initialized = true
|
||||
// Notify current listeners
|
||||
mutex.unlock()
|
||||
}
|
||||
|
||||
/**
|
||||
* Will only suspend if !initialized.
|
||||
*/
|
||||
suspend fun get(): T {
|
||||
// Check if field is initialized and return immediately if it is
|
||||
if (initialized) return content as T
|
||||
|
||||
// Wait for field to initialize
|
||||
mutex.withLock {}
|
||||
|
||||
// Field is initialized, return value
|
||||
return content as T
|
||||
}
|
||||
}
|
@ -40,9 +40,11 @@ import kotlinx.coroutines.launch
|
||||
* @param duration the duration of the toast. Defaults to short.
|
||||
*/
|
||||
fun Context.toast(@StringRes resource: Int, duration: Int = Toast.LENGTH_SHORT) {
|
||||
// SY -->
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
Toast.makeText(this@toast, resource, duration).show()
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
/**
|
||||
@ -52,9 +54,11 @@ fun Context.toast(@StringRes resource: Int, duration: Int = Toast.LENGTH_SHORT)
|
||||
* @param duration the duration of the toast. Defaults to short.
|
||||
*/
|
||||
fun Context.toast(text: String?, duration: Int = Toast.LENGTH_SHORT) {
|
||||
// SY -->
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
Toast.makeText(this@toast, text.orEmpty(), duration).show()
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,9 +48,11 @@ object LocaleHelper {
|
||||
* Returns Display name of a string language code
|
||||
*/
|
||||
fun getSourceDisplayName(lang: String?, context: Context): String {
|
||||
// SY -->
|
||||
if (lang != null && lang.contains("custom|")) {
|
||||
return lang.split("|")[1]
|
||||
}
|
||||
// SY <--
|
||||
return when (lang) {
|
||||
"" -> context.getString(R.string.other_source)
|
||||
SourcePresenter.LAST_USED_KEY -> context.getString(R.string.last_used_source)
|
||||
|
@ -100,17 +100,13 @@ fun ExtendedFloatingActionButton.shrinkOnScroll(recycler: RecyclerView) {
|
||||
* @param items List of strings that are shown as individual chips.
|
||||
* @param onClick Optional on click listener for each chip.
|
||||
*/
|
||||
fun ChipGroup.setChips(items: List<String>?, onClick: (item: String) -> Unit = {}, onLongClick: (item: String) -> Unit = {}) {
|
||||
fun ChipGroup.setChips(items: List<String>?, onClick: (item: String) -> Unit = {}) {
|
||||
removeAllViews()
|
||||
|
||||
items?.forEach { item ->
|
||||
val chip = Chip(context).apply {
|
||||
text = item
|
||||
setOnClickListener { onClick(item) }
|
||||
setOnLongClickListener {
|
||||
onLongClick(item)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
addView(chip)
|
||||
|
@ -71,11 +71,13 @@ open class ExtendedNavigationView @JvmOverloads constructor(
|
||||
* @param context any context.
|
||||
* @param resId the vector resource to load and tint
|
||||
*/
|
||||
// SY -->
|
||||
fun tintVector(context: Context, resId: Int, colorId: Int = R.attr.colorAccent): Drawable {
|
||||
return VectorDrawableCompat.create(context.resources, resId, context.theme)!!.apply {
|
||||
setTint(context.getResourceColor(colorId))
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,6 +108,7 @@ open class ExtendedNavigationView @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
// SY -->
|
||||
class TriStateGroup(resId: Int, group: Group) : MultiStateGroup(resId, group) {
|
||||
|
||||
companion object {
|
||||
@ -128,6 +131,7 @@ open class ExtendedNavigationView @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,7 +4,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.viewpager.widget.PagerAdapter
|
||||
|
||||
abstract class ViewPagerAdapter : androidx.viewpager.widget.PagerAdapter() {
|
||||
abstract class ViewPagerAdapter : PagerAdapter() {
|
||||
|
||||
protected abstract fun createView(container: ViewGroup, position: Int): View
|
||||
|
||||
|
@ -9,8 +9,9 @@ import kotlinx.coroutines.sync.withLock
|
||||
* @author nulldev
|
||||
*/
|
||||
class DeferredField<T> {
|
||||
|
||||
@Volatile
|
||||
private var content: T? = null
|
||||
var content: T? = null
|
||||
|
||||
@Volatile
|
||||
var initialized = false
|
||||
@ -30,17 +31,25 @@ class DeferredField<T> {
|
||||
mutex.unlock()
|
||||
}
|
||||
|
||||
fun set(content: T) {
|
||||
mutex.tryLock()
|
||||
this.content = content
|
||||
initialized = true
|
||||
// Notify current listeners
|
||||
mutex.unlock()
|
||||
}
|
||||
|
||||
/**
|
||||
* Will only suspend if !initialized.
|
||||
*/
|
||||
suspend fun get(): T {
|
||||
// Check if field is initialized and return immediately if it is
|
||||
if (initialized) return content!!
|
||||
if (initialized) return content as T
|
||||
|
||||
// Wait for field to initialize
|
||||
mutex.withLock {}
|
||||
|
||||
// Field is initialized, return value
|
||||
return content!!
|
||||
return content as T
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="?android:attr/textColorSecondary" />
|
||||
</shape>
|
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||
</vector>
|
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM17,13l-5,5 -5,-5h3V9h4v4h3z"/>
|
||||
</vector>
|
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M21,2L3,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h7v2L8,20v2h8v-2h-2v-2h7c1.1,0 2,-0.9 2,-2L23,4c0,-1.1 -0.9,-2 -2,-2zM21,16L3,16L3,4h18v12z"/>
|
||||
</vector>
|
@ -4,6 +4,6 @@
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z"/>
|
||||
android:pathData="M11,18h2v-2h-2v2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM12,6c-2.21,0 -4,1.79 -4,4h2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,2 -3,1.75 -3,5h2c0,-2.25 3,-2.5 3,-5 0,-2.21 -1.79,-4 -4,-4z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
||||
|
@ -5,5 +5,5 @@
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"/>
|
||||
android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
|
||||
</vector>
|
||||
|
@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M8.59,16.34l4.58,-4.59 -4.58,-4.59L10,5.75l6,6 -6,6z"/>
|
||||
</vector>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user