UI improvements

pull/446/head
Koitharu 3 years ago
parent af4845a770
commit c5c907c8dc
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -1,13 +1,16 @@
package org.koitharu.kotatsu.details.ui package org.koitharu.kotatsu.details.ui
import android.content.Context import android.content.Context
import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.text.style.ForegroundColorSpan
import android.text.style.RelativeSizeSpan
import android.transition.AutoTransition import android.transition.AutoTransition
import android.transition.Slide import android.transition.Slide
import android.transition.TransitionManager import android.transition.TransitionManager
import android.view.Gravity import android.view.Gravity
import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -17,6 +20,8 @@ import android.widget.Toast
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
import androidx.core.text.buildSpannedString
import androidx.core.text.inSpans
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
@ -33,12 +38,11 @@ import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
import org.koitharu.kotatsu.core.os.AppShortcutManager import org.koitharu.kotatsu.core.os.AppShortcutManager
import org.koitharu.kotatsu.core.parser.MangaIntent import org.koitharu.kotatsu.core.parser.MangaIntent
import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.core.ui.dialog.RecyclerViewAlertDialog
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.ui.util.MenuInvalidator import org.koitharu.kotatsu.core.ui.util.MenuInvalidator
import org.koitharu.kotatsu.core.util.ViewBadge import org.koitharu.kotatsu.core.util.ViewBadge
import org.koitharu.kotatsu.core.util.ext.doOnExpansionsChanged import org.koitharu.kotatsu.core.util.ext.doOnExpansionsChanged
import org.koitharu.kotatsu.core.util.ext.getAnimationDuration import org.koitharu.kotatsu.core.util.ext.getAnimationDuration
import org.koitharu.kotatsu.core.util.ext.getThemeColor
import org.koitharu.kotatsu.core.util.ext.isAnimationsEnabled import org.koitharu.kotatsu.core.util.ext.isAnimationsEnabled
import org.koitharu.kotatsu.core.util.ext.measureHeight import org.koitharu.kotatsu.core.util.ext.measureHeight
import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.observe
@ -48,10 +52,8 @@ import org.koitharu.kotatsu.core.util.ext.setNavigationIconSafe
import org.koitharu.kotatsu.core.util.ext.textAndVisible import org.koitharu.kotatsu.core.util.ext.textAndVisible
import org.koitharu.kotatsu.databinding.ActivityDetailsBinding import org.koitharu.kotatsu.databinding.ActivityDetailsBinding
import org.koitharu.kotatsu.details.service.MangaPrefetchService import org.koitharu.kotatsu.details.service.MangaPrefetchService
import org.koitharu.kotatsu.details.ui.adapter.branchAD
import org.koitharu.kotatsu.details.ui.model.ChapterListItem import org.koitharu.kotatsu.details.ui.model.ChapterListItem
import org.koitharu.kotatsu.details.ui.model.HistoryInfo import org.koitharu.kotatsu.details.ui.model.HistoryInfo
import org.koitharu.kotatsu.details.ui.model.MangaBranch
import org.koitharu.kotatsu.download.ui.worker.DownloadStartedObserver import org.koitharu.kotatsu.download.ui.worker.DownloadStartedObserver
import org.koitharu.kotatsu.main.ui.owners.NoModalBottomSheetOwner import org.koitharu.kotatsu.main.ui.owners.NoModalBottomSheetOwner
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
@ -157,7 +159,7 @@ class DetailsActivity :
override fun onClick(v: View) { override fun onClick(v: View) {
when (v.id) { when (v.id) {
R.id.button_read -> openReader(isIncognitoMode = false) R.id.button_read -> openReader(isIncognitoMode = false)
R.id.button_dropdown -> showBranchPopupMenu() R.id.button_dropdown -> showBranchPopupMenu(v)
} }
} }
@ -275,20 +277,28 @@ class DetailsActivity :
viewBadge.counter = newChapters viewBadge.counter = newChapters
} }
private fun showBranchPopupMenu() { private fun showBranchPopupMenu(v: View) {
var dialog: DialogInterface? = null val menu = PopupMenu(v.context, v)
val listener = OnListItemClickListener<MangaBranch> { item, _ -> val branches = viewModel.branches.value
viewModel.setSelectedBranch(item.name) for ((i, branch) in branches.withIndex()) {
dialog?.dismiss() val title = buildSpannedString {
append(branch.name ?: getString(R.string.system_default))
append(' ')
append(' ')
inSpans(
ForegroundColorSpan(v.context.getThemeColor(android.R.attr.textColorSecondary, Color.LTGRAY)),
RelativeSizeSpan(0.74f),
) {
append(branch.count.toString())
}
}
menu.menu.add(Menu.NONE, Menu.NONE, i, title)
}
menu.setOnMenuItemClickListener {
viewModel.setSelectedBranch(branches.getOrNull(it.order)?.name)
true
} }
dialog = RecyclerViewAlertDialog.Builder<MangaBranch>(this) menu.show()
.addAdapterDelegate(branchAD(listener))
.setCancelable(true)
.setNegativeButton(android.R.string.cancel, null)
.setTitle(R.string.translations)
.setItems(viewModel.branches.value)
.create()
.also { it.show() }
} }
private fun openReader(isIncognitoMode: Boolean) { private fun openReader(isIncognitoMode: Boolean) {

@ -19,7 +19,7 @@ import org.koitharu.kotatsu.core.os.AppShortcutManager
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.util.ShareHelper import org.koitharu.kotatsu.core.util.ShareHelper
import org.koitharu.kotatsu.download.ui.dialog.DownloadOption import org.koitharu.kotatsu.download.ui.dialog.DownloadOption
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesSheet import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteSheet
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.scrobbling.common.ui.selector.ScrobblingSelectorSheet import org.koitharu.kotatsu.scrobbling.common.ui.selector.ScrobblingSelectorSheet
import org.koitharu.kotatsu.search.ui.multi.MultiSearchActivity import org.koitharu.kotatsu.search.ui.multi.MultiSearchActivity
@ -62,7 +62,7 @@ class DetailsMenuProvider(
R.id.action_favourite -> { R.id.action_favourite -> {
viewModel.manga.value?.let { viewModel.manga.value?.let {
FavouriteCategoriesSheet.show(activity.supportFragmentManager, it) FavouriteSheet.show(activity.supportFragmentManager, it)
} }
} }

@ -3,7 +3,7 @@ package org.koitharu.kotatsu.explore.ui.model
import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
class RecommendationsItem( data class RecommendationsItem(
val manga: Manga val manga: Manga
) : ListModel { ) : ListModel {
@ -12,18 +12,4 @@ class RecommendationsItem(
override fun areItemsTheSame(other: ListModel): Boolean { override fun areItemsTheSame(other: ListModel): Boolean {
return other is RecommendationsItem return other is RecommendationsItem
} }
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as RecommendationsItem
return manga == other.manga
}
override fun hashCode(): Int {
return 31 * manga.hashCode()
}
} }

@ -23,7 +23,7 @@ import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
@AndroidEntryPoint @AndroidEntryPoint
class FavouriteCategoriesSheet : class FavouriteSheet :
BaseAdaptiveSheet<SheetFavoriteCategoriesBinding>(), BaseAdaptiveSheet<SheetFavoriteCategoriesBinding>(),
OnListItemClickListener<MangaCategoryItem> { OnListItemClickListener<MangaCategoryItem> {
@ -53,7 +53,7 @@ class FavouriteCategoriesSheet :
} }
override fun onItemClick(item: MangaCategoryItem, view: View) { override fun onItemClick(item: MangaCategoryItem, view: View) {
viewModel.setChecked(item.id, !item.isChecked) viewModel.setChecked(item.category.id, !item.isChecked)
} }
private fun onContentChanged(categories: List<ListModel>) { private fun onContentChanged(categories: List<ListModel>) {
@ -72,7 +72,7 @@ class FavouriteCategoriesSheet :
fun show(fm: FragmentManager, manga: Manga) = Companion.show(fm, listOf(manga)) fun show(fm: FragmentManager, manga: Manga) = Companion.show(fm, listOf(manga))
fun show(fm: FragmentManager, manga: Collection<Manga>) = fun show(fm: FragmentManager, manga: Collection<Manga>) =
FavouriteCategoriesSheet().withArgs(1) { FavouriteSheet().withArgs(1) {
putParcelableArrayList( putParcelableArrayList(
KEY_MANGA_LIST, KEY_MANGA_LIST,
manga.mapTo(ArrayList(manga.size)) { manga.mapTo(ArrayList(manga.size)) {

@ -14,7 +14,7 @@ import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.BaseViewModel
import org.koitharu.kotatsu.core.util.ext.require import org.koitharu.kotatsu.core.util.ext.require
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesSheet.Companion.KEY_MANGA_LIST import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteSheet.Companion.KEY_MANGA_LIST
import org.koitharu.kotatsu.favourites.ui.categories.select.model.CategoriesHeaderItem import org.koitharu.kotatsu.favourites.ui.categories.select.model.CategoriesHeaderItem
import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem
import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.ListModel
@ -37,8 +37,7 @@ class MangaCategoriesViewModel @Inject constructor(
add(header) add(header)
all.mapTo(this) { all.mapTo(this) {
MangaCategoryItem( MangaCategoryItem(
id = it.id, category = it,
name = it.title,
isChecked = it.id in checked, isChecked = it.id in checked,
) )
} }

@ -1,17 +1,18 @@
package org.koitharu.kotatsu.favourites.ui.categories.select.adapter package org.koitharu.kotatsu.favourites.ui.categories.select.adapter
import androidx.core.view.isVisible
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.util.ext.setChecked import org.koitharu.kotatsu.core.util.ext.setChecked
import org.koitharu.kotatsu.databinding.ItemCheckableNewBinding import org.koitharu.kotatsu.databinding.ItemCategoryCheckableBinding
import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.ListModel
fun mangaCategoryAD( fun mangaCategoryAD(
clickListener: OnListItemClickListener<MangaCategoryItem>, clickListener: OnListItemClickListener<MangaCategoryItem>,
) = adapterDelegateViewBinding<MangaCategoryItem, ListModel, ItemCheckableNewBinding>( ) = adapterDelegateViewBinding<MangaCategoryItem, ListModel, ItemCategoryCheckableBinding>(
{ inflater, parent -> ItemCheckableNewBinding.inflate(inflater, parent, false) }, { inflater, parent -> ItemCategoryCheckableBinding.inflate(inflater, parent, false) },
) { ) {
itemView.setOnClickListener { itemView.setOnClickListener {
@ -19,9 +20,9 @@ fun mangaCategoryAD(
} }
bind { payloads -> bind { payloads ->
with(binding.root) { binding.checkableImageView.setChecked(item.isChecked, ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED !in payloads)
text = item.name binding.textViewTitle.text = item.category.title
setChecked(item.isChecked, ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED in payloads) binding.imageViewTracker.isVisible = item.category.isTrackingEnabled
} binding.imageViewVisible.isVisible = item.category.isVisibleInLibrary
} }
} }

@ -1,16 +1,16 @@
package org.koitharu.kotatsu.favourites.ui.categories.select.model package org.koitharu.kotatsu.favourites.ui.categories.select.model
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.ListModel
class MangaCategoryItem( data class MangaCategoryItem(
val id: Long, val category: FavouriteCategory,
val name: String,
val isChecked: Boolean, val isChecked: Boolean,
) : ListModel { ) : ListModel {
override fun areItemsTheSame(other: ListModel): Boolean { override fun areItemsTheSame(other: ListModel): Boolean {
return other is MangaCategoryItem && other.id == id return other is MangaCategoryItem && other.category.id == category.id
} }
override fun getChangePayload(previousState: ListModel): Any? { override fun getChangePayload(previousState: ListModel): Any? {
@ -20,22 +20,4 @@ class MangaCategoryItem(
super.getChangePayload(previousState) super.getChangePayload(previousState)
} }
} }
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as MangaCategoryItem
if (id != other.id) return false
if (name != other.name) return false
return isChecked == other.isChecked
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + name.hashCode()
result = 31 * result + isChecked.hashCode()
return result
}
} }

@ -41,7 +41,7 @@ import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope
import org.koitharu.kotatsu.databinding.FragmentListBinding import org.koitharu.kotatsu.databinding.FragmentListBinding
import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.download.ui.worker.DownloadStartedObserver import org.koitharu.kotatsu.download.ui.worker.DownloadStartedObserver
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesSheet import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteSheet
import org.koitharu.kotatsu.list.ui.adapter.ListItemType import org.koitharu.kotatsu.list.ui.adapter.ListItemType
import org.koitharu.kotatsu.list.ui.adapter.MangaListAdapter import org.koitharu.kotatsu.list.ui.adapter.MangaListAdapter
import org.koitharu.kotatsu.list.ui.adapter.MangaListListener import org.koitharu.kotatsu.list.ui.adapter.MangaListListener
@ -283,7 +283,7 @@ abstract class MangaListFragment :
} }
R.id.action_favourite -> { R.id.action_favourite -> {
FavouriteCategoriesSheet.show(childFragmentManager, selectedItems) FavouriteSheet.show(childFragmentManager, selectedItems)
mode.finish() mode.finish()
true true
} }

@ -27,7 +27,7 @@ import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf
import org.koitharu.kotatsu.databinding.ActivitySearchMultiBinding import org.koitharu.kotatsu.databinding.ActivitySearchMultiBinding
import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.download.ui.worker.DownloadStartedObserver import org.koitharu.kotatsu.download.ui.worker.DownloadStartedObserver
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesSheet import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteSheet
import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration
import org.koitharu.kotatsu.list.ui.adapter.MangaListListener import org.koitharu.kotatsu.list.ui.adapter.MangaListListener
import org.koitharu.kotatsu.list.ui.model.ListHeader import org.koitharu.kotatsu.list.ui.model.ListHeader
@ -159,7 +159,7 @@ class MultiSearchActivity :
} }
R.id.action_favourite -> { R.id.action_favourite -> {
FavouriteCategoriesSheet.show(supportFragmentManager, collectSelectedItems()) FavouriteSheet.show(supportFragmentManager, collectSelectedItems())
mode.finish() mode.finish()
true true
} }

@ -2,7 +2,7 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:tint="#000000" android:tint="?colorControlNormal"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path <path

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="?listPreferredItemHeightSmall"
android:paddingStart="?android:listPreferredItemPaddingStart"
android:paddingEnd="?android:listPreferredItemPaddingEnd"
tools:ignore="RtlSymmetry">
<org.koitharu.kotatsu.core.ui.widgets.CheckableImageView
android:id="@+id/checkableImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="?android:listChoiceIndicatorMultiple" />
<TextView
android:id="@+id/textView_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="?listPreferredItemPaddingStart"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?attr/textAppearanceBodyMedium"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/imageView_tracker"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="@id/checkableImageView"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/lorem[1]" />
<ImageView
android:id="@+id/imageView_tracker"
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_marginStart="4dp"
android:contentDescription="@string/check_for_new_chapters"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/imageView_visible"
app:layout_constraintStart_toEndOf="@id/textView_title"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_notification" />
<ImageView
android:id="@+id/imageView_visible"
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_marginStart="4dp"
android:contentDescription="@string/show_on_shelf"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/imageView_tracker"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_eye" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -18,9 +18,9 @@
android:textAppearance="@style/TextAppearance.Kotatsu.SectionHeader" android:textAppearance="@style/TextAppearance.Kotatsu.SectionHeader"
tools:text="@tools:sample/lorem[2]" /> tools:text="@tools:sample/lorem[2]" />
<Button <com.google.android.material.button.MaterialButton
android:id="@+id/button_more" android:id="@+id/button_more"
style="@style/Widget.Kotatsu.Button.More" style="@style/Widget.Kotatsu.Button.More.Small"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="invisible" android:visibility="invisible"

@ -119,6 +119,12 @@
<item name="android:minWidth">48dp</item> <item name="android:minWidth">48dp</item>
</style> </style>
<style name="Widget.Kotatsu.Button.More.Small">
<item name="android:insetTop">0dp</item>
<item name="android:insetBottom">0dp</item>
<item name="android:minHeight">42dp</item>
</style>
<style name="Widget.Kotatsu.ToggleButton" parent="Widget.Material3.Button.OutlinedButton"> <style name="Widget.Kotatsu.ToggleButton" parent="Widget.Material3.Button.OutlinedButton">
<item name="android:checkable">true</item> <item name="android:checkable">true</item>
<item name="android:textAlignment">textStart</item> <item name="android:textAlignment">textStart</item>

Loading…
Cancel
Save