UI Revamp of Recents

*Now Endless scrolling in ungrouped/history/updates
*Removed going to history/updates controller in grouped (will later be removed entirely)
*Always showing a header to switch modes, instead of using a filter button (which will later be replaced
This commit is contained in:
Jays2Kings 2021-04-06 17:06:22 -04:00
parent 2d10680fd9
commit 0c66d3b8b6
12 changed files with 260 additions and 109 deletions

View File

@ -283,7 +283,7 @@ class PreferencesHelper(val context: Context) {
fun extensionUpdatesCount() = rxPrefs.getInteger("ext_updates_count", 0)
fun recentsViewType() = rxPrefs.getInteger("recents_view_type", 0)
fun recentsViewType() = flowPrefs.getInt("recents_view_type", 0)
fun lastExtCheck() = rxPrefs.getLong("last_ext_check", 0)

View File

@ -52,9 +52,8 @@ import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.library.LibraryController
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersController
import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadController
import eu.kanade.tachiyomi.ui.recents.RecentsController
import eu.kanade.tachiyomi.ui.recents.RecentsPresenter
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.ui.setting.AboutController
import eu.kanade.tachiyomi.ui.setting.SettingsController
@ -473,11 +472,11 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
SHORTCUT_LIBRARY -> binding.bottomNav.selectedItemId = R.id.nav_library
SHORTCUT_RECENTLY_UPDATED, SHORTCUT_RECENTLY_READ -> {
binding.bottomNav.selectedItemId = R.id.nav_recents
val controller: Controller = when (intent.action) {
SHORTCUT_RECENTLY_UPDATED -> RecentChaptersController()
else -> RecentlyReadController()
val viewType = when (intent.action) {
SHORTCUT_RECENTLY_UPDATED -> RecentsPresenter.VIEW_TYPE_ONLY_UPDATES
else -> RecentsPresenter.VIEW_TYPE_ONLY_HISTORY
}
router.pushController(controller.withFadeTransaction())
router.pushController(RecentsController(viewType).withFadeTransaction())
}
SHORTCUT_BROWSE -> binding.bottomNav.selectedItemId = R.id.nav_browse
SHORTCUT_EXTENSIONS -> {

View File

@ -29,8 +29,8 @@ class RecentMangaAdapter(val delegate: RecentsInterface) :
fun onCoverClick(position: Int)
fun markAsRead(position: Int)
fun isSearching(): Boolean
fun showHistory()
fun showUpdates()
fun setViewType(viewType: Int)
fun getViewType(): Int
}
override fun onItemSwiped(position: Int, direction: Int) {

View File

@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.recents
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.tabs.TabLayout
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
import eu.davidea.flexibleadapter.items.IFlexible
@ -62,8 +63,19 @@ class RecentMangaHeaderItem(val recentsType: Int) :
private val binding = RecentsHeaderItemBinding.bind(view)
init {
binding.actionHistory.setOnClickListener { adapter.delegate.showHistory() }
binding.actionUpdate.setOnClickListener { adapter.delegate.showUpdates() }
listOf(R.string.grouped, R.string.all, R.string.history, R.string.updates).forEach { resId ->
binding.recentsTabs.addTab(binding.recentsTabs.newTab().setText(resId))
}
val selectedTab = (this@Holder.bindingAdapter as? RecentMangaAdapter)?.delegate?.getViewType() ?: 0
binding.recentsTabs.selectTab(binding.recentsTabs.getTabAt(selectedTab))
binding.recentsTabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
(this@Holder.bindingAdapter as? RecentMangaAdapter)?.delegate?.setViewType(tab?.position ?: 0)
}
override fun onTabUnselected(tab: TabLayout.Tab?) { }
override fun onTabReselected(tab: TabLayout.Tab?) { }
})
}
fun bind(recentsType: Int) {
@ -75,8 +87,9 @@ class RecentMangaHeaderItem(val recentsType: Int) :
else -> R.string.continue_reading
}
)
binding.actionHistory.visibleIf(recentsType == -1)
binding.actionUpdate.visibleIf(recentsType == -1)
binding.recentsTabs.visibleIf(recentsType == -1)
val selectedTab = (this@Holder.bindingAdapter as? RecentMangaAdapter)?.delegate?.getViewType() ?: 0
binding.recentsTabs.selectTab(binding.recentsTabs.getTabAt(selectedTab))
binding.title.visibleIf(recentsType != -1)
}
}

View File

@ -14,7 +14,6 @@ import androidx.appcompat.widget.SearchView
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType
import com.google.android.material.bottomsheet.BottomSheetBehavior
@ -22,6 +21,7 @@ import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.BackupRestoreService
import eu.kanade.tachiyomi.data.database.models.History
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.download.DownloadService
@ -34,9 +34,8 @@ import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.main.RootSearchInterface
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersController
import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadController
import eu.kanade.tachiyomi.ui.recently_read.RemoveHistoryDialog
import eu.kanade.tachiyomi.ui.source.browse.ProgressItem
import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.spToPx
import eu.kanade.tachiyomi.util.system.toast
@ -65,6 +64,7 @@ class RecentsController(bundle: Bundle? = null) :
FlexibleAdapter.OnItemClickListener,
FlexibleAdapter.OnItemLongClickListener,
FlexibleAdapter.OnItemMoveListener,
FlexibleAdapter.EndlessScrollListener,
RootSearchInterface,
BottomSheetController,
RemoveHistoryDialog.Listener {
@ -74,11 +74,16 @@ class RecentsController(bundle: Bundle? = null) :
retainViewMode = RetainViewMode.RETAIN_DETACH
}
constructor(viewType: Int) : this() {
presenter.toggleGroupRecents(viewType, false)
}
/**
* Adapter containing the recent manga.
*/
private var adapter = RecentMangaAdapter(this)
private var progressItem: ProgressItem? = null
private var presenter = RecentsPresenter(this)
private var snack: Snackbar? = null
private var lastChapterId: Long? = null
@ -113,6 +118,7 @@ class RecentsController(bundle: Bundle? = null) :
adapter.itemTouchHelperCallback.setSwipeFlags(
ItemTouchHelper.LEFT
)
resetProgressItem()
val attrsArray = intArrayOf(android.R.attr.actionBarSize)
val array = view.context.obtainStyledAttributes(attrsArray)
val appBarHeight = array.getDimensionPixelSize(0, 0)
@ -257,6 +263,10 @@ class RecentsController(bundle: Bundle? = null) :
binding.downloadBottomSheet.dlBottomSheet.dismiss()
return true
}
if (presenter.preferences.recentsViewType().get() != presenter.viewType) {
presenter.toggleGroupRecents(RecentsPresenter.VIEW_TYPE_GROUP_ALL, false)
return true
}
return false
}
@ -284,14 +294,29 @@ class RecentsController(bundle: Bundle? = null) :
fun refresh() = presenter.getRecents()
fun showLists(recents: List<RecentMangaItem>) {
fun showLists(recents: List<RecentMangaItem>, hasNewItems: Boolean, shouldMoveToTop: Boolean = false) {
if (view == null) return
binding.swipeRefresh.isRefreshing = LibraryUpdateService.isRunning()
adapter.updateItems(recents)
adapter.removeAllScrollableHeaders()
if (presenter.viewType > 0) {
adapter.headerItems.forEach {
if (it != presenter.generalHeader) {
adapter.removeScrollableHeader(it)
}
}
if (!adapter.headerItems.any { it === presenter.generalHeader }) {
adapter.addScrollableHeader(presenter.generalHeader)
}
adapter.onLoadMoreComplete(null)
if (!hasNewItems || presenter.viewType == RecentsPresenter.VIEW_TYPE_GROUP_ALL || presenter.query.isNotEmpty() ||
recents.isEmpty()
) {
onAddPageError()
} else if (hasNewItems && presenter.viewType != RecentsPresenter.VIEW_TYPE_GROUP_ALL && presenter.query.isEmpty()) {
resetProgressItem()
}
if (shouldMoveToTop) {
binding.recycler.scrollToPosition(0)
}
if (lastChapterId != null) {
refreshItem(lastChapterId ?: 0L)
lastChapterId = null
@ -339,20 +364,32 @@ class RecentsController(bundle: Bundle? = null) :
router.pushController(MangaDetailsController(manga).withFadeTransaction())
}
override fun showHistory() = router.pushController(RecentlyReadController().withFadeTransaction())
override fun showUpdates() = router.pushController(RecentChaptersController().withFadeTransaction())
fun showHistory() {
presenter.toggleGroupRecents(RecentsPresenter.VIEW_TYPE_ONLY_HISTORY, false)
}
fun showUpdates() {
presenter.toggleGroupRecents(RecentsPresenter.VIEW_TYPE_ONLY_UPDATES, false)
}
override fun setViewType(viewType: Int) {
if (viewType != presenter.viewType) {
presenter.toggleGroupRecents(viewType)
}
}
override fun getViewType() = presenter.viewType
override fun onItemClick(view: View?, position: Int): Boolean {
val item = adapter.getItem(position) ?: return false
if (item is RecentMangaItem) {
if (item.mch.manga.id == null) {
val headerItem = adapter.getHeaderOf(item) as? RecentMangaHeaderItem
val controller: Controller = when (headerItem?.recentsType) {
RecentMangaHeaderItem.NEW_CHAPTERS -> RecentChaptersController()
RecentMangaHeaderItem.CONTINUE_READING -> RecentlyReadController()
when (headerItem?.recentsType) {
RecentMangaHeaderItem.NEW_CHAPTERS -> showUpdates()
RecentMangaHeaderItem.CONTINUE_READING -> showHistory()
else -> return false
}
router.pushController(controller.withFadeTransaction())
} else {
val activity = activity ?: return false
val intent = ReaderActivity.newIntent(activity, item.mch.manga, item.chapter)
@ -440,6 +477,7 @@ class RecentsController(bundle: Bundle? = null) :
setOnQueryTextChangeListener(searchView) {
if (presenter.query != it) {
presenter.query = it ?: return@setOnQueryTextChangeListener false
resetProgressItem()
refresh()
}
true
@ -515,4 +553,31 @@ class RecentsController(bundle: Bundle? = null) :
}
return super.onOptionsItemSelected(item)
}
override fun noMoreLoad(newItemsSize: Int) {}
override fun onLoadMore(lastPosition: Int, currentPage: Int) {
val view = view ?: return
if (presenter.finished || BackupRestoreService.isRunning(view.context.applicationContext)) {
onAddPageError()
return
}
presenter.requestNext()
}
private fun onAddPageError() {
adapter.onLoadMoreComplete(null)
adapter.endlessTargetCount = 0
adapter.setEndlessScrollListener(null, progressItem!!)
adapter.setEndlessProgressItem(null)
}
/**
* Sets a new progress item and reenables the scroll listener.
*/
private fun resetProgressItem() {
progressItem = ProgressItem()
adapter.endlessTargetCount = 0
adapter.setEndlessScrollListener(this, progressItem!!)
}
}

View File

@ -12,7 +12,6 @@ import eu.kanade.tachiyomi.data.download.model.DownloadQueue
import eu.kanade.tachiyomi.data.library.LibraryServiceListener
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.recent_updates.DateItem
import eu.kanade.tachiyomi.util.system.executeOnIO
@ -42,6 +41,10 @@ class RecentsPresenter(
var recentItems = listOf<RecentMangaItem>()
private set
var query = ""
set(value) {
field = value
page = 0
}
private val newAdditionsHeader = RecentMangaHeaderItem(RecentMangaHeaderItem.NEWLY_ADDED)
private val newChaptersHeader = RecentMangaHeaderItem(RecentMangaHeaderItem.NEW_CHAPTERS)
val generalHeader = RecentMangaHeaderItem(-1)
@ -49,7 +52,17 @@ class RecentsPresenter(
RecentMangaHeaderItem
.CONTINUE_READING
)
var viewType: Int = preferences.recentsViewType().getOrDefault()
var finished = false
var shouldMoveToTop = false
var viewType: Int = preferences.recentsViewType().get()
private var page = 0
set(value) {
field = value
if (value == 0) {
finished = false
shouldMoveToTop = true
}
}
fun onCreate() {
downloadManager.addListener(this)
@ -63,25 +76,44 @@ class RecentsPresenter(
getRecents()
}
fun getRecents() {
fun getRecents(updatePageCount: Boolean = false, retryCount: Int = 0, itemCount: Int = 0) {
val oldQuery = query
scope.launch {
val isUngrouped = viewType > 0 && query.isEmpty()
// groupRecents && query.isEmpty()
if (retryCount > 20) {
finished = true
setDownloadedChapters(recentItems)
withContext(Dispatchers.Main) { controller.showLists(recentItems, false) }
}
if (updatePageCount) {
page++
}
val isUngrouped = viewType > VIEW_TYPE_GROUP_ALL && query.isEmpty()
val cal = Calendar.getInstance().apply {
time = Date()
when {
query.isNotEmpty() -> add(Calendar.YEAR, -50)
isUngrouped -> add(Calendar.MONTH, -1)
isUngrouped -> add(Calendar.MONTH, -(page + 1))
else -> add(Calendar.MONTH, -1)
}
}
val startCal = Calendar.getInstance().apply {
time = Date()
when {
query.isNotEmpty() -> {}
isUngrouped && !updatePageCount -> {}
isUngrouped -> add(Calendar.MONTH, -page)
else -> {}
}
}
val calWeek = Calendar.getInstance().apply {
time = Date()
when {
query.isNotEmpty() -> add(Calendar.YEAR, -50)
isUngrouped -> add(Calendar.MONTH, -1)
isUngrouped -> add(Calendar.MONTH, -(page + 1))
else -> add(Calendar.WEEK_OF_YEAR, -1)
}
}
@ -95,27 +127,29 @@ class RecentsPresenter(
}
}
val cReading = if (viewType != 3) {
if (query.isEmpty() && viewType != 2) {
db.getRecentsWithUnread(cal.time, query, isUngrouped).executeOnIO()
val cReading = if (viewType != VIEW_TYPE_ONLY_UPDATES) {
if (query.isEmpty() && viewType != VIEW_TYPE_ONLY_HISTORY) {
db.getRecentsWithUnread(startCal.time, cal.time, query, isUngrouped)
.executeOnIO()
} else db.getRecentMangaLimit(
startCal.time,
cal.time,
if (viewType == 2) 200 else 8,
if (viewType == VIEW_TYPE_ONLY_HISTORY) 200 else 8,
query
).executeOnIO()
} else emptyList()
val rUpdates = when {
viewType == 3 -> db.getRecentChapters(calWeek.time).executeOnIO().map {
viewType == VIEW_TYPE_ONLY_UPDATES -> db.getRecentChapters(startCal.time, calWeek.time).executeOnIO().map {
MangaChapterHistory(it.manga, it.chapter, HistoryImpl())
}
viewType != 2 -> db.getUpdatedManga(calWeek.time, query, isUngrouped).executeOnIO()
viewType != VIEW_TYPE_ONLY_HISTORY -> db.getUpdatedManga(startCal.time, calWeek.time, query, isUngrouped).executeOnIO()
else -> emptyList()
}
rUpdates.forEach {
it.history.last_read = it.chapter.date_fetch
}
val nAdditions = if (viewType < 2) {
db.getRecentlyAdded(calDay.time, query, isUngrouped).executeOnIO()
val nAdditions = if (viewType < VIEW_TYPE_ONLY_HISTORY) {
db.getRecentlyAdded(startCal.time, calDay.time, query, isUngrouped).executeOnIO()
} else emptyList()
nAdditions.forEach {
it.history.last_read = it.manga.date_added
@ -124,35 +158,33 @@ class RecentsPresenter(
val mangaList = (cReading + rUpdates + nAdditions).sortedByDescending {
it.history.last_read
}.distinctBy {
if (query.isEmpty() && viewType != 3) it.manga.id else it.chapter.id
if (query.isEmpty() && viewType != VIEW_TYPE_ONLY_HISTORY) it.manga.id else it.chapter.id
}
val pairs = mangaList.mapNotNull {
val chapter = when {
viewType == 3 -> it.chapter
viewType == VIEW_TYPE_ONLY_HISTORY -> it.chapter
it.chapter.read || it.chapter.id == null -> getNextChapter(it.manga)
it.history.id == null -> getFirstUpdatedChapter(it.manga, it.chapter)
else -> it.chapter
}
if (chapter == null) if ((query.isNotEmpty() || viewType > 1) &&
if (chapter == null) if ((query.isNotEmpty() || viewType > VIEW_TYPE_UNGROUP_ALL) &&
it.chapter.id != null
) Pair(it, it.chapter)
else null
else Pair(it, chapter)
}
if (query.isEmpty() && !isUngrouped) {
val newItems = if (query.isEmpty() && !isUngrouped) {
val nChaptersItems =
pairs.filter { it.first.history.id == null && it.first.chapter.id != null }
.sortedWith(
Comparator<Pair<MangaChapterHistory, Chapter>> { f1, f2 ->
if (abs(f1.second.date_fetch - f2.second.date_fetch) <=
TimeUnit.HOURS.toMillis(12)
) {
f2.second.date_upload.compareTo(f1.second.date_upload)
} else {
f2.second.date_fetch.compareTo(f1.second.date_fetch)
}
.sortedWith { f1, f2 ->
if (abs(f1.second.date_fetch - f2.second.date_fetch) <=
TimeUnit.HOURS.toMillis(12)
) {
f2.second.date_upload.compareTo(f1.second.date_upload)
} else {
f2.second.date_fetch.compareTo(f1.second.date_fetch)
}
)
}
.take(4).map {
RecentMangaItem(
it.first,
@ -171,36 +203,43 @@ class RecentsPresenter(
} + RecentMangaItem(header = continueReadingHeader)
val nAdditionsItems = pairs.filter { it.first.chapter.id == null }.take(4)
.map { RecentMangaItem(it.first, it.second, newAdditionsHeader) }
recentItems =
listOf(nChaptersItems, cReadingItems, nAdditionsItems).sortedByDescending {
it.firstOrNull()?.mch?.history?.last_read ?: 0L
}.flatten()
listOf(nChaptersItems, cReadingItems, nAdditionsItems).sortedByDescending {
it.firstOrNull()?.mch?.history?.last_read ?: 0L
}.flatten()
} else {
recentItems =
if (viewType == 3) {
val map = TreeMap<Date, MutableList<Pair<MangaChapterHistory, Chapter>>> {
d1, d2 ->
d2
.compareTo(d1)
if (viewType == VIEW_TYPE_ONLY_UPDATES) {
val map = TreeMap<Date, MutableList<Pair<MangaChapterHistory, Chapter>>> {
d1, d2 ->
d2
.compareTo(d1)
}
val byDay =
pairs.groupByTo(map, { getMapKey(it.first.history.last_read) })
byDay.flatMap {
val dateItem = DateItem(it.key, true)
it.value.map { item ->
RecentMangaItem(item.first, item.second, dateItem)
}
val byDay =
pairs.groupByTo(map, { getMapKey(it.first.history.last_read) })
byDay.flatMap {
val dateItem = DateItem(it.key, true)
it.value.map { item ->
RecentMangaItem(item.first, item.second, dateItem)
}
}
} else pairs.map { RecentMangaItem(it.first, it.second, null) }
if (isUngrouped && recentItems.isEmpty()) {
recentItems = listOf(
RecentMangaItem(header = newChaptersHeader),
RecentMangaItem(header = continueReadingHeader)
)
}
}
} else pairs.map { RecentMangaItem(it.first, it.second, null) }
}
recentItems = if (page == 0) {
newItems
} else {
recentItems + newItems
}
val newCount = itemCount + newItems.size
val hasNewItems = newItems.isNotEmpty()
if (newCount < 25 && viewType != VIEW_TYPE_GROUP_ALL && query.isEmpty()) {
page++
getRecents(true, retryCount + (if (hasNewItems) 0 else 1), newCount)
return@launch
}
setDownloadedChapters(recentItems)
withContext(Dispatchers.Main) { controller.showLists(recentItems) }
withContext(Dispatchers.Main) {
controller.showLists(recentItems, hasNewItems, shouldMoveToTop)
shouldMoveToTop = false
}
}
}
@ -226,9 +265,12 @@ class RecentsPresenter(
scope.cancel()
}
fun toggleGroupRecents(pref: Int) {
preferences.recentsViewType().set(pref)
fun toggleGroupRecents(pref: Int, updatePref: Boolean = true) {
if (updatePref) {
preferences.recentsViewType().set(pref)
}
viewType = pref
page = 0
getRecents()
}
@ -259,7 +301,7 @@ class RecentsPresenter(
scope.launch {
setDownloadedChapters(recentItems)
withContext(Dispatchers.Main) {
controller.showLists(recentItems)
controller.showLists(recentItems, true)
}
}
}
@ -289,7 +331,7 @@ class RecentsPresenter(
download = null
}
controller.showLists(recentItems)
controller.showLists(recentItems, true)
}
}
@ -367,7 +409,16 @@ class RecentsPresenter(
getRecents()
}
private companion object {
var lastRecents: List<RecentMangaItem>? = null
fun requestNext() {
getRecents(true)
}
companion object {
private var lastRecents: List<RecentMangaItem>? = null
const val VIEW_TYPE_GROUP_ALL = 0
const val VIEW_TYPE_UNGROUP_ALL = 1
const val VIEW_TYPE_ONLY_HISTORY = 2
const val VIEW_TYPE_ONLY_UPDATES = 3
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="0.80" android:color="?attr/colorAccent" />
</selector>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Based on mtrl_tabs_icon_color_selector_colored.
Ensures visibility on top of the background color.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/md_white_1000" android:state_selected="true"/>
<item android:alpha="0.60" android:color="?attr/colorOnBackground"/>
</selector>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:end="2dp"
android:start="2dp" >
<shape>
<corners android:radius="4dp" />
<solid android:color="@color/accent_alpha" />
<size android:height="32sp"/>
</shape>
</item>
</layer-list>

View File

@ -21,30 +21,17 @@
app:layout_constraintHorizontal_bias="0.0"
tools:text="@string/recent_updates" />
<com.google.android.material.button.MaterialButton
android:id="@+id/action_history"
android:visibility="gone"
android:layout_width="wrap_content"
<com.google.android.material.tabs.TabLayout
android:id="@+id/recents_tabs"
style="@style/Theme.Widget.Tabs.Highlight"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:icon="@drawable/ic_history_24dp"
android:layout_marginStart="12dp"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="@string/history"
style="@style/Theme.Widget.Button.RoundedOutline"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/action_update"
android:layout_width="wrap_content"
android:visibility="gone"
android:layout_height="wrap_content"
app:icon="@drawable/ic_update_24dp"
android:layout_marginEnd="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="@string/updates"
style="@style/Theme.Widget.Button.RoundedOutline"/>
app:tabIndicatorColor="?attr/colorAccent"
app:tabGravity="fill"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -224,6 +224,7 @@
<string name="no_recent_chapters">No recent chapters</string>
<string name="no_recently_read_manga">No recently read manga</string>
<string name="group_all">Group all</string>
<string name="grouped">Grouped</string>
<string name="ungroup_all">Ungroup all</string>
<string name="only_history">Only history</string>
<string name="only_updates">Only updates</string>

View File

@ -214,13 +214,22 @@
<item name="tabTextColor">@color/tabs_selector</item>
<item name="tabRippleColor">@color/rippleColor</item>
<item name="tabIndicatorFullWidth">false</item>
<item name="tabIndicatorHeight">3dp</item>
<item name="tabInlineLabel">true</item>
<item name="tabMinWidth">75dp</item>
<item name="tabMode">scrollable</item>
<item name="tabTextAppearance">@style/TextAppearance.Widget.Tab</item>
</style>
<style name="Theme.Widget.Tabs.Highlight" parent="Theme.Widget.Tabs">
<item name="android:background">@android:color/transparent</item>
<item name="tabIndicatorGravity">center</item>
<item name="tabTextColor">@color/tabs_selector_alt</item>
<item name="tabIndicator">@drawable/tab_highlight_indicator</item>
<item name="tabMaxWidth">0dp</item>
<item name="tabMode">fixed</item>
<item name="tabIndicatorFullWidth">true</item>
</style>
<!--==============-->
<!--Widgets.Button-->
<!--==============-->