Browse Source

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
Carlos 7 years ago
parent
commit
40b222f8bc
25 changed files with 468 additions and 109 deletions
  1. 4 1
      app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenHelper.kt
  2. 5 1
      app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/TrackTypeMapping.kt
  3. 2 1
      app/src/main/java/eu/kanade/tachiyomi/data/database/models/Track.kt
  4. 2 0
      app/src/main/java/eu/kanade/tachiyomi/data/database/models/TrackImpl.kt
  5. 5 0
      app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt
  6. 2 1
      app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt
  7. 2 1
      app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt
  8. 7 1
      app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt
  9. 30 6
      app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt
  10. 2 1
      app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt
  11. 31 25
      app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt
  12. 14 3
      app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt
  13. 62 0
      app/src/main/java/eu/kanade/tachiyomi/data/track/model/TrackSearch.kt
  14. 2 1
      app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt
  15. 21 6
      app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyanimelistApi.kt
  16. 3 2
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackAdapter.kt
  17. 17 3
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackController.kt
  18. 3 2
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackHolder.kt
  19. 1 0
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackPresenter.kt
  20. 39 4
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchAdapter.kt
  21. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchDialog.kt
  22. 9 8
      app/src/main/res/layout/track_item.xml
  23. 43 26
      app/src/main/res/layout/track_search_dialog.xml
  24. 154 13
      app/src/main/res/layout/track_search_item.xml
  25. 6 1
      app/src/main/res/values/strings.xml

+ 4 - 1
app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenHelper.kt

@@ -17,7 +17,7 @@ class DbOpenHelper(context: Context)
         /**
         /**
          * Version of the database.
          * Version of the database.
          */
          */
-        const val DATABASE_VERSION = 5
+        const val DATABASE_VERSION = 6
     }
     }
 
 
     override fun onCreate(db: SQLiteDatabase) = with(db) {
     override fun onCreate(db: SQLiteDatabase) = with(db) {
@@ -54,6 +54,9 @@ class DbOpenHelper(context: Context)
         if (oldVersion < 5) {
         if (oldVersion < 5) {
             db.execSQL(ChapterTable.addScanlator)
             db.execSQL(ChapterTable.addScanlator)
         }
         }
+        if (oldVersion < 6) {
+            db.execSQL(TrackTable.addTrackingUrl)
+        }
     }
     }
 
 
     override fun onConfigure(db: SQLiteDatabase) {
     override fun onConfigure(db: SQLiteDatabase) {

+ 5 - 1
app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/TrackTypeMapping.kt

@@ -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_SYNC_ID
 import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_TITLE
 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_TOTAL_CHAPTERS
+import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_TRACKING_URL
 import eu.kanade.tachiyomi.data.database.tables.TrackTable.TABLE
 import eu.kanade.tachiyomi.data.database.tables.TrackTable.TABLE
 
 
 class TrackTypeMapping : SQLiteTypeMapping<Track>(
 class TrackTypeMapping : SQLiteTypeMapping<Track>(
@@ -40,7 +41,7 @@ class TrackPutResolver : DefaultPutResolver<Track>() {
             .whereArgs(obj.id)
             .whereArgs(obj.id)
             .build()
             .build()
 
 
-    override fun mapToContentValues(obj: Track) = ContentValues(9).apply {
+    override fun mapToContentValues(obj: Track) = ContentValues(10).apply {
         put(COL_ID, obj.id)
         put(COL_ID, obj.id)
         put(COL_MANGA_ID, obj.manga_id)
         put(COL_MANGA_ID, obj.manga_id)
         put(COL_SYNC_ID, obj.sync_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_LAST_CHAPTER_READ, obj.last_chapter_read)
         put(COL_TOTAL_CHAPTERS, obj.total_chapters)
         put(COL_TOTAL_CHAPTERS, obj.total_chapters)
         put(COL_STATUS, obj.status)
         put(COL_STATUS, obj.status)
+        put(COL_TRACKING_URL, obj.tracking_url)
         put(COL_SCORE, obj.score)
         put(COL_SCORE, obj.score)
+
     }
     }
 }
 }
 
 
@@ -65,6 +68,7 @@ class TrackGetResolver : DefaultGetResolver<Track>() {
         total_chapters = cursor.getInt(cursor.getColumnIndex(COL_TOTAL_CHAPTERS))
         total_chapters = cursor.getInt(cursor.getColumnIndex(COL_TOTAL_CHAPTERS))
         status = cursor.getInt(cursor.getColumnIndex(COL_STATUS))
         status = cursor.getInt(cursor.getColumnIndex(COL_STATUS))
         score = cursor.getFloat(cursor.getColumnIndex(COL_SCORE))
         score = cursor.getFloat(cursor.getColumnIndex(COL_SCORE))
+        tracking_url = cursor.getString(cursor.getColumnIndex(COL_TRACKING_URL))
     }
     }
 }
 }
 
 

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/data/database/models/Track.kt

@@ -22,6 +22,8 @@ interface Track : Serializable {
 
 
     var status: Int
     var status: Int
 
 
+    var tracking_url: String
+
     fun copyPersonalFrom(other: Track) {
     fun copyPersonalFrom(other: Track) {
         last_chapter_read = other.last_chapter_read
         last_chapter_read = other.last_chapter_read
         score = other.score
         score = other.score
@@ -29,7 +31,6 @@ interface Track : Serializable {
     }
     }
 
 
     companion object {
     companion object {
-
         fun create(serviceId: Int): Track = TrackImpl().apply {
         fun create(serviceId: Int): Track = TrackImpl().apply {
             sync_id = serviceId
             sync_id = serviceId
         }
         }

+ 2 - 0
app/src/main/java/eu/kanade/tachiyomi/data/database/models/TrackImpl.kt

@@ -20,6 +20,8 @@ class TrackImpl : Track {
 
 
     override var status: Int = 0
     override var status: Int = 0
 
 
+    override lateinit var tracking_url: String
+
     override fun equals(other: Any?): Boolean {
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
         if (this === other) return true
         if (other == null || javaClass != other.javaClass) return false
         if (other == null || javaClass != other.javaClass) return false

+ 5 - 0
app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt

@@ -22,6 +22,8 @@ object TrackTable {
 
 
     const val COL_TOTAL_CHAPTERS = "total_chapters"
     const val COL_TOTAL_CHAPTERS = "total_chapters"
 
 
+    const val COL_TRACKING_URL = "remote_url"
+
     val createTableQuery: String
     val createTableQuery: String
         get() = """CREATE TABLE $TABLE(
         get() = """CREATE TABLE $TABLE(
             $COL_ID INTEGER NOT NULL PRIMARY KEY,
             $COL_ID INTEGER NOT NULL PRIMARY KEY,
@@ -33,9 +35,12 @@ object TrackTable {
             $COL_TOTAL_CHAPTERS INTEGER NOT NULL,
             $COL_TOTAL_CHAPTERS INTEGER NOT NULL,
             $COL_STATUS INTEGER NOT NULL,
             $COL_STATUS INTEGER NOT NULL,
             $COL_SCORE FLOAT NOT NULL,
             $COL_SCORE FLOAT NOT NULL,
+            $COL_TRACKING_URL TEXT NOT NULL,
             UNIQUE ($COL_MANGA_ID, $COL_SYNC_ID) ON CONFLICT REPLACE,
             UNIQUE ($COL_MANGA_ID, $COL_SYNC_ID) ON CONFLICT REPLACE,
             FOREIGN KEY($COL_MANGA_ID) REFERENCES ${MangaTable.TABLE} (${MangaTable.COL_ID})
             FOREIGN KEY($COL_MANGA_ID) REFERENCES ${MangaTable.TABLE} (${MangaTable.COL_ID})
             ON DELETE CASCADE
             ON DELETE CASCADE
             )"""
             )"""
 
 
+    val addTrackingUrl: String
+        get() = "ALTER TABLE $TABLE ADD COLUMN $COL_TRACKING_URL TEXT DEFAULT ''"
 }
 }

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt

@@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.track
 import android.support.annotation.CallSuper
 import android.support.annotation.CallSuper
 import android.support.annotation.DrawableRes
 import android.support.annotation.DrawableRes
 import eu.kanade.tachiyomi.data.database.models.Track
 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.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.network.NetworkHelper
 import eu.kanade.tachiyomi.network.NetworkHelper
 import okhttp3.OkHttpClient
 import okhttp3.OkHttpClient
@@ -44,7 +45,7 @@ abstract class TrackService(val id: Int) {
 
 
     abstract fun bind(track: Track): Observable<Track>
     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>
     abstract fun refresh(track: Track): Observable<Track>
 
 

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt

@@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.preference.getOrDefault
 import eu.kanade.tachiyomi.data.preference.getOrDefault
 import eu.kanade.tachiyomi.data.track.TrackService
 import eu.kanade.tachiyomi.data.track.TrackService
+import eu.kanade.tachiyomi.data.track.model.TrackSearch
 import rx.Completable
 import rx.Completable
 import rx.Observable
 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)
         return api.search(query)
     }
     }
 
 

+ 7 - 1
app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt

@@ -5,6 +5,7 @@ import com.github.salomonbrys.kotson.int
 import com.github.salomonbrys.kotson.string
 import com.github.salomonbrys.kotson.string
 import com.google.gson.JsonObject
 import com.google.gson.JsonObject
 import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.database.models.Track
+import eu.kanade.tachiyomi.data.track.model.TrackSearch
 import eu.kanade.tachiyomi.network.POST
 import eu.kanade.tachiyomi.network.POST
 import okhttp3.FormBody
 import okhttp3.FormBody
 import okhttp3.OkHttpClient
 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)
         return rest.search(query, 1)
                 .map { list ->
                 .map { list ->
                     list.filter { it.type != "Novel" }.map { it.toTrack() }
                     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 clientSecret = "nlGB5OmgE9YWq5dr3gIDbTQV0C"
         private const val clientUrl = "tachiyomi://anilist-auth"
         private const val clientUrl = "tachiyomi://anilist-auth"
         private const val baseUrl = "https://anilist.co/api/"
         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()
         fun authUrl() = Uri.parse("${baseUrl}auth/authorize").buildUpon()
                 .appendQueryParameter("grant_type", "authorization_code")
                 .appendQueryParameter("grant_type", "authorization_code")

+ 30 - 6
app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt

@@ -1,21 +1,45 @@
 package eu.kanade.tachiyomi.data.track.anilist
 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.database.models.Track
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.data.preference.getOrDefault
 import eu.kanade.tachiyomi.data.preference.getOrDefault
 import eu.kanade.tachiyomi.data.track.TrackManager
 import eu.kanade.tachiyomi.data.track.TrackManager
+import eu.kanade.tachiyomi.data.track.model.TrackSearch
 import uy.kohesive.injekt.injectLazy
 import uy.kohesive.injekt.injectLazy
+import java.text.SimpleDateFormat
+import java.util.*
 
 
 data class ALManga(
 data class ALManga(
         val id: Int,
         val id: Int,
         val title_romaji: String,
         val title_romaji: String,
+        val image_url_lge: String,
+        val description: String,
         val type: String,
         val type: String,
+        val publishing_status: String,
+        val start_date_fuzzy: String,
         val total_chapters: Int) {
         val total_chapters: Int) {
 
 
-    fun toTrack() = Track.create(TrackManager.ANILIST).apply {
+    fun toTrack() = TrackSearch.create(TrackManager.ANILIST).apply {
         remote_id = [email protected]
         remote_id = [email protected]
         title = title_romaji
         title = title_romaji
         total_chapters = [email protected]_chapters
         total_chapters = [email protected]_chapters
+        cover_url = image_url_lge
+        summary = description
+        tracking_url = AnilistApi.mangaUrl(remote_id)
+        publishing_status = [email protected]_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()
 private val preferences: PreferencesHelper by injectLazy()
 
 
 fun Track.toAnilistScore(): String = when (preferences.anilistScoreType().getOrDefault()) {
 fun Track.toAnilistScore(): String = when (preferences.anilistScoreType().getOrDefault()) {
-    // 10 point
+// 10 point
     0 -> (score.toInt() / 10).toString()
     0 -> (score.toInt() / 10).toString()
-    // 100 point
+// 100 point
     1 -> score.toInt().toString()
     1 -> score.toInt().toString()
-    // 5 stars
+// 5 stars
     2 -> when {
     2 -> when {
         score == 0f -> "0"
         score == 0f -> "0"
         score < 30 -> "1"
         score < 30 -> "1"
@@ -73,14 +97,14 @@ fun Track.toAnilistScore(): String = when (preferences.anilistScoreType().getOrD
         score < 90 -> "4"
         score < 90 -> "4"
         else -> "5"
         else -> "5"
     }
     }
-    // Smiley
+// Smiley
     3 -> when {
     3 -> when {
         score == 0f -> "0"
         score == 0f -> "0"
         score <= 30 -> ":("
         score <= 30 -> ":("
         score <= 60 -> ":|"
         score <= 60 -> ":|"
         else -> ":)"
         else -> ":)"
     }
     }
-    // 10 point decimal
+// 10 point decimal
     4 -> (score / 10).toString()
     4 -> (score / 10).toString()
     else -> throw Exception("Unknown score type")
     else -> throw Exception("Unknown score type")
 }
 }

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt

@@ -6,6 +6,7 @@ import com.google.gson.Gson
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.track.TrackService
 import eu.kanade.tachiyomi.data.track.TrackService
+import eu.kanade.tachiyomi.data.track.model.TrackSearch
 import rx.Completable
 import rx.Completable
 import rx.Observable
 import rx.Observable
 import uy.kohesive.injekt.injectLazy
 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)
         return api.search(query)
     }
     }
 
 

+ 31 - 25
app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt

@@ -4,6 +4,7 @@ import com.github.salomonbrys.kotson.*
 import com.google.gson.GsonBuilder
 import com.google.gson.GsonBuilder
 import com.google.gson.JsonObject
 import com.google.gson.JsonObject
 import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.database.models.Track
+import eu.kanade.tachiyomi.data.track.model.TrackSearch
 import eu.kanade.tachiyomi.network.POST
 import eu.kanade.tachiyomi.network.POST
 import okhttp3.FormBody
 import okhttp3.FormBody
 import okhttp3.OkHttpClient
 import okhttp3.OkHttpClient
@@ -27,25 +28,25 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
         return Observable.defer {
         return Observable.defer {
             // @formatter:off
             // @formatter:off
             val data = jsonObject(
             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
             // @formatter:on
 
 
@@ -61,13 +62,13 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
         return Observable.defer {
         return Observable.defer {
             // @formatter:off
             // @formatter:off
             val data = jsonObject(
             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
             // @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)
         return rest.search(query)
                 .map { json ->
                 .map { json ->
                     val data = json["data"].array
                     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 clientSecret = "54d7307928f63414defd96399fc31ba847961ceaecef3a5fd93144e960c0e151"
         private const val baseUrl = "https://kitsu.io/api/edge/"
         private const val baseUrl = "https://kitsu.io/api/edge/"
         private const val loginUrl = "https://kitsu.io/api/"
         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",
         fun refreshTokenRequest(token: String) = POST("${loginUrl}oauth/token",

+ 14 - 3
app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt

@@ -5,24 +5,35 @@ import com.github.salomonbrys.kotson.*
 import com.google.gson.JsonObject
 import com.google.gson.JsonObject
 import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.track.TrackManager
 import eu.kanade.tachiyomi.data.track.TrackManager
+import eu.kanade.tachiyomi.data.track.model.TrackSearch
 
 
 open class KitsuManga(obj: JsonObject) {
 open class KitsuManga(obj: JsonObject) {
     val id by obj.byInt
     val id by obj.byInt
     val canonicalTitle by obj["attributes"].byString
     val canonicalTitle by obj["attributes"].byString
     val chapterCount = obj["attributes"].obj.get("chapterCount").nullInt
     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
     @CallSuper
-    open fun toTrack() = Track.create(TrackManager.KITSU).apply {
+    open fun toTrack() = TrackSearch.create(TrackManager.KITSU).apply {
         remote_id = [email protected]
         remote_id = [email protected]
         title = canonicalTitle
         title = canonicalTitle
         total_chapters = chapterCount ?: 0
         total_chapters = chapterCount ?: 0
+        cover_url = original
+        summary = synopsis
+        tracking_url = KitsuApi.mangaUrl(remote_id)
+        publishing_status = [email protected]
+        publishing_type = type
+        start_date = startDate.orEmpty()
     }
     }
 }
 }
 
 
 class KitsuLibManga(obj: JsonObject, manga: JsonObject) : KitsuManga(manga) {
 class KitsuLibManga(obj: JsonObject, manga: JsonObject) : KitsuManga(manga) {
     val remoteId by obj.byInt("id")
     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 ratingTwenty = obj["attributes"].obj.get("ratingTwenty").nullString
     val progress by obj["attributes"].byInt
     val progress by obj["attributes"].byInt
 
 

+ 62 - 0
app/src/main/java/eu/kanade/tachiyomi/data/track/model/TrackSearch.kt

@@ -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
+        }
+
+    }
+
+}

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt

@@ -4,6 +4,7 @@ import android.content.Context
 import android.graphics.Color
 import android.graphics.Color
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.database.models.Track
+import eu.kanade.tachiyomi.data.track.model.TrackSearch
 import eu.kanade.tachiyomi.data.track.TrackService
 import eu.kanade.tachiyomi.data.track.TrackService
 import rx.Completable
 import rx.Completable
 import rx.Observable
 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())
         return api.search(query, getUsername())
     }
     }
 
 

+ 21 - 6
app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyanimelistApi.kt

@@ -4,6 +4,7 @@ import android.net.Uri
 import android.util.Xml
 import android.util.Xml
 import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.track.TrackManager
 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.GET
 import eu.kanade.tachiyomi.network.POST
 import eu.kanade.tachiyomi.network.POST
 import eu.kanade.tachiyomi.network.asObservable
 import eu.kanade.tachiyomi.network.asObservable
@@ -12,6 +13,7 @@ import eu.kanade.tachiyomi.util.selectInt
 import eu.kanade.tachiyomi.util.selectText
 import eu.kanade.tachiyomi.util.selectText
 import okhttp3.*
 import okhttp3.*
 import org.jsoup.Jsoup
 import org.jsoup.Jsoup
+import org.jsoup.parser.Parser
 import org.xmlpull.v1.XmlSerializer
 import org.xmlpull.v1.XmlSerializer
 import rx.Observable
 import rx.Observable
 import java.io.StringWriter
 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)) {
         return if (query.startsWith(PREFIX_MY)) {
             val realQuery = query.substring(PREFIX_MY.length).toLowerCase().trim()
             val realQuery = query.substring(PREFIX_MY.length).toLowerCase().trim()
             getList(username)
             getList(username)
@@ -46,34 +48,42 @@ class MyanimelistApi(private val client: OkHttpClient, username: String, passwor
         } else {
         } else {
             client.newCall(GET(getSearchUrl(query), headers))
             client.newCall(GET(getSearchUrl(query), headers))
                     .asObservable()
                     .asObservable()
-                    .map { Jsoup.parse(it.body()!!.string()) }
+                    .map { Jsoup.parse(Parser.unescapeEntities(it.body()!!.string(), false), "", Parser.xmlParser()) }
                     .flatMap { Observable.from(it.select("entry")) }
                     .flatMap { Observable.from(it.select("entry")) }
                     .filter { it.select("type").text() != "Novel" }
                     .filter { it.select("type").text() != "Novel" }
                     .map {
                     .map {
-                        Track.create(TrackManager.MYANIMELIST).apply {
+                        TrackSearch.create(TrackManager.MYANIMELIST).apply {
                             title = it.selectText("title")!!
                             title = it.selectText("title")!!
                             remote_id = it.selectInt("id")
                             remote_id = it.selectInt("id")
                             total_chapters = it.selectInt("chapters")
                             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()
                     .toList()
         }
         }
     }
     }
 
 
-    fun getList(username: String): Observable<List<Track>> {
+    fun getList(username: String): Observable<List<TrackSearch>> {
         return client
         return client
                 .newCall(GET(getListUrl(username), headers))
                 .newCall(GET(getListUrl(username), headers))
                 .asObservable()
                 .asObservable()
-                .map { Jsoup.parse(it.body()!!.string()) }
+                .map { Jsoup.parse(Parser.unescapeEntities(it.body()!!.string(), false), "", Parser.xmlParser()) }
                 .flatMap { Observable.from(it.select("manga")) }
                 .flatMap { Observable.from(it.select("manga")) }
                 .map {
                 .map {
-                    Track.create(TrackManager.MYANIMELIST).apply {
+                    TrackSearch.create(TrackManager.MYANIMELIST).apply {
                         title = it.selectText("series_title")!!
                         title = it.selectText("series_title")!!
                         remote_id = it.selectInt("series_mangadb_id")
                         remote_id = it.selectInt("series_mangadb_id")
                         last_chapter_read = it.selectInt("my_read_chapters")
                         last_chapter_read = it.selectInt("my_read_chapters")
                         status = it.selectInt("my_status")
                         status = it.selectInt("my_status")
                         score = it.selectInt("my_score").toFloat()
                         score = it.selectInt("my_score").toFloat()
                         total_chapters = it.selectInt("series_chapters")
                         total_chapters = it.selectInt("series_chapters")
+                        cover_url = it.selectText("series_image")!!
+                        tracking_url = MyanimelistApi.mangaUrl(remote_id)
                     }
                     }
                 }
                 }
                 .toList()
                 .toList()
@@ -176,6 +186,11 @@ class MyanimelistApi(private val client: OkHttpClient, username: String, passwor
 
 
     companion object {
     companion object {
         const val baseUrl = "https://myanimelist.net"
         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 ENTRY_TAG = "entry"
         private val CHAPTER_TAG = "chapter"
         private val CHAPTER_TAG = "chapter"

+ 3 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackAdapter.kt

@@ -15,7 +15,7 @@ class TrackAdapter(controller: TrackController) : RecyclerView.Adapter<TrackHold
             }
             }
         }
         }
 
 
-    val rowClickListener: OnRowClickListener = controller
+    val rowClickListener: OnClickListener = controller
 
 
     fun getItem(index: Int): TrackItem? {
     fun getItem(index: Int): TrackItem? {
         return items.getOrNull(index)
         return items.getOrNull(index)
@@ -34,7 +34,8 @@ class TrackAdapter(controller: TrackController) : RecyclerView.Adapter<TrackHold
         holder.bind(items[position])
         holder.bind(items[position])
     }
     }
 
 
-    interface OnRowClickListener {
+    interface OnClickListener {
+        fun onLogoClick(position: Int)
         fun onTitleClick(position: Int)
         fun onTitleClick(position: Int)
         fun onStatusClick(position: Int)
         fun onStatusClick(position: Int)
         fun onChaptersClick(position: Int)
         fun onChaptersClick(position: Int)

+ 17 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackController.kt

@@ -1,19 +1,22 @@
 package eu.kanade.tachiyomi.ui.manga.track
 package eu.kanade.tachiyomi.ui.manga.track
 
 
+import android.content.Intent
+import android.net.Uri
 import android.support.v7.widget.LinearLayoutManager
 import android.support.v7.widget.LinearLayoutManager
 import android.view.LayoutInflater
 import android.view.LayoutInflater
 import android.view.View
 import android.view.View
 import android.view.ViewGroup
 import android.view.ViewGroup
 import com.jakewharton.rxbinding.support.v4.widget.refreshes
 import com.jakewharton.rxbinding.support.v4.widget.refreshes
 import eu.kanade.tachiyomi.R
 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.base.controller.NucleusController
 import eu.kanade.tachiyomi.ui.manga.MangaController
 import eu.kanade.tachiyomi.ui.manga.MangaController
 import eu.kanade.tachiyomi.util.toast
 import eu.kanade.tachiyomi.util.toast
 import kotlinx.android.synthetic.main.track_controller.*
 import kotlinx.android.synthetic.main.track_controller.*
+import timber.log.Timber
 
 
 class TrackController : NucleusController<TrackPresenter>(),
 class TrackController : NucleusController<TrackPresenter>(),
-        TrackAdapter.OnRowClickListener,
+        TrackAdapter.OnClickListener,
         SetTrackStatusDialog.Listener,
         SetTrackStatusDialog.Listener,
         SetTrackChaptersDialog.Listener,
         SetTrackChaptersDialog.Listener,
         SetTrackScoreDialog.Listener {
         SetTrackScoreDialog.Listener {
@@ -58,12 +61,13 @@ class TrackController : NucleusController<TrackPresenter>(),
         (parentController as? MangaController)?.setTrackingIcon(atLeastOneLink)
         (parentController as? MangaController)?.setTrackingIcon(atLeastOneLink)
     }
     }
 
 
-    fun onSearchResults(results: List<Track>) {
+    fun onSearchResults(results: List<TrackSearch>) {
         getSearchDialog()?.onSearchResults(results)
         getSearchDialog()?.onSearchResults(results)
     }
     }
 
 
     @Suppress("UNUSED_PARAMETER")
     @Suppress("UNUSED_PARAMETER")
     fun onSearchResultsError(error: Throwable) {
     fun onSearchResultsError(error: Throwable) {
+        Timber.e(error)
         getSearchDialog()?.onSearchResultsError()
         getSearchDialog()?.onSearchResultsError()
     }
     }
 
 
@@ -80,6 +84,16 @@ class TrackController : NucleusController<TrackPresenter>(),
         activity?.toast(error.message)
         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) {
     override fun onTitleClick(position: Int) {
         val item = adapter?.getItem(position) ?: return
         val item = adapter?.getItem(position) ?: return
         TrackSearchDialog(this, item.service).showDialog(router, TAG_SEARCH_CONTROLLER)
         TrackSearchDialog(this, item.service).showDialog(router, TAG_SEARCH_CONTROLLER)

+ 3 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackHolder.kt

@@ -7,9 +7,10 @@ import eu.kanade.tachiyomi.ui.base.holder.BaseViewHolder
 import kotlinx.android.synthetic.main.track_item.*
 import kotlinx.android.synthetic.main.track_item.*
 
 
 class TrackHolder(view: View, adapter: TrackAdapter) : BaseViewHolder(view) {
 class TrackHolder(view: View, adapter: TrackAdapter) : BaseViewHolder(view) {
-    
+
     init {
     init {
         val listener = adapter.rowClickListener
         val listener = adapter.rowClickListener
+        logo_container.setOnClickListener { listener.onLogoClick(adapterPosition) }
         title_container.setOnClickListener { listener.onTitleClick(adapterPosition) }
         title_container.setOnClickListener { listener.onTitleClick(adapterPosition) }
         status_container.setOnClickListener { listener.onStatusClick(adapterPosition) }
         status_container.setOnClickListener { listener.onStatusClick(adapterPosition) }
         chapters_container.setOnClickListener { listener.onChaptersClick(adapterPosition) }
         chapters_container.setOnClickListener { listener.onChaptersClick(adapterPosition) }
@@ -21,7 +22,7 @@ class TrackHolder(view: View, adapter: TrackAdapter) : BaseViewHolder(view) {
     fun bind(item: TrackItem) {
     fun bind(item: TrackItem) {
         val track = item.track
         val track = item.track
         track_logo.setImageResource(item.service.getLogo())
         track_logo.setImageResource(item.service.getLogo())
-        logo.setBackgroundColor(item.service.getLogoColor())
+        logo_container.setBackgroundColor(item.service.getLogoColor())
         if (track != null) {
         if (track != null) {
             track_title.setTextAppearance(itemView.context, R.style.TextAppearance_Regular_Body1_Secondary)
             track_title.setTextAppearance(itemView.context, R.style.TextAppearance_Regular_Body1_Secondary)
             track_title.setAllCaps(false)
             track_title.setAllCaps(false)

+ 1 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackPresenter.kt

@@ -16,6 +16,7 @@ import rx.schedulers.Schedulers
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
 import uy.kohesive.injekt.api.get
 
 
+
 class TrackPresenter(
 class TrackPresenter(
         val manga: Manga,
         val manga: Manga,
         preferences: PreferencesHelper = Injekt.get(),
         preferences: PreferencesHelper = Injekt.get(),

+ 39 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchAdapter.kt

@@ -4,14 +4,17 @@ import android.content.Context
 import android.view.View
 import android.view.View
 import android.view.ViewGroup
 import android.view.ViewGroup
 import android.widget.ArrayAdapter
 import android.widget.ArrayAdapter
+import com.bumptech.glide.load.engine.DiskCacheStrategy
 import eu.kanade.tachiyomi.R
 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 eu.kanade.tachiyomi.util.inflate
 import kotlinx.android.synthetic.main.track_search_item.view.*
 import kotlinx.android.synthetic.main.track_search_item.view.*
 import java.util.*
 import java.util.*
 
 
 class TrackSearchAdapter(context: Context)
 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 {
     override fun getView(position: Int, view: View?, parent: ViewGroup): View {
         var v = view
         var v = view
@@ -30,7 +33,7 @@ class TrackSearchAdapter(context: Context)
         return v
         return v
     }
     }
 
 
-    fun setItems(syncs: List<Track>) {
+    fun setItems(syncs: List<TrackSearch>) {
         setNotifyOnChange(false)
         setNotifyOnChange(false)
         clear()
         clear()
         addAll(syncs)
         addAll(syncs)
@@ -39,8 +42,40 @@ class TrackSearchAdapter(context: Context)
 
 
     class TrackSearchHolder(private val view: View) {
     class TrackSearchHolder(private val view: View) {
 
 
-        fun onSetValues(track: Track) {
+        fun onSetValues(track: TrackSearch) {
             view.track_search_title.text = track.title
             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
+                }
+
+            }
         }
         }
     }
     }
 
 

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchDialog.kt

@@ -8,6 +8,7 @@ import com.jakewharton.rxbinding.widget.itemClicks
 import com.jakewharton.rxbinding.widget.textChanges
 import com.jakewharton.rxbinding.widget.textChanges
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.database.models.Track
 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.TrackManager
 import eu.kanade.tachiyomi.data.track.TrackService
 import eu.kanade.tachiyomi.data.track.TrackService
 import eu.kanade.tachiyomi.ui.base.controller.DialogController
 import eu.kanade.tachiyomi.ui.base.controller.DialogController
@@ -114,11 +115,10 @@ class TrackSearchDialog : DialogController {
         val view = dialogView ?: return
         val view = dialogView ?: return
         view.progress.visibility = View.VISIBLE
         view.progress.visibility = View.VISIBLE
         view.track_search_list.visibility = View.GONE
         view.track_search_list.visibility = View.GONE
-
         trackController.presenter.search(query, service)
         trackController.presenter.search(query, service)
     }
     }
 
 
-    fun onSearchResults(results: List<Track>) {
+    fun onSearchResults(results: List<TrackSearch>) {
         selectedItem = null
         selectedItem = null
         val view = dialogView ?: return
         val view = dialogView ?: return
         view.progress.visibility = View.GONE
         view.progress.visibility = View.GONE

+ 9 - 8
app/src/main/res/layout/track_item.xml

@@ -11,12 +11,13 @@
         android:layout_height="wrap_content">
         android:layout_height="wrap_content">
 
 
         <FrameLayout
         <FrameLayout
-            android:id="@+id/logo"
+            android:id="@+id/logo_container"
             android:layout_width="48dp"
             android:layout_width="48dp"
             android:layout_height="0dp"
             android:layout_height="0dp"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintLeft_toLeftOf="parent"
             app:layout_constraintLeft_toLeftOf="parent"
             app:layout_constraintTop_toTopOf="parent"
             app:layout_constraintTop_toTopOf="parent"
+            android:clickable="true"
             tools:background="#2E51A2">
             tools:background="#2E51A2">
 
 
             <ImageView
             <ImageView
@@ -35,7 +36,7 @@
             android:background="?attr/selectable_list_drawable"
             android:background="?attr/selectable_list_drawable"
             android:clickable="true"
             android:clickable="true"
             android:padding="16dp"
             android:padding="16dp"
-            app:layout_constraintLeft_toRightOf="@+id/logo"
+            app:layout_constraintLeft_toRightOf="@+id/logo_container"
             app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintTop_toTopOf="parent">
             app:layout_constraintTop_toTopOf="parent">
 
 
@@ -68,7 +69,7 @@
             android:layout_marginRight="16dp"
             android:layout_marginRight="16dp"
             android:layout_marginStart="16dp"
             android:layout_marginStart="16dp"
             android:background="?android:attr/divider"
             android:background="?android:attr/divider"
-            app:layout_constraintLeft_toRightOf="@+id/logo"
+            app:layout_constraintLeft_toRightOf="@+id/logo_container"
             app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintTop_toBottomOf="@+id/title_container" />
             app:layout_constraintTop_toBottomOf="@+id/title_container" />
 
 
@@ -79,7 +80,7 @@
             android:background="?attr/selectable_list_drawable"
             android:background="?attr/selectable_list_drawable"
             android:clickable="true"
             android:clickable="true"
             android:padding="16dp"
             android:padding="16dp"
-            app:layout_constraintLeft_toRightOf="@+id/logo"
+            app:layout_constraintLeft_toRightOf="@+id/logo_container"
             app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintTop_toBottomOf="@+id/divider1">
             app:layout_constraintTop_toBottomOf="@+id/divider1">
 
 
@@ -110,7 +111,7 @@
             android:layout_marginRight="16dp"
             android:layout_marginRight="16dp"
             android:layout_marginStart="16dp"
             android:layout_marginStart="16dp"
             android:background="?android:attr/divider"
             android:background="?android:attr/divider"
-            app:layout_constraintLeft_toRightOf="@+id/logo"
+            app:layout_constraintLeft_toRightOf="@+id/logo_container"
             app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintTop_toBottomOf="@+id/status_container" />
             app:layout_constraintTop_toBottomOf="@+id/status_container" />
 
 
@@ -121,7 +122,7 @@
             android:background="?attr/selectable_list_drawable"
             android:background="?attr/selectable_list_drawable"
             android:clickable="true"
             android:clickable="true"
             android:padding="16dp"
             android:padding="16dp"
-            app:layout_constraintLeft_toRightOf="@+id/logo"
+            app:layout_constraintLeft_toRightOf="@+id/logo_container"
             app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintTop_toBottomOf="@+id/divider2">
             app:layout_constraintTop_toBottomOf="@+id/divider2">
 
 
@@ -152,7 +153,7 @@
             android:layout_marginRight="16dp"
             android:layout_marginRight="16dp"
             android:layout_marginStart="16dp"
             android:layout_marginStart="16dp"
             android:background="?android:attr/divider"
             android:background="?android:attr/divider"
-            app:layout_constraintLeft_toRightOf="@+id/logo"
+            app:layout_constraintLeft_toRightOf="@+id/logo_container"
             app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintTop_toBottomOf="@+id/chapters_container" />
             app:layout_constraintTop_toBottomOf="@+id/chapters_container" />
 
 
@@ -163,7 +164,7 @@
             android:background="?attr/selectable_list_drawable"
             android:background="?attr/selectable_list_drawable"
             android:clickable="true"
             android:clickable="true"
             android:padding="16dp"
             android:padding="16dp"
-            app:layout_constraintLeft_toRightOf="@+id/logo"
+            app:layout_constraintLeft_toRightOf="@+id/logo_container"
             app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintTop_toBottomOf="@+id/divider3">
             app:layout_constraintTop_toBottomOf="@+id/divider3">
 
 

+ 43 - 26
app/src/main/res/layout/track_search_dialog.xml

@@ -1,47 +1,64 @@
 <?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
+<android.support.constraint.ConstraintLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     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_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_height="wrap_content"
     android:orientation="vertical">
     android:orientation="vertical">
 
 
-    <LinearLayout
+    <EditText
+        android:id="@+id/track_search"
         android:layout_width="match_parent"
         android:layout_width="match_parent"
-        android:layout_height="?attr/actionBarSize"
-        android:gravity="center"
-        android:orientation="horizontal"
-        android:paddingLeft="@dimen/margin_left"
-        android:paddingRight="@dimen/margin_right">
-
-        <EditText
-            android:id="@+id/track_search"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:hint="@string/title"/>
-
-    </LinearLayout>
+        android:layout_height="wrap_content"
+        android:hint="@string/title"
+        android:layout_marginEnd="16dp"
+        android:layout_marginStart="16dp"
+        app:layout_constraintTop_toTopOf="parent"/>
 
 
     <ProgressBar
     <ProgressBar
         android:id="@+id/progress"
         android:id="@+id/progress"
         style="?android:attr/progressBarStyle"
         style="?android:attr/progressBarStyle"
         android:layout_width="wrap_content"
         android:layout_width="wrap_content"
-        android:layout_height="fill_parent"
-        android:layout_gravity="center_vertical|center_horizontal"
-        android:paddingBottom="32dp"
-        android:paddingTop="32dp"
-        android:visibility="gone"/>
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="32dp"
+        android:layout_marginTop="32dp"
+        android:visibility="gone"
+        app:layout_constraintBottom_toTopOf="@id/divider1"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/track_search"
+        tools:visibility="visible"/>
 
 
     <ListView
     <ListView
         android:id="@+id/track_search_list"
         android:id="@+id/track_search_list"
+        style="@style/Theme.Widget.CardView"
         android:layout_width="match_parent"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:layout_height="0dp"
+        android:layout_marginTop="40dp"
         android:choiceMode="singleChoice"
         android:choiceMode="singleChoice"
         android:clipToPadding="false"
         android:clipToPadding="false"
         android:divider="@null"
         android:divider="@null"
-        android:dividerHeight="0dp"
+        android:dividerHeight="10dp"
+        android:footerDividersEnabled="true"
+        android:headerDividersEnabled="true"
         android:listSelector="?attr/selectable_list_drawable"
         android:listSelector="?attr/selectable_list_drawable"
-        android:scrollbarStyle="outsideOverlay"
-        android:visibility="gone"/>
+        android:paddingBottom="4dp"
+        android:paddingTop="4dp"
+        android:scrollbars="none"
+        android:visibility="gone"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="@+id/track_search"
+        tools:listitem="@layout/track_search_item"
+        tools:visibility="visible"/>
+
+    <View
+        android:id="@+id/divider1"
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:background="?android:attr/divider"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/track_search_list"/>
 
 
-</LinearLayout>
+</android.support.constraint.ConstraintLayout>

+ 154 - 13
app/src/main/res/layout/track_search_item.xml

@@ -1,14 +1,155 @@
 <?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical"
-    android:background="?attr/selectable_list_drawable">
-
-    <TextView
-        android:id="@+id/track_search_title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:padding="10dp"/>
-
-</LinearLayout>
+<android.support.v7.widget.CardView android:id="@+id/cv_manga"
+                                    style="@style/Theme.Widget.CardView.Item"
+                                    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:padding="0dp">
+
+    <android.support.constraint.ConstraintLayout
+        android:id="@+id/linearLayout"
+        android:layout_width="match_parent"
+        android:layout_height="216dp"
+        android:background="?attr/selectable_list_drawable"
+        android:orientation="horizontal">
+        >
+
+        <ImageView
+            android:id="@+id/track_search_cover"
+            android:layout_width="135dp"
+            android:layout_height="match_parent"
+            android:layout_marginBottom="8dp"
+            android:layout_marginEnd="8dp"
+            android:layout_marginStart="8dp"
+            android:layout_marginTop="8dp"
+            android:contentDescription="@string/description_cover"
+            android:scaleType="centerCrop"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintVertical_bias="0.0"
+            tools:src="@drawable/branded_logo_icon"/>
+
+
+        <TextView
+            android:id="@+id/track_search_title"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="8dp"
+            android:layout_marginStart="8dp"
+            android:layout_marginTop="8dp"
+            android:maxLines="3"
+            android:textAppearance="@style/TextAppearance.Regular.Body1.Bold"
+            android:textSize="16sp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toEndOf="@id/track_search_cover"
+            app:layout_constraintTop_toTopOf="parent"
+            tools:text="One Piece"/>
+
+        <TextView
+            android:id="@+id/track_search_type"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="8dp"
+            android:maxLines="1"
+            android:text="@string/track_type"
+            android:textAppearance="@style/TextAppearance.Regular.Body1.Bold"
+            android:textSize="12sp"
+            app:layout_constraintStart_toEndOf="@id/track_search_cover"
+            app:layout_constraintTop_toBottomOf="@id/track_search_title"
+            />
+
+        <TextView
+            android:id="@+id/track_search_type_result"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="8dp"
+            android:maxLines="1"
+            android:textAppearance="@style/TextAppearance.Regular.Body1.Secondary"
+            android:textSize="12sp"
+            app:layout_constraintStart_toEndOf="@id/track_search_type"
+            app:layout_constraintTop_toBottomOf="@id/track_search_title"
+            tools:text="Manga"
+            />
+
+        <TextView
+            android:id="@+id/track_search_start"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="8dp"
+            android:maxLines="1"
+            android:text="@string/track_start_date"
+            android:textAppearance="@style/TextAppearance.Regular.Body1.Bold"
+            android:textSize="12sp"
+            app:layout_constraintStart_toEndOf="@id/track_search_cover"
+            app:layout_constraintTop_toBottomOf="@id/track_search_type"
+            />
+
+        <TextView
+            android:id="@+id/track_search_start_result"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="8dp"
+            android:maxLines="1"
+            android:textAppearance="@style/TextAppearance.Regular.Body1.Secondary"
+            android:textSize="12sp"
+            app:layout_constraintStart_toEndOf="@id/track_search_start"
+            app:layout_constraintTop_toBottomOf="@id/track_search_type"
+            tools:text="2018-10-01"
+            />
+
+        <TextView
+            android:id="@+id/track_search_status"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="8dp"
+            android:maxLines="1"
+            android:text="@string/track_status"
+            android:textAppearance="@style/TextAppearance.Regular.Body1.Bold"
+            android:textSize="12sp"
+            app:layout_constraintStart_toEndOf="@id/track_search_cover"
+            app:layout_constraintTop_toBottomOf="@id/track_search_start"
+            />
+
+        <TextView
+            android:id="@+id/track_search_status_result"
+            android:layout_width="wrap_content"
+            android:layout_height="0dp"
+            android:layout_marginStart="8dp"
+            android:maxLines="1"
+            android:textAppearance="@style/TextAppearance.Regular.Body1.Secondary"
+            android:textSize="12sp"
+            app:layout_constraintStart_toEndOf="@id/track_search_status"
+            app:layout_constraintTop_toBottomOf="@id/track_search_start"
+            tools:text="Ongoing"
+            />
+
+        <TextView
+            android:id="@+id/track_search_summary"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginBottom="8dp"
+            android:layout_marginRight="8dp"
+            android:layout_marginStart="8dp"
+            android:layout_marginTop="8dp"
+            android:ellipsize="end"
+            android:maxLines="7"
+            android:textAppearance="@style/TextAppearance.Regular.Body1.Secondary"
+            android:textSize="12sp"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0.0"
+            app:layout_constraintStart_toEndOf="@id/track_search_cover"
+            app:layout_constraintTop_toBottomOf="@+id/track_search_status"
+            app:layout_constraintVertical_bias="0.333"
+            tools:text="This is the summary of the manga that fits This is the summary of the manga that fits This is the summary of the manga that fits This is the summary of the manga that fits This is the summary of the manga that fits This is the summary of the manga that fits This is the summary of the manga that fits "/>
+
+        <android.support.constraint.Guideline
+            android:id="@+id/guideline"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            app:layout_constraintGuide_begin="150dp"/>
+
+    </android.support.constraint.ConstraintLayout>
+</android.support.v7.widget.CardView>

+ 6 - 1
app/src/main/res/values/strings.xml

@@ -378,7 +378,7 @@
     <string name="download_unread">Download unread</string>
     <string name="download_unread">Download unread</string>
     <string name="confirm_delete_chapters">Are you sure you want to delete selected chapters?</string>
     <string name="confirm_delete_chapters">Are you sure you want to delete selected chapters?</string>
 
 
-    <!-- MyAnimeList fragment -->
+    <!-- Tracking Screen -->
     <string name="manga_tracking_tab">Tracking</string>
     <string name="manga_tracking_tab">Tracking</string>
     <string name="reading">Reading</string>
     <string name="reading">Reading</string>
     <string name="completed">Completed</string>
     <string name="completed">Completed</string>
@@ -388,6 +388,11 @@
     <string name="score">Score</string>
     <string name="score">Score</string>
     <string name="title">Title</string>
     <string name="title">Title</string>
     <string name="status">Status</string>
     <string name="status">Status</string>
+    <string name="track_status">Status</string>
+    <string name="track_start_date">Started</string>
+    <string name="track_type">Type</string>
+    <string name="track_author">Author</string>
+    <string name="url_not_set">Manga url is not set please click title and select manga again</string>
 
 
     <!-- Category activity -->
     <!-- Category activity -->
     <string name="error_category_exists">A category with this name already exists!</string>
     <string name="error_category_exists">A category with this name already exists!</string>