Fix recomposition causing repeat get of extras

This commit is contained in:
Ash 2022-03-28 18:12:21 +08:00
parent a1ceb9a489
commit 67b033f1ec
4 changed files with 137 additions and 122 deletions

View File

@ -14,7 +14,9 @@ class MainActivity : ComponentActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
setContent { setContent {
HomeEntry() HomeEntry(intent.extras).also {
intent.replaceExtras(null)
}
} }
} }
} }

View File

@ -1,5 +1,6 @@
package me.ash.reader.ui.page.common package me.ash.reader.ui.page.common
import android.os.Bundle
import androidx.compose.animation.* import androidx.compose.animation.*
import androidx.compose.animation.core.Spring import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring import androidx.compose.animation.core.spring
@ -27,7 +28,9 @@ import me.ash.reader.ui.theme.AppTheme
@OptIn(ExperimentalAnimationApi::class, androidx.compose.material.ExperimentalMaterialApi::class) @OptIn(ExperimentalAnimationApi::class, androidx.compose.material.ExperimentalMaterialApi::class)
@Composable @Composable
fun HomeEntry() { fun HomeEntry(
extras: Bundle? = null,
) {
val navController = rememberAnimatedNavController() val navController = rememberAnimatedNavController()
AppTheme { AppTheme {
@ -40,100 +43,100 @@ fun HomeEntry() {
Column(modifier = Modifier.background(MaterialTheme.colorScheme.surface)) { Column(modifier = Modifier.background(MaterialTheme.colorScheme.surface)) {
Row( Row(
modifier = Modifier modifier = Modifier
.weight(1f) .weight(1f)
.statusBarsPadding() .statusBarsPadding()
) {
AnimatedNavHost(
navController = navController,
startDestination = RouteName.HOME,
) { ) {
AnimatedNavHost( composable(
navController = navController, route = RouteName.HOME,
startDestination = RouteName.HOME, enterTransition = {
slideInHorizontally(
animationSpec = spring(
stiffness = Spring.StiffnessLow,
dampingRatio = Spring.DampingRatioNoBouncy
),
initialOffsetX = { -it }
) + fadeIn(animationSpec = tween(220, delayMillis = 90))
},
exitTransition = {
slideOutHorizontally(
animationSpec = spring(
stiffness = Spring.StiffnessLow,
dampingRatio = Spring.DampingRatioNoBouncy
),
targetOffsetX = { it }
) + fadeOut(animationSpec = tween(220, delayMillis = 90))
},
popEnterTransition = {
slideInHorizontally(
animationSpec = spring(
stiffness = Spring.StiffnessLow,
dampingRatio = Spring.DampingRatioNoBouncy
),
initialOffsetX = { -it }
) + fadeIn(animationSpec = tween(220, delayMillis = 90))
},
popExitTransition = {
slideOutHorizontally(
animationSpec = spring(
stiffness = Spring.StiffnessLow,
dampingRatio = Spring.DampingRatioNoBouncy
),
targetOffsetX = { it }
) + fadeOut(animationSpec = tween(220, delayMillis = 90))
},
) { ) {
composable( HomePage(navController, extras?.get(ExtraName.ARTICLE_ID))
route = RouteName.HOME, }
enterTransition = { composable(
slideInHorizontally( route = RouteName.SETTINGS,
animationSpec = spring( enterTransition = {
stiffness = Spring.StiffnessLow, slideInHorizontally(
dampingRatio = Spring.DampingRatioNoBouncy animationSpec = spring(
), stiffness = Spring.StiffnessLow,
initialOffsetX = { -it } dampingRatio = Spring.DampingRatioNoBouncy
) + fadeIn(animationSpec = tween(220, delayMillis = 90)) ),
}, initialOffsetX = { -it }
exitTransition = { ) + fadeIn(animationSpec = tween(220, delayMillis = 90))
slideOutHorizontally( },
animationSpec = spring( exitTransition = {
stiffness = Spring.StiffnessLow, slideOutHorizontally(
dampingRatio = Spring.DampingRatioNoBouncy animationSpec = spring(
), stiffness = Spring.StiffnessLow,
targetOffsetX = { it } dampingRatio = Spring.DampingRatioNoBouncy
) + fadeOut(animationSpec = tween(220, delayMillis = 90)) ),
}, targetOffsetX = { -it }
popEnterTransition = { ) + fadeOut(animationSpec = tween(220, delayMillis = 90))
slideInHorizontally( },
animationSpec = spring( popEnterTransition = {
stiffness = Spring.StiffnessLow, slideInHorizontally(
dampingRatio = Spring.DampingRatioNoBouncy animationSpec = spring(
), stiffness = Spring.StiffnessLow,
initialOffsetX = { -it } dampingRatio = Spring.DampingRatioNoBouncy
) + fadeIn(animationSpec = tween(220, delayMillis = 90)) ),
}, initialOffsetX = { -it }
popExitTransition = { ) + fadeIn(animationSpec = tween(220, delayMillis = 90))
slideOutHorizontally( },
animationSpec = spring( popExitTransition = {
stiffness = Spring.StiffnessLow, slideOutHorizontally(
dampingRatio = Spring.DampingRatioNoBouncy animationSpec = spring(
), stiffness = Spring.StiffnessLow,
targetOffsetX = { it } dampingRatio = Spring.DampingRatioNoBouncy
) + fadeOut(animationSpec = tween(220, delayMillis = 90)) ),
}, targetOffsetX = { -it }
) { ) + fadeOut(animationSpec = tween(220, delayMillis = 90))
HomePage(navController) },
} ) {
composable( SettingsPage(navController)
route = RouteName.SETTINGS,
enterTransition = {
slideInHorizontally(
animationSpec = spring(
stiffness = Spring.StiffnessLow,
dampingRatio = Spring.DampingRatioNoBouncy
),
initialOffsetX = { -it }
) + fadeIn(animationSpec = tween(220, delayMillis = 90))
},
exitTransition = {
slideOutHorizontally(
animationSpec = spring(
stiffness = Spring.StiffnessLow,
dampingRatio = Spring.DampingRatioNoBouncy
),
targetOffsetX = { -it }
) + fadeOut(animationSpec = tween(220, delayMillis = 90))
},
popEnterTransition = {
slideInHorizontally(
animationSpec = spring(
stiffness = Spring.StiffnessLow,
dampingRatio = Spring.DampingRatioNoBouncy
),
initialOffsetX = { -it }
) + fadeIn(animationSpec = tween(220, delayMillis = 90))
},
popExitTransition = {
slideOutHorizontally(
animationSpec = spring(
stiffness = Spring.StiffnessLow,
dampingRatio = Spring.DampingRatioNoBouncy
),
targetOffsetX = { -it }
) + fadeOut(animationSpec = tween(220, delayMillis = 90))
},
) {
SettingsPage(navController)
}
} }
} }
Spacer( }
modifier = Modifier Spacer(
.navigationBarsHeight() modifier = Modifier
.navigationBarsHeight()
.fillMaxWidth() .fillMaxWidth()
) )
} }

View File

@ -9,15 +9,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.ExperimentalPagerApi
import kotlinx.coroutines.launch
import me.ash.reader.ui.extension.collectAsStateValue import me.ash.reader.ui.extension.collectAsStateValue
import me.ash.reader.ui.extension.findActivity
import me.ash.reader.ui.page.common.ExtraName
import me.ash.reader.ui.page.home.drawer.feed.FeedOptionDrawer import me.ash.reader.ui.page.home.drawer.feed.FeedOptionDrawer
import me.ash.reader.ui.page.home.drawer.feed.FeedOptionViewAction import me.ash.reader.ui.page.home.drawer.feed.FeedOptionViewAction
import me.ash.reader.ui.page.home.drawer.feed.FeedOptionViewModel import me.ash.reader.ui.page.home.drawer.feed.FeedOptionViewModel
@ -32,41 +28,17 @@ import me.ash.reader.ui.widget.ViewPager
@Composable @Composable
fun HomePage( fun HomePage(
navController: NavHostController, navController: NavHostController,
extrasArticleId: Any? = null,
viewModel: HomeViewModel = hiltViewModel(), viewModel: HomeViewModel = hiltViewModel(),
readViewModel: ReadViewModel = hiltViewModel(), readViewModel: ReadViewModel = hiltViewModel(),
feedOptionViewModel: FeedOptionViewModel = hiltViewModel(), feedOptionViewModel: FeedOptionViewModel = hiltViewModel(),
) { ) {
val context = LocalContext.current
val viewState = viewModel.viewState.collectAsStateValue() val viewState = viewModel.viewState.collectAsStateValue()
val filterState = viewModel.filterState.collectAsStateValue() val filterState = viewModel.filterState.collectAsStateValue()
val readState = readViewModel.viewState.collectAsStateValue() val readState = readViewModel.viewState.collectAsStateValue()
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
LaunchedEffect(Unit) { OpenArticleByExtras(extrasArticleId)
context.findActivity()?.let { activity ->
activity.intent?.let { intent ->
intent.extras?.get(ExtraName.ARTICLE_ID)?.let {
readViewModel.dispatch(ReadViewAction.ScrollToItem(2))
scope.launch {
val article = readViewModel
.rssRepository.get()
.findArticleById(it.toString()) ?: return@launch
readViewModel.dispatch(ReadViewAction.InitData(article))
if (article.feed.isFullContent) readViewModel.dispatch(ReadViewAction.RenderFullContent)
else readViewModel.dispatch(ReadViewAction.RenderDescriptionContent)
readViewModel.dispatch(ReadViewAction.RenderDescriptionContent)
viewModel.dispatch(
HomeViewAction.ScrollToPage(
scope = scope,
targetPage = 2,
)
)
}
}
intent.extras?.remove(ExtraName.ARTICLE_ID)
}
}
}
BackHandler(true) { BackHandler(true) {
val currentPage = viewState.pagerState.currentPage val currentPage = viewState.pagerState.currentPage

View File

@ -0,0 +1,38 @@
package me.ash.reader.ui.page.home
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.rememberCoroutineScope
import androidx.hilt.navigation.compose.hiltViewModel
import kotlinx.coroutines.launch
import me.ash.reader.ui.page.home.read.ReadViewAction
import me.ash.reader.ui.page.home.read.ReadViewModel
@Composable
fun OpenArticleByExtras(
extrasArticleId: Any? = null,
homeViewModel: HomeViewModel = hiltViewModel(),
readViewModel: ReadViewModel = hiltViewModel(),
) {
val scope = rememberCoroutineScope()
LaunchedEffect(extrasArticleId) {
extrasArticleId?.let {
readViewModel.dispatch(ReadViewAction.ScrollToItem(2))
this.launch {
val article = readViewModel
.rssRepository.get()
.findArticleById(it.toString()) ?: return@launch
readViewModel.dispatch(ReadViewAction.InitData(article))
if (article.feed.isFullContent) readViewModel.dispatch(ReadViewAction.RenderFullContent)
else readViewModel.dispatch(ReadViewAction.RenderDescriptionContent)
readViewModel.dispatch(ReadViewAction.RenderDescriptionContent)
homeViewModel.dispatch(
HomeViewAction.ScrollToPage(
scope = scope,
targetPage = 2,
)
)
}
}
}
}