Skip to content

Commit

Permalink
[All] Update to collectAsStateWithLifecycle to latest alpha (#995)
Browse files Browse the repository at this point in the history
  • Loading branch information
astamato committed Oct 10, 2022
2 parents 0a3ac4d + 0a38a42 commit 9dad1d8
Show file tree
Hide file tree
Showing 15 changed files with 50 additions and 25 deletions.
2 changes: 1 addition & 1 deletion JetNews/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ dependencies {
implementation(libs.androidx.lifecycle.viewmodel.savedstate)
implementation(libs.androidx.lifecycle.livedata.ktx)
implementation(libs.androidx.lifecycle.viewModelCompose)

implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.window)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.remember
import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.example.jetnews.ui.article.ArticleScreen
import com.example.jetnews.ui.home.HomeScreenType.ArticleDetails
import com.example.jetnews.ui.home.HomeScreenType.Feed
Expand All @@ -40,6 +41,7 @@ import com.example.jetnews.ui.home.HomeScreenType.FeedWithArticleDetails
* @param openDrawer (event) request opening the app drawer
* @param snackbarHostState (state) state for the [Scaffold] component on this screen
*/
@OptIn(ExperimentalLifecycleComposeApi::class)
@Composable
fun HomeRoute(
homeViewModel: HomeViewModel,
Expand All @@ -48,7 +50,7 @@ fun HomeRoute(
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() }
) {
// UiState of the HomeScreen
val uiState by homeViewModel.uiState.collectAsState()
val uiState by homeViewModel.uiState.collectAsStateWithLifecycle()

HomeRoute(
uiState = uiState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
Expand All @@ -69,6 +68,8 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.constrainHeight
import androidx.compose.ui.unit.constrainWidth
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.example.jetnews.R
import com.example.jetnews.data.Result
import com.example.jetnews.data.interests.InterestSection
Expand Down Expand Up @@ -166,15 +167,16 @@ fun InterestsScreen(
* Remembers the content for each tab on the Interests screen
* gathering application data from [InterestsViewModel]
*/
@OptIn(ExperimentalLifecycleComposeApi::class)
@Composable
fun rememberTabContent(interestsViewModel: InterestsViewModel): List<TabContent> {
// UiState of the InterestsScreen
val uiState by interestsViewModel.uiState.collectAsState()
val uiState by interestsViewModel.uiState.collectAsStateWithLifecycle()

// Describe the screen sections here since each section needs 2 states and 1 event.
// Pass them to the stateless InterestsScreen using a tabContent.
val topicsSection = TabContent(Sections.Topics) {
val selectedTopics by interestsViewModel.selectedTopics.collectAsState()
val selectedTopics by interestsViewModel.selectedTopics.collectAsStateWithLifecycle()
TabWithSections(
sections = uiState.topics,
selectedTopics = selectedTopics,
Expand All @@ -183,7 +185,7 @@ fun rememberTabContent(interestsViewModel: InterestsViewModel): List<TabContent>
}

val peopleSection = TabContent(Sections.People) {
val selectedPeople by interestsViewModel.selectedPeople.collectAsState()
val selectedPeople by interestsViewModel.selectedPeople.collectAsStateWithLifecycle()
TabWithTopics(
topics = uiState.people,
selectedTopics = selectedPeople,
Expand All @@ -192,7 +194,8 @@ fun rememberTabContent(interestsViewModel: InterestsViewModel): List<TabContent>
}

val publicationSection = TabContent(Sections.Publications) {
val selectedPublications by interestsViewModel.selectedPublications.collectAsState()
val selectedPublications by interestsViewModel.selectedPublications
.collectAsStateWithLifecycle()
TabWithTopics(
topics = uiState.publications,
selectedTopics = selectedPublications,
Expand Down
4 changes: 2 additions & 2 deletions Jetcaster/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ Using the example of the home screen in the [`com.example.jetcaster.ui.home`](ap

- The ViewModel is implemented as [`HomeViewModel`][homevm], which exposes a `StateFlow<HomeViewState>` for the UI to observe.
- [`HomeViewState`][homevm] contains the complete view state for the home screen as an [`@Immutable`](https://developer.android.com/reference/kotlin/androidx/compose/runtime/Immutable) `data class`.
- The Home Compose UI in [`Home.kt`][homeui] uses [`HomeViewModel`][homevm], and observes it's [`HomeViewState`][homevm] as Compose [State](https://developer.android.com/reference/kotlin/androidx/compose/runtime/State), using [`collectAsState()`](https://developer.android.com/reference/kotlin/androidx/compose/package-summary#collectasstate):
- The Home Compose UI in [`Home.kt`][homeui] uses [`HomeViewModel`][homevm], and observes it's [`HomeViewState`][homevm] as Compose [State](https://developer.android.com/reference/kotlin/androidx/compose/runtime/State), using [`collectAsStateWithLifecycle()`](https://developer.android.com/reference/kotlin/androidx/lifecycle/compose/package-summary#(kotlinx.coroutines.flow.StateFlow).collectAsStateWithLifecycle(androidx.lifecycle.LifecycleOwner,androidx.lifecycle.Lifecycle.State,kotlin.coroutines.CoroutineContext)):

``` kotlin
val viewModel: HomeViewModel = viewModel()
val viewState by viewModel.state.collectAsState()
val viewState by viewModel.state.collectAsStateWithLifecycle()
```

This pattern is used across the different screens:
Expand Down
1 change: 1 addition & 0 deletions Jetcaster/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ dependencies {

implementation(libs.androidx.lifecycle.runtime)
implementation(libs.androidx.lifecycle.viewModelCompose)
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.androidx.navigation.compose)

implementation(libs.androidx.window)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ import androidx.compose.material.icons.filled.Search
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand All @@ -68,6 +67,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage
import com.example.jetcaster.R
Expand All @@ -90,12 +91,13 @@ import java.time.Duration
import java.time.LocalDateTime
import java.time.OffsetDateTime

@OptIn(ExperimentalLifecycleComposeApi::class)
@Composable
fun Home(
navigateToPlayer: (String) -> Unit,
viewModel: HomeViewModel = viewModel()
) {
val viewState by viewModel.state.collectAsState()
val viewState by viewModel.state.collectAsStateWithLifecycle()
Surface(Modifier.fillMaxSize()) {
HomeContent(
featuredPodcasts = viewState.featuredPodcasts,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ import androidx.compose.material.icons.rounded.PlayCircleFilled
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
Expand All @@ -68,6 +67,8 @@ import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension.Companion.fillToConstraints
import androidx.constraintlayout.compose.Dimension.Companion.preferredWrapContent
import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage
import coil.request.ImageRequest
Expand All @@ -85,6 +86,7 @@ import com.example.jetcaster.util.viewModelProviderFactoryOf
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle

@OptIn(ExperimentalLifecycleComposeApi::class)
@Composable
fun PodcastCategory(
categoryId: Long,
Expand All @@ -101,7 +103,7 @@ fun PodcastCategory(
factory = viewModelProviderFactoryOf { PodcastCategoryViewModel(categoryId) }
)

val viewState by viewModel.state.collectAsState()
val viewState by viewModel.state.collectAsStateWithLifecycle()

/**
* TODO: reset scroll position when category changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,24 @@ import androidx.compose.material.Tab
import androidx.compose.material.TabPosition
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.jetcaster.data.Category
import com.example.jetcaster.ui.home.category.PodcastCategory
import com.example.jetcaster.ui.theme.Keyline1

@OptIn(ExperimentalLifecycleComposeApi::class)
@Composable
fun Discover(
navigateToPlayer: (String) -> Unit,
modifier: Modifier = Modifier
) {
val viewModel: DiscoverViewModel = viewModel()
val viewState by viewModel.state.collectAsState()
val viewState by viewModel.state.collectAsStateWithLifecycle()

val selectedCategory = viewState.selectedCategory

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ import androidx.compose.material.icons.rounded.PlayCircleFilled
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand All @@ -77,6 +76,8 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.window.layout.FoldingFeature
import coil.compose.AsyncImage
import coil.request.ImageRequest
Expand All @@ -94,14 +95,15 @@ import kotlinx.coroutines.flow.StateFlow
/**
* Stateful version of the Podcast player
*/
@OptIn(ExperimentalLifecycleComposeApi::class)
@Composable
fun PlayerScreen(
viewModel: PlayerViewModel,
devicePosture: StateFlow<DevicePosture>,
onBackPress: () -> Unit
) {
val uiState = viewModel.uiState
val devicePostureValue by devicePosture.collectAsState()
val devicePostureValue by devicePosture.collectAsStateWithLifecycle()
PlayerScreen(uiState, devicePostureValue, onBackPress)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ private val initialMessages = listOf(
),
Message(
"Taylor Brooks",
"@aliconors Take a look at the `Flow.collectAsState()` APIs",
"@aliconors Take a look at the `Flow.collectAsStateWithLifecycle()` APIs",
"8:05 PM"
),
Message(
Expand Down
1 change: 1 addition & 0 deletions Jetsnack/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.viewModelCompose)
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.constraintlayout.compose)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.DeleteForever
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
Expand All @@ -70,6 +69,8 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ChainStyle
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.jetsnack.R
import com.example.jetsnack.model.OrderLine
Expand All @@ -86,13 +87,14 @@ import com.example.jetsnack.ui.theme.AlphaNearOpaque
import com.example.jetsnack.ui.theme.JetsnackTheme
import com.example.jetsnack.ui.utils.formatPrice

@OptIn(ExperimentalLifecycleComposeApi::class)
@Composable
fun Cart(
onSnackClick: (Long) -> Unit,
modifier: Modifier = Modifier,
viewModel: CartViewModel = viewModel(factory = CartViewModel.provideFactory())
) {
val orderLines by viewModel.orderLines.collectAsState()
val orderLines by viewModel.orderLines.collectAsStateWithLifecycle()
val inspiredByCart = remember { SnackRepo.getInspiredByCart() }
Cart(
orderLines = orderLines,
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ Looking for a sample that has the following features?
* [Jetnews - Window Size Classes](https://github.com/android/compose-samples/blob/69e9d862b5ffb321064364d7883e859db6daeccd/JetNews/app/src/main/java/com/example/jetnews/ui/MainActivity.kt#L36)
* [Crane - Window Size Classes](https://github.com/android/compose-samples/blob/e7e8733f9b37d80cdc6e9e05dbabe24ccf20b38f/Crane/app/src/main/java/androidx/compose/samples/crane/home/MainActivity.kt#L72)

## Formatting

To automatically format all samples: Run `./scripts/format.sh`
To check one sample for errors: Navigate to the sample folder and run `./gradlew --init-script buildscripts/init.gradle.kts spotlessCheck`
To format one sample: Navigate to the sample folder and run `./gradlew --init-script buildscripts/init.gradle.kts spotlessApply`

## Updates

To update dependencies to their new stable versions, run:
Expand Down
1 change: 1 addition & 0 deletions Reply/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ dependencies {

implementation(libs.androidx.lifecycle.runtime)
implementation(libs.androidx.lifecycle.viewModelCompose)
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.androidx.navigation.compose)

implementation(libs.androidx.activity.compose)
Expand Down
9 changes: 5 additions & 4 deletions Reply/app/src/main/java/com/example/reply/ui/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSiz
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.window.layout.FoldingFeature
Expand All @@ -46,7 +47,7 @@ class MainActivity : ComponentActivity() {

private val viewModel: ReplyHomeViewModel by viewModels()

@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class, ExperimentalLifecycleComposeApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

Expand Down Expand Up @@ -79,8 +80,8 @@ class MainActivity : ComponentActivity() {
setContent {
ReplyTheme {
val windowSize = calculateWindowSizeClass(this)
val devicePosture by devicePostureFlow.collectAsState()
val uiState by viewModel.uiState.collectAsState()
val devicePosture by devicePostureFlow.collectAsStateWithLifecycle()
val uiState by viewModel.uiState.collectAsStateWithLifecycle()

ReplyApp(
windowSize = windowSize,
Expand Down

0 comments on commit 9dad1d8

Please sign in to comment.