mirror of
https://github.com/mihonapp/mihon.git
synced 2025-08-03 05:11:31 +02:00
Improve tracking search results (#1178)
* initial commit changed tracking info screen added ability to click logo to launch website * added publishing status and type to description. adjusted layout some * added start date to track info * tweaked layout * tweaked layout * tweaked layout * code review changes * code review changes part 2 * code review changes
This commit is contained in:
app/src/main
java
eu
kanade
tachiyomi
data
database
track
ui
res
@@ -17,7 +17,7 @@ class DbOpenHelper(context: Context)
|
||||
/**
|
||||
* Version of the database.
|
||||
*/
|
||||
const val DATABASE_VERSION = 5
|
||||
const val DATABASE_VERSION = 6
|
||||
}
|
||||
|
||||
override fun onCreate(db: SQLiteDatabase) = with(db) {
|
||||
@@ -54,6 +54,9 @@ class DbOpenHelper(context: Context)
|
||||
if (oldVersion < 5) {
|
||||
db.execSQL(ChapterTable.addScanlator)
|
||||
}
|
||||
if (oldVersion < 6) {
|
||||
db.execSQL(TrackTable.addTrackingUrl)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConfigure(db: SQLiteDatabase) {
|
||||
|
@@ -20,6 +20,7 @@ import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_STATUS
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_SYNC_ID
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_TITLE
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_TOTAL_CHAPTERS
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_TRACKING_URL
|
||||
import eu.kanade.tachiyomi.data.database.tables.TrackTable.TABLE
|
||||
|
||||
class TrackTypeMapping : SQLiteTypeMapping<Track>(
|
||||
@@ -40,7 +41,7 @@ class TrackPutResolver : DefaultPutResolver<Track>() {
|
||||
.whereArgs(obj.id)
|
||||
.build()
|
||||
|
||||
override fun mapToContentValues(obj: Track) = ContentValues(9).apply {
|
||||
override fun mapToContentValues(obj: Track) = ContentValues(10).apply {
|
||||
put(COL_ID, obj.id)
|
||||
put(COL_MANGA_ID, obj.manga_id)
|
||||
put(COL_SYNC_ID, obj.sync_id)
|
||||
@@ -49,7 +50,9 @@ class TrackPutResolver : DefaultPutResolver<Track>() {
|
||||
put(COL_LAST_CHAPTER_READ, obj.last_chapter_read)
|
||||
put(COL_TOTAL_CHAPTERS, obj.total_chapters)
|
||||
put(COL_STATUS, obj.status)
|
||||
put(COL_TRACKING_URL, obj.tracking_url)
|
||||
put(COL_SCORE, obj.score)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +68,7 @@ class TrackGetResolver : DefaultGetResolver<Track>() {
|
||||
total_chapters = cursor.getInt(cursor.getColumnIndex(COL_TOTAL_CHAPTERS))
|
||||
status = cursor.getInt(cursor.getColumnIndex(COL_STATUS))
|
||||
score = cursor.getFloat(cursor.getColumnIndex(COL_SCORE))
|
||||
tracking_url = cursor.getString(cursor.getColumnIndex(COL_TRACKING_URL))
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,8 @@ interface Track : Serializable {
|
||||
|
||||
var status: Int
|
||||
|
||||
var tracking_url: String
|
||||
|
||||
fun copyPersonalFrom(other: Track) {
|
||||
last_chapter_read = other.last_chapter_read
|
||||
score = other.score
|
||||
@@ -29,7 +31,6 @@ interface Track : Serializable {
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun create(serviceId: Int): Track = TrackImpl().apply {
|
||||
sync_id = serviceId
|
||||
}
|
||||
|
@@ -20,6 +20,8 @@ class TrackImpl : Track {
|
||||
|
||||
override var status: Int = 0
|
||||
|
||||
override lateinit var tracking_url: String
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || javaClass != other.javaClass) return false
|
||||
|
@@ -22,6 +22,8 @@ object TrackTable {
|
||||
|
||||
const val COL_TOTAL_CHAPTERS = "total_chapters"
|
||||
|
||||
const val COL_TRACKING_URL = "remote_url"
|
||||
|
||||
val createTableQuery: String
|
||||
get() = """CREATE TABLE $TABLE(
|
||||
$COL_ID INTEGER NOT NULL PRIMARY KEY,
|
||||
@@ -33,9 +35,12 @@ object TrackTable {
|
||||
$COL_TOTAL_CHAPTERS INTEGER NOT NULL,
|
||||
$COL_STATUS INTEGER NOT NULL,
|
||||
$COL_SCORE FLOAT NOT NULL,
|
||||
$COL_TRACKING_URL TEXT NOT NULL,
|
||||
UNIQUE ($COL_MANGA_ID, $COL_SYNC_ID) ON CONFLICT REPLACE,
|
||||
FOREIGN KEY($COL_MANGA_ID) REFERENCES ${MangaTable.TABLE} (${MangaTable.COL_ID})
|
||||
ON DELETE CASCADE
|
||||
)"""
|
||||
|
||||
val addTrackingUrl: String
|
||||
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_TRACKING_URL TEXT DEFAULT ''"
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.track
|
||||
import android.support.annotation.CallSuper
|
||||
import android.support.annotation.DrawableRes
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import okhttp3.OkHttpClient
|
||||
@@ -44,7 +45,7 @@ abstract class TrackService(val id: Int) {
|
||||
|
||||
abstract fun bind(track: Track): Observable<Track>
|
||||
|
||||
abstract fun search(query: String): Observable<List<Track>>
|
||||
abstract fun search(query: String): Observable<List<TrackSearch>>
|
||||
|
||||
abstract fun refresh(track: Track): Observable<Track>
|
||||
|
||||
|
@@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import rx.Completable
|
||||
import rx.Observable
|
||||
|
||||
@@ -120,7 +121,7 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
|
||||
}
|
||||
}
|
||||
|
||||
override fun search(query: String): Observable<List<Track>> {
|
||||
override fun search(query: String): Observable<List<TrackSearch>> {
|
||||
return api.search(query)
|
||||
}
|
||||
|
||||
|
@@ -5,6 +5,7 @@ import com.github.salomonbrys.kotson.int
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.JsonObject
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.OkHttpClient
|
||||
@@ -46,7 +47,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
}
|
||||
}
|
||||
|
||||
fun search(query: String): Observable<List<Track>> {
|
||||
fun search(query: String): Observable<List<TrackSearch>> {
|
||||
return rest.search(query, 1)
|
||||
.map { list ->
|
||||
list.filter { it.type != "Novel" }.map { it.toTrack() }
|
||||
@@ -140,6 +141,11 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
private const val clientSecret = "nlGB5OmgE9YWq5dr3gIDbTQV0C"
|
||||
private const val clientUrl = "tachiyomi://anilist-auth"
|
||||
private const val baseUrl = "https://anilist.co/api/"
|
||||
private const val baseMangaUrl = "https://anilist.co/manga/"
|
||||
|
||||
fun mangaUrl(remoteId: Int): String {
|
||||
return baseMangaUrl + remoteId
|
||||
}
|
||||
|
||||
fun authUrl() = Uri.parse("${baseUrl}auth/authorize").buildUpon()
|
||||
.appendQueryParameter("grant_type", "authorization_code")
|
||||
|
@@ -1,21 +1,45 @@
|
||||
package eu.kanade.tachiyomi.data.track.anilist
|
||||
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
data class ALManga(
|
||||
val id: Int,
|
||||
val title_romaji: String,
|
||||
val image_url_lge: String,
|
||||
val description: String,
|
||||
val type: String,
|
||||
val publishing_status: String,
|
||||
val start_date_fuzzy: String,
|
||||
val total_chapters: Int) {
|
||||
|
||||
fun toTrack() = Track.create(TrackManager.ANILIST).apply {
|
||||
fun toTrack() = TrackSearch.create(TrackManager.ANILIST).apply {
|
||||
remote_id = this@ALManga.id
|
||||
title = title_romaji
|
||||
total_chapters = this@ALManga.total_chapters
|
||||
cover_url = image_url_lge
|
||||
summary = description
|
||||
tracking_url = AnilistApi.mangaUrl(remote_id)
|
||||
publishing_status = this@ALManga.publishing_status
|
||||
publishing_type = type
|
||||
if (!start_date_fuzzy.isNullOrBlank()) {
|
||||
start_date = try {
|
||||
val inputDf = SimpleDateFormat("yyyyMMdd", Locale.US)
|
||||
val outputDf = SimpleDateFormat("yyyy-MM-dd", Locale.US)
|
||||
val date = inputDf.parse(BuildConfig.BUILD_TIME)
|
||||
outputDf.format(date)
|
||||
} catch (e: Exception) {
|
||||
start_date_fuzzy.orEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,11 +84,11 @@ fun Track.toAnilistStatus() = when (status) {
|
||||
private val preferences: PreferencesHelper by injectLazy()
|
||||
|
||||
fun Track.toAnilistScore(): String = when (preferences.anilistScoreType().getOrDefault()) {
|
||||
// 10 point
|
||||
// 10 point
|
||||
0 -> (score.toInt() / 10).toString()
|
||||
// 100 point
|
||||
// 100 point
|
||||
1 -> score.toInt().toString()
|
||||
// 5 stars
|
||||
// 5 stars
|
||||
2 -> when {
|
||||
score == 0f -> "0"
|
||||
score < 30 -> "1"
|
||||
@@ -73,14 +97,14 @@ fun Track.toAnilistScore(): String = when (preferences.anilistScoreType().getOrD
|
||||
score < 90 -> "4"
|
||||
else -> "5"
|
||||
}
|
||||
// Smiley
|
||||
// Smiley
|
||||
3 -> when {
|
||||
score == 0f -> "0"
|
||||
score <= 30 -> ":("
|
||||
score <= 60 -> ":|"
|
||||
else -> ":)"
|
||||
}
|
||||
// 10 point decimal
|
||||
// 10 point decimal
|
||||
4 -> (score / 10).toString()
|
||||
else -> throw Exception("Unknown score type")
|
||||
}
|
@@ -6,6 +6,7 @@ import com.google.gson.Gson
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import rx.Completable
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
@@ -96,7 +97,7 @@ class Kitsu(private val context: Context, id: Int) : TrackService(id) {
|
||||
}
|
||||
}
|
||||
|
||||
override fun search(query: String): Observable<List<Track>> {
|
||||
override fun search(query: String): Observable<List<TrackSearch>> {
|
||||
return api.search(query)
|
||||
}
|
||||
|
||||
|
@@ -4,6 +4,7 @@ import com.github.salomonbrys.kotson.*
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonObject
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.OkHttpClient
|
||||
@@ -27,25 +28,25 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
||||
return Observable.defer {
|
||||
// @formatter:off
|
||||
val data = jsonObject(
|
||||
"type" to "libraryEntries",
|
||||
"attributes" to jsonObject(
|
||||
"status" to track.toKitsuStatus(),
|
||||
"progress" to track.last_chapter_read
|
||||
),
|
||||
"relationships" to jsonObject(
|
||||
"user" to jsonObject(
|
||||
"data" to jsonObject(
|
||||
"id" to userId,
|
||||
"type" to "users"
|
||||
)
|
||||
"type" to "libraryEntries",
|
||||
"attributes" to jsonObject(
|
||||
"status" to track.toKitsuStatus(),
|
||||
"progress" to track.last_chapter_read
|
||||
),
|
||||
"media" to jsonObject(
|
||||
"data" to jsonObject(
|
||||
"id" to track.remote_id,
|
||||
"type" to "manga"
|
||||
)
|
||||
"relationships" to jsonObject(
|
||||
"user" to jsonObject(
|
||||
"data" to jsonObject(
|
||||
"id" to userId,
|
||||
"type" to "users"
|
||||
)
|
||||
),
|
||||
"media" to jsonObject(
|
||||
"data" to jsonObject(
|
||||
"id" to track.remote_id,
|
||||
"type" to "manga"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
// @formatter:on
|
||||
|
||||
@@ -61,13 +62,13 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
||||
return Observable.defer {
|
||||
// @formatter:off
|
||||
val data = jsonObject(
|
||||
"type" to "libraryEntries",
|
||||
"id" to track.remote_id,
|
||||
"attributes" to jsonObject(
|
||||
"status" to track.toKitsuStatus(),
|
||||
"progress" to track.last_chapter_read,
|
||||
"ratingTwenty" to track.toKitsuScore()
|
||||
)
|
||||
"type" to "libraryEntries",
|
||||
"id" to track.remote_id,
|
||||
"attributes" to jsonObject(
|
||||
"status" to track.toKitsuStatus(),
|
||||
"progress" to track.last_chapter_read,
|
||||
"ratingTwenty" to track.toKitsuScore()
|
||||
)
|
||||
)
|
||||
// @formatter:on
|
||||
|
||||
@@ -76,7 +77,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
||||
}
|
||||
}
|
||||
|
||||
fun search(query: String): Observable<List<Track>> {
|
||||
fun search(query: String): Observable<List<TrackSearch>> {
|
||||
return rest.search(query)
|
||||
.map { json ->
|
||||
val data = json["data"].array
|
||||
@@ -186,6 +187,11 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
||||
private const val clientSecret = "54d7307928f63414defd96399fc31ba847961ceaecef3a5fd93144e960c0e151"
|
||||
private const val baseUrl = "https://kitsu.io/api/edge/"
|
||||
private const val loginUrl = "https://kitsu.io/api/"
|
||||
private const val baseMangaUrl = "https://kitsu.io/manga/"
|
||||
|
||||
fun mangaUrl(remoteId: Int): String {
|
||||
return baseMangaUrl + remoteId
|
||||
}
|
||||
|
||||
|
||||
fun refreshTokenRequest(token: String) = POST("${loginUrl}oauth/token",
|
||||
|
@@ -5,24 +5,35 @@ import com.github.salomonbrys.kotson.*
|
||||
import com.google.gson.JsonObject
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
|
||||
open class KitsuManga(obj: JsonObject) {
|
||||
val id by obj.byInt
|
||||
val canonicalTitle by obj["attributes"].byString
|
||||
val chapterCount = obj["attributes"].obj.get("chapterCount").nullInt
|
||||
val type = obj["attributes"].obj.get("mangaType").nullString
|
||||
val type = obj["attributes"].obj.get("mangaType").nullString.orEmpty()
|
||||
val original by obj["attributes"].obj["posterImage"].byString
|
||||
val synopsis by obj["attributes"].byString
|
||||
val startDate = obj["attributes"].obj.get("startDate").nullString.orEmpty()
|
||||
val status = obj["attributes"].obj.get("status").nullString.orEmpty()
|
||||
|
||||
@CallSuper
|
||||
open fun toTrack() = Track.create(TrackManager.KITSU).apply {
|
||||
open fun toTrack() = TrackSearch.create(TrackManager.KITSU).apply {
|
||||
remote_id = this@KitsuManga.id
|
||||
title = canonicalTitle
|
||||
total_chapters = chapterCount ?: 0
|
||||
cover_url = original
|
||||
summary = synopsis
|
||||
tracking_url = KitsuApi.mangaUrl(remote_id)
|
||||
publishing_status = this@KitsuManga.status
|
||||
publishing_type = type
|
||||
start_date = startDate.orEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
class KitsuLibManga(obj: JsonObject, manga: JsonObject) : KitsuManga(manga) {
|
||||
val remoteId by obj.byInt("id")
|
||||
val status by obj["attributes"].byString
|
||||
//override val status by obj["attributes"].byString
|
||||
val ratingTwenty = obj["attributes"].obj.get("ratingTwenty").nullString
|
||||
val progress by obj["attributes"].byInt
|
||||
|
||||
|
@@ -0,0 +1,62 @@
|
||||
package eu.kanade.tachiyomi.data.track.model
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
|
||||
class TrackSearch : Track {
|
||||
|
||||
override var id: Long? = null
|
||||
|
||||
override var manga_id: Long = 0
|
||||
|
||||
override var sync_id: Int = 0
|
||||
|
||||
override var remote_id: Int = 0
|
||||
|
||||
override lateinit var title: String
|
||||
|
||||
override var last_chapter_read: Int = 0
|
||||
|
||||
override var total_chapters: Int = 0
|
||||
|
||||
override var score: Float = 0f
|
||||
|
||||
override var status: Int = 0
|
||||
|
||||
override lateinit var tracking_url: String
|
||||
|
||||
var cover_url: String = ""
|
||||
|
||||
var summary: String = ""
|
||||
|
||||
var publishing_status: String = ""
|
||||
|
||||
var publishing_type: String = ""
|
||||
|
||||
var start_date: String = ""
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || javaClass != other.javaClass) return false
|
||||
|
||||
other as Track
|
||||
|
||||
if (manga_id != other.manga_id) return false
|
||||
if (sync_id != other.sync_id) return false
|
||||
return remote_id == other.remote_id
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = (manga_id xor manga_id.ushr(32)).toInt()
|
||||
result = 31 * result + sync_id
|
||||
result = 31 * result + remote_id
|
||||
return result
|
||||
}
|
||||
companion object {
|
||||
|
||||
fun create(serviceId: Int): TrackSearch = TrackSearch().apply {
|
||||
sync_id = serviceId
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -4,6 +4,7 @@ import android.content.Context
|
||||
import android.graphics.Color
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import rx.Completable
|
||||
import rx.Observable
|
||||
@@ -81,7 +82,7 @@ class Myanimelist(private val context: Context, id: Int) : TrackService(id) {
|
||||
}
|
||||
}
|
||||
|
||||
override fun search(query: String): Observable<List<Track>> {
|
||||
override fun search(query: String): Observable<List<TrackSearch>> {
|
||||
return api.search(query, getUsername())
|
||||
}
|
||||
|
||||
|
@@ -4,6 +4,7 @@ import android.net.Uri
|
||||
import android.util.Xml
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.asObservable
|
||||
@@ -12,6 +13,7 @@ import eu.kanade.tachiyomi.util.selectInt
|
||||
import eu.kanade.tachiyomi.util.selectText
|
||||
import okhttp3.*
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.parser.Parser
|
||||
import org.xmlpull.v1.XmlSerializer
|
||||
import rx.Observable
|
||||
import java.io.StringWriter
|
||||
@@ -36,7 +38,7 @@ class MyanimelistApi(private val client: OkHttpClient, username: String, passwor
|
||||
}
|
||||
}
|
||||
|
||||
fun search(query: String, username: String): Observable<List<Track>> {
|
||||
fun search(query: String, username: String): Observable<List<TrackSearch>> {
|
||||
return if (query.startsWith(PREFIX_MY)) {
|
||||
val realQuery = query.substring(PREFIX_MY.length).toLowerCase().trim()
|
||||
getList(username)
|
||||
@@ -46,34 +48,42 @@ class MyanimelistApi(private val client: OkHttpClient, username: String, passwor
|
||||
} else {
|
||||
client.newCall(GET(getSearchUrl(query), headers))
|
||||
.asObservable()
|
||||
.map { Jsoup.parse(it.body()!!.string()) }
|
||||
.map { Jsoup.parse(Parser.unescapeEntities(it.body()!!.string(), false), "", Parser.xmlParser()) }
|
||||
.flatMap { Observable.from(it.select("entry")) }
|
||||
.filter { it.select("type").text() != "Novel" }
|
||||
.map {
|
||||
Track.create(TrackManager.MYANIMELIST).apply {
|
||||
TrackSearch.create(TrackManager.MYANIMELIST).apply {
|
||||
title = it.selectText("title")!!
|
||||
remote_id = it.selectInt("id")
|
||||
total_chapters = it.selectInt("chapters")
|
||||
summary = it.selectText("synopsis")!!
|
||||
cover_url = it.selectText("image")!!
|
||||
tracking_url = MyanimelistApi.mangaUrl(remote_id)
|
||||
publishing_status = it.selectText("status")!!
|
||||
publishing_type = it.selectText("type")!!
|
||||
start_date = it.selectText("start_date")!!
|
||||
}
|
||||
}
|
||||
.toList()
|
||||
}
|
||||
}
|
||||
|
||||
fun getList(username: String): Observable<List<Track>> {
|
||||
fun getList(username: String): Observable<List<TrackSearch>> {
|
||||
return client
|
||||
.newCall(GET(getListUrl(username), headers))
|
||||
.asObservable()
|
||||
.map { Jsoup.parse(it.body()!!.string()) }
|
||||
.map { Jsoup.parse(Parser.unescapeEntities(it.body()!!.string(), false), "", Parser.xmlParser()) }
|
||||
.flatMap { Observable.from(it.select("manga")) }
|
||||
.map {
|
||||
Track.create(TrackManager.MYANIMELIST).apply {
|
||||
TrackSearch.create(TrackManager.MYANIMELIST).apply {
|
||||
title = it.selectText("series_title")!!
|
||||
remote_id = it.selectInt("series_mangadb_id")
|
||||
last_chapter_read = it.selectInt("my_read_chapters")
|
||||
status = it.selectInt("my_status")
|
||||
score = it.selectInt("my_score").toFloat()
|
||||
total_chapters = it.selectInt("series_chapters")
|
||||
cover_url = it.selectText("series_image")!!
|
||||
tracking_url = MyanimelistApi.mangaUrl(remote_id)
|
||||
}
|
||||
}
|
||||
.toList()
|
||||
@@ -176,6 +186,11 @@ class MyanimelistApi(private val client: OkHttpClient, username: String, passwor
|
||||
|
||||
companion object {
|
||||
const val baseUrl = "https://myanimelist.net"
|
||||
const val baseMangaUrl = baseUrl + "/manga/"
|
||||
|
||||
fun mangaUrl(remoteId: Int): String {
|
||||
return baseMangaUrl + remoteId
|
||||
}
|
||||
|
||||
private val ENTRY_TAG = "entry"
|
||||
private val CHAPTER_TAG = "chapter"
|
||||
|
@@ -15,7 +15,7 @@ class TrackAdapter(controller: TrackController) : RecyclerView.Adapter<TrackHold
|
||||
}
|
||||
}
|
||||
|
||||
val rowClickListener: OnRowClickListener = controller
|
||||
val rowClickListener: OnClickListener = controller
|
||||
|
||||
fun getItem(index: Int): TrackItem? {
|
||||
return items.getOrNull(index)
|
||||
@@ -34,7 +34,8 @@ class TrackAdapter(controller: TrackController) : RecyclerView.Adapter<TrackHold
|
||||
holder.bind(items[position])
|
||||
}
|
||||
|
||||
interface OnRowClickListener {
|
||||
interface OnClickListener {
|
||||
fun onLogoClick(position: Int)
|
||||
fun onTitleClick(position: Int)
|
||||
fun onStatusClick(position: Int)
|
||||
fun onChaptersClick(position: Int)
|
||||
|
@@ -1,19 +1,22 @@
|
||||
package eu.kanade.tachiyomi.ui.manga.track
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.support.v7.widget.LinearLayoutManager
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.jakewharton.rxbinding.support.v4.widget.refreshes
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.util.toast
|
||||
import kotlinx.android.synthetic.main.track_controller.*
|
||||
import timber.log.Timber
|
||||
|
||||
class TrackController : NucleusController<TrackPresenter>(),
|
||||
TrackAdapter.OnRowClickListener,
|
||||
TrackAdapter.OnClickListener,
|
||||
SetTrackStatusDialog.Listener,
|
||||
SetTrackChaptersDialog.Listener,
|
||||
SetTrackScoreDialog.Listener {
|
||||
@@ -58,12 +61,13 @@ class TrackController : NucleusController<TrackPresenter>(),
|
||||
(parentController as? MangaController)?.setTrackingIcon(atLeastOneLink)
|
||||
}
|
||||
|
||||
fun onSearchResults(results: List<Track>) {
|
||||
fun onSearchResults(results: List<TrackSearch>) {
|
||||
getSearchDialog()?.onSearchResults(results)
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun onSearchResultsError(error: Throwable) {
|
||||
Timber.e(error)
|
||||
getSearchDialog()?.onSearchResultsError()
|
||||
}
|
||||
|
||||
@@ -80,6 +84,16 @@ class TrackController : NucleusController<TrackPresenter>(),
|
||||
activity?.toast(error.message)
|
||||
}
|
||||
|
||||
override fun onLogoClick(position: Int) {
|
||||
val track = adapter?.getItem(position)?.track ?: return
|
||||
|
||||
if (track.tracking_url.isNullOrBlank()) {
|
||||
activity?.toast(R.string.url_not_set)
|
||||
} else {
|
||||
activity?.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(track.tracking_url)))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTitleClick(position: Int) {
|
||||
val item = adapter?.getItem(position) ?: return
|
||||
TrackSearchDialog(this, item.service).showDialog(router, TAG_SEARCH_CONTROLLER)
|
||||
|
@@ -7,9 +7,10 @@ import eu.kanade.tachiyomi.ui.base.holder.BaseViewHolder
|
||||
import kotlinx.android.synthetic.main.track_item.*
|
||||
|
||||
class TrackHolder(view: View, adapter: TrackAdapter) : BaseViewHolder(view) {
|
||||
|
||||
|
||||
init {
|
||||
val listener = adapter.rowClickListener
|
||||
logo_container.setOnClickListener { listener.onLogoClick(adapterPosition) }
|
||||
title_container.setOnClickListener { listener.onTitleClick(adapterPosition) }
|
||||
status_container.setOnClickListener { listener.onStatusClick(adapterPosition) }
|
||||
chapters_container.setOnClickListener { listener.onChaptersClick(adapterPosition) }
|
||||
@@ -21,7 +22,7 @@ class TrackHolder(view: View, adapter: TrackAdapter) : BaseViewHolder(view) {
|
||||
fun bind(item: TrackItem) {
|
||||
val track = item.track
|
||||
track_logo.setImageResource(item.service.getLogo())
|
||||
logo.setBackgroundColor(item.service.getLogoColor())
|
||||
logo_container.setBackgroundColor(item.service.getLogoColor())
|
||||
if (track != null) {
|
||||
track_title.setTextAppearance(itemView.context, R.style.TextAppearance_Regular_Body1_Secondary)
|
||||
track_title.setAllCaps(false)
|
||||
|
@@ -16,6 +16,7 @@ import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
|
||||
class TrackPresenter(
|
||||
val manga: Manga,
|
||||
preferences: PreferencesHelper = Injekt.get(),
|
||||
|
@@ -4,14 +4,17 @@ import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||
import eu.kanade.tachiyomi.util.gone
|
||||
import eu.kanade.tachiyomi.util.inflate
|
||||
import kotlinx.android.synthetic.main.track_search_item.view.*
|
||||
import java.util.*
|
||||
|
||||
class TrackSearchAdapter(context: Context)
|
||||
: ArrayAdapter<Track>(context, R.layout.track_search_item, ArrayList<Track>()) {
|
||||
: ArrayAdapter<TrackSearch>(context, R.layout.track_search_item, ArrayList<TrackSearch>()) {
|
||||
|
||||
override fun getView(position: Int, view: View?, parent: ViewGroup): View {
|
||||
var v = view
|
||||
@@ -30,7 +33,7 @@ class TrackSearchAdapter(context: Context)
|
||||
return v
|
||||
}
|
||||
|
||||
fun setItems(syncs: List<Track>) {
|
||||
fun setItems(syncs: List<TrackSearch>) {
|
||||
setNotifyOnChange(false)
|
||||
clear()
|
||||
addAll(syncs)
|
||||
@@ -39,8 +42,40 @@ class TrackSearchAdapter(context: Context)
|
||||
|
||||
class TrackSearchHolder(private val view: View) {
|
||||
|
||||
fun onSetValues(track: Track) {
|
||||
fun onSetValues(track: TrackSearch) {
|
||||
view.track_search_title.text = track.title
|
||||
view.track_search_summary.text = track.summary
|
||||
GlideApp.with(view.context).clear(view.track_search_cover)
|
||||
if (!track.cover_url.isNullOrEmpty()) {
|
||||
GlideApp.with(view.context)
|
||||
.load(track.cover_url)
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||
.centerCrop()
|
||||
.into(view.track_search_cover)
|
||||
|
||||
|
||||
if (track.publishing_status.isNullOrBlank()) {
|
||||
view.track_search_status.gone()
|
||||
view.track_search_status_result.gone()
|
||||
} else {
|
||||
view.track_search_status_result.text = track.publishing_status.capitalize()
|
||||
}
|
||||
|
||||
if (track.publishing_type.isNullOrBlank()) {
|
||||
view.track_search_type.gone()
|
||||
view.track_search_type_result.gone()
|
||||
} else {
|
||||
view.track_search_type_result.text = track.publishing_type.capitalize()
|
||||
}
|
||||
|
||||
if (track.start_date.isNullOrBlank()) {
|
||||
view.track_search_start.gone()
|
||||
view.track_search_start_result.gone()
|
||||
} else {
|
||||
view.track_search_start_result.text = track.start_date
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -8,6 +8,7 @@ import com.jakewharton.rxbinding.widget.itemClicks
|
||||
import com.jakewharton.rxbinding.widget.textChanges
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
@@ -114,11 +115,10 @@ class TrackSearchDialog : DialogController {
|
||||
val view = dialogView ?: return
|
||||
view.progress.visibility = View.VISIBLE
|
||||
view.track_search_list.visibility = View.GONE
|
||||
|
||||
trackController.presenter.search(query, service)
|
||||
}
|
||||
|
||||
fun onSearchResults(results: List<Track>) {
|
||||
fun onSearchResults(results: List<TrackSearch>) {
|
||||
selectedItem = null
|
||||
val view = dialogView ?: return
|
||||
view.progress.visibility = View.GONE
|
||||
|
Reference in New Issue
Block a user