Add library fragment
This commit is contained in:
@@ -23,6 +23,7 @@ import org.koitharu.kotatsu.core.ui.uiModule
|
|||||||
import org.koitharu.kotatsu.details.detailsModule
|
import org.koitharu.kotatsu.details.detailsModule
|
||||||
import org.koitharu.kotatsu.favourites.favouritesModule
|
import org.koitharu.kotatsu.favourites.favouritesModule
|
||||||
import org.koitharu.kotatsu.history.historyModule
|
import org.koitharu.kotatsu.history.historyModule
|
||||||
|
import org.koitharu.kotatsu.library.libraryModule
|
||||||
import org.koitharu.kotatsu.local.data.PagesCache
|
import org.koitharu.kotatsu.local.data.PagesCache
|
||||||
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
|
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
|
||||||
import org.koitharu.kotatsu.local.localModule
|
import org.koitharu.kotatsu.local.localModule
|
||||||
@@ -77,6 +78,7 @@ class KotatsuApp : Application() {
|
|||||||
suggestionsModule,
|
suggestionsModule,
|
||||||
shikimoriModule,
|
shikimoriModule,
|
||||||
bookmarksModule,
|
bookmarksModule,
|
||||||
|
libraryModule,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import org.koitharu.kotatsu.core.db.entity.*
|
|||||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||||
import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
|
import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
|
||||||
import org.koitharu.kotatsu.favourites.data.FavouriteEntity
|
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.favourites.data.toFavouriteCategory
|
||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||||
@@ -28,6 +29,11 @@ class FavouritesRepository(
|
|||||||
.mapItems { it.manga.toManga(it.tags.toMangaTags()) }
|
.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> {
|
suspend fun getManga(categoryId: Long): List<Manga> {
|
||||||
val entities = db.favouritesDao.findAll(categoryId)
|
val entities = db.favouritesDao.findAll(categoryId)
|
||||||
return entities.map { it.manga.toManga(it.tags.toMangaTags()) }
|
return entities.map { it.manga.toManga(it.tags.toMangaTags()) }
|
||||||
@@ -163,4 +169,16 @@ class FavouritesRepository(
|
|||||||
.map { x -> SortOrder(x.order, SortOrder.NEWEST) }
|
.map { x -> SortOrder(x.order, SortOrder.NEWEST) }
|
||||||
.distinctUntilChanged()
|
.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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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()) }
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package org.koitharu.kotatsu.search.ui.multi.adapter
|
package org.koitharu.kotatsu.list.ui
|
||||||
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import kotlin.math.roundToInt
|
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class ItemSizeResolver(resources: Resources, settings: AppSettings) {
|
class ItemSizeResolver(resources: Resources, settings: AppSettings) {
|
||||||
|
|
||||||
@@ -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.ListModel
|
||||||
import org.koitharu.kotatsu.list.ui.model.MangaGridModel
|
import org.koitharu.kotatsu.list.ui.model.MangaGridModel
|
||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
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.enqueueWith
|
||||||
import org.koitharu.kotatsu.utils.ext.newImageRequest
|
import org.koitharu.kotatsu.utils.ext.newImageRequest
|
||||||
import org.koitharu.kotatsu.utils.ext.referer
|
import org.koitharu.kotatsu.utils.ext.referer
|
||||||
|
|||||||
@@ -1,19 +1,14 @@
|
|||||||
package org.koitharu.kotatsu.main.ui
|
package org.koitharu.kotatsu.main.ui
|
||||||
|
|
||||||
import android.app.ActivityOptions
|
import android.app.ActivityOptions
|
||||||
import android.content.res.Configuration
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MenuItem
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup.MarginLayoutParams
|
import android.view.ViewGroup.MarginLayoutParams
|
||||||
import androidx.activity.result.ActivityResultCallback
|
import androidx.activity.result.ActivityResultCallback
|
||||||
import androidx.appcompat.app.ActionBarDrawerToggle
|
|
||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
import androidx.core.app.ActivityOptionsCompat
|
import androidx.core.app.ActivityOptionsCompat
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.graphics.Insets
|
import androidx.core.graphics.Insets
|
||||||
import androidx.core.view.*
|
import androidx.core.view.*
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentTransaction
|
import androidx.fragment.app.FragmentTransaction
|
||||||
import androidx.fragment.app.commit
|
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
|
||||||
import com.google.android.material.appbar.AppBarLayout.LayoutParams.*
|
import com.google.android.material.appbar.AppBarLayout.LayoutParams.*
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
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 com.google.android.material.snackbar.Snackbar
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
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.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
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.core.prefs.AppSettings
|
||||||
import org.koitharu.kotatsu.databinding.ActivityMainBinding
|
import org.koitharu.kotatsu.databinding.ActivityMainBinding
|
||||||
import org.koitharu.kotatsu.databinding.NavigationHeaderBinding
|
|
||||||
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
||||||
import org.koitharu.kotatsu.favourites.ui.FavouritesContainerFragment
|
import org.koitharu.kotatsu.favourites.ui.FavouritesContainerFragment
|
||||||
import org.koitharu.kotatsu.history.ui.HistoryListFragment
|
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.Manga
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
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.MangaListActivity
|
||||||
import org.koitharu.kotatsu.search.ui.SearchActivity
|
import org.koitharu.kotatsu.search.ui.SearchActivity
|
||||||
import org.koitharu.kotatsu.search.ui.multi.MultiSearchActivity
|
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.SearchSuggestionListener
|
||||||
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionViewModel
|
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionViewModel
|
||||||
import org.koitharu.kotatsu.settings.AppUpdateChecker
|
import org.koitharu.kotatsu.settings.AppUpdateChecker
|
||||||
import org.koitharu.kotatsu.settings.SettingsActivity
|
|
||||||
import org.koitharu.kotatsu.settings.newsources.NewSourcesDialogFragment
|
import org.koitharu.kotatsu.settings.newsources.NewSourcesDialogFragment
|
||||||
import org.koitharu.kotatsu.settings.onboard.OnboardDialogFragment
|
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.suggestions.ui.SuggestionsWorker
|
||||||
import org.koitharu.kotatsu.tracker.ui.FeedFragment
|
import org.koitharu.kotatsu.tracker.ui.FeedFragment
|
||||||
import org.koitharu.kotatsu.tracker.work.TrackWorker
|
import org.koitharu.kotatsu.tracker.work.TrackWorker
|
||||||
@@ -74,12 +61,6 @@ class MainActivity :
|
|||||||
|
|
||||||
private val viewModel by viewModel<MainViewModel>()
|
private val viewModel by viewModel<MainViewModel>()
|
||||||
private val searchSuggestionViewModel by viewModel<SearchSuggestionViewModel>()
|
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())
|
private val voiceInputLauncher = registerForActivityResult(VoiceInputContract(), VoiceInputCallback())
|
||||||
|
|
||||||
override val appBar: AppBarLayout
|
override val appBar: AppBarLayout
|
||||||
@@ -88,28 +69,6 @@ class MainActivity :
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(ActivityMainBinding.inflate(layoutInflater))
|
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 ->
|
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
|
||||||
if (insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom > 0) {
|
if (insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom > 0) {
|
||||||
@@ -125,18 +84,15 @@ class MainActivity :
|
|||||||
searchSuggestionListener = this@MainActivity
|
searchSuggestionListener = this@MainActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
nav.setOnItemSelectedListener { item ->
|
binding.bottomNav.setOnItemSelectedListener { item ->
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.nav_local_storage -> {
|
R.id.nav_library -> {
|
||||||
viewModel.defaultSection = AppSection.HISTORY
|
setPrimaryFragment(LibraryFragment.newInstance())
|
||||||
setPrimaryFragment(HistoryListFragment.newInstance())
|
|
||||||
}
|
}
|
||||||
R.id.nav_favourites -> {
|
R.id.nav_explore -> {
|
||||||
viewModel.defaultSection = AppSection.FAVOURITES
|
|
||||||
setPrimaryFragment(FavouritesContainerFragment.newInstance())
|
setPrimaryFragment(FavouritesContainerFragment.newInstance())
|
||||||
}
|
}
|
||||||
R.id.nav_feed -> {
|
R.id.nav_feed -> {
|
||||||
viewModel.defaultSection = AppSection.FEED
|
|
||||||
setPrimaryFragment(FeedFragment.newInstance())
|
setPrimaryFragment(FeedFragment.newInstance())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,22 +116,6 @@ class MainActivity :
|
|||||||
viewModel.isResumeEnabled.observe(this, this::onResumeEnabledChanged)
|
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() {
|
override fun onBackPressed() {
|
||||||
val fragment = supportFragmentManager.findFragmentByTag(TAG_SEARCH)
|
val fragment = supportFragmentManager.findFragmentByTag(TAG_SEARCH)
|
||||||
binding.searchView.clearFocus()
|
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) {
|
override fun onClick(v: View) {
|
||||||
when (v.id) {
|
when (v.id) {
|
||||||
R.id.fab -> viewModel.openLastReader()
|
R.id.fab -> viewModel.openLastReader()
|
||||||
@@ -278,12 +212,12 @@ class MainActivity :
|
|||||||
|
|
||||||
override fun onSupportActionModeStarted(mode: ActionMode) {
|
override fun onSupportActionModeStarted(mode: ActionMode) {
|
||||||
super.onSupportActionModeStarted(mode)
|
super.onSupportActionModeStarted(mode)
|
||||||
adjustDrawerLock()
|
showBottomNav(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSupportActionModeFinished(mode: ActionMode) {
|
override fun onSupportActionModeFinished(mode: ActionMode) {
|
||||||
super.onSupportActionModeFinished(mode)
|
super.onSupportActionModeFinished(mode)
|
||||||
adjustDrawerLock()
|
showBottomNav(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onOpenReader(manga: Manga) {
|
private fun onOpenReader(manga: Manga) {
|
||||||
@@ -312,27 +246,23 @@ class MainActivity :
|
|||||||
|
|
||||||
private fun onSearchOpened() {
|
private fun onSearchOpened() {
|
||||||
TransitionManager.beginDelayedTransition(binding.appbar)
|
TransitionManager.beginDelayedTransition(binding.appbar)
|
||||||
drawerToggle?.isDrawerIndicatorEnabled = false
|
|
||||||
binding.toolbarCard.updateLayoutParams<AppBarLayout.LayoutParams> {
|
binding.toolbarCard.updateLayoutParams<AppBarLayout.LayoutParams> {
|
||||||
scrollFlags = SCROLL_FLAG_NO_SCROLL
|
scrollFlags = SCROLL_FLAG_NO_SCROLL
|
||||||
}
|
}
|
||||||
binding.appbar.setBackgroundColor(getThemeColor(materialR.attr.colorSurfaceVariant))
|
binding.appbar.setBackgroundColor(getThemeColor(materialR.attr.colorSurfaceVariant))
|
||||||
binding.appbar.updatePadding(left = 0, right = 0)
|
binding.appbar.updatePadding(left = 0, right = 0)
|
||||||
adjustDrawerLock()
|
|
||||||
adjustFabVisibility(isSearchOpened = true)
|
adjustFabVisibility(isSearchOpened = true)
|
||||||
showBottomNav(false)
|
showBottomNav(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onSearchClosed() {
|
private fun onSearchClosed() {
|
||||||
TransitionManager.beginDelayedTransition(binding.appbar)
|
TransitionManager.beginDelayedTransition(binding.appbar)
|
||||||
drawerToggle?.isDrawerIndicatorEnabled = true
|
|
||||||
binding.toolbarCard.updateLayoutParams<AppBarLayout.LayoutParams> {
|
binding.toolbarCard.updateLayoutParams<AppBarLayout.LayoutParams> {
|
||||||
scrollFlags = SCROLL_FLAG_SCROLL or SCROLL_FLAG_ENTER_ALWAYS
|
scrollFlags = SCROLL_FLAG_SCROLL or SCROLL_FLAG_ENTER_ALWAYS
|
||||||
}
|
}
|
||||||
binding.appbar.background = null
|
binding.appbar.background = null
|
||||||
val padding = resources.getDimensionPixelOffset(R.dimen.margin_normal)
|
val padding = resources.getDimensionPixelOffset(R.dimen.margin_normal)
|
||||||
binding.appbar.updatePadding(left = padding, right = padding)
|
binding.appbar.updatePadding(left = padding, right = padding)
|
||||||
adjustDrawerLock()
|
|
||||||
adjustFabVisibility(isSearchOpened = false)
|
adjustFabVisibility(isSearchOpened = false)
|
||||||
showBottomNav(true)
|
showBottomNav(true)
|
||||||
}
|
}
|
||||||
@@ -369,7 +299,7 @@ class MainActivity :
|
|||||||
isSearchOpened: Boolean = supportFragmentManager.findFragmentByTag(TAG_SEARCH)?.isVisible == true,
|
isSearchOpened: Boolean = supportFragmentManager.findFragmentByTag(TAG_SEARCH)?.isVisible == true,
|
||||||
) {
|
) {
|
||||||
val fab = binding.fab
|
val fab = binding.fab
|
||||||
if (isResumeEnabled && !isSearchOpened && topFragment is HistoryListFragment) {
|
if (isResumeEnabled && !isSearchOpened && topFragment is LibraryFragment) {
|
||||||
if (!fab.isVisible) {
|
if (!fab.isVisible) {
|
||||||
fab.show()
|
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?> {
|
private inner class VoiceInputCallback : ActivityResultCallback<String?> {
|
||||||
|
|
||||||
override fun onActivityResult(result: String?) {
|
override fun onActivityResult(result: String?) {
|
||||||
|
|||||||
@@ -22,12 +22,12 @@ 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.service.DownloadService
|
import org.koitharu.kotatsu.download.ui.service.DownloadService
|
||||||
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesBottomSheet
|
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.MangaSelectionDecoration
|
||||||
import org.koitharu.kotatsu.list.ui.adapter.MangaListListener
|
import org.koitharu.kotatsu.list.ui.adapter.MangaListListener
|
||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||||
import org.koitharu.kotatsu.search.ui.SearchActivity
|
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.search.ui.multi.adapter.MultiSearchAdapter
|
||||||
import org.koitharu.kotatsu.utils.ShareHelper
|
import org.koitharu.kotatsu.utils.ShareHelper
|
||||||
import org.koitharu.kotatsu.utils.ext.findViewsByType
|
import org.koitharu.kotatsu.utils.ext.findViewsByType
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import androidx.recyclerview.widget.RecyclerView.RecycledViewPool
|
|||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
|
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
|
||||||
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
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.MangaSelectionDecoration
|
||||||
import org.koitharu.kotatsu.list.ui.adapter.*
|
import org.koitharu.kotatsu.list.ui.adapter.*
|
||||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||||
|
|||||||
@@ -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.OnListItemClickListener
|
||||||
import org.koitharu.kotatsu.base.ui.list.decor.SpacingItemDecoration
|
import org.koitharu.kotatsu.base.ui.list.decor.SpacingItemDecoration
|
||||||
import org.koitharu.kotatsu.databinding.ItemListGroupBinding
|
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.MangaSelectionDecoration
|
||||||
import org.koitharu.kotatsu.list.ui.adapter.mangaGridItemAD
|
import org.koitharu.kotatsu.list.ui.adapter.mangaGridItemAD
|
||||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
app:layout_insetEdge="bottom"
|
app:layout_insetEdge="bottom"
|
||||||
app:menu="@menu/nav_menu"
|
app:menu="@menu/nav_bottom"
|
||||||
tools:ignore="KeyboardInaccessibleWidget" />
|
tools:ignore="KeyboardInaccessibleWidget" />
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
@@ -1,7 +1,15 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/recyclerView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:clipToPadding="false"
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
android:orientation="vertical"
|
||||||
|
android:paddingLeft="@dimen/list_spacing"
|
||||||
|
android:paddingTop="@dimen/grid_spacing_outer"
|
||||||
|
android:paddingRight="@dimen/list_spacing"
|
||||||
|
android:paddingBottom="@dimen/grid_spacing_outer"
|
||||||
|
app:fastScrollEnabled="true"
|
||||||
|
app:layoutManager="org.koitharu.kotatsu.base.ui.list.FitHeightLinearLayoutManager" />
|
||||||
@@ -3,12 +3,12 @@
|
|||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_local_storage"
|
android:id="@+id/nav_library"
|
||||||
android:icon="@drawable/ic_bookshelf_selector"
|
android:icon="@drawable/ic_bookshelf_selector"
|
||||||
android:title="Library" />
|
android:title="Library" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_favourites"
|
android:id="@+id/nav_explore"
|
||||||
android:icon="@drawable/ic_explore_selector"
|
android:icon="@drawable/ic_explore_selector"
|
||||||
android:title="Explore" />
|
android:title="Explore" />
|
||||||
|
|
||||||
Reference in New Issue
Block a user