Skip to content
This repository was archived by the owner on Jan 5, 2023. It is now read-only.

I followed rule of 3. #418

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion depconstraints/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -55,7 +55,7 @@ val hamcrest = "1.3"
val hilt = Versions.HILT_AGP
val junit = "4.13"
val junitExt = "1.1.1"
val lifecycle = "2.4.0-alpha01"
val lifecycle = "2.4.1"
val lottie = "3.0.0"
val material = "1.4.0-beta01"
val mockito = "3.3.1"
Original file line number Diff line number Diff line change
@@ -26,8 +26,8 @@ import androidx.lifecycle.repeatOnLifecycle
import com.google.samples.apps.iosched.ui.LaunchNavigatonAction.NavigateToMainActivityAction
import com.google.samples.apps.iosched.ui.LaunchNavigatonAction.NavigateToOnboardingAction
import com.google.samples.apps.iosched.ui.onboarding.OnboardingActivity
import com.google.samples.apps.iosched.util.collectLifecycleFlow
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

/**
@@ -41,20 +41,16 @@ class LauncherActivity : AppCompatActivity() {

val viewModel: LaunchViewModel by viewModels()

lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.launchDestination.collect { action ->
when (action) {
is NavigateToMainActivityAction -> startActivity(
Intent(this@LauncherActivity, MainActivity::class.java)
)
is NavigateToOnboardingAction -> startActivity(
Intent(this@LauncherActivity, OnboardingActivity::class.java)
)
}
finish()
}
collectLifecycleFlow(viewModel.launchDestination) { action ->
when (action) {
is NavigateToMainActivityAction -> startActivity(
Intent(this@LauncherActivity, MainActivity::class.java)
)
is NavigateToOnboardingAction -> startActivity(
Intent(this@LauncherActivity, OnboardingActivity::class.java)
)
}
finish()
}
}
}
Original file line number Diff line number Diff line change
@@ -30,9 +30,6 @@ import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
@@ -52,11 +49,10 @@ import com.google.samples.apps.iosched.ui.messages.SnackbarMessageManager
import com.google.samples.apps.iosched.ui.signin.SignInDialogFragment
import com.google.samples.apps.iosched.ui.signin.SignOutDialogFragment
import com.google.samples.apps.iosched.util.HeightTopWindowInsetsListener
import com.google.samples.apps.iosched.util.collectLifecycleFlow
import com.google.samples.apps.iosched.util.signin.FirebaseAuthErrorCodeConverter
import com.google.samples.apps.iosched.util.updateForTheme
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import timber.log.Timber
import java.util.UUID
import javax.inject.Inject
@@ -155,36 +151,20 @@ class MainActivity : AppCompatActivity(), NavigationHost {
navigateTo(requestedNavId)
}

lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
viewModel.navigationActions.collect { action ->
when (action) {
MainNavigationAction.OpenSignIn -> openSignInDialog()
MainNavigationAction.OpenSignOut -> openSignOutDialog()
}
}
}
launch {
viewModel.theme.collect { theme ->
updateForTheme(theme)
}
}
// AR-related Flows
launch {
viewModel.arCoreAvailability.collect { result ->
// Do nothing - activate flow
Timber.d("ArCoreAvailability = $result")
}
}
launch {
viewModel.pinnedSessionsJson.collect { /* Do nothing - activate flow */ }
}
launch {
viewModel.canSignedInUserDemoAr.collect { /* Do nothing - activate flow */ }
}
collectLifecycleFlow(viewModel.navigationActions) { action ->
when (action) {
MainNavigationAction.OpenSignIn -> openSignInDialog()
MainNavigationAction.OpenSignOut -> openSignOutDialog()
}
}
collectLifecycleFlow(viewModel.navigationActions) { /* Do nothing - activate flow */}
collectLifecycleFlow(viewModel.theme) { /* Do nothing - activate flow */ }
collectLifecycleFlow(viewModel.arCoreAvailability) { result ->
// Do nothing - activate flow
Timber.d("ArCoreAvailability = $result")
}
collectLifecycleFlow(viewModel.pinnedSessionsJson) { /* Do nothing - activate flow */ }
collectLifecycleFlow(viewModel.canSignedInUserDemoAr) { /* Do nothing - activate flow */ }

binding.navigationRail?.let {
ViewCompat.setOnApplyWindowInsetsListener(it) { view, insets ->
Original file line number Diff line number Diff line change
@@ -32,6 +32,7 @@ import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.RecyclerView
import com.google.samples.apps.iosched.R
import com.google.samples.apps.iosched.util.collectLifecycleFlow
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
@@ -61,12 +62,8 @@ class MapVariantSelectionDialogFragment : AppCompatDialogFragment() {
adapter = MapVariantAdapter(::selectMapVariant)
view.findViewById<RecyclerView>(R.id.map_variant_list).adapter = adapter

lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
mapViewModel.mapVariant.collect {
adapter.currentSelection = it
}
}
collectLifecycleFlow(mapViewModel.mapVariant) {
adapter.currentSelection = it
}
}

Original file line number Diff line number Diff line change
@@ -23,16 +23,12 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.samples.apps.iosched.R
import com.google.samples.apps.iosched.shared.util.inTransaction
import com.google.samples.apps.iosched.ui.signin.SignInDialogFragment
import com.google.samples.apps.iosched.util.collectLifecycleFlow
import com.google.samples.apps.iosched.util.doOnApplyWindowInsets
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

@AndroidEntryPoint
class OnboardingActivity : AppCompatActivity() {
@@ -57,13 +53,9 @@ class OnboardingActivity : AppCompatActivity() {
}
}

lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.navigationActions.collect { action ->
if (action == OnboardingNavigationAction.NavigateToSignInDialog) {
openSignInDialog()
}
}
collectLifecycleFlow(viewModel.navigationActions) { action ->
if (action == OnboardingNavigationAction.NavigateToSignInDialog) {
openSignInDialog()
}
}
}
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@ import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.samples.apps.iosched.R
import com.google.samples.apps.iosched.model.SessionId
import com.google.samples.apps.iosched.util.collectLifecycleFlow
import com.google.samples.apps.iosched.util.makeBold
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
@@ -92,17 +93,13 @@ class RemoveReservationDialogFragment : AppCompatDialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.snackbarMessages.collect {
// Using Toast instead of Snackbar as it's easier for DialogFragment
Toast.makeText(
requireContext(),
it.messageId,
if (it.longDuration) Toast.LENGTH_LONG else Toast.LENGTH_SHORT
).show()
}
}
collectLifecycleFlow(viewModel.snackbarMessages) {
// Using Toast instead of Snackbar as it's easier for DialogFragment
Toast.makeText(
requireContext(),
it.messageId,
if (it.longDuration) Toast.LENGTH_LONG else Toast.LENGTH_SHORT
).show()
}
}

Original file line number Diff line number Diff line change
@@ -22,15 +22,11 @@ import android.widget.ArrayAdapter
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDialogFragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.samples.apps.iosched.R
import com.google.samples.apps.iosched.model.Theme
import com.google.samples.apps.iosched.util.collectLifecycleFlow
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

@AndroidEntryPoint
class ThemeSettingDialogFragment : AppCompatDialogFragment() {
@@ -61,26 +57,17 @@ class ThemeSettingDialogFragment : AppCompatDialogFragment() {
super.onCreate(savedInstanceState)

// Note you don't need to use viewLifecycleOwner in DialogFragment.
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.availableThemes.collect { themes ->
listAdapter.clear()
listAdapter.addAll(
themes.map { theme ->
ThemeHolder(theme, getTitleForTheme(theme))
}
)

updateSelectedItem(viewModel.theme.value)
collectLifecycleFlow(viewModel.availableThemes) { themes ->
listAdapter.clear()
listAdapter.addAll(
themes.map { theme ->
ThemeHolder(theme, getTitleForTheme(theme))
}
}
)
updateSelectedItem(viewModel.theme.value)
}

lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.theme.collect { updateSelectedItem(it) }
}
}
collectLifecycleFlow(viewModel.theme) { updateSelectedItem(it) }
}

private fun updateSelectedItem(selected: Theme?) {
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@ import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.samples.apps.iosched.databinding.DialogSignInBinding
import com.google.samples.apps.iosched.ui.signin.SignInNavigationAction.RequestSignIn
import com.google.samples.apps.iosched.util.collectLifecycleFlow
import com.google.samples.apps.iosched.util.executeAfter
import com.google.samples.apps.iosched.util.signin.SignInHandler
import dagger.hilt.android.AndroidEntryPoint
@@ -69,17 +70,14 @@ class SignInDialogFragment : AppCompatDialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
signInViewModel.signInNavigationActions.collect { action ->
if (action == RequestSignIn) {
activity?.startActivityForResult(
signInHandler.makeSignInIntent(),
REQUEST_CODE_SIGN_IN
)
dismiss()
}
}
collectLifecycleFlow(signInViewModel.signInNavigationActions) {
action ->
if (action == RequestSignIn) {
activity?.startActivityForResult(
signInHandler.makeSignInIntent(),
REQUEST_CODE_SIGN_IN
)
dismiss()
}
}

Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.samples.apps.iosched.databinding.DialogSignOutBinding
import com.google.samples.apps.iosched.shared.data.signin.AuthenticatedUserInfo
import com.google.samples.apps.iosched.ui.signin.SignInNavigationAction.RequestSignOut
import com.google.samples.apps.iosched.util.collectLifecycleFlow
import com.google.samples.apps.iosched.util.executeAfter
import com.google.samples.apps.iosched.util.signin.SignInHandler
import dagger.hilt.android.AndroidEntryPoint
@@ -73,14 +74,10 @@ class SignOutDialogFragment : AppCompatDialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
signInViewModel.signInNavigationActions.collect { action ->
if (action == RequestSignOut) {
signInHandler.signOut(requireContext())
dismiss()
}
}
collectLifecycleFlow(signInViewModel.signInNavigationActions) { action ->
if (action == RequestSignOut) {
signInHandler.signOut(requireContext())
dismiss()
}
}

Original file line number Diff line number Diff line change
@@ -23,12 +23,8 @@ import android.content.res.TypedArray
import android.graphics.Typeface
import android.net.wifi.WifiConfiguration
import android.os.Build
import android.text.*
import android.text.Layout.Alignment
import android.text.Spannable
import android.text.SpannableString
import android.text.Spanned
import android.text.StaticLayout
import android.text.TextPaint
import android.text.style.StyleSpan
import android.util.TypedValue
import android.view.View
@@ -37,16 +33,21 @@ import androidx.annotation.ColorInt
import androidx.annotation.DimenRes
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.app.AppCompatDialogFragment
import androidx.core.content.res.ResourcesCompat
import androidx.core.os.BuildCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.databinding.ObservableBoolean
import androidx.databinding.ViewDataBinding
import androidx.drawerlayout.widget.DrawerLayout
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.fragment.app.Fragment
import androidx.lifecycle.*
import com.google.samples.apps.iosched.model.Theme
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch

fun ObservableBoolean.hasSameValue(other: ObservableBoolean) = get() == other.get()

@@ -326,3 +327,19 @@ fun Context.getColorFromTheme(colorAttributeId: Int): Int {
typedArray.recycle()
return color
}
/** to collect flow in a life cycle scope for [AppCompatActivity] * */
fun <T> AppCompatActivity.collectLifecycleFlow(flow: Flow<T>, collect: FlowCollector<T>) {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
flow.collect(collect)
}
}
}
/** to collect flow in a life cycle scope for [Fragment] * */
fun <T> Fragment.collectLifecycleFlow(flow: Flow<T>, collect: FlowCollector<T>) {
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
flow.collect(collect)
}
}
}