diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 22bad7dd9..4b0cf6180 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -57,14 +57,19 @@
+
+
+
diff --git a/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryActivity.kt b/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryActivity.kt
new file mode 100644
index 000000000..64b629a65
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryActivity.kt
@@ -0,0 +1,49 @@
+package org.koitharu.kotatsu.history.ui
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.ViewGroup
+import androidx.core.graphics.Insets
+import androidx.core.view.updateLayoutParams
+import androidx.core.view.updatePadding
+import androidx.fragment.app.commit
+import org.koitharu.kotatsu.R
+import org.koitharu.kotatsu.base.ui.BaseActivity
+import org.koitharu.kotatsu.databinding.ActivityContainerBinding
+
+class HistoryActivity : BaseActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(ActivityContainerBinding.inflate(layoutInflater))
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+ val fm = supportFragmentManager
+ if (fm.findFragmentById(R.id.container) == null) {
+ fm.commit {
+ val fragment = HistoryListFragment.newInstance()
+ replace(R.id.container, fragment)
+ }
+ }
+ }
+
+ override fun onWindowInsetsChanged(insets: Insets) {
+ with(binding.toolbar) {
+ updatePadding(
+ left = insets.left,
+ right = insets.right
+ )
+ updateLayoutParams {
+ topMargin = insets.top
+ }
+ }
+ binding.container.updatePadding(
+ bottom = insets.bottom
+ )
+ }
+
+ companion object {
+
+ fun newIntent(context: Context) = Intent(context, HistoryActivity::class.java)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/library/ui/LibraryFragment.kt b/app/src/main/java/org/koitharu/kotatsu/library/ui/LibraryFragment.kt
index ecffa7f33..2d131e85f 100644
--- a/app/src/main/java/org/koitharu/kotatsu/library/ui/LibraryFragment.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/library/ui/LibraryFragment.kt
@@ -17,7 +17,7 @@ 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.history.ui.HistoryActivity
import org.koitharu.kotatsu.library.ui.adapter.LibraryAdapter
import org.koitharu.kotatsu.library.ui.model.LibraryGroupModel
import org.koitharu.kotatsu.list.ui.ItemSizeResolver
@@ -46,7 +46,7 @@ class LibraryFragment : BaseFragment(), MangaListListene
val sizeResolver = ItemSizeResolver(resources, get())
val itemCLickListener = object : OnListItemClickListener {
override fun onItemClick(item: LibraryGroupModel, view: View) {
-
+ onGroupClick(item, view)
}
}
selectionDecoration = MangaSelectionDecoration(view.context)
@@ -153,6 +153,14 @@ class LibraryFragment : BaseFragment(), MangaListListene
actionMode = null
}
+ private fun onGroupClick(item: LibraryGroupModel, view: View) {
+ val intent = when (item) {
+ is LibraryGroupModel.History -> HistoryActivity.newIntent(view.context)
+ is LibraryGroupModel.Favourites -> TODO()
+ }
+ startActivity(intent)
+ }
+
private fun collectSelectedItems(): Set {
val ids = selectionDecoration?.checkedItemsIds
if (ids.isNullOrEmpty()) {
diff --git a/app/src/main/java/org/koitharu/kotatsu/library/ui/LibraryViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/library/ui/LibraryViewModel.kt
index 17b9d9ced..47b38d652 100644
--- a/app/src/main/java/org/koitharu/kotatsu/library/ui/LibraryViewModel.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/library/ui/LibraryViewModel.kt
@@ -5,11 +5,13 @@ import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
+import org.koitharu.kotatsu.R
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.core.ui.DateTimeAgo
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
import org.koitharu.kotatsu.history.domain.HistoryRepository
import org.koitharu.kotatsu.history.domain.MangaWithHistory
@@ -21,6 +23,10 @@ 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
+import org.koitharu.kotatsu.utils.ext.daysDiff
+import java.util.*
+
+private const val HISTORY_MAX_SEGMENTS = 2
class LibraryViewModel(
private val historyRepository: HistoryRepository,
@@ -57,22 +63,54 @@ class LibraryViewModel(
): List {
val result = ArrayList(favourites.keys.size + 1)
if (history.isNotEmpty()) {
- result += LibraryGroupModel.History(mapHistory(history), null)
+ result += mapHistory(history)
}
for ((category, list) in favourites) {
- result += LibraryGroupModel.Favourites(list.toUi(ListMode.GRID, this), category)
+ result += LibraryGroupModel.Favourites(list.toUi(ListMode.GRID, this), category, R.string.show_all)
}
return result
}
- private suspend fun mapHistory(list: List): List {
+ private suspend fun mapHistory(list: List): List {
val showPercent = settings.isReadingIndicatorsEnabled
- val result = ArrayList(list.size)
+ val groups = ArrayList()
+ val map = HashMap>()
for ((manga, history) in list) {
+ val date = timeAgo(history.updatedAt)
val counter = trackingRepository.getNewChaptersCount(manga.id)
val percent = if (showPercent) history.percent else PROGRESS_NONE
- result += manga.toGridModel(counter, percent)
+ if (groups.lastOrNull() != date) {
+ groups.add(date)
+ }
+ map.getOrPut(date) { ArrayList() }.add(manga.toGridModel(counter, percent))
+ }
+ val result = ArrayList(HISTORY_MAX_SEGMENTS)
+ repeat(minOf(HISTORY_MAX_SEGMENTS - 1, groups.size - 1)) { i ->
+ val key = groups[i]
+ val values = map.remove(key)
+ if (!values.isNullOrEmpty()) {
+ result.add(LibraryGroupModel.History(values, key, 0))
+ }
+ }
+ val values = map.values.flatten()
+ if (values.isNotEmpty()) {
+ val key = if (result.isEmpty()) {
+ map.keys.singleOrNull()?.takeUnless { it == DateTimeAgo.LongAgo }
+ } else {
+ map.keys.singleOrNull() ?: DateTimeAgo.LongAgo
+ }
+ result.add(LibraryGroupModel.History(values, key, R.string.show_all))
}
return result
}
+
+ private fun timeAgo(date: Date): DateTimeAgo {
+ val diffDays = -date.daysDiff(System.currentTimeMillis())
+ return when {
+ diffDays < 1 -> DateTimeAgo.Today
+ diffDays == 1 -> DateTimeAgo.Yesterday
+ diffDays <= 3 -> DateTimeAgo.DaysAgo(diffDays)
+ else -> DateTimeAgo.LongAgo
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/library/ui/adapter/LibraryAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/library/ui/adapter/LibraryAdapter.kt
index 48d50fb0e..99e892c25 100644
--- a/app/src/main/java/org/koitharu/kotatsu/library/ui/adapter/LibraryAdapter.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/library/ui/adapter/LibraryAdapter.kt
@@ -56,5 +56,12 @@ class LibraryAdapter(
override fun areContentsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
return Intrinsics.areEqual(oldItem, newItem)
}
+
+ override fun getChangePayload(oldItem: ListModel, newItem: ListModel): Any? {
+ return when {
+ oldItem is LibraryGroupModel && newItem is LibraryGroupModel -> Unit
+ else -> super.getChangePayload(oldItem, newItem)
+ }
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/library/ui/adapter/LibraryGroupAD.kt b/app/src/main/java/org/koitharu/kotatsu/library/ui/adapter/LibraryGroupAD.kt
index 309b056d1..dca6757c4 100644
--- a/app/src/main/java/org/koitharu/kotatsu/library/ui/adapter/LibraryGroupAD.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/library/ui/adapter/LibraryGroupAD.kt
@@ -3,7 +3,7 @@ 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.AsyncListDifferDelegationAdapter
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.list.AdapterDelegateClickListenerAdapter
@@ -16,6 +16,7 @@ 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
+import org.koitharu.kotatsu.utils.ext.setTextAndVisible
fun libraryGroupAD(
sharedPool: RecyclerView.RecycledViewPool,
@@ -30,7 +31,8 @@ fun libraryGroupAD(
) {
binding.recyclerView.setRecycledViewPool(sharedPool)
- val adapter = ListDelegationAdapter(
+ val adapter = AsyncListDifferDelegationAdapter(
+ MangaItemDiffCallback(),
mangaGridItemAD(coil, lifecycleOwner, listener, sizeResolver)
)
binding.recyclerView.addItemDecoration(selectionDecoration)
@@ -38,11 +40,11 @@ fun libraryGroupAD(
val spacing = context.resources.getDimensionPixelOffset(R.dimen.grid_spacing)
binding.recyclerView.addItemDecoration(SpacingItemDecoration(spacing))
val eventListener = AdapterDelegateClickListenerAdapter(this, itemClickListener)
- itemView.setOnClickListener(eventListener)
+ binding.buttonMore.setOnClickListener(eventListener)
bind {
binding.textViewTitle.text = item.getTitle(context.resources)
+ binding.buttonMore.setTextAndVisible(item.showAllButtonText)
adapter.items = item.items
- adapter.notifyDataSetChanged()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/library/ui/adapter/MangaItemDiffCallback.kt b/app/src/main/java/org/koitharu/kotatsu/library/ui/adapter/MangaItemDiffCallback.kt
new file mode 100644
index 000000000..e39d60454
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/library/ui/adapter/MangaItemDiffCallback.kt
@@ -0,0 +1,30 @@
+package org.koitharu.kotatsu.library.ui.adapter
+
+import androidx.recyclerview.widget.DiffUtil
+import org.koitharu.kotatsu.list.ui.adapter.MangaListAdapter
+import org.koitharu.kotatsu.list.ui.model.ListModel
+import org.koitharu.kotatsu.list.ui.model.MangaItemModel
+import kotlin.jvm.internal.Intrinsics
+
+class MangaItemDiffCallback : DiffUtil.ItemCallback() {
+
+ override fun areItemsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
+ oldItem as MangaItemModel
+ newItem as MangaItemModel
+ return oldItem.javaClass == newItem.javaClass && oldItem.id == newItem.id
+ }
+
+ override fun areContentsTheSame(oldItem: ListModel, newItem: ListModel): Boolean {
+ return Intrinsics.areEqual(oldItem, newItem)
+ }
+
+ override fun getChangePayload(oldItem: ListModel, newItem: ListModel): Any? {
+ oldItem as MangaItemModel
+ newItem as MangaItemModel
+ return when {
+ oldItem.progress != newItem.progress -> MangaListAdapter.PAYLOAD_PROGRESS
+ oldItem.counter != newItem.counter -> Unit
+ else -> super.getChangePayload(oldItem, newItem)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/library/ui/model/LibraryGroupModel.kt b/app/src/main/java/org/koitharu/kotatsu/library/ui/model/LibraryGroupModel.kt
index c1cccbf02..20dc18e2f 100644
--- a/app/src/main/java/org/koitharu/kotatsu/library/ui/model/LibraryGroupModel.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/library/ui/model/LibraryGroupModel.kt
@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.library.ui.model
import android.content.res.Resources
+import androidx.annotation.StringRes
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.core.ui.DateTimeAgo
@@ -8,7 +9,8 @@ import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.list.ui.model.MangaItemModel
sealed class LibraryGroupModel(
- val items: List
+ val items: List,
+ @StringRes val showAllButtonText: Int,
) : ListModel {
abstract val key: Any
@@ -17,7 +19,8 @@ sealed class LibraryGroupModel(
class History(
items: List,
val timeAgo: DateTimeAgo?,
- ) : LibraryGroupModel(items) {
+ showAllButtonText: Int,
+ ) : LibraryGroupModel(items, showAllButtonText) {
override val key: Any
get() = timeAgo?.javaClass ?: this::class.java
@@ -32,8 +35,9 @@ sealed class LibraryGroupModel(
other as History
- if (items != other.items) return false
if (timeAgo != other.timeAgo) return false
+ if (showAllButtonText != other.showAllButtonText) return false
+ if (items != other.items) return false
return true
}
@@ -41,6 +45,7 @@ sealed class LibraryGroupModel(
override fun hashCode(): Int {
var result = items.hashCode()
result = 31 * result + (timeAgo?.hashCode() ?: 0)
+ result = 31 * result + showAllButtonText.hashCode()
return result
}
}
@@ -48,7 +53,8 @@ sealed class LibraryGroupModel(
class Favourites(
items: List,
val category: FavouriteCategory,
- ) : LibraryGroupModel(items) {
+ showAllButtonText: Int,
+ ) : LibraryGroupModel(items, showAllButtonText) {
override val key: Any
get() = category.id
@@ -63,8 +69,9 @@ sealed class LibraryGroupModel(
other as Favourites
- if (items != other.items) return false
if (category != other.category) return false
+ if (showAllButtonText != other.showAllButtonText) return false
+ if (items != other.items) return false
return true
}
@@ -72,6 +79,7 @@ sealed class LibraryGroupModel(
override fun hashCode(): Int {
var result = items.hashCode()
result = 31 * result + category.hashCode()
+ result = 31 * result + showAllButtonText.hashCode()
return result
}
}
diff --git a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt
index 445316cc0..b6a46f2dd 100644
--- a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt
@@ -109,13 +109,15 @@ class MainActivity :
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
- if (isSearchOpened()) {
+ val isSearchOpened = isSearchOpened()
+ if (isSearchOpened) {
binding.toolbarCard.updateLayoutParams {
scrollFlags = SCROLL_FLAG_NO_SCROLL
}
binding.appbar.setBackgroundColor(getThemeColor(materialR.attr.colorSurfaceVariant))
binding.appbar.updatePadding(left = 0, right = 0)
}
+ adjustFabVisibility(isSearchOpened = isSearchOpened)
}
override fun onBackPressed() {
@@ -127,7 +129,7 @@ class MainActivity :
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
runOnCommit { onSearchClosed() }
}
- else -> binding.searchView.requestFocus()
+ else -> super.onBackPressed()
}
}
@@ -218,11 +220,13 @@ class MainActivity :
override fun onSupportActionModeStarted(mode: ActionMode) {
super.onSupportActionModeStarted(mode)
+ adjustFabVisibility()
showBottomNav(false)
}
override fun onSupportActionModeFinished(mode: ActionMode) {
super.onSupportActionModeFinished(mode)
+ adjustFabVisibility()
showBottomNav(true)
}
@@ -330,7 +334,12 @@ class MainActivity :
isSearchOpened: Boolean = isSearchOpened(),
) {
val fab = binding.fab
- if (isResumeEnabled && !isSearchOpened && topFragment is LibraryFragment) {
+ if (
+ isResumeEnabled &&
+ !actionModeDelegate.isActionModeStarted &&
+ !isSearchOpened &&
+ topFragment is LibraryFragment
+ ) {
if (!fab.isVisible) {
fab.show()
}