Collapsable manga summary/genre section
This commit is contained in:
parent
e388f0d563
commit
df69559b39
6 changed files with 111 additions and 32 deletions
|
@ -35,9 +35,9 @@ import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
class MangaController : RxController, TabbedController {
|
class MangaController : RxController, TabbedController {
|
||||||
|
|
||||||
constructor(manga: Manga?, fromCatalogue: Boolean = false) : super(Bundle().apply {
|
constructor(manga: Manga?, fromSource: Boolean = false) : super(Bundle().apply {
|
||||||
putLong(MANGA_EXTRA, manga?.id ?: 0)
|
putLong(MANGA_EXTRA, manga?.id ?: 0)
|
||||||
putBoolean(FROM_CATALOGUE_EXTRA, fromCatalogue)
|
putBoolean(FROM_SOURCE_EXTRA, fromSource)
|
||||||
}) {
|
}) {
|
||||||
this.manga = manga
|
this.manga = manga
|
||||||
if (manga != null) {
|
if (manga != null) {
|
||||||
|
@ -59,7 +59,7 @@ class MangaController : RxController, TabbedController {
|
||||||
|
|
||||||
private var adapter: MangaDetailAdapter? = null
|
private var adapter: MangaDetailAdapter? = null
|
||||||
|
|
||||||
val fromCatalogue = args.getBoolean(FROM_CATALOGUE_EXTRA, false)
|
val fromSource = args.getBoolean(FROM_SOURCE_EXTRA, false)
|
||||||
|
|
||||||
val mangaFavoriteRelay: PublishRelay<Boolean> = PublishRelay.create()
|
val mangaFavoriteRelay: PublishRelay<Boolean> = PublishRelay.create()
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ class MangaController : RxController, TabbedController {
|
||||||
binding.mangaPager.offscreenPageLimit = 3
|
binding.mangaPager.offscreenPageLimit = 3
|
||||||
binding.mangaPager.adapter = adapter
|
binding.mangaPager.adapter = adapter
|
||||||
|
|
||||||
if (!fromCatalogue)
|
if (!fromSource)
|
||||||
binding.mangaPager.currentItem = CHAPTERS_CONTROLLER
|
binding.mangaPager.currentItem = CHAPTERS_CONTROLLER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ class MangaController : RxController, TabbedController {
|
||||||
override fun configureRouter(router: Router, position: Int) {
|
override fun configureRouter(router: Router, position: Int) {
|
||||||
if (!router.hasRootController()) {
|
if (!router.hasRootController()) {
|
||||||
val controller = when (position) {
|
val controller = when (position) {
|
||||||
INFO_CONTROLLER -> MangaInfoController()
|
INFO_CONTROLLER -> MangaInfoController(fromSource)
|
||||||
CHAPTERS_CONTROLLER -> ChaptersController()
|
CHAPTERS_CONTROLLER -> ChaptersController()
|
||||||
TRACK_CONTROLLER -> TrackController()
|
TRACK_CONTROLLER -> TrackController()
|
||||||
else -> error("Wrong position $position")
|
else -> error("Wrong position $position")
|
||||||
|
@ -171,7 +171,7 @@ class MangaController : RxController, TabbedController {
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val FROM_CATALOGUE_EXTRA = "from_catalogue"
|
const val FROM_SOURCE_EXTRA = "from_source"
|
||||||
const val MANGA_EXTRA = "manga"
|
const val MANGA_EXTRA = "manga"
|
||||||
|
|
||||||
const val INFO_CONTROLLER = 0
|
const val INFO_CONTROLLER = 0
|
||||||
|
|
|
@ -269,7 +269,7 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
|
||||||
|
|
||||||
private fun initialFetchChapters() {
|
private fun initialFetchChapters() {
|
||||||
// Only fetch if this view is from the catalog and it hasn't requested previously
|
// Only fetch if this view is from the catalog and it hasn't requested previously
|
||||||
if ((parentController as MangaController).fromCatalogue && !presenter.hasRequested) {
|
if ((parentController as MangaController).fromSource && !presenter.hasRequested) {
|
||||||
fetchChaptersFromSource()
|
fetchChaptersFromSource()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import android.graphics.Bitmap
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.text.TextUtils
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuInflater
|
import android.view.MenuInflater
|
||||||
|
@ -51,7 +52,9 @@ import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||||
import eu.kanade.tachiyomi.util.lang.launchInUI
|
import eu.kanade.tachiyomi.util.lang.launchInUI
|
||||||
import eu.kanade.tachiyomi.util.lang.truncateCenter
|
import eu.kanade.tachiyomi.util.lang.truncateCenter
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
|
import eu.kanade.tachiyomi.util.view.gone
|
||||||
import eu.kanade.tachiyomi.util.view.snack
|
import eu.kanade.tachiyomi.util.view.snack
|
||||||
|
import eu.kanade.tachiyomi.util.view.toggle
|
||||||
import eu.kanade.tachiyomi.util.view.visible
|
import eu.kanade.tachiyomi.util.view.visible
|
||||||
import jp.wasabeef.glide.transformations.CropSquareTransformation
|
import jp.wasabeef.glide.transformations.CropSquareTransformation
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
@ -67,8 +70,9 @@ import uy.kohesive.injekt.injectLazy
|
||||||
* Uses R.layout.manga_info_controller.
|
* Uses R.layout.manga_info_controller.
|
||||||
* UI related actions should be called from here.
|
* UI related actions should be called from here.
|
||||||
*/
|
*/
|
||||||
class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
class MangaInfoController(private val fromSource: Boolean = false) :
|
||||||
ChangeMangaCategoriesDialog.Listener {
|
NucleusController<MangaInfoPresenter>(),
|
||||||
|
ChangeMangaCategoriesDialog.Listener {
|
||||||
|
|
||||||
private val preferences: PreferencesHelper by injectLazy()
|
private val preferences: PreferencesHelper by injectLazy()
|
||||||
|
|
||||||
|
@ -241,27 +245,6 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update genres list
|
|
||||||
if (!manga.genre.isNullOrBlank()) {
|
|
||||||
binding.mangaGenresTags.removeAllViews()
|
|
||||||
|
|
||||||
manga.getGenres()?.forEach { genre ->
|
|
||||||
val chip = Chip(view.context).apply {
|
|
||||||
text = genre
|
|
||||||
setOnClickListener { performSearch(genre) }
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.mangaGenresTags.addView(chip)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update description TextView.
|
|
||||||
binding.mangaSummary.text = if (manga.description.isNullOrBlank()) {
|
|
||||||
view.context.getString(R.string.unknown)
|
|
||||||
} else {
|
|
||||||
manga.description
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update status TextView.
|
// Update status TextView.
|
||||||
binding.mangaStatus.setText(when (manga.status) {
|
binding.mangaStatus.setText(when (manga.status) {
|
||||||
SManga.ONGOING -> R.string.ongoing
|
SManga.ONGOING -> R.string.ongoing
|
||||||
|
@ -289,6 +272,76 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
||||||
.into(binding.backdrop!!)
|
.into(binding.backdrop!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Manga info section
|
||||||
|
if (manga.description.isNullOrBlank() && manga.genre.isNullOrBlank()) {
|
||||||
|
hideMangaInfo()
|
||||||
|
} else {
|
||||||
|
// Update description TextView.
|
||||||
|
binding.mangaSummary.text = if (manga.description.isNullOrBlank()) {
|
||||||
|
view.context.getString(R.string.unknown)
|
||||||
|
} else {
|
||||||
|
manga.description
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update genres list
|
||||||
|
if (!manga.genre.isNullOrBlank()) {
|
||||||
|
binding.mangaGenresTags.removeAllViews()
|
||||||
|
|
||||||
|
manga.getGenres()?.forEach { genre ->
|
||||||
|
val chip = Chip(view.context).apply {
|
||||||
|
text = genre
|
||||||
|
setOnClickListener { performSearch(genre) }
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.mangaGenresTags.addView(chip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle showing more or less info
|
||||||
|
binding.mangaSummary.clicks()
|
||||||
|
.onEach { toggleMangaInfo(view.context) }
|
||||||
|
.launchInUI()
|
||||||
|
binding.mangaInfoToggle.clicks()
|
||||||
|
.onEach { toggleMangaInfo(view.context) }
|
||||||
|
.launchInUI()
|
||||||
|
|
||||||
|
// Expand manga info if navigated from source listing
|
||||||
|
if (fromSource) {
|
||||||
|
toggleMangaInfo(view.context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hideMangaInfo() {
|
||||||
|
binding.mangaSummaryLabel.gone()
|
||||||
|
binding.mangaSummary.gone()
|
||||||
|
binding.mangaGenresTags.gone()
|
||||||
|
binding.mangaInfoToggle.gone()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toggleMangaInfo(context: Context) {
|
||||||
|
binding.mangaInfoToggle.text =
|
||||||
|
if (binding.mangaInfoToggle.text == context.getString(R.string.manga_info_expand))
|
||||||
|
context.getString(R.string.manga_info_collapse)
|
||||||
|
else
|
||||||
|
context.getString(R.string.manga_info_expand)
|
||||||
|
|
||||||
|
with(binding.mangaSummary) {
|
||||||
|
maxLines =
|
||||||
|
if (maxLines == Int.MAX_VALUE)
|
||||||
|
3
|
||||||
|
else
|
||||||
|
Int.MAX_VALUE
|
||||||
|
|
||||||
|
ellipsize =
|
||||||
|
if (ellipsize == TextUtils.TruncateAt.END)
|
||||||
|
null
|
||||||
|
else
|
||||||
|
TextUtils.TruncateAt.END
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.mangaGenresTags.toggle()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -80,6 +80,10 @@ inline fun View.visibleIf(block: () -> Boolean) {
|
||||||
visibility = if (block()) View.VISIBLE else View.GONE
|
visibility = if (block()) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun View.toggle() {
|
||||||
|
visibleIf { visibility == View.GONE }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a round TextDrawable into an ImageView determined by input.
|
* Sets a round TextDrawable into an ImageView determined by input.
|
||||||
*
|
*
|
||||||
|
|
|
@ -80,6 +80,7 @@
|
||||||
style="@style/TextAppearance.Medium.Title"
|
style="@style/TextAppearance.Medium.Title"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
android:maxLines="2"
|
android:maxLines="2"
|
||||||
android:text="@string/manga_info_full_title_label"
|
android:text="@string/manga_info_full_title_label"
|
||||||
android:textIsSelectable="false"
|
android:textIsSelectable="false"
|
||||||
|
@ -190,7 +191,9 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingStart="16dp"
|
android:paddingStart="16dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
android:paddingEnd="16dp"
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/guideline">
|
app:layout_constraintTop_toBottomOf="@id/guideline">
|
||||||
|
@ -242,9 +245,8 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:text="@string/pref_category_about"
|
android:text="@string/manga_info_about_label"
|
||||||
android:textIsSelectable="false"
|
android:textIsSelectable="false"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
@ -257,6 +259,10 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:focusable="true"
|
||||||
|
android:maxLines="3"
|
||||||
android:textIsSelectable="false"
|
android:textIsSelectable="false"
|
||||||
app:layout_constraintBottom_toTopOf="@id/manga_genres_tags"
|
app:layout_constraintBottom_toTopOf="@id/manga_genres_tags"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -271,12 +277,25 @@
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
|
android:visibility="gone"
|
||||||
app:chipSpacingHorizontal="4dp"
|
app:chipSpacingHorizontal="4dp"
|
||||||
app:layout_constrainedHeight="true"
|
app:layout_constrainedHeight="true"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/manga_summary" />
|
app:layout_constraintTop_toBottomOf="@id/manga_summary" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/manga_info_toggle"
|
||||||
|
style="@style/Theme.Widget.Button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="4dp"
|
||||||
|
android:text="@string/manga_info_expand"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/manga_genres_tags" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
|
@ -418,6 +418,9 @@
|
||||||
<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>
|
||||||
|
<string name="manga_info_about_label">About</string>
|
||||||
|
<string name="manga_info_expand">Show more info</string>
|
||||||
|
<string name="manga_info_collapse">Show less info</string>
|
||||||
<string name="circular_icon">Circular</string>
|
<string name="circular_icon">Circular</string>
|
||||||
<string name="rounded_icon">Rounded</string>
|
<string name="rounded_icon">Rounded</string>
|
||||||
<string name="square_icon">Square</string>
|
<string name="square_icon">Square</string>
|
||||||
|
|
Reference in a new issue