Address review feedback from Manu

pull/330/head
Don Turner 2 years ago
parent 0d5dd944ea
commit 76daa393b1

@ -206,7 +206,6 @@ class NavigationTest {
@Test @Test
fun whenSettingsDialogDismissed_previousScreenIsDisplayed() { fun whenSettingsDialogDismissed_previousScreenIsDisplayed() {
composeTestRule.apply { composeTestRule.apply {
// Navigate to the saved screen, open the settings dialog, then close it. // Navigate to the saved screen, open the settings dialog, then close it.

@ -30,19 +30,14 @@ import androidx.navigation.compose.ComposeNavigator
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.createGraph import androidx.navigation.createGraph
import androidx.navigation.testing.TestNavHostController import androidx.navigation.testing.TestNavHostController
import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule
import com.google.samples.apps.nowinandroid.core.testing.util.TestNetworkMonitor import com.google.samples.apps.nowinandroid.core.testing.util.TestNetworkMonitor
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -55,31 +50,15 @@ import org.junit.Test
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class) @OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
class NiaAppStateTest { class NiaAppStateTest {
@get:Rule
val mainDispatcherRule = MainDispatcherRule()
@get:Rule @get:Rule
val composeTestRule = createComposeRule() val composeTestRule = createComposeRule()
// Create the test dependencies. // Create the test dependencies.
private lateinit var testScope: TestScope
private val networkMonitor = TestNetworkMonitor() private val networkMonitor = TestNetworkMonitor()
// Subject under test. // Subject under test.
private lateinit var state: NiaAppState private lateinit var state: NiaAppState
@Before
fun setup() {
// We use the Unconfined dispatcher to ensure that coroutines are executed sequentially in
// tests.
testScope = TestScope(UnconfinedTestDispatcher())
}
@After
fun cleanup() {
testScope.cancel()
}
@Test @Test
fun niaAppState_currentDestination() = runTest { fun niaAppState_currentDestination() = runTest {
var currentDestination: String? = null var currentDestination: String? = null
@ -91,7 +70,7 @@ class NiaAppStateTest {
windowSizeClass = getCompactWindowClass(), windowSizeClass = getCompactWindowClass(),
navController = navController, navController = navController,
networkMonitor = networkMonitor, networkMonitor = networkMonitor,
coroutineScope = testScope coroutineScope = backgroundScope
) )
} }
@ -122,20 +101,6 @@ class NiaAppStateTest {
assertTrue(state.topLevelDestinations[2].name.contains("interests", true)) assertTrue(state.topLevelDestinations[2].name.contains("interests", true))
} }
@Test
fun niaAppState_showTopBarForTopLevelDestinations() {
composeTestRule.setContent {
val navController = rememberTestNavController()
state = rememberNiaAppState(
windowSizeClass = getCompactWindowClass(),
navController = navController,
networkMonitor = networkMonitor
)
// Do nothing - we should already be
}
}
@Test @Test
fun niaAppState_showBottomBar_compact() = runTest { fun niaAppState_showBottomBar_compact() = runTest {
composeTestRule.setContent { composeTestRule.setContent {
@ -143,7 +108,7 @@ class NiaAppStateTest {
windowSizeClass = getCompactWindowClass(), windowSizeClass = getCompactWindowClass(),
navController = NavHostController(LocalContext.current), navController = NavHostController(LocalContext.current),
networkMonitor = networkMonitor, networkMonitor = networkMonitor,
coroutineScope = testScope coroutineScope = backgroundScope
) )
} }
@ -158,7 +123,7 @@ class NiaAppStateTest {
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(800.dp, 800.dp)), windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(800.dp, 800.dp)),
navController = NavHostController(LocalContext.current), navController = NavHostController(LocalContext.current),
networkMonitor = networkMonitor, networkMonitor = networkMonitor,
coroutineScope = testScope coroutineScope = backgroundScope
) )
} }
@ -174,7 +139,7 @@ class NiaAppStateTest {
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(900.dp, 1200.dp)), windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(900.dp, 1200.dp)),
navController = NavHostController(LocalContext.current), navController = NavHostController(LocalContext.current),
networkMonitor = networkMonitor, networkMonitor = networkMonitor,
coroutineScope = testScope coroutineScope = backgroundScope
) )
} }
@ -183,27 +148,23 @@ class NiaAppStateTest {
} }
@Test @Test
fun stateIsOfflineWhenNetworkMonitorIsOffline() = runTest { fun stateIsOfflineWhenNetworkMonitorIsOffline() = runTest(UnconfinedTestDispatcher()) {
composeTestRule.setContent { composeTestRule.setContent {
state = NiaAppState( state = NiaAppState(
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(900.dp, 1200.dp)), windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(900.dp, 1200.dp)),
navController = NavHostController(LocalContext.current), navController = NavHostController(LocalContext.current),
networkMonitor = networkMonitor, networkMonitor = networkMonitor,
coroutineScope = testScope coroutineScope = backgroundScope
) )
} }
val collectJob = testScope.launch { state.isOffline.collect() } backgroundScope.launch { state.isOffline.collect() }
networkMonitor.setConnected(false) networkMonitor.setConnected(false)
assertEquals( assertEquals(
true, true,
state.isOffline.value state.isOffline.value
) )
collectJob.cancel()
} }
private fun getCompactWindowClass() = WindowSizeClass.calculateFromSize(DpSize(500.dp, 300.dp)) private fun getCompactWindowClass() = WindowSizeClass.calculateFromSize(DpSize(500.dp, 300.dp))

@ -70,7 +70,8 @@ import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination
@OptIn( @OptIn(
ExperimentalMaterial3Api::class, ExperimentalMaterial3Api::class,
ExperimentalLayoutApi::class, ExperimentalLayoutApi::class,
ExperimentalComposeUiApi::class, ExperimentalLifecycleComposeApi::class ExperimentalComposeUiApi::class,
ExperimentalLifecycleComposeApi::class
) )
@Composable @Composable
fun NiaApp( fun NiaApp(
@ -101,11 +102,10 @@ fun NiaApp(
snackbarHost = { SnackbarHost(snackbarHostState) }, snackbarHost = { SnackbarHost(snackbarHostState) },
topBar = { topBar = {
// Show the top app bar on top level destinations. // Show the top app bar on top level destinations.
val topLevelDestination = val destination = appState.currentTopLevelDestination
appState.topLevelDestinations[appState.currentDestination?.route] if (destination != null) {
if (topLevelDestination != null) {
NiaTopAppBar( NiaTopAppBar(
titleRes = topLevelDestination.titleTextId, titleRes = destination.titleTextId,
actionIcon = NiaIcons.Settings, actionIcon = NiaIcons.Settings,
actionIconContentDescription = stringResource( actionIconContentDescription = stringResource(
id = settingsR.string.top_app_bar_action_icon_description id = settingsR.string.top_app_bar_action_icon_description
@ -113,7 +113,7 @@ fun NiaApp(
colors = TopAppBarDefaults.centerAlignedTopAppBarColors( colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
containerColor = Color.Transparent containerColor = Color.Transparent
), ),
onActionClick = { appState.toggleSettingsDialog(true) } onActionClick = { appState.setShowSettingsDialog(true) }
) )
} }
}, },
@ -141,7 +141,7 @@ fun NiaApp(
if (appState.shouldShowSettingsDialog) { if (appState.shouldShowSettingsDialog) {
SettingsDialog( SettingsDialog(
onDismiss = { appState.toggleSettingsDialog(false) } onDismiss = { appState.setShowSettingsDialog(false) }
) )
} }

@ -76,9 +76,11 @@ class NiaAppState(
@Composable get() = navController @Composable get() = navController
.currentBackStackEntryAsState().value?.destination .currentBackStackEntryAsState().value?.destination
private var _shouldShowSettingsDialog by mutableStateOf(false) val currentTopLevelDestination: TopLevelDestination?
val shouldShowSettingsDialog @Composable get() = topLevelDestinations[currentDestination?.route]
get() = _shouldShowSettingsDialog
var shouldShowSettingsDialog by mutableStateOf(false)
private set
val shouldShowBottomBar: Boolean val shouldShowBottomBar: Boolean
get() = windowSizeClass.widthSizeClass == WindowWidthSizeClass.Compact || get() = windowSizeClass.widthSizeClass == WindowWidthSizeClass.Compact ||
@ -136,8 +138,8 @@ class NiaAppState(
navController.popBackStack() navController.popBackStack()
} }
fun toggleSettingsDialog(shouldShow: Boolean) { fun setShowSettingsDialog(shouldShow: Boolean) {
_shouldShowSettingsDialog = shouldShow shouldShowSettingsDialog = shouldShow
} }
} }

@ -32,9 +32,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import com.google.samples.apps.nowinandroid.core.designsystem.R
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable

@ -18,5 +18,4 @@
<string name="follow">Follow</string> <string name="follow">Follow</string>
<string name="unfollow">Unfollow</string> <string name="unfollow">Unfollow</string>
<string name="browse_topic">Browse topic</string> <string name="browse_topic">Browse topic</string>
<string name="screen_title">Screen title</string>
</resources> </resources>

@ -33,7 +33,7 @@ import kotlinx.coroutines.launch
@HiltViewModel @HiltViewModel
class SettingsViewModel @Inject constructor( class SettingsViewModel @Inject constructor(
private val userDataRepository: UserDataRepository private val userDataRepository: UserDataRepository,
) : ViewModel() { ) : ViewModel() {
val settingsUiState: StateFlow<SettingsUiState> = val settingsUiState: StateFlow<SettingsUiState> =
userDataRepository.userDataStream userDataRepository.userDataStream

Loading…
Cancel
Save