Information Page Improvements (click to search, copy to clipboard, etc) (#1139)

* adds long click to copy details per inorichi/tachiyomi#1127

* Added the latest update date for inorichi/tachiyomi#1098 and possible fix for inorichi/tachiyomi#1141

* cleanup some mistakes I left

* adds modifications to full name display for inorichi/tachiyomi#1141 and click to search on various information pieces for inorichi/tachiyomi#860

* This modifies how the full title shows up in the info pages and also properly ellipsizes the titles in the catalogue/library list views

* Changes full title layout in horizontal mode

* Adds the tags in using AndroidTagGroup library

* reverting the sdk version in the gradle build

* code cleanup

* added back status update
This commit is contained in:
Josh 2018-01-18 12:15:33 -06:00 committed by inorichi
parent fae36aebf4
commit 34d21c1de3
13 changed files with 321 additions and 103 deletions

View File

@ -202,6 +202,7 @@ dependencies {
implementation 'me.zhanghai.android.systemuihelper:library:1.0.0' implementation 'me.zhanghai.android.systemuihelper:library:1.0.0'
implementation 'com.nightlynexus.viewstatepageradapter:viewstatepageradapter:1.0.4' implementation 'com.nightlynexus.viewstatepageradapter:viewstatepageradapter:1.0.4'
implementation 'com.github.mthli:Slice:v1.2' implementation 'com.github.mthli:Slice:v1.2'
implementation 'me.gujun.android.taggroup:library:1.4@aar'
// Conductor // Conductor
implementation "com.bluelinelabs:conductor:2.1.4" implementation "com.bluelinelabs:conductor:2.1.4"

View File

@ -185,10 +185,11 @@ class CatalogueController : NucleusController<CataloguePresenter>(),
// Create query listener which opens the global search view. // Create query listener which opens the global search view.
searchView.queryTextChangeEvents() searchView.queryTextChangeEvents()
.filter { it.isSubmitted } .filter { it.isSubmitted }
.subscribeUntilDestroy { .subscribeUntilDestroy { performGlobalSearch(it.queryText().toString()) }
val query = it.queryText().toString() }
router.pushController(CatalogueSearchController(query).withFadeTransaction())
} fun performGlobalSearch(query: String){
router.pushController(CatalogueSearchController(query).withFadeTransaction())
} }
/** /**

View File

@ -21,10 +21,8 @@ import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.base.controller.RouterPagerAdapter import eu.kanade.tachiyomi.ui.base.controller.*
import eu.kanade.tachiyomi.ui.base.controller.RxController import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController
import eu.kanade.tachiyomi.ui.base.controller.TabbedController
import eu.kanade.tachiyomi.ui.base.controller.requestPermissionsSafe
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersController import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersController
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoController import eu.kanade.tachiyomi.ui.manga.info.MangaInfoController
import eu.kanade.tachiyomi.ui.manga.track.TrackController import eu.kanade.tachiyomi.ui.manga.track.TrackController
@ -34,6 +32,7 @@ import kotlinx.android.synthetic.main.manga_controller.*
import rx.Subscription import rx.Subscription
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.*
class MangaController : RxController, TabbedController { class MangaController : RxController, TabbedController {
@ -63,6 +62,8 @@ class MangaController : RxController, TabbedController {
val fromCatalogue = args.getBoolean(FROM_CATALOGUE_EXTRA, false) val fromCatalogue = args.getBoolean(FROM_CATALOGUE_EXTRA, false)
val lastUpdateRelay: BehaviorRelay<Date> = BehaviorRelay.create()
val chapterCountRelay: BehaviorRelay<Float> = BehaviorRelay.create() val chapterCountRelay: BehaviorRelay<Float> = BehaviorRelay.create()
val mangaFavoriteRelay: PublishRelay<Boolean> = PublishRelay.create() val mangaFavoriteRelay: PublishRelay<Boolean> = PublishRelay.create()
@ -188,4 +189,5 @@ class MangaController : RxController, TabbedController {
.apply { isAccessible = true } .apply { isAccessible = true }
} }
} }

View File

@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.manga.chapter
import android.animation.Animator import android.animation.Animator
import android.animation.AnimatorListenerAdapter import android.animation.AnimatorListenerAdapter
import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.support.design.widget.Snackbar import android.support.design.widget.Snackbar
@ -61,7 +62,7 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
override fun createPresenter(): ChaptersPresenter { override fun createPresenter(): ChaptersPresenter {
val ctrl = parentController as MangaController val ctrl = parentController as MangaController
return ChaptersPresenter(ctrl.manga!!, ctrl.source!!, return ChaptersPresenter(ctrl.manga!!, ctrl.source!!,
ctrl.chapterCountRelay, ctrl.mangaFavoriteRelay) ctrl.chapterCountRelay, ctrl.lastUpdateRelay, ctrl.mangaFavoriteRelay)
} }
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View { override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
@ -292,6 +293,7 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
return true return true
} }
@SuppressLint("StringFormatInvalid")
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean { override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
val count = adapter?.selectedItemCount ?: 0 val count = adapter?.selectedItemCount ?: 0
if (count == 0) { if (count == 0) {

View File

@ -20,6 +20,7 @@ import rx.schedulers.Schedulers
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.*
/** /**
* Presenter of [ChaptersController]. * Presenter of [ChaptersController].
@ -28,6 +29,7 @@ class ChaptersPresenter(
val manga: Manga, val manga: Manga,
val source: Source, val source: Source,
private val chapterCountRelay: BehaviorRelay<Float>, private val chapterCountRelay: BehaviorRelay<Float>,
private val lastUpdateRelay: BehaviorRelay<Date>,
private val mangaFavoriteRelay: PublishRelay<Boolean>, private val mangaFavoriteRelay: PublishRelay<Boolean>,
val preferences: PreferencesHelper = Injekt.get(), val preferences: PreferencesHelper = Injekt.get(),
private val db: DatabaseHelper = Injekt.get(), private val db: DatabaseHelper = Injekt.get(),
@ -91,6 +93,11 @@ class ChaptersPresenter(
// Emit the number of chapters to the info tab. // Emit the number of chapters to the info tab.
chapterCountRelay.call(chapters.maxBy { it.chapter_number }?.chapter_number chapterCountRelay.call(chapters.maxBy { it.chapter_number }?.chapter_number
?: 0f) ?: 0f)
// Emit the upload date of the most recent chapter
lastUpdateRelay.call(Date(chapters.maxBy { it.date_upload }?.date_upload
?: 0))
} }
.subscribe { chaptersRelay.call(it) }) .subscribe { chaptersRelay.call(it) })
} }

View File

@ -2,8 +2,12 @@ package eu.kanade.tachiyomi.ui.manga.info
import android.app.Dialog import android.app.Dialog
import android.app.PendingIntent import android.app.PendingIntent
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
@ -13,6 +17,7 @@ import android.support.v4.content.pm.ShortcutInfoCompat
import android.support.v4.content.pm.ShortcutManagerCompat import android.support.v4.content.pm.ShortcutManagerCompat
import android.support.v4.graphics.drawable.IconCompat import android.support.v4.graphics.drawable.IconCompat
import android.view.* import android.view.*
import android.widget.Toast
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.bumptech.glide.load.resource.bitmap.RoundedCorners
@ -20,6 +25,7 @@ import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.transition.Transition import com.bumptech.glide.request.transition.Transition
import com.jakewharton.rxbinding.support.v4.widget.refreshes import com.jakewharton.rxbinding.support.v4.widget.refreshes
import com.jakewharton.rxbinding.view.clicks import com.jakewharton.rxbinding.view.clicks
import com.jakewharton.rxbinding.view.longClicks
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
@ -31,17 +37,22 @@ import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.base.controller.NucleusController import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.util.getResourceColor import eu.kanade.tachiyomi.util.getResourceColor
import eu.kanade.tachiyomi.util.snack import eu.kanade.tachiyomi.util.snack
import eu.kanade.tachiyomi.util.toast import eu.kanade.tachiyomi.util.toast
import eu.kanade.tachiyomi.util.truncateCenter
import jp.wasabeef.glide.transformations.CropSquareTransformation import jp.wasabeef.glide.transformations.CropSquareTransformation
import jp.wasabeef.glide.transformations.MaskTransformation import jp.wasabeef.glide.transformations.MaskTransformation
import kotlinx.android.synthetic.main.manga_info_controller.* import kotlinx.android.synthetic.main.manga_info_controller.*
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.text.DateFormat
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.*
/** /**
* Fragment that shows manga information. * Fragment that shows manga information.
@ -64,7 +75,7 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
override fun createPresenter(): MangaInfoPresenter { override fun createPresenter(): MangaInfoPresenter {
val ctrl = parentController as MangaController val ctrl = parentController as MangaController
return MangaInfoPresenter(ctrl.manga!!, ctrl.source!!, return MangaInfoPresenter(ctrl.manga!!, ctrl.source!!,
ctrl.chapterCountRelay, ctrl.mangaFavoriteRelay) ctrl.chapterCountRelay, ctrl.lastUpdateRelay, ctrl.mangaFavoriteRelay)
} }
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View { override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
@ -79,6 +90,41 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
// Set SwipeRefresh to refresh manga data. // Set SwipeRefresh to refresh manga data.
swipe_refresh.refreshes().subscribeUntilDestroy { fetchMangaFromSource() } swipe_refresh.refreshes().subscribeUntilDestroy { fetchMangaFromSource() }
manga_full_title.longClicks().subscribeUntilDestroy{
copyToClipboard(view.context.getString(R.string.title), manga_full_title.text.toString())
}
manga_full_title.clicks().subscribeUntilDestroy {
performGlobalSearch(manga_full_title.text.toString())
}
manga_artist.longClicks().subscribeUntilDestroy {
copyToClipboard(manga_artist_label.text.toString(), manga_artist.text.toString())
}
manga_artist.clicks().subscribeUntilDestroy {
performGlobalSearch(manga_artist.text.toString())
}
manga_author.longClicks().subscribeUntilDestroy {
copyToClipboard(manga_author.text.toString(), manga_author.text.toString())
}
manga_author.clicks().subscribeUntilDestroy {
performGlobalSearch(manga_author.text.toString())
}
manga_summary.longClicks().subscribeUntilDestroy {
copyToClipboard(view.context.getString(R.string.description), manga_summary.text.toString())
}
manga_genres_tags.setOnTagClickListener { tag -> performGlobalSearch(tag) }
manga_cover.longClicks().subscribeUntilDestroy {
copyToClipboard(view.context.getString(R.string.title), presenter.manga.title)
}
} }
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@ -107,6 +153,7 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
if (manga.initialized) { if (manga.initialized) {
// Update view. // Update view.
setMangaInfo(manga, source) setMangaInfo(manga, source)
} else { } else {
// Initialize manga. // Initialize manga.
fetchMangaFromSource() fetchMangaFromSource()
@ -122,19 +169,45 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
private fun setMangaInfo(manga: Manga, source: Source?) { private fun setMangaInfo(manga: Manga, source: Source?) {
val view = view ?: return val view = view ?: return
// Update artist TextView. //update full title TextView.
manga_artist.text = manga.artist manga_full_title.text = if (manga.title.isBlank()) {
view.context.getString(R.string.unknown)
// Update author TextView. } else {
manga_author.text = manga.author manga.title
// If manga source is known update source TextView.
if (source != null) {
manga_source.text = source.toString()
} }
// Update genres TextView. // Update artist TextView.
manga_genres.text = manga.genre manga_artist.text = if (manga.artist.isNullOrBlank()) {
view.context.getString(R.string.unknown)
} else {
manga.artist
}
// Update author TextView.
manga_author.text = if (manga.author.isNullOrBlank()) {
view.context.getString(R.string.unknown)
} else {
manga.author
}
// If manga source is known update source TextView.
manga_source.text = if(source == null) {
view.context.getString(R.string.unknown)
} else {
source.toString()
}
// Update genres list
if(manga.genre.isNullOrBlank().not()){
manga_genres_tags.setTags(manga.genre?.split(", "))
}
// Update description TextView.
manga_summary.text = if (manga.description.isNullOrBlank()) {
view.context.getString(R.string.unknown)
} else {
manga.description
}
// Update status TextView. // Update status TextView.
manga_status.setText(when (manga.status) { manga_status.setText(when (manga.status) {
@ -144,9 +217,6 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
else -> R.string.unknown else -> R.string.unknown
}) })
// Update description TextView.
manga_summary.text = manga.description
// Set the favorite drawable to the correct one. // Set the favorite drawable to the correct one.
setFavoriteDrawable(manga.favorite) setFavoriteDrawable(manga.favorite)
@ -168,6 +238,11 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
} }
} }
override fun onDestroyView(view: View) {
manga_genres_tags.setOnTagClickListener(null)
super.onDestroyView(view)
}
/** /**
* Update chapter count TextView. * Update chapter count TextView.
* *
@ -177,6 +252,10 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
manga_chapters?.text = DecimalFormat("#.#").format(count) manga_chapters?.text = DecimalFormat("#.#").format(count)
} }
fun setLastUpdateDate(date: Date){
manga_last_update?.text = DateFormat.getDateInstance(DateFormat.SHORT).format(date)
}
/** /**
* Toggles the favorite status and asks for confirmation to delete downloaded chapters. * Toggles the favorite status and asks for confirmation to delete downloaded chapters.
*/ */
@ -380,6 +459,35 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
}) })
} }
/**
* Copies a string to clipboard
*
* @param label Label to show to the user describing the content
* @param content the actual text to copy to the board
*/
private fun copyToClipboard(label: String, content: String){
if(content.isBlank()) return
val activity = activity ?: return
val view = view ?: return
val clipboard = activity.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
clipboard.primaryClip = ClipData.newPlainText(label, content)
activity.toast( view.context.getString(R.string.copied_to_clipboard, content.truncateCenter(20)),
Toast.LENGTH_SHORT)
}
/**
* Perform a global search using the provided query.
*
* @param query the search query to pass to the search controller
*/
fun performGlobalSearch(query: String){
val router = parentController?.router ?: return
router.pushController(CatalogueSearchController(query).withFadeTransaction())
}
/** /**
* Create shortcut using ShortcutManager. * Create shortcut using ShortcutManager.
* *

View File

@ -18,6 +18,7 @@ import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers 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
import java.util.*
/** /**
* Presenter of MangaInfoFragment. * Presenter of MangaInfoFragment.
@ -28,6 +29,7 @@ class MangaInfoPresenter(
val manga: Manga, val manga: Manga,
val source: Source, val source: Source,
private val chapterCountRelay: BehaviorRelay<Float>, private val chapterCountRelay: BehaviorRelay<Float>,
private val lastUpdateRelay: BehaviorRelay<Date>,
private val mangaFavoriteRelay: PublishRelay<Boolean>, private val mangaFavoriteRelay: PublishRelay<Boolean>,
private val db: DatabaseHelper = Injekt.get(), private val db: DatabaseHelper = Injekt.get(),
private val downloadManager: DownloadManager = Injekt.get(), private val downloadManager: DownloadManager = Injekt.get(),
@ -37,7 +39,7 @@ class MangaInfoPresenter(
/** /**
* Subscription to send the manga to the view. * Subscription to send the manga to the view.
*/ */
private var viewMangaSubcription: Subscription? = null private var viewMangaSubscription: Subscription? = null
/** /**
* Subscription to update the manga from the source. * Subscription to update the manga from the source.
@ -56,14 +58,18 @@ class MangaInfoPresenter(
mangaFavoriteRelay.observeOn(AndroidSchedulers.mainThread()) mangaFavoriteRelay.observeOn(AndroidSchedulers.mainThread())
.subscribe { setFavorite(it) } .subscribe { setFavorite(it) }
.apply { add(this) } .apply { add(this) }
//update last update date
lastUpdateRelay.observeOn(AndroidSchedulers.mainThread())
.subscribeLatestCache(MangaInfoController::setLastUpdateDate)
} }
/** /**
* Sends the active manga to the view. * Sends the active manga to the view.
*/ */
fun sendMangaToView() { fun sendMangaToView() {
viewMangaSubcription?.let { remove(it) } viewMangaSubscription?.let { remove(it) }
viewMangaSubcription = Observable.just(manga) viewMangaSubscription = Observable.just(manga)
.subscribeLatestCache({ view, manga -> view.onNextManga(manga, source) }) .subscribeLatestCache({ view, manga -> view.onNextManga(manga, source) })
} }

View File

@ -1,5 +1,7 @@
package eu.kanade.tachiyomi.util package eu.kanade.tachiyomi.util
import java.lang.Math.floor
/** /**
* Replaces the given string to have at most [count] characters using [replacement] at its end. * Replaces the given string to have at most [count] characters using [replacement] at its end.
* If [replacement] is longer than [count] an exception will be thrown when `length > count`. * If [replacement] is longer than [count] an exception will be thrown when `length > count`.
@ -11,3 +13,16 @@ fun String.chop(count: Int, replacement: String = "..."): String {
this this
} }
/**
* Replaces the given string to have at most [count] characters using [replacement] near the center.
* If [replacement] is longer than [count] an exception will be thrown when `length > count`.
*/
fun String.truncateCenter(count: Int, replacement: String = "..."): String{
if(length <= count)
return this
val pieceLength:Int = floor((count - replacement.length).div(2.0)).toInt()
return "${ take(pieceLength) }$replacement${ takeLast(pieceLength) }"
}

View File

@ -59,6 +59,18 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView
android:text="@string/manga_info_full_title_label"
android:id="@+id/manga_full_title"
style="@style/TextAppearance.Medium.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:textIsSelectable="false"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
<TextView <TextView
android:id="@+id/manga_author_label" android:id="@+id/manga_author_label"
style="@style/TextAppearance.Medium.Body2" style="@style/TextAppearance.Medium.Body2"
@ -66,7 +78,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/manga_info_author_label" android:text="@string/manga_info_author_label"
android:textIsSelectable="false" android:textIsSelectable="false"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toBottomOf="@+id/manga_full_title"
app:layout_constraintLeft_toLeftOf="parent"/> app:layout_constraintLeft_toLeftOf="parent"/>
<TextView <TextView
@ -131,6 +143,30 @@
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
android:layout_marginStart="8dp"/> android:layout_marginStart="8dp"/>
<TextView
android:id="@+id/manga_last_update_label"
style="@style/TextAppearance.Medium.Body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/manga_info_latest_data_label"
android:textIsSelectable="false"
app:layout_constraintTop_toBottomOf="@+id/manga_chapters_label"
app:layout_constraintLeft_toLeftOf="parent"/>
<TextView
android:id="@+id/manga_last_update"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:ellipsize="end"
android:maxLines="1"
android:textIsSelectable="false"
app:layout_constraintBaseline_toBaselineOf="@+id/manga_last_update_label"
app:layout_constraintLeft_toRightOf="@+id/manga_last_update_label"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginStart="8dp"/>
<TextView <TextView
android:id="@+id/manga_status_label" android:id="@+id/manga_status_label"
style="@style/TextAppearance.Medium.Body2" style="@style/TextAppearance.Medium.Body2"
@ -138,7 +174,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/manga_info_status_label" android:text="@string/manga_info_status_label"
android:textIsSelectable="false" android:textIsSelectable="false"
app:layout_constraintTop_toBottomOf="@+id/manga_chapters_label" app:layout_constraintTop_toBottomOf="@+id/manga_last_update_label"
app:layout_constraintLeft_toLeftOf="parent"/> app:layout_constraintLeft_toLeftOf="parent"/>
<TextView <TextView
@ -179,26 +215,6 @@
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
android:layout_marginStart="8dp"/> android:layout_marginStart="8dp"/>
<TextView
android:id="@+id/manga_genres_label"
style="@style/TextAppearance.Medium.Body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/manga_info_genres_label"
android:textIsSelectable="false"
app:layout_constraintTop_toBottomOf="@+id/manga_source_label"
app:layout_constraintLeft_toLeftOf="parent"/>
<TextView
android:id="@+id/manga_genres"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textIsSelectable="false"
app:layout_constraintTop_toBottomOf="@+id/manga_genres_label"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<TextView <TextView
android:id="@+id/manga_summary_label" android:id="@+id/manga_summary_label"
style="@style/TextAppearance.Medium.Body2" style="@style/TextAppearance.Medium.Body2"
@ -206,7 +222,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/description" android:text="@string/description"
android:textIsSelectable="false" android:textIsSelectable="false"
app:layout_constraintTop_toBottomOf="@+id/manga_genres" app:layout_constraintTop_toBottomOf="@+id/manga_source"
app:layout_constraintLeft_toLeftOf="parent"/> app:layout_constraintLeft_toLeftOf="parent"/>
<TextView <TextView
@ -220,6 +236,22 @@
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
android:layout_marginRight="64dp"/> android:layout_marginRight="64dp"/>
<me.gujun.android.taggroup.TagGroup
android:id="@+id/manga_genres_tags"
style="@style/TagGroup"
android:layout_marginTop="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/manga_summary"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:atg_borderStrokeWidth="1dp"
app:atg_backgroundColor="@android:color/transparent"
app:atg_borderColor="@color/md_blue_A400"
app:atg_textColor="@color/md_blue_A400"
android:layout_marginRight="64dp"/>
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
</android.support.v4.widget.NestedScrollView> </android.support.v4.widget.NestedScrollView>

View File

@ -21,10 +21,11 @@
android:paddingTop="8dp" android:paddingTop="8dp"
android:paddingBottom="8dp" android:paddingBottom="8dp"
android:layout_marginLeft="8dp"/> android:layout_marginLeft="8dp"/>
<TextView <TextView
android:id="@+id/title" android:id="@+id/title"
style="@style/TextAppearance.Regular.SubHeading" style="@style/TextAppearance.Regular.SubHeading"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
@ -41,6 +42,28 @@
app:layout_constraintVertical_bias="0.523" app:layout_constraintVertical_bias="0.523"
app:layout_constraintHorizontal_bias="0.007"/> app:layout_constraintHorizontal_bias="0.007"/>
<TextView
android:id="@+id/local_text"
style="@style/TextAppearance.Regular.Caption.Light"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/md_teal_500"
android:paddingBottom="1dp"
android:paddingLeft="3dp"
android:paddingRight="3dp"
android:paddingTop="1dp"
android:layout_centerVertical="true"
android:maxLines="1"
android:text="@string/local_source_badge"
android:visibility="gone"
tools:visibility="visible"
android:layout_marginEnd="8dp"
app:layout_constraintRight_toLeftOf="@+id/unread_text"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp"/>
<TextView <TextView
android:id="@+id/unread_text" android:id="@+id/unread_text"
style="@style/TextAppearance.Regular.Caption.Light" style="@style/TextAppearance.Regular.Caption.Light"
@ -58,6 +81,7 @@
tools:text="130" tools:text="130"
tools:visibility="visible" tools:visibility="visible"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toLeftOf="@+id/download_text"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
@ -81,32 +105,11 @@
tools:text="122" tools:text="122"
tools:visibility="visible" tools:visibility="visible"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
app:layout_constraintRight_toLeftOf="@+id/unread_text" app:layout_constraintRight_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp"/> android:layout_marginBottom="8dp"/>
<TextView
android:id="@+id/local_text"
style="@style/TextAppearance.Regular.Caption.Light"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/md_teal_500"
android:paddingBottom="1dp"
android:paddingLeft="3dp"
android:paddingRight="3dp"
android:paddingTop="1dp"
android:layout_centerVertical="true"
android:maxLines="1"
android:text="@string/local_source_badge"
android:visibility="gone"
tools:visibility="visible"
android:layout_marginEnd="8dp"
app:layout_constraintRight_toLeftOf="@+id/download_text"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp"/>
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>

View File

@ -41,10 +41,10 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:text="22/02/2016" tools:text="22/02/2016"
android:ellipsize="marquee" android:ellipsize="marquee"
android:maxLines="1"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginLeft="16dp"/> android:layout_marginLeft="16dp"
android:singleLine="true" />
<TextView <TextView
android:id="@+id/chapter_pages" android:id="@+id/chapter_pages"
@ -53,10 +53,10 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:text="Pages: 45" tools:text="Pages: 45"
android:ellipsize="marquee" android:ellipsize="marquee"
android:maxLines="1"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/> app:layout_constraintLeft_toLeftOf="parent"
android:singleLine="true" />
<ImageView <ImageView
android:id="@+id/chapter_menu" android:id="@+id/chapter_menu"

View File

@ -83,6 +83,16 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView
android:text="@string/manga_info_full_title_label"
android:id="@+id/manga_full_title"
style="@style/TextAppearance.Medium.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
android:textIsSelectable="false"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
<TextView <TextView
android:id="@+id/manga_author_label" android:id="@+id/manga_author_label"
style="@style/TextAppearance.Medium.Body2" style="@style/TextAppearance.Medium.Body2"
@ -90,9 +100,11 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/manga_info_author_label" android:text="@string/manga_info_author_label"
android:textIsSelectable="false" android:textIsSelectable="false"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintTop_toBottomOf="@+id/manga_full_title"
app:layout_constraintLeft_toLeftOf="parent"/> app:layout_constraintLeft_toLeftOf="parent"/>
<TextView <TextView
android:id="@+id/manga_author" android:id="@+id/manga_author"
style="@style/TextAppearance.Regular.Body1.Secondary" style="@style/TextAppearance.Regular.Body1.Secondary"
@ -152,6 +164,29 @@
app:layout_constraintLeft_toRightOf="@+id/manga_chapters_label" app:layout_constraintLeft_toRightOf="@+id/manga_chapters_label"
app:layout_constraintRight_toRightOf="parent"/> app:layout_constraintRight_toRightOf="parent"/>
<TextView
android:id="@+id/manga_last_update_label"
style="@style/TextAppearance.Medium.Body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/manga_info_latest_data_label"
android:textIsSelectable="false"
app:layout_constraintTop_toBottomOf="@+id/manga_chapters_label"
app:layout_constraintLeft_toLeftOf="parent"/>
<TextView
android:id="@+id/manga_last_update"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:ellipsize="end"
android:maxLines="1"
android:textIsSelectable="false"
app:layout_constraintBaseline_toBaselineOf="@+id/manga_last_update_label"
app:layout_constraintLeft_toRightOf="@+id/manga_last_update_label"
app:layout_constraintRight_toRightOf="parent"/>
<TextView <TextView
android:id="@+id/manga_status_label" android:id="@+id/manga_status_label"
style="@style/TextAppearance.Medium.Body2" style="@style/TextAppearance.Medium.Body2"
@ -159,7 +194,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/manga_info_status_label" android:text="@string/manga_info_status_label"
android:textIsSelectable="false" android:textIsSelectable="false"
app:layout_constraintTop_toBottomOf="@+id/manga_chapters_label" app:layout_constraintTop_toBottomOf="@+id/manga_last_update_label"
app:layout_constraintLeft_toLeftOf="parent"/> app:layout_constraintLeft_toLeftOf="parent"/>
<TextView <TextView
@ -198,26 +233,6 @@
app:layout_constraintLeft_toRightOf="@+id/manga_source_label" app:layout_constraintLeft_toRightOf="@+id/manga_source_label"
app:layout_constraintRight_toRightOf="parent"/> app:layout_constraintRight_toRightOf="parent"/>
<TextView
android:id="@+id/manga_genres_label"
style="@style/TextAppearance.Medium.Body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/manga_info_genres_label"
android:textIsSelectable="false"
app:layout_constraintTop_toBottomOf="@+id/manga_source_label"
app:layout_constraintLeft_toLeftOf="parent"/>
<TextView
android:id="@+id/manga_genres"
style="@style/TextAppearance.Regular.Body1.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textIsSelectable="false"
app:layout_constraintTop_toBottomOf="@+id/manga_genres_label"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
</android.support.v4.widget.NestedScrollView> </android.support.v4.widget.NestedScrollView>
@ -225,17 +240,16 @@
<android.support.v4.widget.NestedScrollView <android.support.v4.widget.NestedScrollView
android:id="@+id/description_scrollview" android:id="@+id/description_scrollview"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="wrap_content"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
android:layout_marginRight="16dp" android:layout_marginRight="16dp"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:layout_marginTop="16dp" android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline"> app:layout_constraintTop_toBottomOf="@+id/guideline">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -261,6 +275,29 @@
</android.support.v4.widget.NestedScrollView> </android.support.v4.widget.NestedScrollView>
<me.gujun.android.taggroup.TagGroup
android:id="@+id/manga_genres_tags"
style="@style/TagGroup"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="16dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:orientation="vertical"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/description_scrollview"
app:layout_constraintBottom_toBottomOf="parent"
app:atg_borderStrokeWidth="1dp"
app:atg_backgroundColor="@android:color/transparent"
app:atg_borderColor="@color/md_blue_A400"
app:atg_textColor="@color/md_blue_A400"
/>
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
</android.support.v4.widget.SwipeRefreshLayout> </android.support.v4.widget.SwipeRefreshLayout>

View File

@ -300,12 +300,14 @@
<string name="unknown">Unknown</string> <string name="unknown">Unknown</string>
<string name="licensed">Licensed</string> <string name="licensed">Licensed</string>
<string name="remove_from_library">Remove from library</string> <string name="remove_from_library">Remove from library</string>
<string name="manga_info_full_title_label">Title</string>
<string name="manga_added_library">Added to library</string> <string name="manga_added_library">Added to library</string>
<string name="manga_removed_library">Removed from library</string> <string name="manga_removed_library">Removed from library</string>
<string name="manga_info_author_label">Author</string> <string name="manga_info_author_label">Author</string>
<string name="manga_info_artist_label">Artist</string> <string name="manga_info_artist_label">Artist</string>
<string name="manga_info_chapters_label">Chapters</string> <string name="manga_info_chapters_label">Chapters</string>
<string name="manga_info_last_chapter_label">Last chapter</string> <string name="manga_info_last_chapter_label">Last chapter</string>
<string name="manga_info_latest_data_label">Updated</string>
<string name="manga_info_status_label">Status</string> <string name="manga_info_status_label">Status</string>
<string name="manga_info_source_label">Source</string> <string name="manga_info_source_label">Source</string>
<string name="manga_info_genres_label">Genres</string> <string name="manga_info_genres_label">Genres</string>
@ -319,6 +321,7 @@
<string name="icon_shape">Icon shape</string> <string name="icon_shape">Icon shape</string>
<string name="icon_creation_fail">Failed to create shortcut!</string> <string name="icon_creation_fail">Failed to create shortcut!</string>
<string name="delete_downloads_for_manga">Delete downloaded chapters?</string> <string name="delete_downloads_for_manga">Delete downloaded chapters?</string>
<string name="copied_to_clipboard">%1$s copied to clipboard</string>
<!-- Manga chapters fragment --> <!-- Manga chapters fragment -->
<string name="manga_chapters_tab">Chapters</string> <string name="manga_chapters_tab">Chapters</string>
@ -457,4 +460,5 @@
<string name="channel_common">Common</string> <string name="channel_common">Common</string>
<string name="channel_library">Library</string> <string name="channel_library">Library</string>
<string name="channel_downloader">Downloader</string> <string name="channel_downloader">Downloader</string>
</resources> </resources>