mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 13:57:57 +01:00 
			
		
		
		
	Move chapter filter/sort/display settings into a sheet
This commit is contained in:
		| @@ -24,10 +24,6 @@ interface Manga : SManga { | ||||
|         setFlags(order, SORT_MASK) | ||||
|     } | ||||
|  | ||||
|     private fun setFlags(flag: Int, mask: Int) { | ||||
|         chapter_flags = chapter_flags and mask.inv() or (flag and mask) | ||||
|     } | ||||
|  | ||||
|     fun sortDescending(): Boolean { | ||||
|         return chapter_flags and SORT_MASK == SORT_DESC | ||||
|     } | ||||
| @@ -36,6 +32,10 @@ interface Manga : SManga { | ||||
|         return genre?.split(", ")?.map { it.trim() } | ||||
|     } | ||||
|  | ||||
|     private fun setFlags(flag: Int, mask: Int) { | ||||
|         chapter_flags = chapter_flags and mask.inv() or (flag and mask) | ||||
|     } | ||||
|  | ||||
|     // Used to display the chapter's title one way or another | ||||
|     var displayMode: Int | ||||
|         get() = chapter_flags and DISPLAY_MASK | ||||
|   | ||||
| @@ -13,7 +13,6 @@ import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import androidx.appcompat.app.AppCompatActivity | ||||
| import androidx.appcompat.view.ActionMode | ||||
| import androidx.core.graphics.drawable.DrawableCompat | ||||
| import androidx.recyclerview.widget.ConcatAdapter | ||||
| import androidx.recyclerview.widget.DividerItemDecoration | ||||
| import androidx.recyclerview.widget.LinearLayoutManager | ||||
| @@ -51,6 +50,7 @@ import eu.kanade.tachiyomi.ui.main.offsetAppbarHeight | ||||
| import eu.kanade.tachiyomi.ui.manga.chapter.ChapterHolder | ||||
| import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem | ||||
| import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersAdapter | ||||
| import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersSettingsSheet | ||||
| import eu.kanade.tachiyomi.ui.manga.chapter.DeleteChaptersDialog | ||||
| import eu.kanade.tachiyomi.ui.manga.chapter.DownloadCustomChaptersDialog | ||||
| import eu.kanade.tachiyomi.ui.manga.chapter.MangaChaptersHeaderAdapter | ||||
| @@ -61,7 +61,6 @@ import eu.kanade.tachiyomi.ui.recent.history.HistoryController | ||||
| import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController | ||||
| import eu.kanade.tachiyomi.ui.webview.WebViewActivity | ||||
| import eu.kanade.tachiyomi.util.hasCustomCover | ||||
| import eu.kanade.tachiyomi.util.system.getResourceColor | ||||
| import eu.kanade.tachiyomi.util.system.toast | ||||
| import eu.kanade.tachiyomi.util.view.getCoordinates | ||||
| import eu.kanade.tachiyomi.util.view.gone | ||||
| @@ -124,6 +123,11 @@ class MangaController : | ||||
|     private var chaptersHeaderAdapter: MangaChaptersHeaderAdapter? = null | ||||
|     private var chaptersAdapter: ChaptersAdapter? = null | ||||
|  | ||||
|     /** | ||||
|      * Sheet containing filter/sort/display items. | ||||
|      */ | ||||
|     private var settingsSheet: ChaptersSettingsSheet? = null | ||||
|  | ||||
|     private var actionFabScrollListener: RecyclerView.OnScrollListener? = null | ||||
|  | ||||
|     /** | ||||
| @@ -178,7 +182,7 @@ class MangaController : | ||||
|  | ||||
|         // Init RecyclerView and adapter | ||||
|         mangaInfoAdapter = MangaInfoHeaderAdapter(this, fromSource) | ||||
|         chaptersHeaderAdapter = MangaChaptersHeaderAdapter() | ||||
|         chaptersHeaderAdapter = MangaChaptersHeaderAdapter(this) | ||||
|         chaptersAdapter = ChaptersAdapter(this, view.context) | ||||
|  | ||||
|         binding.recycler.adapter = ConcatAdapter(mangaInfoAdapter, chaptersHeaderAdapter, chaptersAdapter) | ||||
| @@ -205,6 +209,19 @@ class MangaController : | ||||
|             .launchIn(scope) | ||||
|  | ||||
|         binding.actionToolbar.offsetAppbarHeight(activity!!) | ||||
|  | ||||
|         settingsSheet = ChaptersSettingsSheet(activity!!, presenter) { group -> | ||||
|             if (group is ChaptersSettingsSheet.Filter.FilterGroup) { | ||||
|                 updateFilterIconState() | ||||
|                 chaptersAdapter?.notifyDataSetChanged() | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         updateFilterIconState() | ||||
|     } | ||||
|  | ||||
|     private fun updateFilterIconState() { | ||||
|         chaptersHeaderAdapter?.setHasActiveFilters(settingsSheet?.filters?.hasActiveFilters() == true) | ||||
|     } | ||||
|  | ||||
|     override fun configureFab(fab: ExtendedFloatingActionButton) { | ||||
| @@ -249,6 +266,7 @@ class MangaController : | ||||
|         mangaInfoAdapter = null | ||||
|         chaptersHeaderAdapter = null | ||||
|         chaptersAdapter = null | ||||
|         settingsSheet = null | ||||
|         super.onDestroyView(view) | ||||
|     } | ||||
|  | ||||
| @@ -266,50 +284,10 @@ class MangaController : | ||||
|     } | ||||
|  | ||||
|     override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { | ||||
|         inflater.inflate(R.menu.chapters, menu) | ||||
|         inflater.inflate(R.menu.manga, menu) | ||||
|     } | ||||
|  | ||||
|     override fun onPrepareOptionsMenu(menu: Menu) { | ||||
|         // Initialize menu items. | ||||
|         val menuFilterRead = menu.findItem(R.id.action_filter_read) ?: return | ||||
|         val menuFilterUnread = menu.findItem(R.id.action_filter_unread) | ||||
|         val menuFilterDownloaded = menu.findItem(R.id.action_filter_downloaded) | ||||
|         val menuFilterBookmarked = menu.findItem(R.id.action_filter_bookmarked) | ||||
|         val menuFilterEmpty = menu.findItem(R.id.action_filter_empty) | ||||
|  | ||||
|         // Set correct checkbox values. | ||||
|         menuFilterRead.isChecked = presenter.onlyRead() | ||||
|         menuFilterUnread.isChecked = presenter.onlyUnread() | ||||
|         menuFilterDownloaded.isChecked = presenter.onlyDownloaded() | ||||
|         menuFilterDownloaded.isEnabled = !presenter.forceDownloaded() | ||||
|         menuFilterBookmarked.isChecked = presenter.onlyBookmarked() | ||||
|  | ||||
|         val filterSet = presenter.onlyRead() || presenter.onlyUnread() || presenter.onlyDownloaded() || presenter.onlyBookmarked() | ||||
|         if (filterSet) { | ||||
|             val filterColor = activity!!.getResourceColor(R.attr.colorFilterActive) | ||||
|             DrawableCompat.setTint(menu.findItem(R.id.action_filter).icon, filterColor) | ||||
|         } | ||||
|  | ||||
|         // Only show remove filter option if there's a filter set. | ||||
|         menuFilterEmpty.isVisible = filterSet | ||||
|  | ||||
|         // Display mode submenu | ||||
|         if (presenter.manga.displayMode == Manga.DISPLAY_NAME) { | ||||
|             menu.findItem(R.id.display_title).isChecked = true | ||||
|         } else { | ||||
|             menu.findItem(R.id.display_chapter_number).isChecked = true | ||||
|         } | ||||
|  | ||||
|         // Sorting mode submenu | ||||
|         val sortingItem = when (presenter.manga.sorting) { | ||||
|             Manga.SORTING_SOURCE -> R.id.sort_by_source | ||||
|             Manga.SORTING_NUMBER -> R.id.sort_by_number | ||||
|             Manga.SORTING_UPLOAD_DATE -> R.id.sort_by_upload_date | ||||
|             else -> throw NotImplementedError("Unimplemented sorting method") | ||||
|         } | ||||
|         menu.findItem(sortingItem).isChecked = true | ||||
|         menu.findItem(R.id.action_sort_descending).isChecked = presenter.manga.sortDescending() | ||||
|  | ||||
|         // Hide download options for local manga | ||||
|         menu.findItem(R.id.download_group).isVisible = !isLocalSource | ||||
|  | ||||
| @@ -321,61 +299,10 @@ class MangaController : | ||||
|  | ||||
|     override fun onOptionsItemSelected(item: MenuItem): Boolean { | ||||
|         when (item.itemId) { | ||||
|             R.id.display_title -> { | ||||
|                 item.isChecked = true | ||||
|                 setDisplayMode(Manga.DISPLAY_NAME) | ||||
|             } | ||||
|             R.id.display_chapter_number -> { | ||||
|                 item.isChecked = true | ||||
|                 setDisplayMode(Manga.DISPLAY_NUMBER) | ||||
|             } | ||||
|  | ||||
|             R.id.sort_by_source -> { | ||||
|                 item.isChecked = true | ||||
|                 presenter.setSorting(Manga.SORTING_SOURCE) | ||||
|             } | ||||
|             R.id.sort_by_number -> { | ||||
|                 item.isChecked = true | ||||
|                 presenter.setSorting(Manga.SORTING_NUMBER) | ||||
|             } | ||||
|             R.id.sort_by_upload_date -> { | ||||
|                 item.isChecked = true | ||||
|                 presenter.setSorting(Manga.SORTING_UPLOAD_DATE) | ||||
|             } | ||||
|             R.id.action_sort_descending -> { | ||||
|                 presenter.reverseSortOrder() | ||||
|                 activity?.invalidateOptionsMenu() | ||||
|             } | ||||
|  | ||||
|             R.id.download_next, R.id.download_next_5, R.id.download_next_10, | ||||
|             R.id.download_custom, R.id.download_unread, R.id.download_all | ||||
|             -> downloadChapters(item.itemId) | ||||
|  | ||||
|             R.id.action_filter_unread -> { | ||||
|                 item.isChecked = !item.isChecked | ||||
|                 presenter.setUnreadFilter(item.isChecked) | ||||
|                 activity?.invalidateOptionsMenu() | ||||
|             } | ||||
|             R.id.action_filter_read -> { | ||||
|                 item.isChecked = !item.isChecked | ||||
|                 presenter.setReadFilter(item.isChecked) | ||||
|                 activity?.invalidateOptionsMenu() | ||||
|             } | ||||
|             R.id.action_filter_downloaded -> { | ||||
|                 item.isChecked = !item.isChecked | ||||
|                 presenter.setDownloadedFilter(item.isChecked) | ||||
|                 activity?.invalidateOptionsMenu() | ||||
|             } | ||||
|             R.id.action_filter_bookmarked -> { | ||||
|                 item.isChecked = !item.isChecked | ||||
|                 presenter.setBookmarkedFilter(item.isChecked) | ||||
|                 activity?.invalidateOptionsMenu() | ||||
|             } | ||||
|             R.id.action_filter_empty -> { | ||||
|                 presenter.removeFilters() | ||||
|                 activity?.invalidateOptionsMenu() | ||||
|             } | ||||
|  | ||||
|             R.id.action_edit_categories -> onCategoriesClick() | ||||
|             R.id.action_edit_cover -> handleChangeCover() | ||||
|             R.id.action_migrate -> migrateManga() | ||||
| @@ -756,6 +683,10 @@ class MangaController : | ||||
|         chaptersAdapter?.notifyDataSetChanged() | ||||
|     } | ||||
|  | ||||
|     fun showSettingsSheet() { | ||||
|         settingsSheet?.show() | ||||
|     } | ||||
|  | ||||
|     // SELECTIONS & ACTION MODE | ||||
|  | ||||
|     private fun toggleSelection(position: Int) { | ||||
| @@ -958,11 +889,6 @@ class MangaController : | ||||
|  | ||||
|     // OVERFLOW MENU DIALOGS | ||||
|  | ||||
|     private fun setDisplayMode(id: Int) { | ||||
|         presenter.setDisplayMode(id) | ||||
|         chaptersAdapter?.notifyDataSetChanged() | ||||
|     } | ||||
|  | ||||
|     private fun getUnreadChaptersSorted() = presenter.chapters | ||||
|         .filter { !it.read && it.status == Download.NOT_DOWNLOADED } | ||||
|         .distinctBy { it.name } | ||||
|   | ||||
| @@ -531,17 +531,6 @@ class MangaPresenter( | ||||
|         refreshChapters() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Removes all filters and requests an UI update. | ||||
|      */ | ||||
|     fun removeFilters() { | ||||
|         manga.readFilter = Manga.SHOW_ALL | ||||
|         manga.downloadedFilter = Manga.SHOW_ALL | ||||
|         manga.bookmarkedFilter = Manga.SHOW_ALL | ||||
|         db.updateFlags(manga).executeAsBlocking() | ||||
|         refreshChapters() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the active display mode. | ||||
|      * @param mode the mode to set. | ||||
|   | ||||
| @@ -0,0 +1,239 @@ | ||||
| package eu.kanade.tachiyomi.ui.manga.chapter | ||||
|  | ||||
| import android.app.Activity | ||||
| import android.content.Context | ||||
| import android.util.AttributeSet | ||||
| import android.view.View | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.ui.manga.MangaPresenter | ||||
| import eu.kanade.tachiyomi.widget.ExtendedNavigationView | ||||
| import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog | ||||
|  | ||||
| class ChaptersSettingsSheet( | ||||
|     activity: Activity, | ||||
|     private val presenter: MangaPresenter, | ||||
|     onGroupClickListener: (ExtendedNavigationView.Group) -> Unit | ||||
| ) : TabbedBottomSheetDialog(activity) { | ||||
|  | ||||
|     val filters: Filter | ||||
|     private val sort: Sort | ||||
|     private val display: Display | ||||
|  | ||||
|     init { | ||||
|         filters = Filter(activity) | ||||
|         filters.onGroupClicked = onGroupClickListener | ||||
|  | ||||
|         sort = Sort(activity) | ||||
|         sort.onGroupClicked = onGroupClickListener | ||||
|  | ||||
|         display = Display(activity) | ||||
|         display.onGroupClicked = onGroupClickListener | ||||
|     } | ||||
|  | ||||
|     override fun getTabViews(): List<View> = listOf( | ||||
|         filters, | ||||
|         sort, | ||||
|         display | ||||
|     ) | ||||
|  | ||||
|     override fun getTabTitles(): List<Int> = listOf( | ||||
|         R.string.action_filter, | ||||
|         R.string.action_sort, | ||||
|         R.string.action_display | ||||
|     ) | ||||
|  | ||||
|     /** | ||||
|      * Filters group (unread, downloaded, ...). | ||||
|      */ | ||||
|     inner class Filter @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : | ||||
|         Settings(context, attrs) { | ||||
|  | ||||
|         private val filterGroup = FilterGroup() | ||||
|  | ||||
|         init { | ||||
|             setGroups(listOf(filterGroup)) | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * Returns true if there's at least one filter from [FilterGroup] active. | ||||
|          */ | ||||
|         fun hasActiveFilters(): Boolean { | ||||
|             return filterGroup.items.any { it.checked } | ||||
|         } | ||||
|  | ||||
|         inner class FilterGroup : Group { | ||||
|  | ||||
|             private val read = Item.CheckboxGroup(R.string.action_filter_read, this) | ||||
|             private val unread = Item.CheckboxGroup(R.string.action_filter_unread, this) | ||||
|             private val downloaded = Item.CheckboxGroup(R.string.action_filter_downloaded, this) | ||||
|             private val bookmarked = Item.CheckboxGroup(R.string.action_filter_bookmarked, this) | ||||
|  | ||||
|             override val header = null | ||||
|             override val items = listOf(read, unread, downloaded, bookmarked) | ||||
|             override val footer = null | ||||
|  | ||||
|             override fun initModels() { | ||||
|                 read.checked = presenter.onlyRead() | ||||
|                 unread.checked = presenter.onlyUnread() | ||||
|                 downloaded.checked = presenter.onlyDownloaded() | ||||
|                 downloaded.enabled = !presenter.forceDownloaded() | ||||
|                 bookmarked.checked = presenter.onlyBookmarked() | ||||
|             } | ||||
|  | ||||
|             override fun onItemClicked(item: Item) { | ||||
|                 item as Item.CheckboxGroup | ||||
|                 item.checked = !item.checked | ||||
|                 when (item) { | ||||
|                     read -> presenter.setReadFilter(item.checked) | ||||
|                     unread -> presenter.setUnreadFilter(item.checked) | ||||
|                     downloaded -> presenter.setDownloadedFilter(item.checked) | ||||
|                     bookmarked -> presenter.setBookmarkedFilter(item.checked) | ||||
|                 } | ||||
|  | ||||
|                 initModels() | ||||
|                 item.group.items.forEach { adapter.notifyItemChanged(it) } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sorting group (alphabetically, by last read, ...) and ascending or descending. | ||||
|      */ | ||||
|     inner class Sort @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : | ||||
|         Settings(context, attrs) { | ||||
|  | ||||
|         init { | ||||
|             setGroups(listOf(SortGroup())) | ||||
|         } | ||||
|  | ||||
|         inner class SortGroup : Group { | ||||
|  | ||||
|             private val source = Item.MultiSort(R.string.sort_by_source, this) | ||||
|             private val chapterNum = Item.MultiSort(R.string.sort_by_number, this) | ||||
|             private val uploadDate = Item.MultiSort(R.string.sort_by_upload_date, this) | ||||
|  | ||||
|             override val header = null | ||||
|             override val items = listOf(source, uploadDate, chapterNum) | ||||
|             override val footer = null | ||||
|  | ||||
|             override fun initModels() { | ||||
|                 val sorting = presenter.manga.sorting | ||||
|                 val order = if (presenter.manga.sortDescending()) { | ||||
|                     Item.MultiSort.SORT_DESC | ||||
|                 } else { | ||||
|                     Item.MultiSort.SORT_ASC | ||||
|                 } | ||||
|  | ||||
|                 source.state = | ||||
|                     if (sorting == Manga.SORTING_SOURCE) order else Item.MultiSort.SORT_NONE | ||||
|                 chapterNum.state = | ||||
|                     if (sorting == Manga.SORTING_NUMBER) order else Item.MultiSort.SORT_NONE | ||||
|                 uploadDate.state = | ||||
|                     if (sorting == Manga.SORTING_UPLOAD_DATE) order else Item.MultiSort.SORT_NONE | ||||
|             } | ||||
|  | ||||
|             override fun onItemClicked(item: Item) { | ||||
|                 item as Item.MultiStateGroup | ||||
|                 val prevState = item.state | ||||
|  | ||||
|                 item.group.items.forEach { | ||||
|                     (it as Item.MultiStateGroup).state = | ||||
|                         Item.MultiSort.SORT_NONE | ||||
|                 } | ||||
|                 item.state = when (prevState) { | ||||
|                     Item.MultiSort.SORT_NONE -> Item.MultiSort.SORT_ASC | ||||
|                     Item.MultiSort.SORT_ASC -> Item.MultiSort.SORT_DESC | ||||
|                     Item.MultiSort.SORT_DESC -> Item.MultiSort.SORT_ASC | ||||
|                     else -> throw Exception("Unknown state") | ||||
|                 } | ||||
|  | ||||
|                 when (item) { | ||||
|                     source -> presenter.setSorting(Manga.SORTING_SOURCE) | ||||
|                     chapterNum -> presenter.setSorting(Manga.SORTING_NUMBER) | ||||
|                     uploadDate -> presenter.setSorting(Manga.SORTING_UPLOAD_DATE) | ||||
|                     else -> throw Exception("Unknown sorting") | ||||
|                 } | ||||
|  | ||||
|                 presenter.reverseSortOrder() | ||||
|  | ||||
|                 item.group.items.forEach { adapter.notifyItemChanged(it) } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Display group, to show the library as a list or a grid. | ||||
|      */ | ||||
|     inner class Display @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : | ||||
|         Settings(context, attrs) { | ||||
|  | ||||
|         init { | ||||
|             setGroups(listOf(DisplayGroup())) | ||||
|         } | ||||
|  | ||||
|         inner class DisplayGroup : Group { | ||||
|  | ||||
|             private val displayTitle = Item.Radio(R.string.show_title, this) | ||||
|             private val displayChapterNum = Item.Radio(R.string.show_chapter_number, this) | ||||
|  | ||||
|             override val header = null | ||||
|             override val items = listOf(displayTitle, displayChapterNum) | ||||
|             override val footer = null | ||||
|  | ||||
|             override fun initModels() { | ||||
|                 val mode = presenter.manga.displayMode | ||||
|                 displayTitle.checked = mode == Manga.DISPLAY_NAME | ||||
|                 displayChapterNum.checked = mode == Manga.DISPLAY_NUMBER | ||||
|             } | ||||
|  | ||||
|             override fun onItemClicked(item: Item) { | ||||
|                 item as Item.Radio | ||||
|                 if (item.checked) return | ||||
|  | ||||
|                 item.group.items.forEach { (it as Item.Radio).checked = false } | ||||
|                 item.checked = true | ||||
|  | ||||
|                 when (item) { | ||||
|                     displayTitle -> presenter.setDisplayMode(Manga.DISPLAY_NAME) | ||||
|                     displayChapterNum -> presenter.setDisplayMode(Manga.DISPLAY_NUMBER) | ||||
|                     else -> throw NotImplementedError("Unknown display mode") | ||||
|                 } | ||||
|  | ||||
|                 item.group.items.forEach { adapter.notifyItemChanged(it) } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     open inner class Settings(context: Context, attrs: AttributeSet?) : | ||||
|         ExtendedNavigationView(context, attrs) { | ||||
|  | ||||
|         lateinit var adapter: Adapter | ||||
|  | ||||
|         /** | ||||
|          * Click listener to notify the parent fragment when an item from a group is clicked. | ||||
|          */ | ||||
|         var onGroupClicked: (Group) -> Unit = {} | ||||
|  | ||||
|         fun setGroups(groups: List<Group>) { | ||||
|             adapter = Adapter(groups.map { it.createItems() }.flatten()) | ||||
|             recycler.adapter = adapter | ||||
|  | ||||
|             groups.forEach { it.initModels() } | ||||
|             addView(recycler) | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * Adapter of the recycler view. | ||||
|          */ | ||||
|         inner class Adapter(items: List<Item>) : ExtendedNavigationView.Adapter(items) { | ||||
|  | ||||
|             override fun onItemClicked(item: Item) { | ||||
|                 if (item is GroupedItem) { | ||||
|                     item.group.onItemClicked(item) | ||||
|                     onGroupClicked(item.group) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -3,17 +3,28 @@ package eu.kanade.tachiyomi.ui.manga.chapter | ||||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import androidx.core.graphics.drawable.DrawableCompat | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.databinding.MangaChaptersHeaderBinding | ||||
| import eu.kanade.tachiyomi.ui.manga.MangaController | ||||
| import eu.kanade.tachiyomi.util.system.getResourceColor | ||||
| import kotlinx.coroutines.CoroutineScope | ||||
| import kotlinx.coroutines.Dispatchers | ||||
| import kotlinx.coroutines.ExperimentalCoroutinesApi | ||||
| import kotlinx.coroutines.Job | ||||
| import kotlinx.coroutines.flow.launchIn | ||||
| import kotlinx.coroutines.flow.merge | ||||
| import kotlinx.coroutines.flow.onEach | ||||
| import reactivecircus.flowbinding.android.view.clicks | ||||
|  | ||||
| class MangaChaptersHeaderAdapter : | ||||
| class MangaChaptersHeaderAdapter( | ||||
|     private val controller: MangaController | ||||
| ) : | ||||
|     RecyclerView.Adapter<MangaChaptersHeaderAdapter.HeaderViewHolder>() { | ||||
|  | ||||
|     private var numChapters: Int? = null | ||||
|     private var hasActiveFilters: Boolean = false | ||||
|  | ||||
|     private val scope = CoroutineScope(Job() + Dispatchers.Main) | ||||
|     private lateinit var binding: MangaChaptersHeaderBinding | ||||
| @@ -35,13 +46,31 @@ class MangaChaptersHeaderAdapter : | ||||
|         notifyDataSetChanged() | ||||
|     } | ||||
|  | ||||
|     fun setHasActiveFilters(hasActiveFilters: Boolean) { | ||||
|         this.hasActiveFilters = hasActiveFilters | ||||
|  | ||||
|         notifyDataSetChanged() | ||||
|     } | ||||
|  | ||||
|     inner class HeaderViewHolder(private val view: View) : RecyclerView.ViewHolder(view) { | ||||
|         @ExperimentalCoroutinesApi | ||||
|         fun bind() { | ||||
|             binding.chaptersLabel.text = if (numChapters == null) { | ||||
|                 view.context.getString(R.string.chapters) | ||||
|             } else { | ||||
|                 view.context.resources.getQuantityString(R.plurals.manga_num_chapters, numChapters!!, numChapters) | ||||
|             } | ||||
|  | ||||
|             val filterColor = if (hasActiveFilters) { | ||||
|                 view.context.getResourceColor(R.attr.colorFilterActive) | ||||
|             } else { | ||||
|                 view.context.getResourceColor(R.attr.colorOnPrimary) | ||||
|             } | ||||
|             DrawableCompat.setTint(binding.btnChaptersFilter.icon, filterColor) | ||||
|  | ||||
|             merge(view.clicks(), binding.btnChaptersFilter.clicks()) | ||||
|                 .onEach { controller.showSettingsSheet() } | ||||
|                 .launchIn(scope) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,20 +1,38 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| <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:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|     android:background="?attr/selectableItemBackground" | ||||
|     android:paddingStart="16dp" | ||||
|     android:paddingTop="16dp" | ||||
|     android:paddingTop="4dp" | ||||
|     android:paddingEnd="16dp" | ||||
|     android:paddingBottom="8dp" | ||||
|     android:paddingBottom="4dp" | ||||
|     tools:context=".ui.browse.source.browse.BrowseSourceController"> | ||||
|  | ||||
|     <TextView | ||||
|         android:id="@+id/chapters_label" | ||||
|         style="@style/TextAppearance.Regular.SubHeading" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:text="@string/chapters" | ||||
|         android:textIsSelectable="false" /> | ||||
|         android:textIsSelectable="false" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toStartOf="@+id/btn_chapters_filter" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toTopOf="parent" /> | ||||
|  | ||||
| </RelativeLayout> | ||||
|     <com.google.android.material.button.MaterialButton | ||||
|         android:id="@+id/btn_chapters_filter" | ||||
|         style="@style/Theme.Widget.Button.Icon" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:text="@string/action_filter" | ||||
|         app:icon="@drawable/ic_filter_list_24dp" | ||||
|         app:iconTint="?attr/colorOnPrimary" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintTop_toTopOf="parent" /> | ||||
|  | ||||
| </androidx.constraintlayout.widget.ConstraintLayout> | ||||
|   | ||||
| @@ -1,114 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/action_filter" | ||||
|         android:icon="@drawable/ic_filter_list_24dp" | ||||
|         android:title="@string/action_filter" | ||||
|         app:iconTint="?attr/colorOnPrimary" | ||||
|         app:showAsAction="ifRoom"> | ||||
|         <menu> | ||||
|             <item | ||||
|                 android:id="@+id/action_filter_read" | ||||
|                 android:checkable="true" | ||||
|                 android:title="@string/action_filter_read" /> | ||||
|             <item | ||||
|                 android:id="@+id/action_filter_unread" | ||||
|                 android:checkable="true" | ||||
|                 android:title="@string/action_filter_unread" /> | ||||
|             <item | ||||
|                 android:id="@+id/action_filter_downloaded" | ||||
|                 android:checkable="true" | ||||
|                 android:title="@string/action_filter_downloaded" /> | ||||
|             <item | ||||
|                 android:id="@+id/action_filter_bookmarked" | ||||
|                 android:checkable="true" | ||||
|                 android:title="@string/action_filter_bookmarked" /> | ||||
|             <item | ||||
|                 android:id="@+id/action_filter_empty" | ||||
|                 android:title="@string/action_filter_empty" /> | ||||
|         </menu> | ||||
|     </item> | ||||
|  | ||||
|     <item | ||||
|         android:icon="@drawable/ic_sort_24dp" | ||||
|         android:title="@string/sorting_mode" | ||||
|         app:iconTint="?attr/colorOnPrimary" | ||||
|         app:showAsAction="ifRoom"> | ||||
|         <menu> | ||||
|             <group android:checkableBehavior="single"> | ||||
|                 <item | ||||
|                     android:id="@+id/sort_by_source" | ||||
|                     android:title="@string/sort_by_source" /> | ||||
|                 <item | ||||
|                     android:id="@+id/sort_by_number" | ||||
|                     android:title="@string/sort_by_number" /> | ||||
|                 <item | ||||
|                     android:id="@+id/sort_by_upload_date" | ||||
|                     android:title="@string/sort_by_upload_date" /> | ||||
|             </group> | ||||
|  | ||||
|             <item | ||||
|                 android:id="@+id/action_sort_descending" | ||||
|                 android:checkable="true" | ||||
|                 android:title="@string/action_sort_descending" /> | ||||
|         </menu> | ||||
|     </item> | ||||
|  | ||||
|     <item | ||||
|         android:title="@string/action_display_mode" | ||||
|         app:showAsAction="never"> | ||||
|         <menu> | ||||
|             <group android:checkableBehavior="single"> | ||||
|                 <item | ||||
|                     android:id="@+id/display_title" | ||||
|                     android:title="@string/show_title" /> | ||||
|                 <item | ||||
|                     android:id="@+id/display_chapter_number" | ||||
|                     android:title="@string/show_chapter_number" /> | ||||
|             </group> | ||||
|         </menu> | ||||
|     </item> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/download_group" | ||||
|         android:title="@string/manga_download" | ||||
|         app:showAsAction="never"> | ||||
|         <menu> | ||||
|             <item | ||||
|                 android:id="@+id/download_next" | ||||
|                 android:title="@string/download_1" /> | ||||
|             <item | ||||
|                 android:id="@+id/download_next_5" | ||||
|                 android:title="@string/download_5" /> | ||||
|             <item | ||||
|                 android:id="@+id/download_next_10" | ||||
|                 android:title="@string/download_10" /> | ||||
|             <item | ||||
|                 android:id="@+id/download_custom" | ||||
|                 android:title="@string/download_custom" /> | ||||
|             <item | ||||
|                 android:id="@+id/download_unread" | ||||
|                 android:title="@string/download_unread" /> | ||||
|             <item | ||||
|                 android:id="@+id/download_all" | ||||
|                 android:title="@string/download_all" /> | ||||
|         </menu> | ||||
|     </item> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/action_edit_categories" | ||||
|         android:title="@string/action_edit_categories" | ||||
|         app:showAsAction="never" /> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/action_edit_cover" | ||||
|         android:title="@string/action_edit_cover" | ||||
|         app:showAsAction="never" /> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/action_migrate" | ||||
|         android:title="@string/action_migrate" | ||||
|         app:showAsAction="never" /> | ||||
| </menu> | ||||
							
								
								
									
										47
									
								
								app/src/main/res/menu/manga.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								app/src/main/res/menu/manga.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/download_group" | ||||
|         android:icon="@drawable/ic_get_app_24dp" | ||||
|         android:title="@string/manga_download" | ||||
|         app:iconTint="?attr/colorOnPrimary" | ||||
|         app:showAsAction="ifRoom"> | ||||
|         <menu> | ||||
|             <item | ||||
|                 android:id="@+id/download_next" | ||||
|                 android:title="@string/download_1" /> | ||||
|             <item | ||||
|                 android:id="@+id/download_next_5" | ||||
|                 android:title="@string/download_5" /> | ||||
|             <item | ||||
|                 android:id="@+id/download_next_10" | ||||
|                 android:title="@string/download_10" /> | ||||
|             <item | ||||
|                 android:id="@+id/download_custom" | ||||
|                 android:title="@string/download_custom" /> | ||||
|             <item | ||||
|                 android:id="@+id/download_unread" | ||||
|                 android:title="@string/download_unread" /> | ||||
|             <item | ||||
|                 android:id="@+id/download_all" | ||||
|                 android:title="@string/download_all" /> | ||||
|         </menu> | ||||
|     </item> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/action_edit_categories" | ||||
|         android:title="@string/action_edit_categories" | ||||
|         app:showAsAction="never" /> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/action_edit_cover" | ||||
|         android:title="@string/action_edit_cover" | ||||
|         app:showAsAction="never" /> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/action_migrate" | ||||
|         android:title="@string/action_migrate" | ||||
|         app:showAsAction="never" /> | ||||
| </menu> | ||||
		Reference in New Issue
	
	Block a user