Consolidate Compose content/theme setting

This commit is contained in:
arkon 2022-07-16 17:08:51 -04:00
parent b034f503f8
commit 46ac9fe970
7 changed files with 130 additions and 271 deletions

View file

@ -3,17 +3,12 @@ package eu.kanade.tachiyomi.ui.base.controller
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.databinding.ComposeControllerBinding
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.util.view.setComposeContent
import nucleus.presenter.Presenter
abstract class FullComposeController<P : Presenter<*>>(bundle: Bundle? = null) :
@ -27,14 +22,8 @@ abstract class FullComposeController<P : Presenter<*>>(bundle: Bundle? = null) :
super.onViewCreated(view)
binding.root.apply {
consumeWindowInsets = false
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
TachiyomiTheme {
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onBackground) {
ComposeContent()
}
}
setComposeContent {
ComposeContent()
}
}
}
@ -54,15 +43,9 @@ abstract class ComposeController<P : Presenter<*>>(bundle: Bundle? = null) :
super.onViewCreated(view)
binding.root.apply {
consumeWindowInsets = false
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
setComposeContent {
val nestedScrollInterop = rememberNestedScrollInteropConnection()
TachiyomiTheme {
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onBackground) {
ComposeContent(nestedScrollInterop)
}
}
ComposeContent(nestedScrollInterop)
}
}
}
@ -82,15 +65,9 @@ abstract class BasicComposeController :
super.onViewCreated(view)
binding.root.apply {
consumeWindowInsets = false
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
setComposeContent {
val nestedScrollInterop = rememberNestedScrollInteropConnection()
TachiyomiTheme {
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onBackground) {
ComposeContent(nestedScrollInterop)
}
}
ComposeContent(nestedScrollInterop)
}
}
}
@ -107,15 +84,9 @@ abstract class SearchableComposeController<P : BasePresenter<*>>(bundle: Bundle?
super.onViewCreated(view)
binding.root.apply {
consumeWindowInsets = false
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
setComposeContent {
val nestedScrollInterop = rememberNestedScrollInteropConnection()
TachiyomiTheme {
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onBackground) {
ComposeContent(nestedScrollInterop)
}
}
ComposeContent(nestedScrollInterop)
}
}
}

View file

@ -3,17 +3,11 @@ package eu.kanade.tachiyomi.ui.library
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
import com.google.accompanist.swiperefresh.SwipeRefresh
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
@ -23,7 +17,6 @@ import eu.kanade.presentation.library.components.LibraryComfortableGrid
import eu.kanade.presentation.library.components.LibraryCompactGrid
import eu.kanade.presentation.library.components.LibraryCoverOnlyGrid
import eu.kanade.presentation.library.components.LibraryList
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
@ -31,6 +24,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.ComposeControllerBinding
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.setComposeContent
import eu.kanade.tachiyomi.widget.RecyclerViewPagerAdapter
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -101,80 +95,74 @@ class LibraryAdapter(
*/
override fun bindView(view: View, position: Int) {
(view as ComposeView).apply {
consumeWindowInsets = false
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
TachiyomiTheme {
CompositionLocalProvider(LocalTextStyle provides MaterialTheme.typography.bodySmall, LocalContentColor provides MaterialTheme.colorScheme.onBackground) {
val nestedScrollInterop = rememberNestedScrollInteropConnection()
setComposeContent {
val nestedScrollInterop = rememberNestedScrollInteropConnection()
val category = presenter.categories[position]
val displayMode = presenter.getDisplayMode(index = position)
val mangaList by presenter.getMangaForCategory(categoryId = category.id)
val category = presenter.categories[position]
val displayMode = presenter.getDisplayMode(index = position)
val mangaList by presenter.getMangaForCategory(categoryId = category.id)
val onClickManga = { manga: LibraryManga ->
if (presenter.hasSelection().not()) {
onClickManga(manga)
} else {
presenter.toggleSelection(manga)
}
val onClickManga = { manga: LibraryManga ->
if (presenter.hasSelection().not()) {
onClickManga(manga)
} else {
presenter.toggleSelection(manga)
}
}
val onLongClickManga = { manga: LibraryManga ->
presenter.toggleSelection(manga)
}
SwipeRefresh(
modifier = Modifier.nestedScroll(nestedScrollInterop),
state = rememberSwipeRefreshState(isRefreshing = false),
onRefresh = {
if (LibraryUpdateService.start(context, category)) {
context.toast(R.string.updating_category)
}
val onLongClickManga = { manga: LibraryManga ->
presenter.toggleSelection(manga)
},
indicator = { s, trigger ->
SwipeRefreshIndicator(
state = s,
refreshTriggerDistance = trigger,
)
},
) {
when (displayMode) {
DisplayModeSetting.LIST -> {
LibraryList(
items = mangaList,
selection = presenter.selection,
onClick = onClickManga,
onLongClick = onLongClickManga,
)
}
SwipeRefresh(
modifier = Modifier.nestedScroll(nestedScrollInterop),
state = rememberSwipeRefreshState(isRefreshing = false),
onRefresh = {
if (LibraryUpdateService.start(context, category)) {
context.toast(R.string.updating_category)
}
},
indicator = { s, trigger ->
SwipeRefreshIndicator(
state = s,
refreshTriggerDistance = trigger,
)
},
) {
when (displayMode) {
DisplayModeSetting.LIST -> {
LibraryList(
items = mangaList,
selection = presenter.selection,
onClick = onClickManga,
onLongClick = onLongClickManga,
)
}
DisplayModeSetting.COMPACT_GRID -> {
LibraryCompactGrid(
items = mangaList,
columns = presenter.columns,
selection = presenter.selection,
onClick = onClickManga,
onLongClick = onLongClickManga,
)
}
DisplayModeSetting.COMFORTABLE_GRID -> {
LibraryComfortableGrid(
items = mangaList,
columns = presenter.columns,
selection = presenter.selection,
onClick = onClickManga,
onLongClick = onLongClickManga,
)
}
DisplayModeSetting.COVER_ONLY_GRID -> {
LibraryCoverOnlyGrid(
items = mangaList,
columns = presenter.columns,
selection = presenter.selection,
onClick = onClickManga,
onLongClick = onLongClickManga,
)
}
}
DisplayModeSetting.COMPACT_GRID -> {
LibraryCompactGrid(
items = mangaList,
columns = presenter.columns,
selection = presenter.selection,
onClick = onClickManga,
onLongClick = onLongClickManga,
)
}
DisplayModeSetting.COMFORTABLE_GRID -> {
LibraryComfortableGrid(
items = mangaList,
columns = presenter.columns,
selection = presenter.selection,
onClick = onClickManga,
onLongClick = onLongClickManga,
)
}
DisplayModeSetting.COVER_ONLY_GRID -> {
LibraryCoverOnlyGrid(
items = mangaList,
columns = presenter.columns,
selection = presenter.selection,
onClick = onClickManga,
onLongClick = onLongClickManga,
)
}
}
}

View file

@ -3,12 +3,11 @@ package eu.kanade.tachiyomi.ui.setting.track
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.activity.compose.setContent
import eu.kanade.presentation.components.LoadingScreen
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.util.view.setComposeContent
import uy.kohesive.injekt.injectLazy
abstract class BaseOAuthLoginActivity : BaseActivity() {
@ -20,10 +19,8 @@ abstract class BaseOAuthLoginActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TachiyomiTheme {
LoadingScreen()
}
setComposeContent {
LoadingScreen()
}
handleResult(intent.data)

View file

@ -4,8 +4,6 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.activity.compose.setContent
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.presentation.webview.WebViewScreen
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.network.NetworkHelper
@ -16,6 +14,7 @@ import eu.kanade.tachiyomi.util.system.WebViewUtil
import eu.kanade.tachiyomi.util.system.logcat
import eu.kanade.tachiyomi.util.system.openInBrowser
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.setComposeContent
import okhttp3.HttpUrl.Companion.toHttpUrl
import uy.kohesive.injekt.injectLazy
@ -44,18 +43,16 @@ class WebViewActivity : BaseActivity() {
headers = source.headers.toMultimap().mapValues { it.value.getOrNull(0) ?: "" }.toMutableMap()
}
setContent {
TachiyomiTheme {
WebViewScreen(
onUp = { finish() },
initialTitle = intent.extras?.getString(TITLE_KEY),
url = url,
headers = headers,
onShare = this::shareWebpage,
onOpenInBrowser = this::openInBrowser,
onClearCookies = this::clearCookies,
)
}
setComposeContent {
WebViewScreen(
onUp = { finish() },
initialTitle = intent.extras?.getString(TITLE_KEY),
url = url,
headers = headers,
onShare = this::shareWebpage,
onOpenInBrowser = this::openInBrowser,
onClearCookies = this::clearCookies,
)
}
}

View file

@ -5,42 +5,71 @@ package eu.kanade.tachiyomi.util.view
import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Resources
import android.graphics.Point
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.text.TextUtils
import android.view.Gravity
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.MenuRes
import androidx.annotation.StringRes
import androidx.appcompat.content.res.AppCompatResources
import androidx.appcompat.view.menu.MenuBuilder
import androidx.appcompat.widget.PopupMenu
import androidx.appcompat.widget.TooltipCompat
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionContext
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.core.view.children
import androidx.core.view.descendants
import androidx.core.view.forEach
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.ViewPager
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.snackbar.Snackbar
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.getResourceColor
/**
* Returns coordinates of view.
* Used for animation
*
* @return coordinates of view
*/
fun View.getCoordinates() = Point((left + right) / 2, (top + bottom) / 2)
inline fun ComposeView.setComposeContent(crossinline content: @Composable () -> Unit) {
consumeWindowInsets = false
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
TachiyomiTheme {
CompositionLocalProvider(
LocalTextStyle provides MaterialTheme.typography.bodySmall,
LocalContentColor provides MaterialTheme.colorScheme.onBackground,
) {
content()
}
}
}
}
inline fun ComponentActivity.setComposeContent(
parent: CompositionContext? = null,
crossinline content: @Composable () -> Unit,
) {
setContent(parent) {
TachiyomiTheme {
CompositionLocalProvider(
LocalTextStyle provides MaterialTheme.typography.bodySmall,
LocalContentColor provides MaterialTheme.colorScheme.onBackground,
) {
content()
}
}
}
}
/**
* Shows a snackbar in this view.
@ -164,39 +193,6 @@ inline fun ExtendedFloatingActionButton.shrinkOnScroll(recycler: RecyclerView):
return listener
}
/**
* Replaces chips in a ChipGroup.
*
* @param items List of strings that are shown as individual chips.
* @param onClick Optional on click listener for each chip.
* @param onLongClick Optional on long click listener for each chip.
*/
inline fun ChipGroup.setChips(
items: List<String>?,
noinline onClick: ((item: String) -> Unit)? = null,
noinline onLongClick: ((item: String) -> Unit)? = null,
) {
removeAllViews()
items?.forEach { item ->
val chip = Chip(context).apply {
text = item
if (onClick != null) { setOnClickListener { onClick(item) } }
if (onLongClick != null) { setOnLongClickListener { onLongClick(item); true } }
}
addView(chip)
}
}
/**
* Sets TextView max lines dynamically. Can only be called when the view is already laid out.
*/
inline fun TextView.setMaxLinesAndEllipsize(_ellipsize: TextUtils.TruncateAt = TextUtils.TruncateAt.END) = post {
maxLines = (measuredHeight - paddingTop - paddingBottom) / lineHeight
ellipsize = _ellipsize
}
/**
* Callback will be run immediately when no animation running
*/
@ -228,29 +224,6 @@ inline fun <reified T> ViewGroup.findDescendant(): T? {
return descendants.find { it is T } as? T
}
/**
* Returns the active child view of a ViewPager according to the LayoutParams
*/
fun ViewPager.getActivePageView(): View? {
if (null == adapter || adapter?.count == 0 || childCount == 0) {
return null
}
val positionField = ViewPager.LayoutParams::class.java.getDeclaredField("position")
positionField.isAccessible = true
return children.find { child ->
val layoutParams = child.layoutParams as ViewPager.LayoutParams
try {
if (!layoutParams.isDecor && positionField.getInt(layoutParams) == currentItem) {
return@find true
}
} catch (e: NoSuchFieldException) {
} catch (e: IllegalAccessException) {
}
false
}
}
/**
* Returns a deep copy of the provided [Drawable]
*/

View file

@ -1,66 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/list_item_selector_background"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingVertical="10dp"
android:paddingStart="16dp"
android:paddingEnd="5dp">
<ImageView
android:id="@+id/bookmark_icon"
android:layout_width="16dp"
android:layout_height="0dp"
android:layout_marginEnd="4dp"
android:contentDescription="@string/action_filter_bookmarked"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/chapter_title"
app:layout_constraintEnd_toStartOf="@id/chapter_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/chapter_title"
app:srcCompat="@drawable/ic_bookmark_24dp"
app:tint="?attr/colorAccent"
tools:visibility="visible" />
<TextView
android:id="@+id/chapter_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textAppearance="?attr/textAppearanceBodyMedium"
app:layout_constraintBottom_toTopOf="@+id/chapter_description"
app:layout_constraintEnd_toStartOf="@+id/download"
app:layout_constraintStart_toEndOf="@+id/bookmark_icon"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Title" />
<TextView
android:id="@+id/chapter_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?attr/textAppearanceBodyMedium"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/download"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/chapter_title"
tools:text="22/02/2016 • Scanlator • Page: 45" />
<eu.kanade.tachiyomi.ui.manga.chapter.ChapterDownloadView
android:id="@+id/download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">