diff --git a/app/build.gradle b/app/build.gradle index 7e1c0fdbc..df6a42b98 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -82,7 +82,7 @@ afterEvaluate { } dependencies { //noinspection GradleDependency - implementation('com.github.KotatsuApp:kotatsu-parsers:7c89f53988') { + implementation('com.github.KotatsuApp:kotatsu-parsers:3feb84ac9e') { exclude group: 'org.json', module: 'json' } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt index caeccc694..c23523b3f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt @@ -204,6 +204,9 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { val isUnstableUpdatesAllowed: Boolean get() = prefs.getBoolean(KEY_UPDATES_UNSTABLE, false) + val defaultDetailsTab: Int + get() = prefs.getString(KEY_DETAILS_TAB, null)?.toIntOrNull()?.coerceIn(0, 1) ?: 0 + val isContentPrefetchEnabled: Boolean get() { if (isBackgroundNetworkRestricted()) { @@ -559,6 +562,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { const val KEY_CF_INVERTED = "cf_inverted" const val KEY_CF_GRAYSCALE = "cf_grayscale" const val KEY_IGNORE_DOZE = "ignore_dose" + const val KEY_DETAILS_TAB = "details_tab" // About const val KEY_APP_UPDATE = "app_update" diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/BoundsScrollListener.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/BoundsScrollListener.kt index 9aa7cdf93..b173df3c8 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/BoundsScrollListener.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/BoundsScrollListener.kt @@ -38,4 +38,12 @@ abstract class BoundsScrollListener( firstVisibleItemPosition: Int, visibleItemCount: Int ) = Unit + + fun invalidate(recyclerView: RecyclerView) { + onScrolled(recyclerView, 0, 0) + } + + fun postInvalidate(recyclerView: RecyclerView) = recyclerView.post { + invalidate(recyclerView) + } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersFragment.kt index 87fb0f8a5..8c955c77c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ChaptersFragment.kt @@ -1,6 +1,5 @@ package org.koitharu.kotatsu.details.ui -import android.os.Build import android.os.Bundle import android.view.LayoutInflater import android.view.Menu @@ -57,9 +56,6 @@ class ChaptersFragment : checkNotNull(selectionController).attachToRecyclerView(this) setHasFixedSize(true) adapter = chaptersAdapter - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - scrollIndicators = if (resources.getBoolean(R.bool.is_tablet)) 0 else View.SCROLL_INDICATOR_TOP - } } viewModel.isLoading.observe(viewLifecycleOwner, this::onLoadingStateChanged) viewModel.chapters.observe(viewLifecycleOwner, this::onChaptersChanged) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt index 07cbbec6b..a0076bcb1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt @@ -27,7 +27,6 @@ import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import androidx.core.view.updatePadding import com.google.android.material.bottomsheet.BottomSheetBehavior -import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.snackbar.Snackbar import com.google.android.material.tabs.TabLayoutMediator import dagger.hilt.android.AndroidEntryPoint @@ -38,8 +37,10 @@ import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga import org.koitharu.kotatsu.core.os.AppShortcutManager import org.koitharu.kotatsu.core.parser.MangaIntent +import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.ui.util.MenuInvalidator +import org.koitharu.kotatsu.core.ui.util.ReversibleActionObserver import org.koitharu.kotatsu.core.util.ext.doOnExpansionsChanged import org.koitharu.kotatsu.core.util.ext.getAnimationDuration import org.koitharu.kotatsu.core.util.ext.getThemeColor @@ -77,6 +78,9 @@ class DetailsActivity : @Inject lateinit var appShortcutManager: AppShortcutManager + @Inject + lateinit var settings: AppSettings + private var buttonTip: WeakReference? = null private val viewModel: DetailsViewModel by viewModels() @@ -129,19 +133,16 @@ class DetailsActivity : }, ), ) - viewModel.onShowToast.observeEvent(this) { - makeSnackbar(getString(it), Snackbar.LENGTH_SHORT).show() - } + viewModel.onActionDone.observeEvent(this, ReversibleActionObserver(viewBinding.containerDetails)) viewModel.onShowTip.observeEvent(this) { showTip() } viewModel.historyInfo.observe(this, ::onHistoryChanged) viewModel.selectedBranch.observe(this) { viewBinding.toolbarChapters?.subtitle = it viewBinding.textViewSubtitle?.textAndVisible = it } - viewModel.isChaptersReversed.observe( - this, - MenuInvalidator(viewBinding.toolbarChapters ?: this), - ) + val chaptersMenuInvalidator = MenuInvalidator(viewBinding.toolbarChapters ?: this) + viewModel.isChaptersReversed.observe(this, chaptersMenuInvalidator) + viewModel.isChaptersEmpty.observe(this, chaptersMenuInvalidator) val menuInvalidator = MenuInvalidator(this) viewModel.favouriteCategories.observe(this, menuInvalidator) viewModel.remoteManga.observe(this, menuInvalidator) @@ -304,7 +305,7 @@ class DetailsActivity : tab.removeBadge() } else { val badge = tab.orCreateBadge - badge.horizontalOffset = resources.getDimensionPixelOffset(R.dimen.margin_small) + badge.horizontalOffsetWithText = -resources.getDimensionPixelOffset(R.dimen.margin_small) badge.number = count badge.isVisible = true } @@ -343,9 +344,8 @@ class DetailsActivity : val manga = viewModel.manga.value ?: return val chapterId = viewModel.historyInfo.value.history?.chapterId if (chapterId != null && manga.chapters?.none { x -> x.id == chapterId } == true) { - val snackbar = - makeSnackbar(getString(R.string.chapter_is_missing), Snackbar.LENGTH_SHORT) - snackbar.show() + Snackbar.make(viewBinding.containerDetails, R.string.chapter_is_missing, Snackbar.LENGTH_SHORT) + .show() } else { startActivity( IntentBuilder(this) @@ -365,6 +365,7 @@ class DetailsActivity : val adapter = DetailsPagerAdapter(this) viewBinding.pager.adapter = adapter TabLayoutMediator(viewBinding.tabs, viewBinding.pager, adapter).attach() + viewBinding.pager.setCurrentItem(settings.defaultDetailsTab, false) } private fun showBottomSheet(isVisible: Boolean) { @@ -377,17 +378,6 @@ class DetailsActivity : view.isVisible = isVisible } - private fun makeSnackbar( - text: CharSequence, - @BaseTransientBottomBar.Duration duration: Int, - ): Snackbar { - val sb = Snackbar.make(viewBinding.containerDetails, text, duration) - if (viewBinding.layoutBottom?.isVisible == true) { - sb.anchorView = viewBinding.toolbarChapters - } - return sb - } - private class PrefetchObserver( private val context: Context, ) : FlowCollector?> { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsFragment.kt index 9e94f2966..af835d174 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsFragment.kt @@ -10,8 +10,6 @@ import android.widget.Toast import androidx.appcompat.widget.PopupMenu import androidx.core.content.ContextCompat import androidx.core.graphics.Insets -import androidx.core.text.buildSpannedString -import androidx.core.text.color import androidx.core.text.method.LinkMovementMethodCompat import androidx.core.view.isGone import androidx.core.view.isVisible @@ -23,7 +21,6 @@ import coil.request.SuccessResult import coil.util.CoilUtils import com.google.android.material.chip.Chip import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull import org.koitharu.kotatsu.R import org.koitharu.kotatsu.bookmarks.domain.Bookmark @@ -42,7 +39,6 @@ import org.koitharu.kotatsu.core.util.FileSize import org.koitharu.kotatsu.core.util.ext.crossfade import org.koitharu.kotatsu.core.util.ext.drawableTop import org.koitharu.kotatsu.core.util.ext.enqueueWith -import org.koitharu.kotatsu.core.util.ext.getThemeColor import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty import org.koitharu.kotatsu.core.util.ext.isTextTruncated import org.koitharu.kotatsu.core.util.ext.observe @@ -75,7 +71,6 @@ import org.koitharu.kotatsu.scrobbling.common.ui.selector.ScrobblingSelectorShee import org.koitharu.kotatsu.search.ui.MangaListActivity import org.koitharu.kotatsu.search.ui.SearchActivity import javax.inject.Inject -import com.google.android.material.R as materialR @AndroidEntryPoint class DetailsFragment : @@ -122,7 +117,7 @@ class DetailsFragment : viewModel.description.observe(viewLifecycleOwner, ::onDescriptionChanged) viewModel.localSize.observe(viewLifecycleOwner, ::onLocalSizeChanged) viewModel.relatedManga.observe(viewLifecycleOwner, ::onRelatedMangaChanged) - combine(viewModel.chapters, viewModel.newChaptersCount, ::Pair).observe(viewLifecycleOwner, ::onChaptersChanged) + viewModel.chapters.observe(viewLifecycleOwner, ::onChaptersChanged) } override fun onItemClick(item: Bookmark, view: View) { @@ -204,8 +199,7 @@ class DetailsFragment : } } - private fun onChaptersChanged(data: Pair?, Int>) { - val (chapters, newChapters) = data + private fun onChaptersChanged(chapters: List?) { val infoLayout = requireViewBinding().infoLayout if (chapters.isNullOrEmpty()) { infoLayout.textViewChapters.isVisible = false @@ -213,19 +207,7 @@ class DetailsFragment : val count = chapters.countChaptersByBranch() infoLayout.textViewChapters.isVisible = true val chaptersText = resources.getQuantityString(R.plurals.chapters, count, count) - infoLayout.textViewChapters.text = if (newChapters == 0) { - chaptersText - } else { - buildSpannedString { - append(chaptersText) - append(' ') - color(infoLayout.textViewChapters.context.getThemeColor(materialR.attr.colorError)) { - append("(+") - append(newChapters.toString()) - append(')') - } - } - } + infoLayout.textViewChapters.text = chaptersText } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt index 0a432b28c..bf15a0ac4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt @@ -21,6 +21,7 @@ import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.plus +import okio.FileNotFoundException import org.koitharu.kotatsu.R import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.domain.BookmarksRepository @@ -30,6 +31,7 @@ import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.ui.BaseViewModel +import org.koitharu.kotatsu.core.ui.util.ReversibleAction import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.computeSize @@ -80,7 +82,7 @@ class DetailsViewModel @Inject constructor( private val mangaId = intent.mangaId private var loadingJob: Job - val onShowToast = MutableEventFlow() + val onActionDone = MutableEventFlow() val onShowTip = MutableEventFlow() val onSelectChapter = MutableEventFlow() val onDownloadStarted = MutableEventFlow() @@ -234,7 +236,7 @@ class DetailsViewModel @Inject constructor( fun deleteLocal() { val m = details.value?.local?.manga if (m == null) { - onShowToast.call(R.string.file_not_found) + errorEvent.call(FileNotFoundException()) return } launchLoadingJob(Dispatchers.Default) { @@ -246,7 +248,7 @@ class DetailsViewModel @Inject constructor( fun removeBookmark(bookmark: Bookmark) { launchJob(Dispatchers.Default) { bookmarksRepository.removeBookmark(bookmark) - onShowToast.call(R.string.bookmark_removed) + onActionDone.call(ReversibleAction(R.string.bookmark_removed, null)) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/pages/PagesFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/pages/PagesFragment.kt index 338abd8d4..f6d0ffa70 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/pages/PagesFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/pages/PagesFragment.kt @@ -5,6 +5,8 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.graphics.Insets +import androidx.core.view.isInvisible +import androidx.core.view.isVisible import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.recyclerview.widget.GridLayoutManager @@ -21,7 +23,6 @@ import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.util.RecyclerViewScrollCallback import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.observeEvent -import org.koitharu.kotatsu.core.util.ext.plus import org.koitharu.kotatsu.core.util.ext.showOrHide import org.koitharu.kotatsu.databinding.FragmentPagesBinding import org.koitharu.kotatsu.details.ui.DetailsViewModel @@ -55,9 +56,6 @@ class PagesFragment : private var scrollListener: ScrollListener? = null private val spanSizeLookup = SpanSizeLookup() - private val listCommitCallback = Runnable { - spanSizeLookup.invalidateCache() - } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -66,7 +64,7 @@ class PagesFragment : detailsViewModel.history, detailsViewModel.selectedBranch, ) { details, history, branch -> - if (details?.isLoaded == true) { + if (details != null && (details.isLoaded || details.chapters.isNotEmpty())) { PagesViewModel.State(details, history, branch) } else { null @@ -89,6 +87,7 @@ class PagesFragment : with(binding.recyclerView) { addItemDecoration(TypedListSpacingDecoration(context, false)) adapter = thumbnailsAdapter + setHasFixedSize(true) addOnLayoutChangeListener(spanResolver) spanResolver?.setGridSize(settings.gridSize / 100f, this) addOnScrollListener(ScrollListener().also { scrollListener = it }) @@ -97,6 +96,7 @@ class PagesFragment : it.spanCount = checkNotNull(spanResolver).spanCount } } + detailsViewModel.isChaptersEmpty.observe(viewLifecycleOwner, ::onNoChaptersChanged) viewModel.thumbnails.observe(viewLifecycleOwner, ::onThumbnailsChanged) viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this)) viewModel.isLoading.observe(viewLifecycleOwner) { binding.progressBar.showOrHide(it) } @@ -121,7 +121,7 @@ class PagesFragment : startActivity(intent) } - private fun onThumbnailsChanged(list: List) { + private suspend fun onThumbnailsChanged(list: List) { val adapter = thumbnailsAdapter ?: return if (adapter.itemCount == 0) { var position = list.indexOfFirst { it is PageThumbnail && it.isCurrent } @@ -134,12 +134,24 @@ class PagesFragment : 0 } val scrollCallback = RecyclerViewScrollCallback(requireViewBinding().recyclerView, position, offset) - adapter.setItems(list, listCommitCallback + scrollCallback) + adapter.emit(list) + scrollCallback.run() } else { - adapter.setItems(list, listCommitCallback) + adapter.emit(list) } } else { - adapter.setItems(list, listCommitCallback) + adapter.emit(list) + } + spanSizeLookup.invalidateCache() + viewBinding?.recyclerView?.let { + scrollListener?.postInvalidate(it) + } + } + + private fun onNoChaptersChanged(isNoChapters: Boolean) { + with(viewBinding ?: return) { + textViewHolder.isVisible = isNoChapters + recyclerView.isInvisible = isNoChapters } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/pages/PagesViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/pages/PagesViewModel.kt index 8fc24eb53..dd311149d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/pages/PagesViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/pages/PagesViewModel.kt @@ -66,7 +66,9 @@ class PagesViewModel @Inject constructor( private suspend fun doInit(state: State) { chaptersLoader.init(state.details) val initialChapterId = state.history?.chapterId ?: state.details.allChapters.firstOrNull()?.id ?: return - chaptersLoader.loadSingleChapter(initialChapterId) + if (!chaptersLoader.hasPages(initialChapterId)) { + chaptersLoader.loadSingleChapter(initialChapterId) + } updateList(state.history) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListFragment.kt index 3d108f12b..41240eb32 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListFragment.kt @@ -171,6 +171,9 @@ abstract class MangaListFragment : private suspend fun onListChanged(list: List) { listAdapter?.emit(list) spanSizeLookup.invalidateCache() + viewBinding?.recyclerView?.let { + paginationListener?.postInvalidate(it) + } } private fun resolveException(e: Throwable) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChapterPages.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChapterPages.kt index 56248f4ad..7175f53f2 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChapterPages.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChapterPages.kt @@ -1,6 +1,7 @@ package org.koitharu.kotatsu.reader.domain import androidx.collection.LongSparseArray +import androidx.collection.contains import org.koitharu.kotatsu.reader.ui.pager.ReaderPage class ChapterPages private constructor(private val pages: ArrayDeque) : List by pages { @@ -57,6 +58,8 @@ class ChapterPages private constructor(private val pages: ArrayDeque return pages.subList(range.first, range.last + 1) } + operator fun contains(chapterId: Long) = indices.contains(chapterId) + private fun shiftIndices(delta: Int) { for (i in 0 until indices.size()) { val range = indices.valueAt(i) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChaptersLoader.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChaptersLoader.kt index dec74bbbf..9463b6b87 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChaptersLoader.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChaptersLoader.kt @@ -67,6 +67,10 @@ class ChaptersLoader @Inject constructor( fun peekChapter(chapterId: Long): MangaChapter? = chapters[chapterId] + fun hasPages(chapterId: Long): Boolean { + return chapterId in chapterPages + } + fun getPages(chapterId: Long): List { return chapterPages.subList(chapterId) } diff --git a/app/src/main/res/layout/fragment_chapters.xml b/app/src/main/res/layout/fragment_chapters.xml index c21a0376c..884fc6126 100644 --- a/app/src/main/res/layout/fragment_chapters.xml +++ b/app/src/main/res/layout/fragment_chapters.xml @@ -12,6 +12,7 @@ android:layout_height="match_parent" android:clipToPadding="false" android:orientation="vertical" + android:scrollIndicators="top" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" tools:listitem="@layout/item_chapter" /> diff --git a/app/src/main/res/layout/fragment_pages.xml b/app/src/main/res/layout/fragment_pages.xml index 87c588d72..279574b4e 100644 --- a/app/src/main/res/layout/fragment_pages.xml +++ b/app/src/main/res/layout/fragment_pages.xml @@ -12,6 +12,7 @@ android:layout_height="match_parent" android:clipToPadding="false" android:orientation="vertical" + android:scrollIndicators="top" app:bubbleSize="small" app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" tools:listitem="@layout/item_page_thumb" diff --git a/app/src/main/res/layout/layout_details_info.xml b/app/src/main/res/layout/layout_details_info.xml index 228a38b40..a30392c42 100644 --- a/app/src/main/res/layout/layout_details_info.xml +++ b/app/src/main/res/layout/layout_details_info.xml @@ -17,13 +17,10 @@ @string/frequency_twice_per_month @string/frequency_once_per_month + + @string/chapters + @string/pages + diff --git a/app/src/main/res/values/constants.xml b/app/src/main/res/values/constants.xml index ed0bdc85a..93ba5aeb4 100644 --- a/app/src/main/res/values/constants.xml +++ b/app/src/main/res/values/constants.xml @@ -70,4 +70,8 @@ 14 30 + + 0 + 1 + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e193d6036..7e971f703 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -555,4 +555,5 @@ Safe Suggestive Adult + Default tab diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index bd129354e..74e229471 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -220,6 +220,16 @@ ?textAppearanceLabelMedium + + diff --git a/app/src/main/res/xml/pref_appearance.xml b/app/src/main/res/xml/pref_appearance.xml index d96c2c602..7076d082d 100644 --- a/app/src/main/res/xml/pref_appearance.xml +++ b/app/src/main/res/xml/pref_appearance.xml @@ -46,6 +46,19 @@ + + + + + +