diff --git a/app/src/main/java/com/jacob/wakatimeapp/navigation/AppDestinations.kt b/app/src/main/java/com/jacob/wakatimeapp/navigation/AppDestinations.kt index 0e08d01c..24e2ba95 100644 --- a/app/src/main/java/com/jacob/wakatimeapp/navigation/AppDestinations.kt +++ b/app/src/main/java/com/jacob/wakatimeapp/navigation/AppDestinations.kt @@ -2,10 +2,10 @@ package com.jacob.wakatimeapp.navigation import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.Composable -import com.jacob.wakatimeapp.home.ui.HomePageContent import com.jacob.wakatimeapp.home.ui.HomePageNavigator -import com.jacob.wakatimeapp.login.ui.LoginPageContent +import com.jacob.wakatimeapp.home.ui.HomePageScreen import com.jacob.wakatimeapp.login.ui.LoginPageNavigator +import com.jacob.wakatimeapp.login.ui.LoginPageScreen import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootNavGraph @@ -13,14 +13,14 @@ import com.ramcosta.composedestinations.annotation.RootNavGraph @Destination @Composable fun LoginPage(loginPageNavigator: LoginPageNavigator, scaffoldState: SnackbarHostState) = - LoginPageContent(loginPageNavigator = loginPageNavigator, snackbarHostState = scaffoldState) + LoginPageScreen(loginPageNavigator = loginPageNavigator, snackbarHostState = scaffoldState) @Composable @Destination fun HomePage( homePageNavigator: HomePageNavigator, scaffoldState: SnackbarHostState, -) = HomePageContent( +) = HomePageScreen( navigator = homePageNavigator, snackbarHostState = scaffoldState ) diff --git a/home/src/main/java/com/jacob/wakatimeapp/home/domain/models/HomePageUiData.kt b/home/src/main/java/com/jacob/wakatimeapp/home/domain/models/HomePageUiData.kt index 98a5086a..a97c21e1 100644 --- a/home/src/main/java/com/jacob/wakatimeapp/home/domain/models/HomePageUiData.kt +++ b/home/src/main/java/com/jacob/wakatimeapp/home/domain/models/HomePageUiData.kt @@ -2,6 +2,7 @@ package com.jacob.wakatimeapp.home.domain.models import com.jacob.wakatimeapp.core.models.Project import com.jacob.wakatimeapp.core.models.Time +import com.jacob.wakatimeapp.core.models.UserDetails import com.jacob.wakatimeapp.core.models.WeeklyStats import kotlinx.datetime.LocalDate import kotlinx.serialization.Serializable @@ -14,13 +15,17 @@ data class HomePageUiData( val mostUsedLanguage: String, val mostUsedEditor: String, val mostUsedOs: String, + val photoUrl: String, + val fullName: String, ) -fun WeeklyStats.toLoadedStateData() = HomePageUiData( +fun WeeklyStats.toLoadedStateData(userDetails: UserDetails) = HomePageUiData( timeSpentToday = todaysStats.timeSpent, projectsWorkedOn = todaysStats.projectsWorkedOn, weeklyTimeSpent = dailyStats.associate { it.date to it.timeSpent }, mostUsedLanguage = todaysStats.mostUsedLanguage, mostUsedEditor = todaysStats.mostUsedEditor, mostUsedOs = todaysStats.mostUsedOs, + photoUrl = userDetails.photoUrl, + fullName = userDetails.fullName, ) diff --git a/home/src/main/java/com/jacob/wakatimeapp/home/domain/usecases/GetLast7DaysStatsUC.kt b/home/src/main/java/com/jacob/wakatimeapp/home/domain/usecases/GetLast7DaysStatsUC.kt index 084ddb8d..17208db1 100644 --- a/home/src/main/java/com/jacob/wakatimeapp/home/domain/usecases/GetLast7DaysStatsUC.kt +++ b/home/src/main/java/com/jacob/wakatimeapp/home/domain/usecases/GetLast7DaysStatsUC.kt @@ -2,7 +2,7 @@ package com.jacob.wakatimeapp.home.domain.usecases import arrow.core.left import com.jacob.wakatimeapp.core.models.Error -import com.jacob.wakatimeapp.core.models.WeeklyStats +import com.jacob.wakatimeapp.core.models.UserDetails import com.jacob.wakatimeapp.home.data.local.HomePageCache import com.jacob.wakatimeapp.home.data.network.HomePageNetworkData import com.jacob.wakatimeapp.home.domain.InstantProvider @@ -31,19 +31,22 @@ class GetLast7DaysStatsUC @Inject constructor( ) { private val ioScope = CoroutineScope(dispatcher) - operator fun invoke(cacheValidity: CacheValidity = INVALID) = channelFlow { - val lastRequestTime = homePageCache.getLastRequestTime() + operator fun invoke(userDetails: UserDetails, cacheValidity: CacheValidity = INVALID) = + channelFlow { + val lastRequestTime = homePageCache.getLastRequestTime() - when { - firstRequestOfDay(lastRequestTime) -> makeRequestAndUpdateCache()?.let { send(it) } - !validDataInCache( - lastRequestTime, - cacheValidity - ) -> launch { makeRequestAndUpdateCache()?.let { send(it) } } - } + when { + firstRequestOfDay(lastRequestTime) -> + makeRequestAndUpdateCache(userDetails)?.let { send(it) } - dataFromCache().collect { send(it) } - } + !validDataInCache( + lastRequestTime, + cacheValidity + ) -> launch { makeRequestAndUpdateCache(userDetails)?.let { send(it) } } + } + + dataFromCache().collect { send(it) } + } private fun dataFromCache() = homePageCache.getCachedData() .catch { throwable -> @@ -57,10 +60,11 @@ class GetLast7DaysStatsUC @Inject constructor( * * Returns an [Either.Left] if any errors happened. */ - private suspend fun makeRequestAndUpdateCache() = homePageNetworkData.getLast7DaysStats() - .map(WeeklyStats::toLoadedStateData) - .tap { it.updateCaches() } - .fold(ifLeft = Error::left, ifRight = { null }) + private suspend fun makeRequestAndUpdateCache(userDetails: UserDetails) = + homePageNetworkData.getLast7DaysStats() + .map { it.toLoadedStateData(userDetails) } + .tap { it.updateCaches() } + .fold(ifLeft = Error::left, ifRight = { null }) private suspend fun HomePageUiData.updateCaches() { listOf( diff --git a/home/src/main/java/com/jacob/wakatimeapp/home/ui/HomePageContent.kt b/home/src/main/java/com/jacob/wakatimeapp/home/ui/HomePageScreen.kt similarity index 64% rename from home/src/main/java/com/jacob/wakatimeapp/home/ui/HomePageContent.kt rename to home/src/main/java/com/jacob/wakatimeapp/home/ui/HomePageScreen.kt index ab57d4c1..53a3b894 100644 --- a/home/src/main/java/com/jacob/wakatimeapp/home/ui/HomePageContent.kt +++ b/home/src/main/java/com/jacob/wakatimeapp/home/ui/HomePageScreen.kt @@ -1,5 +1,6 @@ package com.jacob.wakatimeapp.home.ui +import android.content.res.Configuration import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height @@ -16,21 +17,27 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider import androidx.hilt.navigation.compose.hiltViewModel +import com.jacob.wakatimeapp.core.models.Error +import com.jacob.wakatimeapp.core.models.Time import com.jacob.wakatimeapp.core.ui.components.WtaAnimation import com.jacob.wakatimeapp.core.ui.components.cards.TimeSpentCard +import com.jacob.wakatimeapp.core.ui.theme.WakaTimeAppTheme import com.jacob.wakatimeapp.core.ui.theme.assets import com.jacob.wakatimeapp.core.ui.theme.gradients import com.jacob.wakatimeapp.core.ui.theme.spacing +import com.jacob.wakatimeapp.home.domain.models.HomePageUiData import com.jacob.wakatimeapp.home.ui.components.OtherDailyStatsSection import com.jacob.wakatimeapp.home.ui.components.RecentProjects import com.jacob.wakatimeapp.home.ui.components.UserDetailsSection import com.jacob.wakatimeapp.home.ui.components.WeeklyReport import kotlinx.coroutines.launch -import timber.log.Timber @Composable -fun HomePageContent( +fun HomePageScreen( navigator: HomePageNavigator, snackbarHostState: SnackbarHostState, modifier: Modifier = Modifier, @@ -40,13 +47,9 @@ fun HomePageContent( val viewState by viewModel.homePageState.collectAsState() LaunchedEffect(viewState) { - Timber.d(viewState.toString()) if (viewState !is HomePageViewState.Error) return@LaunchedEffect val viewStateError = viewState as HomePageViewState.Error - Timber.e(viewStateError.error.message) - Timber.e(viewStateError.error.exception) - snackBarCoroutineScope.launch { snackbarHostState.showSnackbar( message = viewStateError.error.message, @@ -55,15 +58,28 @@ fun HomePageContent( } } + HomePageContent( + viewState = viewState, + toDetailsPage = navigator::toDetailsPage, + modifier = modifier + ) +} + +@Composable +private fun HomePageContent( + viewState: HomePageViewState, + toDetailsPage: () -> Unit, + modifier: Modifier = Modifier, +) { Column(modifier = modifier.statusBarsPadding()) { - when (val viewSateInstance = viewState) { + when (viewState) { is HomePageViewState.Loading -> HomePageLoading() is HomePageViewState.Loaded -> HomePageLoaded( - homePageViewState = viewSateInstance, - navigator = navigator + homePageViewState = viewState, + toDetailsPage = toDetailsPage, ) - is HomePageViewState.Error -> HomePageError(viewSateInstance) + is HomePageViewState.Error -> HomePageError(viewState) } } } @@ -71,7 +87,7 @@ fun HomePageContent( @Composable private fun HomePageLoaded( homePageViewState: HomePageViewState.Loaded, - navigator: HomePageNavigator, + toDetailsPage: () -> Unit, ) { val scrollState = rememberScrollState() val spacing = MaterialTheme.spacing @@ -81,7 +97,10 @@ private fun HomePageLoaded( .padding(horizontal = spacing.medium) .verticalScroll(scrollState) ) { - UserDetailsSection(homePageViewState.userDetails) + UserDetailsSection( + fullName = homePageViewState.contentData.photoUrl, + photoUrl = homePageViewState.contentData.fullName + ) TimeSpentCard( gradient = MaterialTheme.gradients.primary, @@ -89,7 +108,7 @@ private fun HomePageLoaded( iconId = icons.time, mainText = "Total Time Spent Today", time = homePageViewState.contentData.timeSpentToday, - onClick = navigator::toDetailsPage + onClick = toDetailsPage ) Spacer(modifier = Modifier.height(spacing.small)) @@ -122,3 +141,41 @@ private fun HomePageLoading() = WtaAnimation( text = "Loading..", animationTestTag = HomePageTestTags.LOADING_ANIMATION_ILLUSTRATION ) + +@Preview( + apiLevel = 31, + showSystemUi = true, + showBackground = true, + uiMode = Configuration.UI_MODE_NIGHT_NO or Configuration.UI_MODE_TYPE_NORMAL, +) +@Preview( + apiLevel = 31, + showSystemUi = true, + showBackground = true, + uiMode = Configuration.UI_MODE_NIGHT_YES +) +@Composable +fun HomePagePreview( + @PreviewParameter(HomePagePreviewProvider::class) viewState: HomePageViewState, +) = WakaTimeAppTheme { + HomePageContent(viewState = viewState, toDetailsPage = { }) +} + +class HomePagePreviewProvider : CollectionPreviewParameterProvider( + listOf( + HomePageViewState.Loading, + HomePageViewState.Error(Error.UnknownError("Something went wrong")), + HomePageViewState.Loaded( + contentData = HomePageUiData( + timeSpentToday = Time.ZERO, + projectsWorkedOn = listOf(), + weeklyTimeSpent = mapOf(), + mostUsedLanguage = "", + mostUsedEditor = "", + mostUsedOs = "", + photoUrl = "", + fullName = "", + ) + ), + ) +) diff --git a/home/src/main/java/com/jacob/wakatimeapp/home/ui/HomePageViewModel.kt b/home/src/main/java/com/jacob/wakatimeapp/home/ui/HomePageViewModel.kt index 3533c1e2..274feb04 100644 --- a/home/src/main/java/com/jacob/wakatimeapp/home/ui/HomePageViewModel.kt +++ b/home/src/main/java/com/jacob/wakatimeapp/home/ui/HomePageViewModel.kt @@ -12,8 +12,8 @@ import javax.inject.Inject import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch @HiltViewModel @@ -32,18 +32,14 @@ class HomePageViewModel @Inject constructor( init { viewModelScope.launch(ioDispatcher) { - combine( - getLast7DaysStatsUC(), - userDetailsFlow, - ) { either, userDetails -> - when (either) { - is Left -> HomePageViewState.Error(either.value) + getLast7DaysStatsUC(userDetailsFlow.first()).collect { + _homePageState.value = when (it) { + is Left -> HomePageViewState.Error(it.value) is Right -> HomePageViewState.Loaded( - contentData = either.value, - userDetails = userDetails + contentData = it.value, ) } - }.collect { _homePageState.value = it } + } } } } diff --git a/home/src/main/java/com/jacob/wakatimeapp/home/ui/HomePageViewState.kt b/home/src/main/java/com/jacob/wakatimeapp/home/ui/HomePageViewState.kt index 1e9901d9..777fa393 100644 --- a/home/src/main/java/com/jacob/wakatimeapp/home/ui/HomePageViewState.kt +++ b/home/src/main/java/com/jacob/wakatimeapp/home/ui/HomePageViewState.kt @@ -1,13 +1,11 @@ package com.jacob.wakatimeapp.home.ui import com.jacob.wakatimeapp.core.models.Error as CoreModelsError -import com.jacob.wakatimeapp.core.models.UserDetails import com.jacob.wakatimeapp.home.domain.models.HomePageUiData sealed class HomePageViewState { data class Loaded( val contentData: HomePageUiData, - val userDetails: UserDetails?, ) : HomePageViewState() data class Error(val error: CoreModelsError) : HomePageViewState() diff --git a/home/src/main/java/com/jacob/wakatimeapp/home/ui/components/UserDetailsSection.kt b/home/src/main/java/com/jacob/wakatimeapp/home/ui/components/UserDetailsSection.kt index cd5ac4f1..cf1a1e92 100644 --- a/home/src/main/java/com/jacob/wakatimeapp/home/ui/components/UserDetailsSection.kt +++ b/home/src/main/java/com/jacob/wakatimeapp/home/ui/components/UserDetailsSection.kt @@ -20,7 +20,6 @@ import androidx.compose.ui.unit.sp import coil.compose.rememberAsyncImagePainter import coil.request.ImageRequest.Builder import coil.transform.CircleCropTransformation -import com.jacob.wakatimeapp.core.models.UserDetails import com.jacob.wakatimeapp.core.ui.theme.WakaTimeAppTheme import com.jacob.wakatimeapp.core.ui.theme.assets import com.jacob.wakatimeapp.core.ui.theme.pageTitle @@ -28,7 +27,8 @@ import com.jacob.wakatimeapp.core.ui.theme.spacing @Composable fun UserDetailsSection( - userDetails: UserDetails?, + fullName: String, + photoUrl: String, modifier: Modifier = Modifier, ) = Row( horizontalArrangement = Arrangement.spacedBy(MaterialTheme.spacing.medium), @@ -37,7 +37,7 @@ fun UserDetailsSection( ) { Image( painter = rememberAsyncImagePainter( - Builder(LocalContext.current).data(data = userDetails?.photoUrl) + Builder(LocalContext.current).data(data = photoUrl) .apply { val icons = MaterialTheme.assets.icons transformations(CircleCropTransformation()) @@ -50,7 +50,7 @@ fun UserDetailsSection( modifier = Modifier.size(58.dp) ) Text( - text = userDetails?.fullName.orEmpty(), + text = fullName, style = MaterialTheme.typography.pageTitle.copy( fontSize = 50.sp, baselineShift = BaselineShift(multiplier = 0.3f), @@ -64,20 +64,7 @@ fun UserDetailsSection( @Composable private fun UserDetailsPreview() = WakaTimeAppTheme { UserDetailsSection( - UserDetails( - bio = "", - email = "", - id = "", - timeout = 0, - timezone = "", - username = "", - displayName = "", - lastProject = "", - fullName = "Jacob Bosco", - durationsSliceBy = "", - createdAt = "", - dateFormat = "", - photoUrl = "" - ) + fullName = "", + photoUrl = "", ) } diff --git a/home/src/test/java/com/jacob/wakatimeapp/home/domain/usecases/GetLast7DaysStatsUCRobot.kt b/home/src/test/java/com/jacob/wakatimeapp/home/domain/usecases/GetLast7DaysStatsUCRobot.kt index 68e2ea62..381a525e 100644 --- a/home/src/test/java/com/jacob/wakatimeapp/home/domain/usecases/GetLast7DaysStatsUCRobot.kt +++ b/home/src/test/java/com/jacob/wakatimeapp/home/domain/usecases/GetLast7DaysStatsUCRobot.kt @@ -6,6 +6,7 @@ import com.jacob.wakatimeapp.core.models.DailyStats import com.jacob.wakatimeapp.core.models.Error import com.jacob.wakatimeapp.core.models.StatsRange import com.jacob.wakatimeapp.core.models.Time +import com.jacob.wakatimeapp.core.models.UserDetails import com.jacob.wakatimeapp.core.models.WeeklyStats import com.jacob.wakatimeapp.home.data.local.HomePageCache import com.jacob.wakatimeapp.home.data.network.HomePageNetworkData @@ -55,7 +56,7 @@ internal class GetLast7DaysStatsUCRobot { } suspend fun callUseCase() = apply { - useCase(DEFAULT).toList(results) + useCase(userDetails, DEFAULT).toList(results) } fun resultSizeShouldBe(size: Int = 1) = apply { @@ -118,13 +119,31 @@ internal class GetLast7DaysStatsUCRobot { private val todaysDate = LocalDate(2022, 10, 10) + private val userDetails = UserDetails( + bio = "", + email = "", + id = "", + timeout = 0, + timezone = "", + username = "", + displayName = "", + lastProject = "", + fullName = "", + durationsSliceBy = "", + createdAt = "", + dateFormat = "", + photoUrl = "" + ) + val homePageUiData = HomePageUiData( timeSpentToday = Time.ZERO, projectsWorkedOn = listOf(), weeklyTimeSpent = mapOf(), mostUsedLanguage = "", mostUsedEditor = "", - mostUsedOs = "" + mostUsedOs = "", + photoUrl = "", + fullName = "" ) val weeklyStats = WeeklyStats( diff --git a/home/src/test/java/com/jacob/wakatimeapp/home/usecases/GetLast7DaysStatsUCTest.kt b/home/src/test/java/com/jacob/wakatimeapp/home/domain/usecases/GetLast7DaysStatsUCTest.kt similarity index 97% rename from home/src/test/java/com/jacob/wakatimeapp/home/usecases/GetLast7DaysStatsUCTest.kt rename to home/src/test/java/com/jacob/wakatimeapp/home/domain/usecases/GetLast7DaysStatsUCTest.kt index d0bc7738..c13e8ab3 100644 --- a/home/src/test/java/com/jacob/wakatimeapp/home/usecases/GetLast7DaysStatsUCTest.kt +++ b/home/src/test/java/com/jacob/wakatimeapp/home/domain/usecases/GetLast7DaysStatsUCTest.kt @@ -1,10 +1,9 @@ -package com.jacob.wakatimeapp.home.usecases +package com.jacob.wakatimeapp.home.domain.usecases import arrow.core.left import arrow.core.right import com.jacob.wakatimeapp.core.models.Error.UnknownError import com.jacob.wakatimeapp.home.domain.InstantProvider -import com.jacob.wakatimeapp.home.domain.usecases.GetLast7DaysStatsUCRobot import com.jacob.wakatimeapp.home.domain.usecases.GetLast7DaysStatsUCRobot.Companion.homePageUiData import com.jacob.wakatimeapp.home.domain.usecases.GetLast7DaysStatsUCRobot.Companion.invalidDataInstant import com.jacob.wakatimeapp.home.domain.usecases.GetLast7DaysStatsUCRobot.Companion.previousDay diff --git a/login/src/main/java/com/jacob/wakatimeapp/login/ui/LoginPageContent.kt b/login/src/main/java/com/jacob/wakatimeapp/login/ui/LoginPageScreen.kt similarity index 73% rename from login/src/main/java/com/jacob/wakatimeapp/login/ui/LoginPageContent.kt rename to login/src/main/java/com/jacob/wakatimeapp/login/ui/LoginPageScreen.kt index f3de7469..c00a5fe2 100644 --- a/login/src/main/java/com/jacob/wakatimeapp/login/ui/LoginPageContent.kt +++ b/login/src/main/java/com/jacob/wakatimeapp/login/ui/LoginPageScreen.kt @@ -1,7 +1,7 @@ package com.jacob.wakatimeapp.login.ui import android.content.Intent -import android.content.res.Configuration.UI_MODE_NIGHT_YES +import android.content.res.Configuration import androidx.activity.compose.ManagedActivityResultLauncher import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.ActivityResult @@ -35,6 +35,8 @@ import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.jacob.wakatimeapp.core.ui.modifiers.gesturesDisabled @@ -47,7 +49,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @Composable -fun LoginPageContent( +fun LoginPageScreen( loginPageNavigator: LoginPageNavigator, snackbarHostState: SnackbarHostState, modifier: Modifier = Modifier, @@ -72,23 +74,43 @@ fun LoginPageContent( } } - val launcher = authActivityResultLauncher(viewModel) + LoginPageContent( + viewState = viewState, + getLoginAuthIntent = viewModel::getAuthIntent, + authDataNotFound = viewModel::authDataNotFound, + exchangeToken = viewModel::exchangeToken + ) +} + +@Composable +private fun LoginPageContent( + viewState: LoginPageState, + getLoginAuthIntent: () -> Intent?, + authDataNotFound: (Intent) -> Unit, + exchangeToken: (Intent) -> Unit, +) { + val launcher = authActivityResultLauncher( + authDataNotFound = authDataNotFound, + exchangeToken = exchangeToken + ) when (viewState) { is LoginPageState.Idle, is LoginPageState.Error -> LoginPageIdleState( - viewModel, + getLoginAuthIntent = getLoginAuthIntent, launcher = launcher ) is LoginPageState.Loading -> Box( - modifier = Modifier.fillMaxSize() + modifier = Modifier + .fillMaxSize() .gesturesDisabled() ) { CircularProgressIndicator( - modifier = Modifier.align(Alignment.Center) + modifier = Modifier + .align(Alignment.Center) .size(60.dp), ) - LoginPageIdleState(viewModel, launcher = launcher) + LoginPageIdleState(getLoginAuthIntent = getLoginAuthIntent, launcher = launcher) } else -> Unit @@ -108,9 +130,9 @@ private fun showSnackBar( @Composable private fun LoginPageIdleState( - viewModel: LoginPageViewModel, modifier: Modifier = Modifier, launcher: ManagedActivityResultLauncher, + getLoginAuthIntent: () -> Intent?, ) { val spacing = MaterialTheme.spacing @@ -124,7 +146,7 @@ private fun LoginPageIdleState( .padding(horizontal = spacing.small) ) { AppTitle() - LoginButton(onClick = { launcher.launch(viewModel.getAuthIntent()) }) + LoginButton(onClick = { launcher.launch(getLoginAuthIntent()) }) } } @@ -135,14 +157,17 @@ private fun AppTitle() = Text( ) @Composable -private fun authActivityResultLauncher(viewModel: LoginPageViewModel) = +private fun authActivityResultLauncher( + authDataNotFound: (Intent) -> Unit, + exchangeToken: (Intent) -> Unit, +) = rememberLauncherForActivityResult(StartActivityForResult()) { result -> val data = result.data if (data == null) { - viewModel.authDataNotFound(result.data!!) + authDataNotFound(result.data!!) return@rememberLauncherForActivityResult } - data.let(viewModel::exchangeToken) + data.let(exchangeToken) } @Composable @@ -183,10 +208,34 @@ private fun LoginButton( } } -@Preview(showBackground = true, uiMode = UI_MODE_NIGHT_YES) +@Preview( + apiLevel = 31, + showSystemUi = true, + showBackground = true, + uiMode = Configuration.UI_MODE_NIGHT_NO or Configuration.UI_MODE_TYPE_NORMAL, +) +@Preview( + apiLevel = 31, + showSystemUi = true, + showBackground = true, + uiMode = Configuration.UI_MODE_NIGHT_YES +) @Composable -private fun LoginButtonPreview() = WakaTimeAppTheme { LoginButton {} } +private fun LoginPagePreview( + @PreviewParameter(LoginPagePreviewProvider::class) state: LoginPageState, +) = WakaTimeAppTheme { + LoginPageContent( + viewState = state, + getLoginAuthIntent = { null }, + authDataNotFound = {}, + exchangeToken = {} + ) +} -@Preview(showBackground = true) -@Composable -private fun LoginButtonPreview2() = WakaTimeAppTheme { LoginButton {} } +class LoginPagePreviewProvider : PreviewParameterProvider { + override val values = sequenceOf( + LoginPageState.Idle, + LoginPageState.Loading, + LoginPageState.Error("Error"), + ) +}