Add library fragment

This commit is contained in:
Koitharu
2022-07-04 09:38:39 +03:00
parent 0eff85dca3
commit ebdc2dfb0e
17 changed files with 510 additions and 97 deletions

View File

@@ -23,6 +23,7 @@ import org.koitharu.kotatsu.core.ui.uiModule
import org.koitharu.kotatsu.details.detailsModule
import org.koitharu.kotatsu.favourites.favouritesModule
import org.koitharu.kotatsu.history.historyModule
import org.koitharu.kotatsu.library.libraryModule
import org.koitharu.kotatsu.local.data.PagesCache
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
import org.koitharu.kotatsu.local.localModule
@@ -77,6 +78,7 @@ class KotatsuApp : Application() {
suggestionsModule,
shikimoriModule,
bookmarksModule,
libraryModule,
)
}
}

View File

@@ -7,6 +7,7 @@ import org.koitharu.kotatsu.core.db.entity.*
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
import org.koitharu.kotatsu.favourites.data.FavouriteEntity
import org.koitharu.kotatsu.favourites.data.FavouriteManga
import org.koitharu.kotatsu.favourites.data.toFavouriteCategory
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.SortOrder
@@ -28,6 +29,11 @@ class FavouritesRepository(
.mapItems { it.manga.toManga(it.tags.toMangaTags()) }
}
fun observeAllGrouped(order: SortOrder): Flow<Map<FavouriteCategory, List<Manga>>> {
return db.favouritesDao.observeAll(order)
.map { list -> groupByCategory(list) }
}
suspend fun getManga(categoryId: Long): List<Manga> {
val entities = db.favouritesDao.findAll(categoryId)
return entities.map { it.manga.toManga(it.tags.toMangaTags()) }
@@ -163,4 +169,16 @@ class FavouritesRepository(
.map { x -> SortOrder(x.order, SortOrder.NEWEST) }
.distinctUntilChanged()
}
private fun groupByCategory(list: List<FavouriteManga>): Map<FavouriteCategory, List<Manga>> {
val map = HashMap<FavouriteCategory, MutableList<Manga>>()
for (item in list) {
val manga = item.manga.toManga(item.tags.toMangaTags())
for (category in item.categories) {
map.getOrPut(category.toFavouriteCategory()) { ArrayList() }
.add(manga)
}
}
return map
}
}

View File

@@ -0,0 +1,11 @@
package org.koitharu.kotatsu.library
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
import org.koitharu.kotatsu.library.ui.LibraryViewModel
val libraryModule
get() = module {
viewModel { LibraryViewModel(get(), get(), get(), get(), get()) }
}

View File

@@ -0,0 +1,186 @@
package org.koitharu.kotatsu.library.ui
import android.os.Bundle
import android.view.*
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.core.graphics.Insets
import androidx.core.view.updatePadding
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.snackbar.Snackbar
import org.koin.android.ext.android.get
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BaseFragment
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.databinding.FragmentLibraryBinding
import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.download.ui.service.DownloadService
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesBottomSheet
import org.koitharu.kotatsu.history.ui.HistoryListFragment
import org.koitharu.kotatsu.library.ui.adapter.LibraryAdapter
import org.koitharu.kotatsu.library.ui.model.LibraryGroupModel
import org.koitharu.kotatsu.list.ui.ItemSizeResolver
import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration
import org.koitharu.kotatsu.list.ui.adapter.MangaListListener
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.utils.ShareHelper
import org.koitharu.kotatsu.utils.ext.findViewsByType
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
class LibraryFragment : BaseFragment<FragmentLibraryBinding>(), MangaListListener, ActionMode.Callback {
private val viewModel by viewModel<LibraryViewModel>()
private var adapter: LibraryAdapter? = null
private var selectionDecoration: MangaSelectionDecoration? = null
private var actionMode: ActionMode? = null
override fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): FragmentLibraryBinding {
return FragmentLibraryBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val sizeResolver = ItemSizeResolver(resources, get())
val itemCLickListener = object : OnListItemClickListener<LibraryGroupModel> {
override fun onItemClick(item: LibraryGroupModel, view: View) {
}
}
selectionDecoration = MangaSelectionDecoration(view.context)
adapter = LibraryAdapter(
lifecycleOwner = viewLifecycleOwner,
coil = get(),
listener = this,
itemClickListener = itemCLickListener,
sizeResolver = sizeResolver,
selectionDecoration = checkNotNull(selectionDecoration),
)
binding.recyclerView.adapter = adapter
binding.recyclerView.setHasFixedSize(true)
viewModel.content.observe(viewLifecycleOwner, ::onListChanged)
viewModel.onError.observe(viewLifecycleOwner, ::onError)
}
override fun onDestroyView() {
super.onDestroyView()
adapter = null
selectionDecoration = null
actionMode = null
}
override fun onItemClick(item: Manga, view: View) {
if (selectionDecoration?.checkedItemsCount != 0) {
selectionDecoration?.toggleItemChecked(item.id)
if (selectionDecoration?.checkedItemsCount == 0) {
actionMode?.finish()
} else {
actionMode?.invalidate()
invalidateItemDecorations()
}
return
}
val intent = DetailsActivity.newIntent(view.context, item)
startActivity(intent)
}
override fun onItemLongClick(item: Manga, view: View): Boolean {
if (actionMode == null) {
actionMode = (activity as? AppCompatActivity)?.startSupportActionMode(this)
}
return actionMode?.also {
selectionDecoration?.setItemIsChecked(item.id, true)
invalidateItemDecorations()
it.invalidate()
} != null
}
override fun onRetryClick(error: Throwable) = Unit
override fun onTagRemoveClick(tag: MangaTag) = Unit
override fun onFilterClick() = Unit
override fun onEmptyActionClick() = Unit
override fun onWindowInsetsChanged(insets: Insets) {
binding.recyclerView.updatePadding(
left = insets.left,
right = insets.right,
top = insets.top,
bottom = insets.bottom,
)
}
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.menuInflater.inflate(R.menu.mode_remote, menu)
return true
}
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.title = selectionDecoration?.checkedItemsCount?.toString()
return true
}
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
val ctx = context ?: return false
return when (item.itemId) {
R.id.action_share -> {
ShareHelper(ctx).shareMangaLinks(collectSelectedItems())
mode.finish()
true
}
R.id.action_favourite -> {
FavouriteCategoriesBottomSheet.show(childFragmentManager, collectSelectedItems())
mode.finish()
true
}
R.id.action_save -> {
DownloadService.confirmAndStart(ctx, collectSelectedItems())
mode.finish()
true
}
else -> false
}
}
override fun onDestroyActionMode(mode: ActionMode) {
selectionDecoration?.clearSelection()
invalidateItemDecorations()
actionMode = null
}
private fun collectSelectedItems(): Set<Manga> {
val ids = selectionDecoration?.checkedItemsIds
if (ids.isNullOrEmpty()) {
return emptySet()
}
return emptySet()//viewModel.getItems(ids)
}
private fun invalidateItemDecorations() {
binding.recyclerView.findViewsByType(RecyclerView::class.java).forEach {
it.invalidateItemDecorations()
}
}
private fun onListChanged(list: List<ListModel>) {
adapter?.items = list
}
private fun onError(e: Throwable) {
Snackbar.make(
binding.recyclerView,
e.getDisplayMessage(resources),
Snackbar.LENGTH_SHORT
).show()
}
companion object {
fun newInstance() = LibraryFragment()
}
}

View File

@@ -0,0 +1,78 @@
package org.koitharu.kotatsu.library.ui
import androidx.lifecycle.LiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
import org.koitharu.kotatsu.base.ui.BaseViewModel
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.core.os.ShortcutsRepository
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ListMode
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
import org.koitharu.kotatsu.history.domain.HistoryRepository
import org.koitharu.kotatsu.history.domain.MangaWithHistory
import org.koitharu.kotatsu.history.domain.PROGRESS_NONE
import org.koitharu.kotatsu.library.ui.model.LibraryGroupModel
import org.koitharu.kotatsu.list.domain.ListExtraProvider
import org.koitharu.kotatsu.list.ui.model.*
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
class LibraryViewModel(
private val historyRepository: HistoryRepository,
private val favouritesRepository: FavouritesRepository,
private val shortcutsRepository: ShortcutsRepository,
private val trackingRepository: TrackingRepository,
private val settings: AppSettings,
) : BaseViewModel(), ListExtraProvider {
val content: LiveData<List<ListModel>> = combine(
historyRepository.observeAllWithHistory(),
favouritesRepository.observeAllGrouped(SortOrder.NEWEST),
) { history, favourites ->
mapList(history, favourites)
}.catch { e ->
e.toErrorState(canRetry = false)
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState))
override suspend fun getCounter(mangaId: Long): Int {
return trackingRepository.getNewChaptersCount(mangaId)
}
override suspend fun getProgress(mangaId: Long): Float {
return if (settings.isReadingIndicatorsEnabled) {
historyRepository.getProgress(mangaId)
} else {
PROGRESS_NONE
}
}
private suspend fun mapList(
history: List<MangaWithHistory>,
favourites: Map<FavouriteCategory, List<Manga>>,
): List<ListModel> {
val result = ArrayList<ListModel>(favourites.keys.size + 1)
if (history.isNotEmpty()) {
result += LibraryGroupModel.History(mapHistory(history), null)
}
for ((category, list) in favourites) {
result += LibraryGroupModel.Favourites(list.toUi(ListMode.GRID, this), category)
}
return result
}
private suspend fun mapHistory(list: List<MangaWithHistory>): List<MangaItemModel> {
val showPercent = settings.isReadingIndicatorsEnabled
val result = ArrayList<MangaItemModel>(list.size)
for ((manga, history) in list) {
val counter = trackingRepository.getNewChaptersCount(manga.id)
val percent = if (showPercent) history.percent else PROGRESS_NONE
result += manga.toGridModel(counter, percent)
}
return result
}
}

View File

@@ -0,0 +1,60 @@
package org.koitharu.kotatsu.library.ui.adapter
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.library.ui.model.LibraryGroupModel
import org.koitharu.kotatsu.list.ui.ItemSizeResolver
import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration
import org.koitharu.kotatsu.list.ui.adapter.*
import org.koitharu.kotatsu.list.ui.model.ListModel
import kotlin.jvm.internal.Intrinsics
class LibraryAdapter(
lifecycleOwner: LifecycleOwner,
coil: ImageLoader,
listener: MangaListListener,
sizeResolver: ItemSizeResolver,
selectionDecoration: MangaSelectionDecoration,
itemClickListener: OnListItemClickListener<LibraryGroupModel>,
) : AsyncListDifferDelegationAdapter<ListModel>(DiffCallback()) {
init {
val pool = RecyclerView.RecycledViewPool()
delegatesManager
.addDelegate(
libraryGroupAD(
sharedPool = pool,
lifecycleOwner = lifecycleOwner,
coil = coil,
sizeResolver = sizeResolver,
selectionDecoration = selectionDecoration,
listener = listener,
itemClickListener = itemClickListener,
)
)
.addDelegate(loadingStateAD())
.addDelegate(loadingFooterAD())
.addDelegate(emptyStateListAD(listener))
.addDelegate(errorStateListAD(listener))
}
private class DiffCallback : DiffUtil.ItemCallback<ListModel>() {
override fun areItemsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
return when {
oldItem is LibraryGroupModel && newItem is LibraryGroupModel -> {
oldItem.key == newItem.key
}
else -> oldItem.javaClass == newItem.javaClass
}
}
override fun areContentsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
return Intrinsics.areEqual(oldItem, newItem)
}
}
}

View File

@@ -0,0 +1,48 @@
package org.koitharu.kotatsu.library.ui.adapter
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.ListDelegationAdapter
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.list.AdapterDelegateClickListenerAdapter
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.base.ui.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.databinding.ItemListGroupBinding
import org.koitharu.kotatsu.library.ui.model.LibraryGroupModel
import org.koitharu.kotatsu.list.ui.ItemSizeResolver
import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration
import org.koitharu.kotatsu.list.ui.adapter.mangaGridItemAD
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.Manga
fun libraryGroupAD(
sharedPool: RecyclerView.RecycledViewPool,
lifecycleOwner: LifecycleOwner,
coil: ImageLoader,
sizeResolver: ItemSizeResolver,
selectionDecoration: MangaSelectionDecoration,
listener: OnListItemClickListener<Manga>,
itemClickListener: OnListItemClickListener<LibraryGroupModel>,
) = adapterDelegateViewBinding<LibraryGroupModel, ListModel, ItemListGroupBinding>(
{ layoutInflater, parent -> ItemListGroupBinding.inflate(layoutInflater, parent, false) }
) {
binding.recyclerView.setRecycledViewPool(sharedPool)
val adapter = ListDelegationAdapter(
mangaGridItemAD(coil, lifecycleOwner, listener, sizeResolver)
)
binding.recyclerView.addItemDecoration(selectionDecoration)
binding.recyclerView.adapter = adapter
val spacing = context.resources.getDimensionPixelOffset(R.dimen.grid_spacing)
binding.recyclerView.addItemDecoration(SpacingItemDecoration(spacing))
val eventListener = AdapterDelegateClickListenerAdapter(this, itemClickListener)
itemView.setOnClickListener(eventListener)
bind {
binding.textViewTitle.text = item.getTitle(context.resources)
adapter.items = item.items
adapter.notifyDataSetChanged()
}
}

View File

@@ -0,0 +1,78 @@
package org.koitharu.kotatsu.library.ui.model
import android.content.res.Resources
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.core.ui.DateTimeAgo
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.list.ui.model.MangaItemModel
sealed class LibraryGroupModel(
val items: List<MangaItemModel>
) : ListModel {
abstract val key: Any
abstract fun getTitle(resources: Resources): CharSequence
class History(
items: List<MangaItemModel>,
val timeAgo: DateTimeAgo?,
) : LibraryGroupModel(items) {
override val key: Any
get() = timeAgo?.javaClass ?: this::class.java
override fun getTitle(resources: Resources): CharSequence {
return timeAgo?.format(resources) ?: resources.getString(R.string.history)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as History
if (items != other.items) return false
if (timeAgo != other.timeAgo) return false
return true
}
override fun hashCode(): Int {
var result = items.hashCode()
result = 31 * result + (timeAgo?.hashCode() ?: 0)
return result
}
}
class Favourites(
items: List<MangaItemModel>,
val category: FavouriteCategory,
) : LibraryGroupModel(items) {
override val key: Any
get() = category.id
override fun getTitle(resources: Resources): CharSequence {
return category.title
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Favourites
if (items != other.items) return false
if (category != other.category) return false
return true
}
override fun hashCode(): Int {
var result = items.hashCode()
result = 31 * result + category.hashCode()
return result
}
}
}

View File

@@ -1,9 +1,9 @@
package org.koitharu.kotatsu.search.ui.multi.adapter
package org.koitharu.kotatsu.list.ui
import android.content.res.Resources
import kotlin.math.roundToInt
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.prefs.AppSettings
import kotlin.math.roundToInt
class ItemSizeResolver(resources: Resources, settings: AppSettings) {

View File

@@ -15,7 +15,7 @@ import org.koitharu.kotatsu.history.domain.PROGRESS_NONE
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.list.ui.model.MangaGridModel
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.search.ui.multi.adapter.ItemSizeResolver
import org.koitharu.kotatsu.list.ui.ItemSizeResolver
import org.koitharu.kotatsu.utils.ext.enqueueWith
import org.koitharu.kotatsu.utils.ext.newImageRequest
import org.koitharu.kotatsu.utils.ext.referer

View File

@@ -1,19 +1,14 @@
package org.koitharu.kotatsu.main.ui
import android.app.ActivityOptions
import android.content.res.Configuration
import android.os.Bundle
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup.MarginLayoutParams
import androidx.activity.result.ActivityResultCallback
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.view.ActionMode
import androidx.core.app.ActivityOptionsCompat
import androidx.core.content.ContextCompat
import androidx.core.graphics.Insets
import androidx.core.view.*
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction
import androidx.fragment.app.commit
@@ -22,8 +17,6 @@ import androidx.transition.TransitionManager
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.AppBarLayout.LayoutParams.*
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.navigation.NavigationBarView
import com.google.android.material.navigation.NavigationView
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -31,19 +24,15 @@ import org.koin.android.ext.android.get
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BaseActivity
import org.koitharu.kotatsu.core.prefs.AppSection
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.ActivityMainBinding
import org.koitharu.kotatsu.databinding.NavigationHeaderBinding
import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.favourites.ui.FavouritesContainerFragment
import org.koitharu.kotatsu.history.ui.HistoryListFragment
import org.koitharu.kotatsu.local.ui.LocalListFragment
import org.koitharu.kotatsu.library.ui.LibraryFragment
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.reader.ui.ReaderActivity
import org.koitharu.kotatsu.remotelist.ui.RemoteListFragment
import org.koitharu.kotatsu.search.ui.MangaListActivity
import org.koitharu.kotatsu.search.ui.SearchActivity
import org.koitharu.kotatsu.search.ui.multi.MultiSearchActivity
@@ -51,10 +40,8 @@ import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionFragment
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionListener
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionViewModel
import org.koitharu.kotatsu.settings.AppUpdateChecker
import org.koitharu.kotatsu.settings.SettingsActivity
import org.koitharu.kotatsu.settings.newsources.NewSourcesDialogFragment
import org.koitharu.kotatsu.settings.onboard.OnboardDialogFragment
import org.koitharu.kotatsu.suggestions.ui.SuggestionsFragment
import org.koitharu.kotatsu.suggestions.ui.SuggestionsWorker
import org.koitharu.kotatsu.tracker.ui.FeedFragment
import org.koitharu.kotatsu.tracker.work.TrackWorker
@@ -74,12 +61,6 @@ class MainActivity :
private val viewModel by viewModel<MainViewModel>()
private val searchSuggestionViewModel by viewModel<SearchSuggestionViewModel>()
private lateinit var nav: NavigationBarView
private lateinit var navHeaderBinding: NavigationHeaderBinding
private var drawerToggle: ActionBarDrawerToggle? = null
private var drawer: DrawerLayout? = null
private val voiceInputLauncher = registerForActivityResult(VoiceInputContract(), VoiceInputCallback())
override val appBar: AppBarLayout
@@ -88,28 +69,6 @@ class MainActivity :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityMainBinding.inflate(layoutInflater))
navHeaderBinding = NavigationHeaderBinding.inflate(layoutInflater)
nav = binding.bottomNav
drawer = binding.root as? DrawerLayout
drawerToggle = drawer?.let {
ActionBarDrawerToggle(
this,
it,
binding.toolbar,
R.string.open_menu,
R.string.close_menu
).apply {
setHomeAsUpIndicator(
ContextCompat.getDrawable(this@MainActivity, materialR.drawable.abc_ic_ab_back_material)
)
setToolbarNavigationClickListener {
binding.searchView.hideKeyboard()
onBackPressed()
}
it.addDrawerListener(this)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
}
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
if (insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom > 0) {
@@ -125,18 +84,15 @@ class MainActivity :
searchSuggestionListener = this@MainActivity
}
nav.setOnItemSelectedListener { item ->
binding.bottomNav.setOnItemSelectedListener { item ->
when (item.itemId) {
R.id.nav_local_storage -> {
viewModel.defaultSection = AppSection.HISTORY
setPrimaryFragment(HistoryListFragment.newInstance())
R.id.nav_library -> {
setPrimaryFragment(LibraryFragment.newInstance())
}
R.id.nav_favourites -> {
viewModel.defaultSection = AppSection.FAVOURITES
R.id.nav_explore -> {
setPrimaryFragment(FavouritesContainerFragment.newInstance())
}
R.id.nav_feed -> {
viewModel.defaultSection = AppSection.FEED
setPrimaryFragment(FeedFragment.newInstance())
}
}
@@ -160,22 +116,6 @@ class MainActivity :
viewModel.isResumeEnabled.observe(this, this::onResumeEnabledChanged)
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
drawerToggle?.isDrawerIndicatorEnabled =
drawer?.getDrawerLockMode(GravityCompat.START) == DrawerLayout.LOCK_MODE_UNLOCKED
}
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
drawerToggle?.syncState()
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
drawerToggle?.onConfigurationChanged(newConfig)
}
override fun onBackPressed() {
val fragment = supportFragmentManager.findFragmentByTag(TAG_SEARCH)
binding.searchView.clearFocus()
@@ -189,12 +129,6 @@ class MainActivity :
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return drawerToggle?.onOptionsItemSelected(item) == true || when (item.itemId) {
else -> super.onOptionsItemSelected(item)
}
}
override fun onClick(v: View) {
when (v.id) {
R.id.fab -> viewModel.openLastReader()
@@ -278,12 +212,12 @@ class MainActivity :
override fun onSupportActionModeStarted(mode: ActionMode) {
super.onSupportActionModeStarted(mode)
adjustDrawerLock()
showBottomNav(false)
}
override fun onSupportActionModeFinished(mode: ActionMode) {
super.onSupportActionModeFinished(mode)
adjustDrawerLock()
showBottomNav(true)
}
private fun onOpenReader(manga: Manga) {
@@ -312,27 +246,23 @@ class MainActivity :
private fun onSearchOpened() {
TransitionManager.beginDelayedTransition(binding.appbar)
drawerToggle?.isDrawerIndicatorEnabled = false
binding.toolbarCard.updateLayoutParams<AppBarLayout.LayoutParams> {
scrollFlags = SCROLL_FLAG_NO_SCROLL
}
binding.appbar.setBackgroundColor(getThemeColor(materialR.attr.colorSurfaceVariant))
binding.appbar.updatePadding(left = 0, right = 0)
adjustDrawerLock()
adjustFabVisibility(isSearchOpened = true)
showBottomNav(false)
}
private fun onSearchClosed() {
TransitionManager.beginDelayedTransition(binding.appbar)
drawerToggle?.isDrawerIndicatorEnabled = true
binding.toolbarCard.updateLayoutParams<AppBarLayout.LayoutParams> {
scrollFlags = SCROLL_FLAG_SCROLL or SCROLL_FLAG_ENTER_ALWAYS
}
binding.appbar.background = null
val padding = resources.getDimensionPixelOffset(R.dimen.margin_normal)
binding.appbar.updatePadding(left = padding, right = padding)
adjustDrawerLock()
adjustFabVisibility(isSearchOpened = false)
showBottomNav(true)
}
@@ -369,7 +299,7 @@ class MainActivity :
isSearchOpened: Boolean = supportFragmentManager.findFragmentByTag(TAG_SEARCH)?.isVisible == true,
) {
val fab = binding.fab
if (isResumeEnabled && !isSearchOpened && topFragment is HistoryListFragment) {
if (isResumeEnabled && !isSearchOpened && topFragment is LibraryFragment) {
if (!fab.isVisible) {
fab.show()
}
@@ -380,14 +310,6 @@ class MainActivity :
}
}
private fun adjustDrawerLock() {
val drawer = drawer ?: return
val isLocked = actionModeDelegate.isActionModeStarted || (drawerToggle?.isDrawerIndicatorEnabled == false)
drawer.setDrawerLockMode(
if (isLocked) DrawerLayout.LOCK_MODE_LOCKED_CLOSED else DrawerLayout.LOCK_MODE_UNLOCKED
)
}
private inner class VoiceInputCallback : ActivityResultCallback<String?> {
override fun onActivityResult(result: String?) {

View File

@@ -22,12 +22,12 @@ import org.koitharu.kotatsu.databinding.ActivitySearchMultiBinding
import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.download.ui.service.DownloadService
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesBottomSheet
import org.koitharu.kotatsu.list.ui.ItemSizeResolver
import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration
import org.koitharu.kotatsu.list.ui.adapter.MangaListListener
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.search.ui.SearchActivity
import org.koitharu.kotatsu.search.ui.multi.adapter.ItemSizeResolver
import org.koitharu.kotatsu.search.ui.multi.adapter.MultiSearchAdapter
import org.koitharu.kotatsu.utils.ShareHelper
import org.koitharu.kotatsu.utils.ext.findViewsByType

View File

@@ -6,6 +6,7 @@ import androidx.recyclerview.widget.RecyclerView.RecycledViewPool
import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.list.ui.ItemSizeResolver
import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration
import org.koitharu.kotatsu.list.ui.adapter.*
import org.koitharu.kotatsu.list.ui.model.ListModel

View File

@@ -10,6 +10,7 @@ import org.koitharu.kotatsu.base.ui.list.AdapterDelegateClickListenerAdapter
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.base.ui.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.databinding.ItemListGroupBinding
import org.koitharu.kotatsu.list.ui.ItemSizeResolver
import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration
import org.koitharu.kotatsu.list.ui.adapter.mangaGridItemAD
import org.koitharu.kotatsu.list.ui.model.ListModel