Skip to content

Commit

Permalink
make effect channel flow private, provide subscribe function
Browse files Browse the repository at this point in the history
  • Loading branch information
danielyrovas committed Apr 28, 2024
1 parent 78f5464 commit 7e1e37c
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 39 deletions.
22 changes: 8 additions & 14 deletions app/src/main/java/org/yrovas/linklater/ui/screens/HomeScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
Expand All @@ -25,13 +24,12 @@ import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.PreferencesScreenDestination
import com.ramcosta.composedestinations.generated.destinations.SaveBookmarkScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import org.yrovas.linklater.show
import org.yrovas.linklater.ui.common.AppBar
import org.yrovas.linklater.ui.component.BookmarkRow
import org.yrovas.linklater.ui.common.Frame
import org.yrovas.linklater.ui.common.Icon
import org.yrovas.linklater.ui.common.RefreshIcon
import org.yrovas.linklater.ui.component.BookmarkRow
import org.yrovas.linklater.ui.state.HomeScreenState
import org.yrovas.linklater.ui.state.HomeScreenState.Effect
import org.yrovas.linklater.ui.state.HomeScreenState.Event
Expand All @@ -50,18 +48,14 @@ fun HomeScreen(
val bookmarkCount by state.bookmarkCount.collectAsState()
val listState = rememberLazyListState()

LaunchedEffect(true) {
scope.launch {
state.effect.collect { effect ->
when (effect) {
is Effect.RefreshError -> {
snackState.show(effect.error)
}
state.subscribeEffects(scope) { effect ->
when (effect) {
is Effect.RefreshError -> {
snackState.show(effect.error)
}

Effect.RefreshOk -> {
listState.animateScrollToItem(0)
}
}
Effect.RefreshOk -> {
listState.animateScrollToItem(0)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ fun SaveBookmarkActivityScreen(
nav: DestinationsNavigator,
saveBookmarkScreenState: () -> SaveBookmarkScreenState,
snackState: SnackbarHostState,
context: Context = LocalContext.current,
) {
val context: Context = LocalContext.current
val state = viewModel { saveBookmarkScreenState() }
LaunchedEffect(true) {
val url = (context as SaveBookmarkActivity).extractURL()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.interaction.MutableInteractionSource
Expand Down Expand Up @@ -78,7 +77,6 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import org.yrovas.linklater.readClipboard
import org.yrovas.linklater.show
import org.yrovas.linklater.ui.activity.launch
Expand All @@ -98,8 +96,8 @@ import kotlin.math.round
fun SaveBookmarkScreen(
nav: DestinationsNavigator,
snackState: SnackbarHostState,
context: Context = LocalContext.current,
state: () -> SaveBookmarkScreenState,
context: Context = LocalContext.current,
back: () -> Unit = { nav.popBackStack() },
onSubmitSuccess: suspend () -> Unit = {
context.launch {
Expand All @@ -109,29 +107,22 @@ fun SaveBookmarkScreen(
},
) {
@Suppress("NAME_SHADOWING") val state = viewModel { state() }

val isSubmitting by state.isSubmitting.collectAsState()
val scope = rememberCoroutineScope()
LaunchedEffect(true) {
scope.launch {
state.effect.collect { effect ->
when (effect) {
Effect.SubmitSuccess -> onSubmitSuccess()
is Effect.SubmitError -> {
snackState.show(effect.error)
}

is Effect.InvalidBookmark -> {
snackState.showSnackbar(effect.message)
}
}
var showTagRow by remember { mutableStateOf(false) }

state.subscribeEffects(scope) { effect ->
when (effect) {
Effect.SubmitSuccess -> onSubmitSuccess()
is Effect.SubmitError -> {
snackState.show(effect.error)
}
}
}

var showTagRow by remember { mutableStateOf(false) }
val onTagFocus = { b: Boolean ->
showTagRow = b
is Effect.InvalidBookmark -> {
snackState.showSnackbar(effect.message)
}
}
}

Frame(
Expand Down Expand Up @@ -159,7 +150,9 @@ fun SaveBookmarkScreen(
) {
CircularProgressIndicator()
} else {
SaveBookmarkFields(state = state, onTagFocus = onTagFocus)
SaveBookmarkFields(state = state, onTagFocus = {
showTagRow = it
})
}
}
}
Expand Down
44 changes: 42 additions & 2 deletions app/src/main/java/org/yrovas/linklater/ui/state/ScreenState.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
package org.yrovas.linklater.ui.state

import android.annotation.SuppressLint
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.repeatOnLifecycle
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

interface ScreenEvent

Expand All @@ -15,9 +24,9 @@ interface ScreenEffect
abstract class ScreenState<Event : ScreenEvent, Effect : ScreenEffect> :
ViewModel() {
private val _event: MutableSharedFlow<Event> = MutableSharedFlow()
protected val event = _event.asSharedFlow()
private val event = _event.asSharedFlow()
private val _effect: Channel<Effect> = Channel()
val effect = _effect.receiveAsFlow() // consumeAsFlow?
private val effect = _effect.receiveAsFlow() // consumeAsFlow?

private fun subscribeEvents() {
viewModelScope.launch {
Expand All @@ -42,4 +51,35 @@ abstract class ScreenState<Event : ScreenEvent, Effect : ScreenEffect> :
init {
subscribeEvents()
}

@SuppressLint("ComposableNaming")
@Composable
fun subscribeEffects(onEffect: (Effect) -> Unit) {
val lifecycleOwner = LocalLifecycleOwner.current
LaunchedEffect(effect, lifecycleOwner.lifecycle) {
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
withContext(Dispatchers.Main.immediate) {
effect.collect(onEffect)
}
}
}
}

@SuppressLint("ComposableNaming")
@Composable
fun subscribeEffects(
scope: CoroutineScope,
onEffect: suspend (Effect) -> Unit,
) {
val lifecycleOwner = LocalLifecycleOwner.current
LaunchedEffect(effect, lifecycleOwner.lifecycle) {
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
withContext(Dispatchers.Main.immediate) {
effect.collect {
scope.launch { onEffect(it) }
}
}
}
}
}
}

0 comments on commit 7e1e37c

Please sign in to comment.