mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-28 17:19:00 +03:00
Merge branch 'upstream'
This commit is contained in:
commit
491ad02c56
27 changed files with 1042 additions and 598 deletions
|
@ -158,7 +158,7 @@ dependencies {
|
|||
implementation("androidx.work:work-runtime-ktx:2.7.0-alpha04")
|
||||
|
||||
// UI library
|
||||
implementation("com.google.android.material:material:1.4.0-beta01")
|
||||
implementation("com.google.android.material:material:1.4.0-rc01")
|
||||
|
||||
"standardImplementation"("com.google.firebase:firebase-core:19.0.0")
|
||||
|
||||
|
|
|
@ -2,48 +2,52 @@ package eu.kanade.tachiyomi.data.backup.legacy
|
|||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.github.salomonbrys.kotson.fromJson
|
||||
import com.github.salomonbrys.kotson.registerTypeAdapter
|
||||
import com.github.salomonbrys.kotson.registerTypeHierarchyAdapter
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonArray
|
||||
import eu.kanade.tachiyomi.animesource.AnimeSource
|
||||
import eu.kanade.tachiyomi.animesource.model.toSAnime
|
||||
import eu.kanade.tachiyomi.data.backup.AbstractBackupManager
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.CURRENT_VERSION
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.Companion.CURRENT_VERSION
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.CategoryTypeAdapter
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.ChapterTypeAdapter
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.HistoryTypeAdapter
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.MangaTypeAdapter
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.TrackTypeAdapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Anime
|
||||
import eu.kanade.tachiyomi.data.database.models.CategoryImpl
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.CategoryImplTypeSerializer
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.CategoryTypeSerializer
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.ChapterImplTypeSerializer
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.ChapterTypeSerializer
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.HistoryTypeSerializer
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.MangaImplTypeSerializer
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.MangaTypeSerializer
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.TrackImplTypeSerializer
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.TrackTypeSerializer
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
|
||||
import eu.kanade.tachiyomi.data.database.models.History
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.database.models.TrackImpl
|
||||
import eu.kanade.tachiyomi.data.database.models.toAnimeInfo
|
||||
import eu.kanade.tachiyomi.data.database.models.toMangaInfo
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.model.toSManga
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.modules.SerializersModule
|
||||
import kotlinx.serialization.modules.contextual
|
||||
import kotlin.math.max
|
||||
|
||||
class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : AbstractBackupManager(context) {
|
||||
|
||||
val parser: Gson = when (version) {
|
||||
2 -> GsonBuilder()
|
||||
.registerTypeAdapter<MangaImpl>(MangaTypeAdapter.build())
|
||||
.registerTypeHierarchyAdapter<ChapterImpl>(ChapterTypeAdapter.build())
|
||||
.registerTypeAdapter<CategoryImpl>(CategoryTypeAdapter.build())
|
||||
.registerTypeAdapter<DHistory>(HistoryTypeAdapter.build())
|
||||
.registerTypeHierarchyAdapter<TrackImpl>(TrackTypeAdapter.build())
|
||||
.create()
|
||||
val parser: Json = when (version) {
|
||||
2 -> Json {
|
||||
// Forks may have added items to backup
|
||||
ignoreUnknownKeys = true
|
||||
|
||||
// Register custom serializers
|
||||
serializersModule = SerializersModule {
|
||||
contextual(MangaTypeSerializer)
|
||||
contextual(MangaImplTypeSerializer)
|
||||
contextual(ChapterTypeSerializer)
|
||||
contextual(ChapterImplTypeSerializer)
|
||||
contextual(CategoryTypeSerializer)
|
||||
contextual(CategoryImplTypeSerializer)
|
||||
contextual(TrackTypeSerializer)
|
||||
contextual(TrackImplTypeSerializer)
|
||||
contextual(HistoryTypeSerializer)
|
||||
}
|
||||
}
|
||||
else -> throw Exception("Unknown backup version")
|
||||
}
|
||||
|
||||
|
@ -63,13 +67,6 @@ class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : Ab
|
|||
insertManga(manga)
|
||||
}
|
||||
|
||||
fun restoreAnimeNoFetch(anime: Anime, dbAnime: Anime) {
|
||||
anime.id = dbAnime.id
|
||||
anime.copyFrom(dbAnime)
|
||||
anime.favorite = true
|
||||
insertAnime(anime)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches manga information
|
||||
*
|
||||
|
@ -87,32 +84,14 @@ class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : Ab
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches manga information
|
||||
*
|
||||
* @param source source of manga
|
||||
* @param manga manga that needs updating
|
||||
* @return Updated manga.
|
||||
*/
|
||||
suspend fun fetchAnime(source: AnimeSource, manga: Anime): Anime {
|
||||
val networkManga = source.getAnimeDetails(manga.toAnimeInfo())
|
||||
return manga.also {
|
||||
it.copyFrom(networkManga.toSAnime())
|
||||
it.favorite = true
|
||||
it.initialized = true
|
||||
it.id = insertAnime(manga)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the categories from Json
|
||||
*
|
||||
* @param jsonCategories array containing categories
|
||||
* @param backupCategories array containing categories
|
||||
*/
|
||||
internal fun restoreCategories(jsonCategories: JsonArray) {
|
||||
internal fun restoreCategories(backupCategories: List<Category>) {
|
||||
// Get categories from file and from db
|
||||
val dbCategories = databaseHelper.getCategories().executeAsBlocking()
|
||||
val backupCategories = parser.fromJson<List<CategoryImpl>>(jsonCategories)
|
||||
|
||||
// Iterate over them
|
||||
backupCategories.forEach { category ->
|
||||
|
|
|
@ -2,88 +2,80 @@ package eu.kanade.tachiyomi.data.backup.legacy
|
|||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.github.salomonbrys.kotson.fromJson
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import com.google.gson.stream.JsonReader
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.AbstractBackupRestore
|
||||
import eu.kanade.tachiyomi.data.backup.BackupNotifier
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.models.Backup
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.MANGAS
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.models.MangaObject
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.database.models.TrackImpl
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.decodeFromJsonElement
|
||||
import kotlinx.serialization.json.intOrNull
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okio.buffer
|
||||
import okio.source
|
||||
import java.util.Date
|
||||
|
||||
class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBackupRestore<LegacyBackupManager>(context, notifier) {
|
||||
|
||||
override suspend fun performRestore(uri: Uri): Boolean {
|
||||
val reader = JsonReader(context.contentResolver.openInputStream(uri)!!.bufferedReader())
|
||||
val json = JsonParser.parseReader(reader).asJsonObject
|
||||
// Read the json and create a Json Object,
|
||||
// cannot use the backupManager json deserializer one because its not initialized yet
|
||||
val backupObject = Json.decodeFromString<JsonObject>(
|
||||
context.contentResolver.openInputStream(uri)!!.source().buffer().use { it.readUtf8() }
|
||||
)
|
||||
|
||||
val version = json.get(Backup.VERSION)?.asInt ?: 1
|
||||
// Get parser version
|
||||
val version = backupObject["version"]?.jsonPrimitive?.intOrNull ?: 1
|
||||
|
||||
// Initialize manager
|
||||
backupManager = LegacyBackupManager(context, version)
|
||||
|
||||
val mangasJson = json.get(MANGAS).asJsonArray
|
||||
restoreAmount = mangasJson.size() + 1 // +1 for categories
|
||||
// Decode the json object to a Backup object
|
||||
val backup = backupManager.parser.decodeFromJsonElement<Backup>(backupObject)
|
||||
|
||||
restoreAmount = backup.mangas.size + 1 // +1 for categories
|
||||
|
||||
// Restore categories
|
||||
json.get(Backup.CATEGORIES)?.let { restoreCategories(it) }
|
||||
backup.categories?.let { restoreCategories(it) }
|
||||
|
||||
// Store source mapping for error messages
|
||||
sourceMapping = LegacyBackupRestoreValidator.getSourceMapping(json)
|
||||
sourceMapping = LegacyBackupRestoreValidator.getSourceMapping(backup.extensions ?: emptyList())
|
||||
|
||||
// Restore individual manga
|
||||
mangasJson.forEach {
|
||||
backup.mangas.forEach {
|
||||
if (job?.isActive != true) {
|
||||
return false
|
||||
}
|
||||
|
||||
restoreManga(it.asJsonObject)
|
||||
restoreManga(it)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun restoreCategories(categoriesJson: JsonElement) {
|
||||
private fun restoreCategories(categoriesJson: List<Category>) {
|
||||
db.inTransaction {
|
||||
backupManager.restoreCategories(categoriesJson.asJsonArray)
|
||||
backupManager.restoreCategories(categoriesJson)
|
||||
}
|
||||
|
||||
restoreProgress += 1
|
||||
showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.categories))
|
||||
}
|
||||
|
||||
private suspend fun restoreManga(mangaJson: JsonObject) {
|
||||
val manga = backupManager.parser.fromJson<MangaImpl>(
|
||||
mangaJson.get(
|
||||
Backup.MANGA
|
||||
)
|
||||
)
|
||||
val chapters = backupManager.parser.fromJson<List<ChapterImpl>>(
|
||||
mangaJson.get(Backup.CHAPTERS)
|
||||
?: JsonArray()
|
||||
)
|
||||
val categories = backupManager.parser.fromJson<List<String>>(
|
||||
mangaJson.get(Backup.CATEGORIES)
|
||||
?: JsonArray()
|
||||
)
|
||||
val history = backupManager.parser.fromJson<List<DHistory>>(
|
||||
mangaJson.get(Backup.HISTORY)
|
||||
?: JsonArray()
|
||||
)
|
||||
val tracks = backupManager.parser.fromJson<List<TrackImpl>>(
|
||||
mangaJson.get(Backup.TRACK)
|
||||
?: JsonArray()
|
||||
)
|
||||
private suspend fun restoreManga(mangaJson: MangaObject) {
|
||||
val manga = mangaJson.manga
|
||||
val chapters = mangaJson.chapters ?: emptyList()
|
||||
val categories = mangaJson.categories ?: emptyList()
|
||||
val history = mangaJson.history ?: emptyList()
|
||||
val tracks = mangaJson.track ?: emptyList()
|
||||
|
||||
val source = backupManager.sourceManager.get(manga.source)
|
||||
val sourceName = sourceMapping[manga.source] ?: manga.source.toString()
|
||||
|
|
|
@ -2,12 +2,12 @@ package eu.kanade.tachiyomi.data.backup.legacy
|
|||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import com.google.gson.stream.JsonReader
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.AbstractBackupRestoreValidator
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.models.Backup
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import okio.buffer
|
||||
import okio.source
|
||||
|
||||
class LegacyBackupRestoreValidator : AbstractBackupRestoreValidator() {
|
||||
/**
|
||||
|
@ -17,30 +17,30 @@ class LegacyBackupRestoreValidator : AbstractBackupRestoreValidator() {
|
|||
* @return List of missing sources or missing trackers.
|
||||
*/
|
||||
override fun validate(context: Context, uri: Uri): Results {
|
||||
val reader = JsonReader(context.contentResolver.openInputStream(uri)!!.bufferedReader())
|
||||
val json = JsonParser.parseReader(reader).asJsonObject
|
||||
val backupManager = LegacyBackupManager(context)
|
||||
|
||||
val version = json.get(Backup.VERSION)
|
||||
val mangasJson = json.get(Backup.MANGAS)
|
||||
if (version == null || mangasJson == null) {
|
||||
val backup = backupManager.parser.decodeFromString<Backup>(
|
||||
context.contentResolver.openInputStream(uri)!!.source().buffer().use { it.readUtf8() }
|
||||
)
|
||||
|
||||
if (backup.version == null) {
|
||||
throw Exception(context.getString(R.string.invalid_backup_file_missing_data))
|
||||
}
|
||||
|
||||
val mangas = mangasJson.asJsonArray
|
||||
if (mangas.size() == 0) {
|
||||
if (backup.mangas.isEmpty()) {
|
||||
throw Exception(context.getString(R.string.invalid_backup_file_missing_manga))
|
||||
}
|
||||
|
||||
val sources = getSourceMapping(json)
|
||||
val sources = getSourceMapping(backup.extensions ?: emptyList())
|
||||
val missingSources = sources
|
||||
.filter { sourceManager.get(it.key) == null }
|
||||
.values
|
||||
.sorted()
|
||||
|
||||
val trackers = mangas
|
||||
.filter { it.asJsonObject.has("track") }
|
||||
.flatMap { it.asJsonObject["track"].asJsonArray }
|
||||
.map { it.asJsonObject["s"].asInt }
|
||||
val trackers = backup.mangas
|
||||
.filterNot { it.track.isNullOrEmpty() }
|
||||
.flatMap { it.track ?: emptyList() }
|
||||
.map { it.sync_id }
|
||||
.distinct()
|
||||
val missingTrackers = trackers
|
||||
.mapNotNull { trackManager.getService(it) }
|
||||
|
@ -52,12 +52,10 @@ class LegacyBackupRestoreValidator : AbstractBackupRestoreValidator() {
|
|||
}
|
||||
|
||||
companion object {
|
||||
fun getSourceMapping(json: JsonObject): Map<Long, String> {
|
||||
val extensionsMapping = json.get(Backup.EXTENSIONS) ?: return emptyMap()
|
||||
|
||||
return extensionsMapping.asJsonArray
|
||||
fun getSourceMapping(extensionsMapping: List<String>): Map<Long, String> {
|
||||
return extensionsMapping
|
||||
.map {
|
||||
val items = it.asString.split(":")
|
||||
val items = it.split(":")
|
||||
items[0].toLong() to items[1]
|
||||
}
|
||||
.toMap()
|
||||
|
|
|
@ -1,30 +1,37 @@
|
|||
package eu.kanade.tachiyomi.data.backup.legacy.models
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import kotlinx.serialization.Contextual
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Json values
|
||||
*/
|
||||
object Backup {
|
||||
const val CURRENT_VERSION = 2
|
||||
const val MANGA = "manga"
|
||||
const val MANGAS = "mangas"
|
||||
const val ANIMES = "animes"
|
||||
const val TRACK = "track"
|
||||
const val ANIMETRACK = "animetrack"
|
||||
const val CHAPTERS = "chapters"
|
||||
const val EPISODES = "episodes"
|
||||
const val CATEGORIES = "categories"
|
||||
const val ANIMECATEGORIES = "animecategories"
|
||||
const val EXTENSIONS = "extensions"
|
||||
const val ANIMEEXTENSIONS = "animeextensions"
|
||||
const val HISTORY = "history"
|
||||
const val VERSION = "version"
|
||||
@Serializable
|
||||
data class Backup(
|
||||
val version: Int? = null,
|
||||
var mangas: MutableList<MangaObject> = mutableListOf(),
|
||||
var categories: List<@Contextual Category>? = null,
|
||||
var extensions: List<String>? = null
|
||||
) {
|
||||
companion object {
|
||||
const val CURRENT_VERSION = 2
|
||||
|
||||
fun getDefaultFilename(): String {
|
||||
val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date())
|
||||
return "tachiyomi_$date.json"
|
||||
fun getDefaultFilename(): String {
|
||||
val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date())
|
||||
return "tachiyomi_$date.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class MangaObject(
|
||||
var manga: @Contextual Manga,
|
||||
var chapters: List<@Contextual Chapter>? = null,
|
||||
var categories: List<String>? = null,
|
||||
var track: List<@Contextual Track>? = null,
|
||||
var history: List<@Contextual DHistory>? = null
|
||||
)
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
||||
|
||||
import com.github.salomonbrys.kotson.typeAdapter
|
||||
import com.google.gson.TypeAdapter
|
||||
import eu.kanade.tachiyomi.data.database.models.CategoryImpl
|
||||
|
||||
/**
|
||||
* JSON Serializer used to write / read [CategoryImpl] to / from json
|
||||
*/
|
||||
object CategoryTypeAdapter {
|
||||
|
||||
fun build(): TypeAdapter<CategoryImpl> {
|
||||
return typeAdapter {
|
||||
write {
|
||||
beginArray()
|
||||
value(it.name)
|
||||
value(it.order)
|
||||
endArray()
|
||||
}
|
||||
|
||||
read {
|
||||
beginArray()
|
||||
val category = CategoryImpl()
|
||||
category.name = nextString()
|
||||
category.order = nextInt()
|
||||
endArray()
|
||||
category
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.database.models.CategoryImpl
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.JsonDecoder
|
||||
import kotlinx.serialization.json.JsonEncoder
|
||||
import kotlinx.serialization.json.add
|
||||
import kotlinx.serialization.json.buildJsonArray
|
||||
import kotlinx.serialization.json.int
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
|
||||
/**
|
||||
* JSON Serializer used to write / read [CategoryImpl] to / from json
|
||||
*/
|
||||
open class CategoryBaseSerializer<T : Category> : KSerializer<T> {
|
||||
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Category")
|
||||
|
||||
override fun serialize(encoder: Encoder, value: T) {
|
||||
encoder as JsonEncoder
|
||||
encoder.encodeJsonElement(
|
||||
buildJsonArray {
|
||||
add(value.name)
|
||||
add(value.order)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun deserialize(decoder: Decoder): T {
|
||||
// make a category impl and cast as T so that the serializer accepts it
|
||||
return CategoryImpl().apply {
|
||||
decoder as JsonDecoder
|
||||
val array = decoder.decodeJsonElement().jsonArray
|
||||
name = array[0].jsonPrimitive.content
|
||||
order = array[1].jsonPrimitive.int
|
||||
} as T
|
||||
}
|
||||
}
|
||||
|
||||
// Allow for serialization of a category and category impl
|
||||
object CategoryTypeSerializer : CategoryBaseSerializer<Category>()
|
||||
|
||||
object CategoryImplTypeSerializer : CategoryBaseSerializer<CategoryImpl>()
|
|
@ -1,59 +0,0 @@
|
|||
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
||||
|
||||
import com.github.salomonbrys.kotson.typeAdapter
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.stream.JsonToken
|
||||
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
|
||||
|
||||
/**
|
||||
* JSON Serializer used to write / read [ChapterImpl] to / from json
|
||||
*/
|
||||
object ChapterTypeAdapter {
|
||||
|
||||
private const val URL = "u"
|
||||
private const val READ = "r"
|
||||
private const val BOOKMARK = "b"
|
||||
private const val LAST_READ = "l"
|
||||
|
||||
fun build(): TypeAdapter<ChapterImpl> {
|
||||
return typeAdapter {
|
||||
write {
|
||||
if (it.read || it.bookmark || it.last_page_read != 0) {
|
||||
beginObject()
|
||||
name(URL)
|
||||
value(it.url)
|
||||
if (it.read) {
|
||||
name(READ)
|
||||
value(1)
|
||||
}
|
||||
if (it.bookmark) {
|
||||
name(BOOKMARK)
|
||||
value(1)
|
||||
}
|
||||
if (it.last_page_read != 0) {
|
||||
name(LAST_READ)
|
||||
value(it.last_page_read)
|
||||
}
|
||||
endObject()
|
||||
}
|
||||
}
|
||||
|
||||
read {
|
||||
val chapter = ChapterImpl()
|
||||
beginObject()
|
||||
while (hasNext()) {
|
||||
if (peek() == JsonToken.NAME) {
|
||||
when (nextName()) {
|
||||
URL -> chapter.url = nextString()
|
||||
READ -> chapter.read = nextInt() == 1
|
||||
BOOKMARK -> chapter.bookmark = nextInt() == 1
|
||||
LAST_READ -> chapter.last_page_read = nextInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
endObject()
|
||||
chapter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.JsonDecoder
|
||||
import kotlinx.serialization.json.JsonEncoder
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlinx.serialization.json.intOrNull
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import kotlinx.serialization.json.put
|
||||
|
||||
/**
|
||||
* JSON Serializer used to write / read [ChapterImpl] to / from json
|
||||
*/
|
||||
open class ChapterBaseSerializer<T : Chapter> : KSerializer<T> {
|
||||
|
||||
override val descriptor = buildClassSerialDescriptor("Chapter")
|
||||
|
||||
override fun serialize(encoder: Encoder, value: T) {
|
||||
encoder as JsonEncoder
|
||||
encoder.encodeJsonElement(
|
||||
buildJsonObject {
|
||||
put(URL, value.url)
|
||||
if (value.read) {
|
||||
put(READ, 1)
|
||||
}
|
||||
if (value.bookmark) {
|
||||
put(BOOKMARK, 1)
|
||||
}
|
||||
if (value.last_page_read != 0) {
|
||||
put(LAST_READ, value.last_page_read)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun deserialize(decoder: Decoder): T {
|
||||
// make a chapter impl and cast as T so that the serializer accepts it
|
||||
return ChapterImpl().apply {
|
||||
decoder as JsonDecoder
|
||||
val jsonObject = decoder.decodeJsonElement().jsonObject
|
||||
url = jsonObject[URL]!!.jsonPrimitive.content
|
||||
read = jsonObject[READ]?.jsonPrimitive?.intOrNull == 1
|
||||
bookmark = jsonObject[BOOKMARK]?.jsonPrimitive?.intOrNull == 1
|
||||
last_page_read = jsonObject[LAST_READ]?.jsonPrimitive?.intOrNull ?: last_page_read
|
||||
} as T
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val URL = "u"
|
||||
private const val READ = "r"
|
||||
private const val BOOKMARK = "b"
|
||||
private const val LAST_READ = "l"
|
||||
}
|
||||
}
|
||||
|
||||
// Allow for serialization of a chapter and chapter impl
|
||||
object ChapterTypeSerializer : ChapterBaseSerializer<Chapter>()
|
||||
|
||||
object ChapterImplTypeSerializer : ChapterBaseSerializer<ChapterImpl>()
|
|
@ -1,32 +0,0 @@
|
|||
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
||||
|
||||
import com.github.salomonbrys.kotson.typeAdapter
|
||||
import com.google.gson.TypeAdapter
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
|
||||
|
||||
/**
|
||||
* JSON Serializer used to write / read [DHistory] to / from json
|
||||
*/
|
||||
object HistoryTypeAdapter {
|
||||
|
||||
fun build(): TypeAdapter<DHistory> {
|
||||
return typeAdapter {
|
||||
write {
|
||||
if (it.lastRead != 0L) {
|
||||
beginArray()
|
||||
value(it.url)
|
||||
value(it.lastRead)
|
||||
endArray()
|
||||
}
|
||||
}
|
||||
|
||||
read {
|
||||
beginArray()
|
||||
val url = nextString()
|
||||
val lastRead = nextLong()
|
||||
endArray()
|
||||
DHistory(url, lastRead)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
||||
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.JsonDecoder
|
||||
import kotlinx.serialization.json.JsonEncoder
|
||||
import kotlinx.serialization.json.add
|
||||
import kotlinx.serialization.json.buildJsonArray
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import kotlinx.serialization.json.long
|
||||
|
||||
/**
|
||||
* JSON Serializer used to write / read [DHistory] to / from json
|
||||
*/
|
||||
object HistoryTypeSerializer : KSerializer<DHistory> {
|
||||
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("History")
|
||||
|
||||
override fun serialize(encoder: Encoder, value: DHistory) {
|
||||
encoder as JsonEncoder
|
||||
encoder.encodeJsonElement(
|
||||
buildJsonArray {
|
||||
add(value.url)
|
||||
add(value.lastRead)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): DHistory {
|
||||
decoder as JsonDecoder
|
||||
val array = decoder.decodeJsonElement().jsonArray
|
||||
return DHistory(
|
||||
url = array[0].jsonPrimitive.content,
|
||||
lastRead = array[1].jsonPrimitive.long
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
||||
|
||||
import com.github.salomonbrys.kotson.typeAdapter
|
||||
import com.google.gson.TypeAdapter
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||
|
||||
/**
|
||||
* JSON Serializer used to write / read [MangaImpl] to / from json
|
||||
*/
|
||||
object MangaTypeAdapter {
|
||||
|
||||
fun build(): TypeAdapter<MangaImpl> {
|
||||
return typeAdapter {
|
||||
write {
|
||||
beginArray()
|
||||
value(it.url)
|
||||
value(it.title)
|
||||
value(it.source)
|
||||
value(it.viewer_flags)
|
||||
value(it.chapter_flags)
|
||||
endArray()
|
||||
}
|
||||
|
||||
read {
|
||||
beginArray()
|
||||
val manga = MangaImpl()
|
||||
manga.url = nextString()
|
||||
manga.title = nextString()
|
||||
manga.source = nextLong()
|
||||
manga.viewer_flags = nextInt()
|
||||
manga.chapter_flags = nextInt()
|
||||
endArray()
|
||||
manga
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.JsonDecoder
|
||||
import kotlinx.serialization.json.JsonEncoder
|
||||
import kotlinx.serialization.json.add
|
||||
import kotlinx.serialization.json.buildJsonArray
|
||||
import kotlinx.serialization.json.int
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import kotlinx.serialization.json.long
|
||||
|
||||
/**
|
||||
* JSON Serializer used to write / read [MangaImpl] to / from json
|
||||
*/
|
||||
open class MangaBaseSerializer<T : Manga> : KSerializer<T> {
|
||||
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Manga")
|
||||
|
||||
override fun serialize(encoder: Encoder, value: T) {
|
||||
encoder as JsonEncoder
|
||||
encoder.encodeJsonElement(
|
||||
buildJsonArray {
|
||||
add(value.url)
|
||||
add(value.title)
|
||||
add(value.source)
|
||||
add(value.viewer_flags)
|
||||
add(value.chapter_flags)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun deserialize(decoder: Decoder): T {
|
||||
// make a manga impl and cast as T so that the serializer accepts it
|
||||
return MangaImpl().apply {
|
||||
decoder as JsonDecoder
|
||||
val array = decoder.decodeJsonElement().jsonArray
|
||||
url = array[0].jsonPrimitive.content
|
||||
title = array[1].jsonPrimitive.content
|
||||
source = array[2].jsonPrimitive.long
|
||||
viewer_flags = array[3].jsonPrimitive.int
|
||||
chapter_flags = array[4].jsonPrimitive.int
|
||||
} as T
|
||||
}
|
||||
}
|
||||
|
||||
// Allow for serialization of a manga and manga impl
|
||||
object MangaTypeSerializer : MangaBaseSerializer<Manga>()
|
||||
|
||||
object MangaImplTypeSerializer : MangaBaseSerializer<MangaImpl>()
|
|
@ -1,59 +0,0 @@
|
|||
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
||||
|
||||
import com.github.salomonbrys.kotson.typeAdapter
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.stream.JsonToken
|
||||
import eu.kanade.tachiyomi.data.database.models.TrackImpl
|
||||
|
||||
/**
|
||||
* JSON Serializer used to write / read [TrackImpl] to / from json
|
||||
*/
|
||||
object TrackTypeAdapter {
|
||||
|
||||
private const val SYNC = "s"
|
||||
private const val MEDIA = "r"
|
||||
private const val LIBRARY = "ml"
|
||||
private const val TITLE = "t"
|
||||
private const val LAST_READ = "l"
|
||||
private const val TRACKING_URL = "u"
|
||||
|
||||
fun build(): TypeAdapter<TrackImpl> {
|
||||
return typeAdapter {
|
||||
write {
|
||||
beginObject()
|
||||
name(TITLE)
|
||||
value(it.title)
|
||||
name(SYNC)
|
||||
value(it.sync_id)
|
||||
name(MEDIA)
|
||||
value(it.media_id)
|
||||
name(LIBRARY)
|
||||
value(it.library_id)
|
||||
name(LAST_READ)
|
||||
value(it.last_chapter_read)
|
||||
name(TRACKING_URL)
|
||||
value(it.tracking_url)
|
||||
endObject()
|
||||
}
|
||||
|
||||
read {
|
||||
val track = TrackImpl()
|
||||
beginObject()
|
||||
while (hasNext()) {
|
||||
if (peek() == JsonToken.NAME) {
|
||||
when (nextName()) {
|
||||
TITLE -> track.title = nextString()
|
||||
SYNC -> track.sync_id = nextInt()
|
||||
MEDIA -> track.media_id = nextInt()
|
||||
LIBRARY -> track.library_id = nextLong()
|
||||
LAST_READ -> track.last_chapter_read = nextInt()
|
||||
TRACKING_URL -> track.tracking_url = nextString()
|
||||
}
|
||||
}
|
||||
}
|
||||
endObject()
|
||||
track
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.database.models.TrackImpl
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.JsonDecoder
|
||||
import kotlinx.serialization.json.JsonEncoder
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlinx.serialization.json.int
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import kotlinx.serialization.json.long
|
||||
import kotlinx.serialization.json.put
|
||||
|
||||
/**
|
||||
* JSON Serializer used to write / read [TrackImpl] to / from json
|
||||
*/
|
||||
open class TrackBaseSerializer<T : Track> : KSerializer<T> {
|
||||
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Track")
|
||||
|
||||
override fun serialize(encoder: Encoder, value: T) {
|
||||
encoder as JsonEncoder
|
||||
encoder.encodeJsonElement(
|
||||
buildJsonObject {
|
||||
put(TITLE, value.title)
|
||||
put(SYNC, value.sync_id)
|
||||
put(MEDIA, value.media_id)
|
||||
put(LIBRARY, value.library_id)
|
||||
put(LAST_READ, value.last_chapter_read)
|
||||
put(TRACKING_URL, value.tracking_url)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun deserialize(decoder: Decoder): T {
|
||||
// make a track impl and cast as T so that the serializer accepts it
|
||||
return TrackImpl().apply {
|
||||
decoder as JsonDecoder
|
||||
val jsonObject = decoder.decodeJsonElement().jsonObject
|
||||
title = jsonObject[TITLE]!!.jsonPrimitive.content
|
||||
sync_id = jsonObject[SYNC]!!.jsonPrimitive.int
|
||||
media_id = jsonObject[MEDIA]!!.jsonPrimitive.int
|
||||
library_id = jsonObject[LIBRARY]!!.jsonPrimitive.long
|
||||
last_chapter_read = jsonObject[LAST_READ]!!.jsonPrimitive.int
|
||||
tracking_url = jsonObject[TRACKING_URL]!!.jsonPrimitive.content
|
||||
} as T
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SYNC = "s"
|
||||
private const val MEDIA = "r"
|
||||
private const val LIBRARY = "ml"
|
||||
private const val TITLE = "t"
|
||||
private const val LAST_READ = "l"
|
||||
private const val TRACKING_URL = "u"
|
||||
}
|
||||
}
|
||||
|
||||
// Allow for serialization of a track and track impl
|
||||
object TrackTypeSerializer : TrackBaseSerializer<Track>()
|
||||
|
||||
object TrackImplTypeSerializer : TrackBaseSerializer<TrackImpl>()
|
|
@ -243,7 +243,7 @@ class AnimeInfoHeaderAdapter(
|
|||
setFavoriteButtonState(anime.favorite)
|
||||
|
||||
// Set cover if changed.
|
||||
listOf(binding.mangaCover, binding.backdrop).forEach {
|
||||
listOfNotNull(binding.mangaCover, binding.backdrop).forEach {
|
||||
it.loadAny(anime.thumbnail_url)
|
||||
}
|
||||
|
||||
|
@ -277,7 +277,8 @@ class AnimeInfoHeaderAdapter(
|
|||
merge(
|
||||
binding.mangaSummaryText.clicks(),
|
||||
binding.mangaInfoToggleMore.clicks(),
|
||||
binding.mangaInfoToggleLess.clicks()
|
||||
binding.mangaInfoToggleLess.clicks(),
|
||||
binding.mangaSummarySection.clicks()
|
||||
)
|
||||
.onEach { toggleAnimeInfo() }
|
||||
.launchIn(controller.viewScope)
|
||||
|
@ -288,6 +289,13 @@ class AnimeInfoHeaderAdapter(
|
|||
toggleAnimeInfo()
|
||||
initialLoad = false
|
||||
}
|
||||
|
||||
// Refreshes will change the state and it needs to be set to correct state to display correctly
|
||||
if (binding.mangaSummaryText.maxLines == 2) {
|
||||
binding.mangaSummarySection.transitionToState(R.id.start)
|
||||
} else {
|
||||
binding.mangaSummarySection.transitionToState(R.id.end)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,18 +306,17 @@ class AnimeInfoHeaderAdapter(
|
|||
private fun toggleAnimeInfo() {
|
||||
val isCurrentlyExpanded = binding.mangaSummaryText.maxLines != 2
|
||||
|
||||
binding.mangaInfoToggleMoreScrim.isVisible = isCurrentlyExpanded
|
||||
binding.mangaInfoToggleMore.isVisible = isCurrentlyExpanded
|
||||
binding.mangaInfoToggleLess.isVisible = !isCurrentlyExpanded
|
||||
if (isCurrentlyExpanded) {
|
||||
binding.mangaSummarySection.transitionToStart()
|
||||
} else {
|
||||
binding.mangaSummarySection.transitionToEnd()
|
||||
}
|
||||
|
||||
binding.mangaSummaryText.maxLines = if (isCurrentlyExpanded) {
|
||||
2
|
||||
} else {
|
||||
Int.MAX_VALUE
|
||||
}
|
||||
|
||||
binding.mangaGenresTagsCompact.isVisible = isCurrentlyExpanded
|
||||
binding.mangaGenresTagsFullChips.isVisible = !isCurrentlyExpanded
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -178,7 +178,9 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
|
|||
controller?.showSettingsSheet()
|
||||
}
|
||||
R.id.nav_updates -> {
|
||||
router.pushController(DownloadTabsController().withFadeTransaction())
|
||||
if (router.backstackSize == 1) {
|
||||
router.pushController(DownloadTabsController().withFadeTransaction())
|
||||
}
|
||||
}
|
||||
R.id.nav_animelib -> {
|
||||
val controller = router.getControllerWithTag(id.toString()) as? AnimelibController
|
||||
|
|
|
@ -243,7 +243,7 @@ class MangaInfoHeaderAdapter(
|
|||
setFavoriteButtonState(manga.favorite)
|
||||
|
||||
// Set cover if changed.
|
||||
listOf(binding.mangaCover, binding.backdrop).forEach {
|
||||
listOfNotNull(binding.mangaCover, binding.backdrop).forEach {
|
||||
it.loadAny(manga)
|
||||
}
|
||||
|
||||
|
@ -277,7 +277,8 @@ class MangaInfoHeaderAdapter(
|
|||
merge(
|
||||
binding.mangaSummaryText.clicks(),
|
||||
binding.mangaInfoToggleMore.clicks(),
|
||||
binding.mangaInfoToggleLess.clicks()
|
||||
binding.mangaInfoToggleLess.clicks(),
|
||||
binding.mangaSummarySection.clicks()
|
||||
)
|
||||
.onEach { toggleMangaInfo() }
|
||||
.launchIn(controller.viewScope)
|
||||
|
@ -288,6 +289,13 @@ class MangaInfoHeaderAdapter(
|
|||
toggleMangaInfo()
|
||||
initialLoad = false
|
||||
}
|
||||
|
||||
// Refreshes will change the state and it needs to be set to correct state to display correctly
|
||||
if (binding.mangaSummaryText.maxLines == 2) {
|
||||
binding.mangaSummarySection.transitionToState(R.id.start)
|
||||
} else {
|
||||
binding.mangaSummarySection.transitionToState(R.id.end)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,18 +306,17 @@ class MangaInfoHeaderAdapter(
|
|||
private fun toggleMangaInfo() {
|
||||
val isCurrentlyExpanded = binding.mangaSummaryText.maxLines != 2
|
||||
|
||||
binding.mangaInfoToggleMoreScrim.isVisible = isCurrentlyExpanded
|
||||
binding.mangaInfoToggleMore.isVisible = isCurrentlyExpanded
|
||||
binding.mangaInfoToggleLess.isVisible = !isCurrentlyExpanded
|
||||
if (isCurrentlyExpanded) {
|
||||
binding.mangaSummarySection.transitionToStart()
|
||||
} else {
|
||||
binding.mangaSummarySection.transitionToEnd()
|
||||
}
|
||||
|
||||
binding.mangaSummaryText.maxLines = if (isCurrentlyExpanded) {
|
||||
2
|
||||
} else {
|
||||
Int.MAX_VALUE
|
||||
}
|
||||
|
||||
binding.mangaGenresTagsCompact.isVisible = isCurrentlyExpanded
|
||||
binding.mangaGenresTagsFullChips.isVisible = !isCurrentlyExpanded
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -271,8 +271,8 @@ fun Context.createFileInCacheDir(name: String): File {
|
|||
}
|
||||
|
||||
/**
|
||||
* We consider anything with a width of >= 600dp as a tablet, i.e. with layouts in layout-sw600dp.
|
||||
* We consider anything with a width of >= 720dp as a tablet, i.e. with layouts in layout-w720dp.
|
||||
*/
|
||||
fun Context.isTablet(): Boolean {
|
||||
return resources.configuration.screenWidthDp >= 600
|
||||
return (resources.displayMetrics.widthPixels / resources.displayMetrics.density) >= 720
|
||||
}
|
||||
|
|
282
app/src/main/res/layout-w720dp/manga_info_header.xml
Normal file
282
app/src/main/res/layout-w720dp/manga_info_header.xml
Normal file
|
@ -0,0 +1,282 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layoutDescription="@xml/manga_info_header_scene_sw600dp"
|
||||
tools:context=".ui.browse.source.browse.BrowseSourceController">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/backdrop"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginBottom="-32dp"
|
||||
android:alpha="0.2"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/manga_cover"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:background="@mipmap/ic_launcher" />
|
||||
|
||||
<View
|
||||
android:id="@+id/backdrop_overlay"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:alpha="1"
|
||||
android:background="@drawable/manga_info_gradient"
|
||||
android:backgroundTint="?android:attr/colorBackground"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/backdrop"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/manga_cover"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="@dimen/tablet_horizontal_cover_margin"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginEnd="@dimen/tablet_horizontal_cover_margin"
|
||||
android:background="@drawable/rounded_rectangle"
|
||||
android:contentDescription="@string/description_cover"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintDimensionRatio="w,3:2"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@mipmap/ic_launcher" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/manga_detail"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="-8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/backdrop">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_full_title"
|
||||
style="@style/TextAppearance.Medium.Title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:gravity="bottom"
|
||||
android:maxLines="3"
|
||||
android:text="@string/manga_info_full_title_label"
|
||||
android:textAlignment="center"
|
||||
android:textIsSelectable="false"
|
||||
app:autoSizeMaxTextSize="20sp"
|
||||
app:autoSizeMinTextSize="12sp"
|
||||
app:autoSizeStepGranularity="2sp"
|
||||
app:autoSizeTextType="uniform" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_author"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="center"
|
||||
android:textIsSelectable="false"
|
||||
tools:text="Author" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_artist"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:textIsSelectable="false"
|
||||
tools:text="Artist" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/manga_status_row"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_status"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textIsSelectable="false"
|
||||
tools:text="Status" />
|
||||
|
||||
<TextView
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:text="•"
|
||||
android:textIsSelectable="false"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_source"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textIsSelectable="false"
|
||||
tools:text="Source" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_favorite"
|
||||
style="@style/Theme.Widget.Button.Action"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/add_to_library"
|
||||
app:icon="@drawable/ic_favorite_border_24dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/btn_tracking"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_detail" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_tracking"
|
||||
style="@style/Theme.Widget.Button.Action"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/manga_tracking_tab"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_sync_24dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/btn_webview"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/btn_favorite"
|
||||
app:layout_constraintTop_toTopOf="@+id/btn_favorite"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_webview"
|
||||
style="@style/Theme.Widget.Button.Action"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/action_web_view"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_public_24dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/btn_tracking"
|
||||
app:layout_constraintTop_toTopOf="@+id/btn_favorite"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.constraintlayout.motion.widget.MotionLayout
|
||||
android:id="@+id/manga_summary_section"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layoutDescription="@xml/manga_summary_section_scene"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/btn_favorite">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_summary_text"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:maxLines="2"
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_cover"
|
||||
tools:text="Collapsed summary content Collapsed summary content Collapsed summary content Collapsed summary content Collapsed summary content Collapsed summary content" />
|
||||
|
||||
<View
|
||||
android:id="@+id/manga_info_toggle_more_scrim"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/manga_info_more_gradient"
|
||||
android:backgroundTint="?android:attr/colorBackground"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/manga_info_toggle_more"
|
||||
app:layout_constraintEnd_toStartOf="@+id/manga_info_toggle_more"
|
||||
app:layout_constraintTop_toTopOf="@+id/manga_info_toggle_more" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/manga_info_toggle_more"
|
||||
style="@style/Theme.Widget.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/manga_info_expand"
|
||||
android:textAlignment="viewEnd"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/manga_summary_text"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/manga_info_toggle_less"
|
||||
style="@style/Theme.Widget.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/manga_info_collapse"
|
||||
android:textAlignment="viewEnd"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_summary_text"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/manga_genres_tags_compact"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:requiresFadingEdge="horizontal"
|
||||
android:scrollbars="none"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_summary_text">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/manga_genres_tags_compact_chips"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="8dp"
|
||||
app:chipSpacingHorizontal="4dp"
|
||||
app:singleLine="true" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/manga_genres_tags_full_chips"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:visibility="gone"
|
||||
app:chipSpacingHorizontal="4dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_info_toggle_less"
|
||||
tools:visibility="gone" />
|
||||
|
||||
</androidx.constraintlayout.motion.widget.MotionLayout>
|
||||
|
||||
</androidx.constraintlayout.motion.widget.MotionLayout>
|
|
@ -168,100 +168,107 @@
|
|||
app:layout_constraintTop_toTopOf="@+id/btn_favorite"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_summary_text"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:maxLines="2"
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/btn_favorite"
|
||||
tools:text="Collapsed summary content Collapsed summary content Collapsed summary content Collapsed summary content Collapsed summary content Collapsed summary content" />
|
||||
|
||||
<View
|
||||
android:id="@+id/manga_info_toggle_more_scrim"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/manga_info_more_gradient"
|
||||
android:backgroundTint="?android:attr/colorBackground"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/manga_info_toggle_more"
|
||||
app:layout_constraintEnd_toStartOf="@+id/manga_info_toggle_more"
|
||||
app:layout_constraintTop_toTopOf="@+id/manga_info_toggle_more" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/manga_info_toggle_more"
|
||||
style="@style/Theme.Widget.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/manga_info_expand"
|
||||
android:textAlignment="viewEnd"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/manga_summary_text"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/manga_info_toggle_less"
|
||||
style="@style/Theme.Widget.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/manga_info_collapse"
|
||||
android:textAlignment="viewEnd"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_summary_text"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/manga_genres_tags_compact"
|
||||
<androidx.constraintlayout.motion.widget.MotionLayout
|
||||
android:id="@+id/manga_summary_section"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:requiresFadingEdge="horizontal"
|
||||
android:scrollbars="none"
|
||||
app:layoutDescription="@xml/manga_summary_section_scene"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_summary_text">
|
||||
app:layout_constraintTop_toBottomOf="@+id/btn_favorite">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/manga_genres_tags_compact_chips"
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_summary_text"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:maxLines="2"
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_cover"
|
||||
tools:text="Collapsed summary content Collapsed summary content Collapsed summary content Collapsed summary content Collapsed summary content Collapsed summary content" />
|
||||
|
||||
<View
|
||||
android:id="@+id/manga_info_toggle_more_scrim"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/manga_info_more_gradient"
|
||||
android:backgroundTint="?android:attr/colorBackground"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/manga_info_toggle_more"
|
||||
app:layout_constraintEnd_toStartOf="@+id/manga_info_toggle_more"
|
||||
app:layout_constraintTop_toTopOf="@+id/manga_info_toggle_more" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/manga_info_toggle_more"
|
||||
style="@style/Theme.Widget.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/manga_info_expand"
|
||||
android:textAlignment="viewEnd"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/manga_summary_text"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/manga_info_toggle_less"
|
||||
style="@style/Theme.Widget.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/manga_info_collapse"
|
||||
android:textAlignment="viewEnd"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_summary_text"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/manga_genres_tags_compact"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:requiresFadingEdge="horizontal"
|
||||
android:scrollbars="none"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_summary_text">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/manga_genres_tags_compact_chips"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="8dp"
|
||||
app:chipSpacingHorizontal="4dp"
|
||||
app:singleLine="true" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/manga_genres_tags_full_chips"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:visibility="gone"
|
||||
app:chipSpacingHorizontal="4dp"
|
||||
app:singleLine="true" />
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_info_toggle_less"
|
||||
tools:visibility="gone" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/manga_genres_tags_full_chips"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:visibility="gone"
|
||||
app:chipSpacingHorizontal="4dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_info_toggle_less"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/manga_summary_section"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:constraint_referenced_ids="manga_summary_text,manga_info_toggle_more,manga_info_toggle_more_scrim,manga_genres_tags_compact" />
|
||||
</androidx.constraintlayout.motion.widget.MotionLayout>
|
||||
|
||||
</androidx.constraintlayout.motion.widget.MotionLayout>
|
||||
|
|
4
app/src/main/res/values-sw600dp-port/dimens.xml
Normal file
4
app/src/main/res/values-sw600dp-port/dimens.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="tablet_horizontal_cover_margin">80dp</dimen>
|
||||
</resources>
|
|
@ -14,4 +14,6 @@
|
|||
<dimen name="action_toolbar_list_padding">72dp</dimen>
|
||||
|
||||
<dimen name="screen_edge_margin">16dp</dimen>
|
||||
|
||||
<dimen name="tablet_horizontal_cover_margin">128dp</dimen>
|
||||
</resources>
|
||||
|
|
|
@ -6,62 +6,15 @@
|
|||
motion:constraintSetEnd="@+id/end"
|
||||
motion:constraintSetStart="@id/start"
|
||||
motion:duration="@android:integer/config_mediumAnimTime">
|
||||
<KeyFrameSet>
|
||||
<KeyPosition
|
||||
motion:keyPositionType="pathRelative"
|
||||
motion:motionTarget="@+id/manga_detail" />
|
||||
</KeyFrameSet>
|
||||
<KeyFrameSet></KeyFrameSet>
|
||||
<OnClick motion:targetId="@+id/manga_cover" />
|
||||
</Transition>
|
||||
|
||||
<ConstraintSet android:id="@+id/start">
|
||||
<Constraint
|
||||
android:id="@+id/manga_info_toggle_more"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
motion:layout_constraintBottom_toBottomOf="@+id/manga_summary_text"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_genres_tags_compact"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/manga_summary_text"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_info_toggle_more_scrim"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="0dp"
|
||||
motion:layout_constraintBottom_toBottomOf="@+id/manga_info_toggle_more"
|
||||
motion:layout_constraintEnd_toStartOf="@+id/manga_info_toggle_more"
|
||||
motion:layout_constraintTop_toTopOf="@+id/manga_info_toggle_more"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_info_toggle_less"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/manga_summary_text"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_genres_tags_full_chips"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:visibility="gone"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@id/manga_info_toggle_less"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/btn_tracking"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="visible"
|
||||
motion:layout_constraintEnd_toStartOf="@+id/btn_webview"
|
||||
motion:layout_constraintHorizontal_bias="0.5"
|
||||
motion:layout_constraintStart_toEndOf="@+id/btn_favorite"
|
||||
|
@ -71,12 +24,19 @@
|
|||
android:id="@+id/btn_webview"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="visible"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintHorizontal_bias="0.5"
|
||||
motion:layout_constraintStart_toEndOf="@+id/btn_tracking"
|
||||
motion:layout_constraintTop_toTopOf="@+id/btn_favorite"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_summary_section"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/btn_favorite"
|
||||
motion:visibilityMode="ignore" />
|
||||
</ConstraintSet>
|
||||
|
||||
<ConstraintSet android:id="@+id/end">
|
||||
|
@ -134,19 +94,10 @@
|
|||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@id/manga_cover" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_info_toggle_less"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="visible"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/manga_summary_text"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/btn_tracking"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="visible"
|
||||
motion:layout_constraintEnd_toStartOf="@+id/btn_webview"
|
||||
motion:layout_constraintHorizontal_bias="0.5"
|
||||
motion:layout_constraintStart_toEndOf="@+id/btn_favorite"
|
||||
|
@ -166,55 +117,18 @@
|
|||
android:id="@+id/btn_webview"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="visible"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintHorizontal_bias="0.5"
|
||||
motion:layout_constraintStart_toEndOf="@+id/btn_tracking"
|
||||
motion:layout_constraintTop_toTopOf="@+id/btn_favorite"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_summary_text"
|
||||
android:id="@+id/manga_summary_section"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/btn_favorite"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_info_toggle_more_scrim"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="0dp"
|
||||
motion:layout_constraintBottom_toBottomOf="@+id/manga_info_toggle_more"
|
||||
motion:layout_constraintEnd_toStartOf="@+id/manga_info_toggle_more"
|
||||
motion:layout_constraintTop_toTopOf="@+id/manga_info_toggle_more"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_info_toggle_more"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
motion:layout_constraintBottom_toBottomOf="@+id/manga_summary_text"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_genres_tags_compact"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/manga_summary_text"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_genres_tags_full_chips"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:visibility="visible"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/manga_info_toggle_less"
|
||||
motion:visibilityMode="ignore" />
|
||||
</ConstraintSet>
|
||||
</MotionScene>
|
||||
|
|
59
app/src/main/res/xml/manga_info_header_scene_sw600dp.xml
Normal file
59
app/src/main/res/xml/manga_info_header_scene_sw600dp.xml
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:motion="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<Transition
|
||||
motion:constraintSetEnd="@+id/end"
|
||||
motion:constraintSetStart="@id/start"
|
||||
motion:duration="@android:integer/config_mediumAnimTime">
|
||||
<KeyFrameSet></KeyFrameSet>
|
||||
<OnClick motion:targetId="@+id/manga_cover" />
|
||||
</Transition>
|
||||
|
||||
<ConstraintSet android:id="@+id/start">
|
||||
<Constraint
|
||||
android:id="@+id/manga_summary_section"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/btn_favorite"
|
||||
motion:visibilityMode="ignore" />
|
||||
</ConstraintSet>
|
||||
|
||||
<ConstraintSet android:id="@+id/end">
|
||||
|
||||
<Constraint
|
||||
android:id="@+id/manga_summary_section"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@id/btn_favorite"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_detail"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/manga_cover" />
|
||||
<Constraint
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:layout_marginStart="0dp"
|
||||
motion:layout_constraintTop_toTopOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintDimensionRatio="w,3:2"
|
||||
android:layout_marginTop="0dp"
|
||||
android:id="@+id/manga_cover" />
|
||||
</ConstraintSet>
|
||||
</MotionScene>
|
142
app/src/main/res/xml/manga_summary_section_scene.xml
Normal file
142
app/src/main/res/xml/manga_summary_section_scene.xml
Normal file
|
@ -0,0 +1,142 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:motion="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<Transition
|
||||
motion:constraintSetEnd="@+id/end"
|
||||
motion:constraintSetStart="@id/start"
|
||||
motion:duration="1">
|
||||
<KeyFrameSet></KeyFrameSet>
|
||||
<OnClick motion:clickAction="toggle" />
|
||||
</Transition>
|
||||
|
||||
<ConstraintSet android:id="@+id/start">
|
||||
<Constraint
|
||||
android:id="@+id/manga_info_toggle_more_scrim"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="visible"
|
||||
motion:layout_constraintBottom_toBottomOf="@+id/manga_info_toggle_more"
|
||||
motion:layout_constraintEnd_toStartOf="@+id/manga_info_toggle_more"
|
||||
motion:layout_constraintTop_toTopOf="@+id/manga_info_toggle_more" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_info_toggle_more"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="visible"
|
||||
motion:layout_constraintBottom_toBottomOf="@+id/manga_summary_text"
|
||||
motion:layout_constraintEnd_toEndOf="parent" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_info_toggle_less"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/manga_summary_text" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_genres_tags_compact"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="visible"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/manga_summary_text" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_genres_tags_full_chips"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:visibility="gone"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/manga_info_toggle_less" />
|
||||
</ConstraintSet>
|
||||
|
||||
<ConstraintSet android:id="@+id/end">
|
||||
<Constraint
|
||||
android:id="@+id/manga_info_toggle_more_scrim"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="gone"
|
||||
motion:layout_constraintBottom_toBottomOf="@+id/manga_info_toggle_more"
|
||||
motion:layout_constraintEnd_toStartOf="@+id/manga_info_toggle_more"
|
||||
motion:layout_constraintTop_toTopOf="@+id/manga_info_toggle_more" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_info_toggle_more"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
motion:layout_constraintBottom_toBottomOf="@+id/manga_summary_text"
|
||||
motion:layout_constraintEnd_toEndOf="parent" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_info_toggle_less"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="visible"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/manga_summary_text" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_genres_tags_compact"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/manga_summary_text" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_genres_tags_full_chips"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:visibility="visible"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/manga_info_toggle_less" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_summary_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/manga_cover"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_summary_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/manga_cover"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_summary_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/manga_cover"
|
||||
motion:visibilityMode="ignore" />
|
||||
<Constraint
|
||||
android:id="@+id/manga_summary_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
motion:layout_constraintEnd_toEndOf="parent"
|
||||
motion:layout_constraintStart_toStartOf="parent"
|
||||
motion:layout_constraintTop_toBottomOf="@+id/manga_cover"
|
||||
motion:visibilityMode="ignore" />
|
||||
</ConstraintSet>
|
||||
</MotionScene>
|
|
@ -3,9 +3,6 @@ package eu.kanade.tachiyomi.data.backup
|
|||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import com.github.salomonbrys.kotson.fromJson
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.CustomRobolectricGradleTestRunner
|
||||
import eu.kanade.tachiyomi.data.backup.legacy.LegacyBackupManager
|
||||
|
@ -17,12 +14,16 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
|
|||
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.database.models.TrackImpl
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
@ -47,16 +48,10 @@ import uy.kohesive.injekt.api.addSingleton
|
|||
@RunWith(CustomRobolectricGradleTestRunner::class)
|
||||
class BackupTest {
|
||||
// Create root object
|
||||
var root = JsonObject()
|
||||
var root = Backup()
|
||||
|
||||
// Create information object
|
||||
var information = JsonObject()
|
||||
|
||||
// Create manga array
|
||||
var mangaEntries = JsonArray()
|
||||
|
||||
// Create category array
|
||||
var categoryEntries = JsonArray()
|
||||
var information = buildJsonObject {}
|
||||
|
||||
lateinit var app: Application
|
||||
lateinit var context: Context
|
||||
|
@ -83,11 +78,6 @@ class BackupTest {
|
|||
|
||||
source = mock(HttpSource::class.java)
|
||||
`when`(legacyBackupManager.sourceManager.get(anyLong())).thenReturn(source)
|
||||
|
||||
root.add(Backup.MANGAS, mangaEntries)
|
||||
root.add(Backup.CATEGORIES, categoryEntries)
|
||||
|
||||
clearJson()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -95,11 +85,8 @@ class BackupTest {
|
|||
*/
|
||||
@Test
|
||||
fun testRestoreEmptyCategory() {
|
||||
// Create backup of empty database
|
||||
legacyBackupManager.backupCategories(categoryEntries)
|
||||
|
||||
// Restore Json
|
||||
legacyBackupManager.restoreCategories(categoryEntries)
|
||||
legacyBackupManager.restoreCategories(root.categories ?: emptyList())
|
||||
|
||||
// Check if empty
|
||||
val dbCats = db.getCategories().executeAsBlocking()
|
||||
|
@ -115,7 +102,7 @@ class BackupTest {
|
|||
val category = addSingleCategory("category")
|
||||
|
||||
// Restore Json
|
||||
legacyBackupManager.restoreCategories(categoryEntries)
|
||||
legacyBackupManager.restoreCategories(root.categories ?: emptyList())
|
||||
|
||||
// Check if successful
|
||||
val dbCats = legacyBackupManager.databaseHelper.getCategories().executeAsBlocking()
|
||||
|
@ -139,7 +126,7 @@ class BackupTest {
|
|||
db.insertCategory(category).executeAsBlocking()
|
||||
|
||||
// Restore Json
|
||||
legacyBackupManager.restoreCategories(categoryEntries)
|
||||
legacyBackupManager.restoreCategories(root.categories ?: emptyList())
|
||||
|
||||
// Check if successful
|
||||
val dbCats = legacyBackupManager.databaseHelper.getCategories().executeAsBlocking()
|
||||
|
@ -167,9 +154,6 @@ class BackupTest {
|
|||
assertThat(favoriteManga[0].readingModeType).isEqualTo(ReadingModeType.VERTICAL.flagValue)
|
||||
assertThat(favoriteManga[0].orientationType).isEqualTo(OrientationType.PORTRAIT.flagValue)
|
||||
|
||||
// Update json with all options enabled
|
||||
mangaEntries.add(legacyBackupManager.backupMangaObject(manga, 1))
|
||||
|
||||
// Change manga in database to default values
|
||||
val dbManga = getSingleManga("One Piece")
|
||||
dbManga.id = manga.id
|
||||
|
@ -198,9 +182,9 @@ class BackupTest {
|
|||
|
||||
// Restore Json
|
||||
// Create JSON from manga to test parser
|
||||
val json = legacyBackupManager.parser.toJsonTree(manga)
|
||||
val json = legacyBackupManager.parser.encodeToString(manga)
|
||||
// Restore JSON from manga to test parser
|
||||
val jsonManga = legacyBackupManager.parser.fromJson<MangaImpl>(json)
|
||||
val jsonManga = legacyBackupManager.parser.decodeFromString<Manga>(json)
|
||||
|
||||
// Restore manga with fetch observable
|
||||
val networkManga = getSingleManga("One Piece")
|
||||
|
@ -237,8 +221,8 @@ class BackupTest {
|
|||
}
|
||||
|
||||
// Check parser
|
||||
val chaptersJson = legacyBackupManager.parser.toJsonTree(chapters)
|
||||
val restoredChapters = legacyBackupManager.parser.fromJson<List<ChapterImpl>>(chaptersJson)
|
||||
val chaptersJson = legacyBackupManager.parser.encodeToString(chapters)
|
||||
val restoredChapters = legacyBackupManager.parser.decodeFromString<List<Chapter>>(chaptersJson)
|
||||
|
||||
// Fetch chapters from upstream
|
||||
// Create list
|
||||
|
@ -275,8 +259,8 @@ class BackupTest {
|
|||
historyList.add(historyJson)
|
||||
|
||||
// Check parser
|
||||
val historyListJson = legacyBackupManager.parser.toJsonTree(historyList)
|
||||
val history = legacyBackupManager.parser.fromJson<List<DHistory>>(historyListJson)
|
||||
val historyListJson = legacyBackupManager.parser.encodeToString(historyList)
|
||||
val history = legacyBackupManager.parser.decodeFromString<List<DHistory>>(historyListJson)
|
||||
|
||||
// Restore categories
|
||||
legacyBackupManager.restoreHistoryForManga(history)
|
||||
|
@ -314,8 +298,8 @@ class BackupTest {
|
|||
// Check parser and restore already in database
|
||||
var trackList = listOf(track)
|
||||
// Check parser
|
||||
var trackListJson = legacyBackupManager.parser.toJsonTree(trackList)
|
||||
var trackListRestore = legacyBackupManager.parser.fromJson<List<TrackImpl>>(trackListJson)
|
||||
var trackListJson = legacyBackupManager.parser.encodeToString(trackList)
|
||||
var trackListRestore = legacyBackupManager.parser.decodeFromString<List<Track>>(trackListJson)
|
||||
legacyBackupManager.restoreTrackForManga(manga, trackListRestore)
|
||||
|
||||
// Assert if restore works.
|
||||
|
@ -337,8 +321,8 @@ class BackupTest {
|
|||
trackList = listOf(track2)
|
||||
|
||||
// Check parser
|
||||
trackListJson = legacyBackupManager.parser.toJsonTree(trackList)
|
||||
trackListRestore = legacyBackupManager.parser.fromJson<List<TrackImpl>>(trackListJson)
|
||||
trackListJson = legacyBackupManager.parser.encodeToString(trackList)
|
||||
trackListRestore = legacyBackupManager.parser.decodeFromString<List<Track>>(trackListJson)
|
||||
legacyBackupManager.restoreTrackForManga(manga2, trackListRestore)
|
||||
|
||||
// Assert if restore works.
|
||||
|
@ -348,16 +332,13 @@ class BackupTest {
|
|||
}
|
||||
|
||||
private fun clearJson() {
|
||||
root = JsonObject()
|
||||
information = JsonObject()
|
||||
mangaEntries = JsonArray()
|
||||
categoryEntries = JsonArray()
|
||||
root = Backup()
|
||||
information = buildJsonObject {}
|
||||
}
|
||||
|
||||
private fun addSingleCategory(name: String): Category {
|
||||
val category = Category.create(name)
|
||||
val catJson = legacyBackupManager.parser.toJsonTree(category)
|
||||
categoryEntries.add(catJson)
|
||||
root.categories = listOf(category)
|
||||
return category
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue