Allow VectorPainter to be cached
This commit is contained in:
1 parent
9a32b020cf
commit
0a2268d4de
2 files changed
+118
-95
No files matched your search
@@ -116,6 +116,7 @@ import com.hippo.ehviewer.ui.settings.showNewVersion
|
||||
import com.hippo.ehviewer.ui.tools.IconFix
|
||||
import com.hippo.ehviewer.ui.tools.LocalDialogState
|
||||
import com.hippo.ehviewer.ui.tools.LocalTouchSlopProvider
|
||||
import com.hippo.ehviewer.ui.tools.ProvideVectorPainterCache
|
||||
import com.hippo.ehviewer.updater.AppUpdater
|
||||
import com.hippo.ehviewer.util.AppConfig
|
||||
import com.hippo.ehviewer.util.ExceptionUtils
|
||||
@@ -323,85 +324,87 @@ class MainActivity : EhActivity() {
|
||||
LocalDrawerLockHandle provides lockDrawerHandle,
|
||||
LocalSnackbarHostState provides snackbarState,
|
||||
) {
|
||||
Scaffold(snackbarHost = { SnackbarHost(snackbarState) }) {
|
||||
LocalTouchSlopProvider(Settings.touchSlopFactor.toFloat()) {
|
||||
ModalNavigationDrawer(
|
||||
drawerContent = {
|
||||
ModalDrawerSheet(
|
||||
modifier = Modifier.widthIn(max = (configuration.screenWidthDp - 56).dp),
|
||||
windowInsets = WindowInsets.systemBars.only(WindowInsetsSides.Start),
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
Column(
|
||||
modifier = Modifier.verticalScroll(scrollState)
|
||||
.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Bottom)),
|
||||
ProvideVectorPainterCache {
|
||||
Scaffold(snackbarHost = { SnackbarHost(snackbarState) }) {
|
||||
LocalTouchSlopProvider(Settings.touchSlopFactor.toFloat()) {
|
||||
ModalNavigationDrawer(
|
||||
drawerContent = {
|
||||
ModalDrawerSheet(
|
||||
modifier = Modifier.widthIn(max = (configuration.screenWidthDp - 56).dp),
|
||||
windowInsets = WindowInsets.systemBars.only(WindowInsetsSides.Start),
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.sadpanda_low_poly),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
|
||||
contentScale = ContentScale.FillWidth,
|
||||
)
|
||||
navItems.forEach { (direction, stringId, icon) ->
|
||||
val scrollState = rememberScrollState()
|
||||
Column(
|
||||
modifier = Modifier.verticalScroll(scrollState)
|
||||
.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Bottom)),
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.sadpanda_low_poly),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
|
||||
contentScale = ContentScale.FillWidth,
|
||||
)
|
||||
navItems.forEach { (direction, stringId, icon) ->
|
||||
NavigationDrawerItem(
|
||||
label = {
|
||||
Text(text = stringResource(id = stringId))
|
||||
},
|
||||
selected = currentDestination === direction,
|
||||
onClick = {
|
||||
navController.navigate(direction.route)
|
||||
closeDrawer()
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 12.dp),
|
||||
icon = {
|
||||
IconFix(imageVector = icon, contentDescription = null)
|
||||
},
|
||||
)
|
||||
}
|
||||
NavigationDrawerItem(
|
||||
label = {
|
||||
Text(text = stringResource(id = stringId))
|
||||
Text(text = stringResource(id = R.string.settings))
|
||||
},
|
||||
selected = currentDestination === direction,
|
||||
selected = false,
|
||||
onClick = {
|
||||
navController.navigate(direction.route)
|
||||
closeDrawer()
|
||||
closeDrawer { startActivity(Intent(applicationContext, ConfigureActivity::class.java)) }
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 12.dp),
|
||||
icon = {
|
||||
IconFix(imageVector = icon, contentDescription = null)
|
||||
Icon(imageVector = Icons.Default.Settings, contentDescription = null)
|
||||
},
|
||||
)
|
||||
}
|
||||
NavigationDrawerItem(
|
||||
label = {
|
||||
Text(text = stringResource(id = R.string.settings))
|
||||
},
|
||||
selected = false,
|
||||
onClick = {
|
||||
closeDrawer { startActivity(Intent(applicationContext, ConfigureActivity::class.java)) }
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 12.dp),
|
||||
icon = {
|
||||
Icon(imageVector = Icons.Default.Settings, contentDescription = null)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
drawerState = navDrawerState,
|
||||
gesturesEnabled = !drawerLocked || navDrawerState.isOpen,
|
||||
) {
|
||||
val sheet = sideSheet.firstOrNull()
|
||||
SideDrawer(
|
||||
drawerContent = {
|
||||
if (sheet != null) {
|
||||
ModalDrawerSheet(
|
||||
modifier = Modifier.widthIn(max = (configuration.screenWidthDp - 112).dp),
|
||||
drawerShape = ShapeDefaults.Large.copy(topEnd = CornerSize(0), bottomEnd = CornerSize(0)),
|
||||
windowInsets = WindowInsets.systemBars.only(WindowInsetsSides.Top + WindowInsetsSides.End),
|
||||
) {
|
||||
CompositionLocalProvider(LocalViewConfiguration provides viewConfiguration) {
|
||||
sheet(sideSheetState)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
drawerState = sideSheetState,
|
||||
gesturesEnabled = sheet != null && !drawerLocked,
|
||||
drawerState = navDrawerState,
|
||||
gesturesEnabled = !drawerLocked || navDrawerState.isOpen,
|
||||
) {
|
||||
CompositionLocalProvider(LocalViewConfiguration provides viewConfiguration) {
|
||||
DestinationsNavHost(
|
||||
navGraph = NavGraphs.root,
|
||||
startRoute = navItems[Settings.launchPage].first,
|
||||
engine = rememberNavHostEngine(rootDefaultAnimations = ehNavAnim),
|
||||
navController = navController,
|
||||
)
|
||||
val sheet = sideSheet.firstOrNull()
|
||||
SideDrawer(
|
||||
drawerContent = {
|
||||
if (sheet != null) {
|
||||
ModalDrawerSheet(
|
||||
modifier = Modifier.widthIn(max = (configuration.screenWidthDp - 112).dp),
|
||||
drawerShape = ShapeDefaults.Large.copy(topEnd = CornerSize(0), bottomEnd = CornerSize(0)),
|
||||
windowInsets = WindowInsets.systemBars.only(WindowInsetsSides.Top + WindowInsetsSides.End),
|
||||
) {
|
||||
CompositionLocalProvider(LocalViewConfiguration provides viewConfiguration) {
|
||||
sheet(sideSheetState)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
drawerState = sideSheetState,
|
||||
gesturesEnabled = sheet != null && !drawerLocked,
|
||||
) {
|
||||
CompositionLocalProvider(LocalViewConfiguration provides viewConfiguration) {
|
||||
DestinationsNavHost(
|
||||
navGraph = NavGraphs.root,
|
||||
startRoute = navItems[Settings.launchPage].first,
|
||||
engine = rememberNavHostEngine(rootDefaultAnimations = ehNavAnim),
|
||||
navController = navController,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,15 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.runtime.Applier
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Composition
|
||||
import androidx.compose.runtime.CompositionContext
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.ReusableComposition
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCompositionContext
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
@@ -21,35 +22,33 @@ import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
@Stable
|
||||
@Composable
|
||||
private fun rememberNeverRecomposeVectorPainter(image: ImageVector): VectorPainter {
|
||||
val context = rememberCompositionContext()
|
||||
var b by remember(image) { mutableStateOf<VectorPainter?>(null) }
|
||||
val composition = remember(image) {
|
||||
val composition = ReusableComposition(
|
||||
object : Applier<Unit> {
|
||||
override val current = Unit
|
||||
override fun clear() = Unit
|
||||
override fun move(from: Int, to: Int, count: Int) = Unit
|
||||
override fun remove(index: Int, count: Int) = Unit
|
||||
override fun up() = Unit
|
||||
override fun insertTopDown(index: Int, instance: Unit) = Unit
|
||||
override fun insertBottomUp(index: Int, instance: Unit) = Unit
|
||||
override fun down(node: Unit) = Unit
|
||||
},
|
||||
context,
|
||||
)
|
||||
composition.apply {
|
||||
setContent {
|
||||
b = rememberVectorPainter(image = image)
|
||||
composition.deactivate()
|
||||
val cache = LocalVectorPainterCache.current
|
||||
return remember(image) {
|
||||
val (context, map) = cache
|
||||
map.computeIfAbsent(image) {
|
||||
lateinit var b: VectorPainter
|
||||
val composition = ReusableComposition(
|
||||
object : Applier<Unit> {
|
||||
override val current = Unit
|
||||
override fun clear() = Unit
|
||||
override fun move(from: Int, to: Int, count: Int) = Unit
|
||||
override fun remove(index: Int, count: Int) = Unit
|
||||
override fun up() = Unit
|
||||
override fun insertTopDown(index: Int, instance: Unit) = Unit
|
||||
override fun insertBottomUp(index: Int, instance: Unit) = Unit
|
||||
override fun down(node: Unit) = Unit
|
||||
},
|
||||
context,
|
||||
)
|
||||
composition.apply {
|
||||
setContent {
|
||||
b = rememberVectorPainter(image = image)
|
||||
composition.deactivate()
|
||||
}
|
||||
}
|
||||
}
|
||||
composition to b
|
||||
}.second
|
||||
}
|
||||
DisposableEffect(composition) {
|
||||
onDispose {
|
||||
composition.dispose()
|
||||
}
|
||||
}
|
||||
return b!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -66,3 +65,24 @@ fun IconFix(
|
||||
tint = tint,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ProvideVectorPainterCache(content: @Composable () -> Unit) {
|
||||
val compositionContext = rememberCompositionContext()
|
||||
val cache = remember { mutableMapOf<ImageVector, Pair<Composition, VectorPainter>>() }
|
||||
val provides = remember { compositionContext to cache }
|
||||
CompositionLocalProvider(
|
||||
LocalVectorPainterCache provides provides,
|
||||
content = content,
|
||||
)
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
cache.values.forEach { (composition, _) -> composition.dispose() }
|
||||
cache.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typealias VectorPainterCache = Pair<CompositionContext, MutableMap<ImageVector, Pair<Composition, VectorPainter>>>
|
||||
|
||||
val LocalVectorPainterCache = compositionLocalOf<VectorPainterCache> { error("CompositionLocal LocalSideSheetState not present!") }
|
||||
Reference in new issue
Block a user