diff --git a/.DS_Store b/.DS_Store index da07aa68..9042e813 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/app/src/main/java/com/cornellappdev/uplift/ui/MainNavigationWrapper.kt b/app/src/main/java/com/cornellappdev/uplift/ui/MainNavigationWrapper.kt index ab6ac345..e28b00bf 100644 --- a/app/src/main/java/com/cornellappdev/uplift/ui/MainNavigationWrapper.kt +++ b/app/src/main/java/com/cornellappdev/uplift/ui/MainNavigationWrapper.kt @@ -40,6 +40,7 @@ import com.cornellappdev.uplift.ui.screens.classes.ClassDetailScreen import com.cornellappdev.uplift.ui.screens.classes.ClassScreen import com.cornellappdev.uplift.ui.screens.gyms.GymDetailScreen import com.cornellappdev.uplift.ui.screens.gyms.HomeScreen +import com.cornellappdev.uplift.ui.screens.onboarding.GoalPromptScreen import com.cornellappdev.uplift.ui.screens.onboarding.ProfileCreationScreen import com.cornellappdev.uplift.ui.screens.onboarding.SignInPromptScreen import com.cornellappdev.uplift.ui.screens.profile.ProfileScreen @@ -237,6 +238,9 @@ fun MainNavigationWrapper( composable { ProfileCreationScreen() } + composable { + GoalPromptScreen() + } composable { CapacityReminderScreen() } @@ -329,6 +333,10 @@ sealed class UpliftRootRoute { @Serializable data object Profile : UpliftRootRoute() + @Serializable + data object GoalsPrompt : UpliftRootRoute() + + @Serializable data object CapacityReminders : UpliftRootRoute() diff --git a/app/src/main/java/com/cornellappdev/uplift/ui/screens/onboarding/GoalsPromptScreen.kt b/app/src/main/java/com/cornellappdev/uplift/ui/screens/onboarding/GoalsPromptScreen.kt new file mode 100644 index 00000000..bd736592 --- /dev/null +++ b/app/src/main/java/com/cornellappdev/uplift/ui/screens/onboarding/GoalsPromptScreen.kt @@ -0,0 +1,118 @@ +package com.cornellappdev.uplift.ui.screens.onboarding + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.credentials.Credential +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.cornellappdev.uplift.ui.components.goalsetting.GoalSlider +import com.cornellappdev.uplift.ui.components.onboarding.auth.LogInButton +import com.cornellappdev.uplift.ui.viewmodels.onboarding.GoalsPromptViewModel +import com.cornellappdev.uplift.util.GRAY01 +import com.cornellappdev.uplift.util.montserratFamily + +/** + * @param goalValue: value of the goal slider + * @param onGoalValueChange: callback for when the goal slider value is changed + * @return GoalPromptScreen composable + */ +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun GoalPromptScreen( + viewModel: GoalsPromptViewModel = hiltViewModel(), +) { + + val currentGoal by viewModel.goalValue.collectAsStateWithLifecycle() + + Scaffold( + topBar = { + TopAppBar( + title = { + Box( + modifier = Modifier.fillMaxHeight(), + contentAlignment = Alignment.BottomStart + ) { + Text( + text = "Set your goals.", + fontSize = 24.sp, + fontFamily = montserratFamily, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(bottom = 16.dp) + ) + } + }, + modifier = Modifier + .height(120.dp) + .shadow(elevation = 20.dp, ambientColor = GRAY01), + colors = TopAppBarDefaults.topAppBarColors( + containerColor = Color.White, + ) + ) + }, + modifier = Modifier.fillMaxSize(), + ) { padding -> + Column( + modifier = Modifier + .padding(padding) + .fillMaxSize() + .background(color = Color.White), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .weight(1f) + .verticalScroll(rememberScrollState()), + horizontalAlignment = Alignment.CenterHorizontally + ) { + GoalSlider(value = currentGoal, onValueChange = { viewModel.onGoalValueChange(it) }) + } + + // Buttons pinned to the bottom + Column( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 32.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + LogInButton { viewModel.onSignInWithGoogle() } + SkipButton { viewModel.onSkip() } + } + } + } +} + +@Preview(showBackground = true) +@Composable +fun GoalPromptScreenPreview() { + var sliderVal by remember { mutableFloatStateOf(0f) } + GoalPromptScreen() +} diff --git a/app/src/main/java/com/cornellappdev/uplift/ui/screens/onboarding/SignInPromptScreen.kt b/app/src/main/java/com/cornellappdev/uplift/ui/screens/onboarding/SignInPromptScreen.kt index 4bf8778f..3c7ae7ae 100644 --- a/app/src/main/java/com/cornellappdev/uplift/ui/screens/onboarding/SignInPromptScreen.kt +++ b/app/src/main/java/com/cornellappdev/uplift/ui/screens/onboarding/SignInPromptScreen.kt @@ -112,7 +112,7 @@ private fun SignInPromptScreenContent( } @Composable -private fun SkipButton(onClick: () -> Unit) { +fun SkipButton(onClick: () -> Unit) { TextButton( onClick = onClick ) { diff --git a/app/src/main/java/com/cornellappdev/uplift/ui/viewmodels/onboarding/GoalsPromptViewModel.kt b/app/src/main/java/com/cornellappdev/uplift/ui/viewmodels/onboarding/GoalsPromptViewModel.kt new file mode 100644 index 00000000..72865874 --- /dev/null +++ b/app/src/main/java/com/cornellappdev/uplift/ui/viewmodels/onboarding/GoalsPromptViewModel.kt @@ -0,0 +1,58 @@ +package com.cornellappdev.uplift.ui.viewmodels.onboarding + +import android.net.Uri +import android.util.Log +import androidx.lifecycle.viewModelScope +import com.cornellappdev.uplift.data.repositories.UserInfoRepository +import com.cornellappdev.uplift.ui.UpliftRootRoute +import com.cornellappdev.uplift.ui.nav.RootNavigationRepository +import com.cornellappdev.uplift.ui.viewmodels.UpliftViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +data class GoalsPromptUiState( + val name: String = "", + val imageUri: Uri? = null +) + +@HiltViewModel +class GoalsPromptViewModel @Inject constructor( + private val userInfoRepository: UserInfoRepository, + private val rootNavigationRepository: RootNavigationRepository, +) : UpliftViewModel(GoalsPromptUiState()) { + + private val _goalValue = MutableStateFlow(0f) + val goalValue: StateFlow = _goalValue.asStateFlow() + + init { + viewModelScope.launch { + // TODO: Change this later to reflect correct inputs + val user = userInfoRepository.getFirebaseUser() + val name = user?.displayName ?: "" + applyMutation { + copy(name = name) + } + } + } + + fun onGoalValueChange(newValue: Float) { + _goalValue.value = newValue + } + + // TODO: Change skip and google sign in to reflect correct behavior + fun onSkip() { + navigateToHome() + } + + fun onSignInWithGoogle() { + navigateToHome() + } + + fun navigateToHome() { + rootNavigationRepository.navigate(UpliftRootRoute.Home) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/uplift/ui/viewmodels/onboarding/ProfileCreationViewModel.kt b/app/src/main/java/com/cornellappdev/uplift/ui/viewmodels/onboarding/ProfileCreationViewModel.kt index 8304a629..03327365 100644 --- a/app/src/main/java/com/cornellappdev/uplift/ui/viewmodels/onboarding/ProfileCreationViewModel.kt +++ b/app/src/main/java/com/cornellappdev/uplift/ui/viewmodels/onboarding/ProfileCreationViewModel.kt @@ -38,7 +38,7 @@ class ProfileCreationViewModel @Inject constructor( val email = user?.email ?: "" val netId = email.substring(0, email.indexOf('@')) if (userInfoRepository.createUser(email, name, netId)) { - navigateToHome() + navigateToGoals() } else { //TODO: Add error handling Log.e("Error", "User not created") @@ -53,6 +53,11 @@ class ProfileCreationViewModel @Inject constructor( } } + private fun navigateToGoals() { + rootNavigationRepository.navigate(UpliftRootRoute.GoalsPrompt) + } + + // Possibly get rid of this function private fun navigateToHome() { rootNavigationRepository.navigate(UpliftRootRoute.Home) }