diff --git a/app/src/main/java/com/android/periodpals/ui/authentication/SignIn.kt b/app/src/main/java/com/android/periodpals/ui/authentication/SignIn.kt index 4883bf02c..bfd25d9f3 100644 --- a/app/src/main/java/com/android/periodpals/ui/authentication/SignIn.kt +++ b/app/src/main/java/com/android/periodpals/ui/authentication/SignIn.kt @@ -15,7 +15,9 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults @@ -36,7 +38,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp import com.android.periodpals.R import com.android.periodpals.model.authentication.AuthenticationViewModel import com.android.periodpals.model.user.UserAuthenticationState @@ -54,6 +55,7 @@ import com.android.periodpals.ui.navigation.Screen import com.android.periodpals.ui.theme.Pink40 import com.android.periodpals.ui.theme.Purple80 import com.android.periodpals.ui.theme.PurpleGrey80 +import com.android.periodpals.ui.theme.dimens @Composable fun SignInScreen( @@ -80,115 +82,140 @@ fun SignInScreen( // Purple-ish background GradedBackground(Purple80, Pink40, PurpleGrey80, SignInScreen.BACKGROUND) - Column( - modifier = Modifier.fillMaxSize().padding(padding).padding(60.dp), + LazyColumn( + modifier = + Modifier.fillMaxSize() + .padding(padding) + .padding( + horizontal = MaterialTheme.dimens.large, + vertical = MaterialTheme.dimens.medium3), horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(48.dp, Alignment.CenterVertically), - ) { - // Welcome text - AuthWelcomeText( - text = "Welcome to PeriodPals", - color = Color.Black, - testTag = SignInScreen.TITLE_TEXT, - ) - - // Rectangle with login fields and button - Box( - modifier = - Modifier.fillMaxWidth() - .border(1.dp, Color.Gray, RectangleShape) - .background(Color.White) - .padding(24.dp)) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterVertically), - ) { - // Sign in instruction - AuthInstruction( - text = "Sign in to your account", - testTag = SignInScreen.INSTRUCTION_TEXT, - ) - - // Email input and error message - AuthEmailInput( - email = email, - onEmailChange = { email = it }, - testTag = SignInScreen.EMAIL_FIELD, - ) - if (emailErrorMessage.isNotEmpty()) { - ErrorText(emailErrorMessage, SignInScreen.EMAIL_ERROR_TEXT) - } - - // Password input and error message - AuthPasswordInput( - password = password, - onPasswordChange = { password = it }, - passwordVisible = passwordVisible, - onPasswordVisibilityChange = { passwordVisible = !passwordVisible }, - testTag = SignInScreen.PASSWORD_FIELD, - visibilityTestTag = SignInScreen.PASSWORD_VISIBILITY_BUTTON, - ) - if (passwordErrorMessage.isNotEmpty()) { - ErrorText(passwordErrorMessage, SignInScreen.PASSWORD_ERROR_TEXT) - } - - // Sign in button - AuthButton( - text = "Sign in", - onClick = { - emailErrorMessage = validateEmail(email) - passwordErrorMessage = validatePassword(password) - - if (emailErrorMessage.isEmpty() && passwordErrorMessage.isEmpty()) { - authenticationViewModel.logInWithEmail(email, password) - authenticationViewModel.isUserLoggedIn() - val loginSuccess = userState is UserAuthenticationState.Success - if (loginSuccess) { - // with supabase - Toast.makeText(context, "Login Successful", Toast.LENGTH_SHORT).show() - navigationActions.navigateTo(Screen.PROFILE) - } else { - Toast.makeText(context, "Login Failed", Toast.LENGTH_SHORT).show() - } - } else { - Toast.makeText(context, "Invalid email or password.", Toast.LENGTH_SHORT) - .show() + verticalArrangement = + Arrangement.spacedBy(MaterialTheme.dimens.medium1, Alignment.CenterVertically)) { + // Welcome text + item { + AuthWelcomeText( + text = "Welcome to PeriodPals", + color = Color.Black, + testTag = SignInScreen.TITLE_TEXT, + ) + } + + // Rectangle with login fields and button + item { + Box( + modifier = + Modifier.fillMaxWidth() + .wrapContentHeight() + .border(MaterialTheme.dimens.borderLine, Color.Gray, RectangleShape) + .background(Color.White) + .padding( + horizontal = MaterialTheme.dimens.medium1, + vertical = MaterialTheme.dimens.small3)) { + Column( + modifier = Modifier.fillMaxWidth().wrapContentHeight(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = + Arrangement.spacedBy( + MaterialTheme.dimens.small2, Alignment.CenterVertically), + ) { + // Sign in instruction + AuthInstruction( + text = "Sign in to your account", + testTag = SignInScreen.INSTRUCTION_TEXT, + ) + + // Email input and error message + AuthEmailInput( + email = email, + onEmailChange = { email = it }, + testTag = SignInScreen.EMAIL_FIELD, + ) + if (emailErrorMessage.isNotEmpty()) { + ErrorText(emailErrorMessage, SignInScreen.EMAIL_ERROR_TEXT) } - }, - testTag = SignInScreen.SIGN_IN_BUTTON, - ) - - // Or continue with text - AuthSecondInstruction( - text = "Or continue with", - testTag = SignInScreen.CONTINUE_WITH_TEXT, - ) - - // Google sign in button - GoogleButton( - onClick = { - Toast.makeText( - context, - "Use other login method for now, thanks!", - Toast.LENGTH_SHORT, - ) - .show() - }, - testTag = SignInScreen.GOOGLE_BUTTON, - ) - } + + // Password input and error message + AuthPasswordInput( + password = password, + onPasswordChange = { password = it }, + passwordVisible = passwordVisible, + onPasswordVisibilityChange = { passwordVisible = !passwordVisible }, + testTag = SignInScreen.PASSWORD_FIELD, + visibilityTestTag = SignInScreen.PASSWORD_VISIBILITY_BUTTON, + ) + if (passwordErrorMessage.isNotEmpty()) { + ErrorText(passwordErrorMessage, SignInScreen.PASSWORD_ERROR_TEXT) + } + + // Sign in button + AuthButton( + text = "Sign in", + onClick = { + emailErrorMessage = validateEmail(email) + passwordErrorMessage = validatePassword(password) + + if (emailErrorMessage.isEmpty() && passwordErrorMessage.isEmpty()) { + authenticationViewModel.logInWithEmail(email, password) + authenticationViewModel.isUserLoggedIn() + val loginSuccess = userState is UserAuthenticationState.Success + if (loginSuccess) { + // with supabase + Toast.makeText(context, "Login Successful", Toast.LENGTH_SHORT) + .show() + navigationActions.navigateTo(Screen.PROFILE) + } else { + Toast.makeText(context, "Login Failed", Toast.LENGTH_SHORT).show() + } + } else { + Toast.makeText( + context, "Invalid email or password.", Toast.LENGTH_SHORT) + .show() + } + }, + testTag = SignInScreen.SIGN_IN_BUTTON, + ) + + // Or continue with text + AuthSecondInstruction( + text = "Or continue with", + testTag = SignInScreen.CONTINUE_WITH_TEXT, + ) + + // Google sign in button + GoogleButton( + onClick = { + Toast.makeText( + context, + "Use other login method for now, thanks!", + Toast.LENGTH_SHORT, + ) + .show() + }, + testTag = SignInScreen.GOOGLE_BUTTON, + ) + } + } + } + + item { + Row( + modifier = Modifier.fillMaxWidth().wrapContentHeight(), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically) { + Text( + text = "Not registered yet? ", + style = MaterialTheme.typography.bodyMedium) + Text( + text = "Sign up here!", + modifier = + Modifier.clickable { navigationActions.navigateTo(Screen.SIGN_UP) } + .testTag(SignInScreen.NOT_REGISTERED_BUTTON), + color = Color.Blue, + style = MaterialTheme.typography.bodyMedium) + } } - Row(modifier = Modifier) { - Text("Not registered yet? ") - Text( - text = "Sign up here!", - modifier = - Modifier.clickable { navigationActions.navigateTo(Screen.SIGN_UP) } - .testTag(SignInScreen.NOT_REGISTERED_BUTTON), - color = Color.Blue, - ) - } - } + } }, ) } @@ -224,7 +251,7 @@ fun GoogleButton(onClick: () -> Unit, modifier: Modifier = Modifier, testTag: St onClick = onClick, colors = ButtonDefaults.buttonColors(containerColor = Color.White), shape = RoundedCornerShape(50), - border = BorderStroke(1.dp, Color.LightGray), + border = BorderStroke(MaterialTheme.dimens.borderLine, Color.LightGray), ) { Row( verticalAlignment = Alignment.CenterVertically, @@ -233,9 +260,9 @@ fun GoogleButton(onClick: () -> Unit, modifier: Modifier = Modifier, testTag: St Image( painter = painterResource(id = R.drawable.google_logo), contentDescription = "Google Logo", - modifier = Modifier.size(24.dp), + modifier = Modifier.size(MaterialTheme.dimens.iconSize), ) - Spacer(modifier = Modifier.size(8.dp)) + Spacer(modifier = Modifier.size(MaterialTheme.dimens.small2)) Text( text = "Sign in with Google", color = Color.Black, diff --git a/app/src/main/java/com/android/periodpals/ui/components/AuthComponents.kt b/app/src/main/java/com/android/periodpals/ui/components/AuthComponents.kt index b9604c741..b6cfbf3c8 100644 --- a/app/src/main/java/com/android/periodpals/ui/components/AuthComponents.kt +++ b/app/src/main/java/com/android/periodpals/ui/components/AuthComponents.kt @@ -5,7 +5,8 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons @@ -19,19 +20,22 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.onFocusEvent import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.testTag -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import com.android.periodpals.ui.theme.Purple40 +import com.android.periodpals.ui.theme.dimens /** * A composable that displays a graded background with [gradeFrom] and [gradeTo] colors and @@ -39,29 +43,21 @@ import com.android.periodpals.ui.theme.Purple40 */ @Composable fun GradedBackground(gradeFrom: Color, gradeTo: Color, background: Color, testTag: String) { - Box(modifier = Modifier.fillMaxSize().background(Color.Transparent).testTag(testTag)) { + Box(modifier = Modifier.fillMaxSize().background(background).testTag(testTag)) { Canvas(modifier = Modifier.fillMaxSize()) { val gradientBrush = Brush.verticalGradient( - colors = listOf(gradeFrom, gradeTo), startY = 0f, endY = size.minDimension * 3 / 2) + colors = listOf(gradeFrom, gradeTo), startY = 0f, endY = size.height * 2 / 3) - drawRect( - color = background, - topLeft = Offset(0f, size.minDimension), - size = Size(size.width, size.height - size.minDimension)) - - drawRect( - brush = gradientBrush, - topLeft = Offset((size.width - size.minDimension) / 2, 0f), - size = Size(size.width, size.minDimension)) + drawRect(brush = gradientBrush, size = Size(size.width, size.height / 2)) drawArc( brush = gradientBrush, startAngle = 0f, sweepAngle = 180f, useCenter = true, - topLeft = Offset(0f, size.minDimension / 2), - size = Size(size.width, size.minDimension)) + topLeft = Offset(0f, size.height / 3), + size = Size(size.width, size.height / 3)) } } } @@ -73,13 +69,11 @@ fun GradedBackground(gradeFrom: Color, gradeTo: Color, background: Color, testTa @Composable fun AuthWelcomeText(text: String, color: Color, testTag: String) { Text( - modifier = Modifier.fillMaxWidth().padding(vertical = 16.dp).testTag(testTag), + modifier = Modifier.fillMaxWidth().wrapContentHeight().testTag(testTag), text = text, textAlign = TextAlign.Center, color = color, - style = - MaterialTheme.typography.headlineLarge.copy( - fontSize = 40.sp, lineHeight = 64.sp, fontWeight = FontWeight.SemiBold)) + style = MaterialTheme.typography.headlineLarge) } /** @@ -88,10 +82,10 @@ fun AuthWelcomeText(text: String, color: Color, testTag: String) { @Composable fun AuthInstruction(text: String, testTag: String) { Text( - modifier = Modifier.testTag(testTag), + modifier = Modifier.fillMaxWidth().wrapContentHeight().testTag(testTag), text = text, - style = - MaterialTheme.typography.bodyLarge.copy(fontSize = 20.sp, fontWeight = FontWeight.Medium)) + textAlign = TextAlign.Center, + style = MaterialTheme.typography.bodyLarge) } /** @@ -101,9 +95,10 @@ fun AuthInstruction(text: String, testTag: String) { @Composable fun AuthSecondInstruction(text: String, testTag: String) { Text( - modifier = Modifier.testTag(testTag), + modifier = Modifier.fillMaxWidth().wrapContentHeight().testTag(testTag), text = text, - style = MaterialTheme.typography.bodyLarge.copy(fontWeight = FontWeight.Medium)) + textAlign = TextAlign.Center, + style = MaterialTheme.typography.bodyLarge) } /** @@ -111,11 +106,23 @@ fun AuthSecondInstruction(text: String, testTag: String) { */ @Composable fun AuthEmailInput(email: String, onEmailChange: (String) -> Unit, testTag: String) { + var isFocused by remember { mutableStateOf(false) } + OutlinedTextField( - modifier = Modifier.fillMaxWidth().wrapContentSize().testTag(testTag), + modifier = + Modifier.fillMaxWidth().wrapContentHeight().testTag(testTag).onFocusEvent { focusState -> + isFocused = focusState.isFocused + }, value = email, onValueChange = onEmailChange, - label = { Text("Email") }) + textStyle = MaterialTheme.typography.labelMedium, + label = { + Text( + text = "Email", + style = + if (isFocused || email.isNotEmpty()) MaterialTheme.typography.labelSmall + else MaterialTheme.typography.labelMedium) + }) } /** @@ -131,11 +138,23 @@ fun AuthPasswordInput( testTag: String, visibilityTestTag: String ) { + var isFocused by remember { mutableStateOf(false) } + OutlinedTextField( - modifier = Modifier.fillMaxWidth().testTag(testTag), + modifier = + Modifier.fillMaxWidth().wrapContentHeight().testTag(testTag).onFocusEvent { focusState -> + isFocused = focusState.isFocused + }, value = password, onValueChange = onPasswordChange, - label = { Text("Password") }, + textStyle = MaterialTheme.typography.labelMedium, + label = { + Text( + "Password", + style = + if (isFocused || password.isNotEmpty()) MaterialTheme.typography.labelSmall + else MaterialTheme.typography.labelMedium) + }, visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), trailingIcon = { @@ -144,7 +163,8 @@ fun AuthPasswordInput( onClick = onPasswordVisibilityChange, modifier = Modifier.testTag(visibilityTestTag)) { Icon( imageVector = image, - contentDescription = if (passwordVisible) "Hide password" else "Show password") + contentDescription = if (passwordVisible) "Hide password" else "Show password", + modifier = Modifier.size(MaterialTheme.dimens.iconSize)) } }) } @@ -160,6 +180,6 @@ fun AuthButton(text: String, onClick: () -> Unit, testTag: String) { onClick = onClick, colors = ButtonDefaults.buttonColors(containerColor = Purple40), shape = RoundedCornerShape(50)) { - Text(text = text, color = Color.White, fontSize = 16.sp, fontWeight = FontWeight.Medium) + Text(text = text, color = Color.White, style = MaterialTheme.typography.bodyMedium) } } diff --git a/app/src/main/java/com/android/periodpals/ui/components/ErrorComponent.kt b/app/src/main/java/com/android/periodpals/ui/components/ErrorComponent.kt index 2afeea395..a50d8f59e 100644 --- a/app/src/main/java/com/android/periodpals/ui/components/ErrorComponent.kt +++ b/app/src/main/java/com/android/periodpals/ui/components/ErrorComponent.kt @@ -1,6 +1,7 @@ package com.android.periodpals.ui.components import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -15,8 +16,9 @@ import androidx.compose.ui.text.style.TextAlign @Composable fun ErrorText(message: String, testTag: String) { Text( - modifier = Modifier.fillMaxWidth().testTag(testTag), + modifier = Modifier.fillMaxWidth().wrapContentHeight().testTag(testTag), text = message, color = Color.Red, - style = MaterialTheme.typography.bodyMedium.copy(textAlign = TextAlign.Start)) + textAlign = TextAlign.Start, + style = MaterialTheme.typography.labelMedium) } diff --git a/app/src/main/java/com/android/periodpals/ui/theme/AppUtil.kt b/app/src/main/java/com/android/periodpals/ui/theme/AppUtil.kt index b546d7be2..7f6c0db20 100644 --- a/app/src/main/java/com/android/periodpals/ui/theme/AppUtil.kt +++ b/app/src/main/java/com/android/periodpals/ui/theme/AppUtil.kt @@ -21,4 +21,4 @@ fun ProvideAppUtils( } /** A composition local representing the application dimensions. */ -val LocalAppDimens = compositionLocalOf { CompactDimens } +val LocalAppDimens = compositionLocalOf { CompactLargeDimens } diff --git a/app/src/main/java/com/android/periodpals/ui/theme/Color.kt b/app/src/main/java/com/android/periodpals/ui/theme/Color.kt index 9701f827d..89dde425b 100644 --- a/app/src/main/java/com/android/periodpals/ui/theme/Color.kt +++ b/app/src/main/java/com/android/periodpals/ui/theme/Color.kt @@ -1,7 +1,11 @@ package com.android.periodpals.ui.theme +import androidx.compose.material3.ColorScheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme import androidx.compose.ui.graphics.Color +// TODO: delete val Purple80 = Color(0xFFD0BCFF) val PurpleGrey80 = Color(0xFFCCC2DC) val Pink80 = Color(0xFFEFB8C8) @@ -10,76 +14,80 @@ val Purple40 = Color(0xFF6650a4) val PurpleGrey40 = Color(0xFF625b71) val Pink40 = Color(0xFF7D5260) -/* Light theme, still in development and thus not in use */ -val primaryLight = Color(0xFF415F91) -val onPrimaryLight = Color(0xFFFFFFFF) -val primaryContainerLight = Color(0xFFD6E3FF) -val onPrimaryContainerLight = Color(0xFF001B3E) -val secondaryLight = Color(0xFF565F71) -val onSecondaryLight = Color(0xFFFFFFFF) -val secondaryContainerLight = Color(0xFFDAE2F9) -val onSecondaryContainerLight = Color(0xFF131C2B) -val tertiaryLight = Color(0xFF5C5891) -val onTertiaryLight = Color(0xFFFFFFFF) -val tertiaryContainerLight = Color(0xFFE3DFFF) -val onTertiaryContainerLight = Color(0xFF18124A) -val errorLight = Color(0xFFBA1A1A) -val onErrorLight = Color(0xFFFFFFFF) -val errorContainerLight = Color(0xFFFFDAD6) -val onErrorContainerLight = Color(0xFF410002) -val backgroundLight = Color(0xFFF9F9FF) -val onBackgroundLight = Color(0xFF191C20) -val surfaceLight = Color(0xFFF9F9FF) -val onSurfaceLight = Color(0xFF191C20) -val surfaceVariantLight = Color(0xFFE0E2EC) -val onSurfaceVariantLight = Color(0xFF44474E) -val outlineLight = Color(0xFF74777F) -val outlineVariantLight = Color(0xFFC4C6D0) -val scrimLight = Color(0xFF000000) -val inverseSurfaceLight = Color(0xFF2E3036) -val inverseOnSurfaceLight = Color(0xFFF0F0F7) -val inversePrimaryLight = Color(0xFFAAC7FF) -val surfaceDimLight = Color(0xFFD9D9E0) -val surfaceBrightLight = Color(0xFFF9F9FF) -val surfaceContainerLowestLight = Color(0xFFFFFFFF) -val surfaceContainerLowLight = Color(0xFFF3F3FA) -val surfaceContainerLight = Color(0xFFEDEDF4) -val surfaceContainerHighLight = Color(0xFFE7E8EE) -val surfaceContainerHighestLight = Color(0xFFE2E2E9) +object PeriodPalsColor { + val LightTheme: ColorScheme = + lightColorScheme( + primary = Color(0xFF415F91), + onPrimary = Color(0xFFFFFFFF), + primaryContainer = Color(0xFFD6E3FF), + onPrimaryContainer = Color(0xFF001B3E), + secondary = Color(0xFF565F71), + onSecondary = Color(0xFFFFFFFF), + secondaryContainer = Color(0xFFDAE2F9), + onSecondaryContainer = Color(0xFF131C2B), + tertiary = Color(0xFF5C5891), + onTertiary = Color(0xFFFFFFFF), + tertiaryContainer = Color(0xFFE3DFFF), + onTertiaryContainer = Color(0xFF18124A), + error = Color(0xFFBA1A1A), + onError = Color(0xFFFFFFFF), + errorContainer = Color(0xFFFFDAD6), + onErrorContainer = Color(0xFF410002), + background = Color(0xFFF9F9FF), + onBackground = Color(0xFF191C20), + surface = Color(0xFFF9F9FF), + onSurface = Color(0xFF191C20), + surfaceVariant = Color(0xFFE0E2EC), + onSurfaceVariant = Color(0xFF44474E), + outline = Color(0xFF74777F), + outlineVariant = Color(0xFFC4C6D0), + scrim = Color(0xFF000000), + inverseSurface = Color(0xFF2E3036), + inverseOnSurface = Color(0xFFF0F0F7), + inversePrimary = Color(0xFFAAC7FF), + surfaceDim = Color(0xFFD9D9E0), + surfaceBright = Color(0xFFF9F9FF), + surfaceContainerLowest = Color(0xFFFFFFFF), + surfaceContainerLow = Color(0xFFF3F3FA), + surfaceContainer = Color(0xFFEDEDF4), + surfaceContainerHigh = Color(0xFFE7E8EE), + surfaceContainerHighest = Color(0xFFE2E2E9)) -/* Dark theme, still in development and thus not in use */ -val primaryDark = Color(0xFFAAC7FF) -val onPrimaryDark = Color(0xFF0A305F) -val primaryContainerDark = Color(0xFF284777) -val onPrimaryContainerDark = Color(0xFFD6E3FF) -val secondaryDark = Color(0xFFBEC6DC) -val onSecondaryDark = Color(0xFF283141) -val secondaryContainerDark = Color(0xFF3E4759) -val onSecondaryContainerDark = Color(0xFFDAE2F9) -val tertiaryDark = Color(0xFFC5C0FF) -val onTertiaryDark = Color(0xFF2D2960) -val tertiaryContainerDark = Color(0xFF444078) -val onTertiaryContainerDark = Color(0xFFE3DFFF) -val errorDark = Color(0xFFFFB4AB) -val onErrorDark = Color(0xFF690005) -val errorContainerDark = Color(0xFF93000A) -val onErrorContainerDark = Color(0xFFFFDAD6) -val backgroundDark = Color(0xFF111318) -val onBackgroundDark = Color(0xFFE2E2E9) -val surfaceDark = Color(0xFF111318) -val onSurfaceDark = Color(0xFFE2E2E9) -val surfaceVariantDark = Color(0xFF44474E) -val onSurfaceVariantDark = Color(0xFFC4C6D0) -val outlineDark = Color(0xFF8E9099) -val outlineVariantDark = Color(0xFF44474E) -val scrimDark = Color(0xFF000000) -val inverseSurfaceDark = Color(0xFFE2E2E9) -val inverseOnSurfaceDark = Color(0xFF2E3036) -val inversePrimaryDark = Color(0xFF415F91) -val surfaceDimDark = Color(0xFF111318) -val surfaceBrightDark = Color(0xFF37393E) -val surfaceContainerLowestDark = Color(0xFF0C0E13) -val surfaceContainerLowDark = Color(0xFF191C20) -val surfaceContainerDark = Color(0xFF1D2024) -val surfaceContainerHighDark = Color(0xFF282A2F) -val surfaceContainerHighestDark = Color(0xFF33353A) + val DarkTheme: ColorScheme = + darkColorScheme( + primary = Color(0xFFAAC7FF), + onPrimary = Color(0xFF0A305F), + primaryContainer = Color(0xFF284777), + onPrimaryContainer = Color(0xFFD6E3FF), + secondary = Color(0xFFBEC6DC), + onSecondary = Color(0xFF283141), + secondaryContainer = Color(0xFF3E4759), + onSecondaryContainer = Color(0xFFDAE2F9), + tertiary = Color(0xFFC5C0FF), + onTertiary = Color(0xFF2D2960), + tertiaryContainer = Color(0xFF444078), + onTertiaryContainer = Color(0xFFE3DFFF), + error = Color(0xFFFFB4AB), + onError = Color(0xFF690005), + errorContainer = Color(0xFF93000A), + onErrorContainer = Color(0xFFFFDAD6), + background = Color(0xFF111318), + onBackground = Color(0xFFE2E2E9), + surface = Color(0xFF111318), + onSurface = Color(0xFFE2E2E9), + surfaceVariant = Color(0xFF44474E), + onSurfaceVariant = Color(0xFFC4C6D0), + outline = Color(0xFF8E9099), + outlineVariant = Color(0xFF44474E), + scrim = Color(0xFF000000), + inverseSurface = Color(0xFFE2E2E9), + inverseOnSurface = Color(0xFF2E3036), + inversePrimary = Color(0xFF415F91), + surfaceDim = Color(0xFF111318), + surfaceBright = Color(0xFF37393E), + surfaceContainerLowest = Color(0xFF0C0E13), + surfaceContainerLow = Color(0xFF191C20), + surfaceContainer = Color(0xFF1D2024), + surfaceContainerHigh = Color(0xFF282A2F), + surfaceContainerHighest = Color(0xFF33353A)) +} diff --git a/app/src/main/java/com/android/periodpals/ui/theme/Dimens.kt b/app/src/main/java/com/android/periodpals/ui/theme/Dimens.kt index 559d691e3..24e523660 100644 --- a/app/src/main/java/com/android/periodpals/ui/theme/Dimens.kt +++ b/app/src/main/java/com/android/periodpals/ui/theme/Dimens.kt @@ -19,64 +19,65 @@ data class Dimens( val medium2: Dp = 0.dp, val medium3: Dp = 0.dp, val large: Dp = 0.dp, + val borderLine: Dp = 1.dp, val buttonHeight: Dp = 40.dp, - val iconSize: Dp = 24.dp, - // val logoSize: Dp = 42.dp + val iconSize: Dp = 24.dp ) +// Width <= 360dp val CompactSmallDimens = Dimens( - small1 = 5.dp, + small1 = 3.dp, small2 = 6.dp, - small3 = 8.dp, - medium1 = 15.dp, - medium2 = 26.dp, + small3 = 12.dp, + medium1 = 18.dp, + medium2 = 24.dp, medium3 = 30.dp, large = 45.dp, - buttonHeight = 30.dp, - // logoSize = 36.dp ) +// 360dp < Width <= 500dp val CompactMediumDimens = Dimens( - small1 = 8.dp, - small2 = 13.dp, - small3 = 17.dp, + small1 = 4.dp, + small2 = 8.dp, + small3 = 16.dp, medium1 = 24.dp, - medium2 = 30.dp, + medium2 = 32.dp, medium3 = 40.dp, - large = 65.dp) + large = 60.dp) -val CompactDimens = +// 500dp < Width +val CompactLargeDimens = Dimens( - small1 = 10.dp, - small2 = 15.dp, + small1 = 5.dp, + small2 = 10.dp, small3 = 20.dp, medium1 = 30.dp, - medium2 = 36.dp, - medium3 = 40.dp, - large = 80.dp) + medium2 = 40.dp, + medium3 = 50.dp, + large = 65.dp) val MediumDimens = Dimens( - small1 = 10.dp, - small2 = 15.dp, - small3 = 20.dp, - medium1 = 30.dp, - medium2 = 36.dp, - medium3 = 40.dp, - large = 110.dp, + small1 = 8.dp, + small2 = 16.dp, + small3 = 32.dp, + medium1 = 48.dp, + medium2 = 64.dp, + medium3 = 80.dp, + large = 120.dp, // logoSize = 55.dp ) val ExpandedDimens = Dimens( - small1 = 15.dp, - small2 = 20.dp, - small3 = 25.dp, - medium1 = 35.dp, - medium2 = 30.dp, - medium3 = 45.dp, - large = 130.dp, + small1 = 9.dp, + small2 = 18.dp, + small3 = 36.dp, + medium1 = 54.dp, + medium2 = 72.dp, + medium3 = 90.dp, + large = 135.dp, // logoSize = 72.dp ) diff --git a/app/src/main/java/com/android/periodpals/ui/theme/Theme.kt b/app/src/main/java/com/android/periodpals/ui/theme/Theme.kt index b9d040bba..95462e20a 100644 --- a/app/src/main/java/com/android/periodpals/ui/theme/Theme.kt +++ b/app/src/main/java/com/android/periodpals/ui/theme/Theme.kt @@ -1,16 +1,14 @@ package com.android.periodpals.ui.theme import android.app.Activity +import android.widget.Toast import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.darkColorScheme -import androidx.compose.material3.lightColorScheme import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext @@ -18,118 +16,19 @@ import androidx.compose.ui.platform.LocalView import androidx.core.view.WindowCompat import com.android.periodpals.MainActivity -private val DarkColorScheme = - darkColorScheme(primary = Purple80, secondary = PurpleGrey80, tertiary = Pink80) - -private val LightColorScheme = - lightColorScheme( - primary = Purple40, - secondary = PurpleGrey40, - tertiary = Pink40, - - // Other default colors to override - background = Color(0xFFFFFBFE), - surface = Color(0xFFFFFBFE), - onPrimary = Color.White, - onSecondary = Color.White, - onTertiary = Color.White, - onBackground = Color(0xFF1C1B1F), - onSurface = Color(0xFF1C1B1F), - ) - -/* Color themes still in development */ -private val lightSchemeInDev = - lightColorScheme( - primary = primaryLight, - onPrimary = onPrimaryLight, - primaryContainer = primaryContainerLight, - onPrimaryContainer = onPrimaryContainerLight, - secondary = secondaryLight, - onSecondary = onSecondaryLight, - secondaryContainer = secondaryContainerLight, - onSecondaryContainer = onSecondaryContainerLight, - tertiary = tertiaryLight, - onTertiary = onTertiaryLight, - tertiaryContainer = tertiaryContainerLight, - onTertiaryContainer = onTertiaryContainerLight, - error = errorLight, - onError = onErrorLight, - errorContainer = errorContainerLight, - onErrorContainer = onErrorContainerLight, - background = backgroundLight, - onBackground = onBackgroundLight, - surface = surfaceLight, - onSurface = onSurfaceLight, - surfaceVariant = surfaceVariantLight, - onSurfaceVariant = onSurfaceVariantLight, - outline = outlineLight, - outlineVariant = outlineVariantLight, - scrim = scrimLight, - inverseSurface = inverseSurfaceLight, - inverseOnSurface = inverseOnSurfaceLight, - inversePrimary = inversePrimaryLight, - surfaceDim = surfaceDimLight, - surfaceBright = surfaceBrightLight, - surfaceContainerLowest = surfaceContainerLowestLight, - surfaceContainerLow = surfaceContainerLowLight, - surfaceContainer = surfaceContainerLight, - surfaceContainerHigh = surfaceContainerHighLight, - surfaceContainerHighest = surfaceContainerHighestLight, - ) - -private val darkSchemeInDev = - darkColorScheme( - primary = primaryDark, - onPrimary = onPrimaryDark, - primaryContainer = primaryContainerDark, - onPrimaryContainer = onPrimaryContainerDark, - secondary = secondaryDark, - onSecondary = onSecondaryDark, - secondaryContainer = secondaryContainerDark, - onSecondaryContainer = onSecondaryContainerDark, - tertiary = tertiaryDark, - onTertiary = onTertiaryDark, - tertiaryContainer = tertiaryContainerDark, - onTertiaryContainer = onTertiaryContainerDark, - error = errorDark, - onError = onErrorDark, - errorContainer = errorContainerDark, - onErrorContainer = onErrorContainerDark, - background = backgroundDark, - onBackground = onBackgroundDark, - surface = surfaceDark, - onSurface = onSurfaceDark, - surfaceVariant = surfaceVariantDark, - onSurfaceVariant = onSurfaceVariantDark, - outline = outlineDark, - outlineVariant = outlineVariantDark, - scrim = scrimDark, - inverseSurface = inverseSurfaceDark, - inverseOnSurface = inverseOnSurfaceDark, - inversePrimary = inversePrimaryDark, - surfaceDim = surfaceDimDark, - surfaceBright = surfaceBrightDark, - surfaceContainerLowest = surfaceContainerLowestDark, - surfaceContainerLow = surfaceContainerLowDark, - surfaceContainer = surfaceContainerDark, - surfaceContainerHigh = surfaceContainerHighDark, - surfaceContainerHighest = surfaceContainerHighestDark, - ) +// Largest compact S width +private const val COMPACT_S = 360 +// Largest compact M width +private const val COMPACT_M = 420 @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) @Composable fun PeriodPalsAppTheme( darkTheme: Boolean = isSystemInDarkTheme(), - // Dynamic color is available on Android 12+ - dynamicColor: Boolean = true, activity: Activity = LocalContext.current as MainActivity, content: @Composable () -> Unit ) { - val colorScheme = - when { - darkTheme -> DarkColorScheme - else -> LightColorScheme - } + val colorScheme = if (darkTheme) PeriodPalsColor.DarkTheme else PeriodPalsColor.LightTheme // Match the system bar to the primary color of the app when the app isn't in edit mode (that is, // actually running in a device/emulator) @@ -145,30 +44,43 @@ fun PeriodPalsAppTheme( val window = calculateWindowSizeClass(activity = activity) val config = LocalConfiguration.current - var appDimens = CompactDimens - var typography = CompactTypography + var appDimens = CompactLargeDimens + var typography = CompactLargeTypography + var toasty = "" when (window.widthSizeClass) { WindowWidthSizeClass.Compact -> { - if (config.screenWidthDp <= 360) { + if (config.screenWidthDp <= COMPACT_S) { + // Emulator Small Phone API 34 appDimens = CompactSmallDimens typography = CompactSmallTypography - } else if (config.screenWidthDp < 599) { + toasty = "CompactSmall" + } else if (config.screenWidthDp <= COMPACT_M) { + // Emulator Pixel 2 API 34 appDimens = CompactMediumDimens typography = CompactMediumTypography + toasty = "CompactMedium" } else { - appDimens = CompactDimens - typography = CompactTypography + // Emulator Pixel 9 Pro XL API 34 + appDimens = CompactLargeDimens + typography = CompactLargeTypography + toasty = "CompactLarge" } } WindowWidthSizeClass.Medium -> { + // Emulator Medium Tablet API 34 appDimens = MediumDimens typography = MediumTypography + toasty = "Medium" } WindowWidthSizeClass.Expanded -> { + // Pixel C API 34 appDimens = ExpandedDimens typography = ExpandedTypography + toasty = "Expanded" } } + // TODO: delete + Toast.makeText(activity, toasty, Toast.LENGTH_SHORT).show() ProvideAppUtils(appDimens = appDimens) { MaterialTheme(colorScheme = colorScheme, typography = typography, content = content) diff --git a/app/src/main/java/com/android/periodpals/ui/theme/Type.kt b/app/src/main/java/com/android/periodpals/ui/theme/Type.kt index c3d701d38..6c173d410 100644 --- a/app/src/main/java/com/android/periodpals/ui/theme/Type.kt +++ b/app/src/main/java/com/android/periodpals/ui/theme/Type.kt @@ -13,195 +13,128 @@ import com.android.periodpals.R val Nunito_Sans = FontFamily( listOf( - Font( - resId = R.font.nunito_sans_black, - weight = FontWeight.Black, - style = FontStyle.Normal), + Font(resId = R.font.nunito_sans_black, weight = FontWeight.Black), Font( resId = R.font.nunito_sans_black_italic, weight = FontWeight.Black, style = FontStyle.Italic), - Font( - resId = R.font.nunito_sans_bold, - weight = FontWeight.Bold, - style = FontStyle.Normal), + Font(resId = R.font.nunito_sans_bold, weight = FontWeight.Bold), Font( resId = R.font.nunito_sans_bold_italic, weight = FontWeight.Bold, style = FontStyle.Italic), - Font( - resId = R.font.nunito_sans_extra_bold, - weight = FontWeight.ExtraBold, - style = FontStyle.Normal), + Font(resId = R.font.nunito_sans_extra_bold, weight = FontWeight.ExtraBold), Font( resId = R.font.nunito_sans_extra_bold_italic, weight = FontWeight.ExtraBold, style = FontStyle.Italic), - Font( - resId = R.font.nunito_sans_extra_light, - weight = FontWeight.ExtraLight, - style = FontStyle.Normal), + Font(resId = R.font.nunito_sans_extra_light, weight = FontWeight.ExtraLight), Font( resId = R.font.nunito_sans_extra_light_italic, weight = FontWeight.ExtraLight, style = FontStyle.Italic), - Font( - resId = R.font.nunito_sans_italic, - weight = FontWeight.Normal, - style = FontStyle.Italic), - Font( - resId = R.font.nunito_sans_light, - weight = FontWeight.Light, - style = FontStyle.Normal), + Font(resId = R.font.nunito_sans_italic, style = FontStyle.Italic), + Font(resId = R.font.nunito_sans_light, weight = FontWeight.Light), Font( resId = R.font.nunito_sans_light_italic, weight = FontWeight.Light, style = FontStyle.Italic), - Font( - resId = R.font.nunito_sans_regular, - weight = FontWeight.Normal, - style = FontStyle.Normal), - Font( - resId = R.font.nunito_sans_semi_bold, - weight = FontWeight.SemiBold, - style = FontStyle.Normal), + Font(resId = R.font.nunito_sans_regular), + Font(resId = R.font.nunito_sans_semi_bold, weight = FontWeight.SemiBold), Font( resId = R.font.nunito_sans_semi_bold_italic, weight = FontWeight.SemiBold, style = FontStyle.Italic))) -// Set of Material typography styles to start with -val CompactTypography = - Typography( - headlineLarge = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Black, - fontStyle = FontStyle.Normal, - fontSize = 32.sp), - headlineMedium = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Bold, - fontStyle = FontStyle.Normal, - fontSize = 24.sp), - titleMedium = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Medium, - fontStyle = FontStyle.Normal, - fontSize = 14.sp), - labelMedium = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Normal, - fontStyle = FontStyle.Normal, - fontSize = 14.sp)) +fun createTypography( + headlineLargeSize: Int, + titleMediumSize: Int, + bodyLargeSize: Int, + bodyMediumSize: Int, + labelMediumSize: Int, + labelSmallSize: Int +): Typography { + return Typography( + headlineLarge = + TextStyle( + fontFamily = Nunito_Sans, + fontWeight = FontWeight.Black, + fontStyle = FontStyle.Normal, + fontSize = headlineLargeSize.sp, + lineHeight = (headlineLargeSize * 1.5).sp), + titleMedium = + TextStyle( + fontFamily = Nunito_Sans, + fontWeight = FontWeight.Medium, + fontStyle = FontStyle.Normal, + fontSize = titleMediumSize.sp), + bodyLarge = + TextStyle( + fontFamily = Nunito_Sans, + fontWeight = FontWeight.SemiBold, + fontStyle = FontStyle.Normal, + fontSize = bodyLargeSize.sp), + bodyMedium = + TextStyle( + fontFamily = Nunito_Sans, + fontWeight = FontWeight.Medium, + fontStyle = FontStyle.Normal, + fontSize = bodyMediumSize.sp), + labelMedium = + TextStyle( + fontFamily = Nunito_Sans, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + fontSize = labelMediumSize.sp), + labelSmall = + TextStyle( + fontFamily = Nunito_Sans, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + fontSize = labelSmallSize.sp)) +} + +val CompactSmallTypography = + createTypography( + headlineLargeSize = 32, + titleMediumSize = 10, + bodyLargeSize = 18, + bodyMediumSize = 16, + labelMediumSize = 14, + labelSmallSize = 12) val CompactMediumTypography = - Typography( - headlineLarge = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Black, - fontStyle = FontStyle.Normal, - fontSize = 28.sp), - headlineMedium = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Bold, - fontStyle = FontStyle.Normal, - fontSize = 22.sp), - titleMedium = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Medium, - fontStyle = FontStyle.Normal, - fontSize = 14.sp), - labelMedium = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Normal, - fontStyle = FontStyle.Normal, - fontSize = 14.sp)) + createTypography( + headlineLargeSize = 40, + titleMediumSize = 14, + bodyLargeSize = 20, + bodyMediumSize = 18, + labelMediumSize = 16, + labelSmallSize = 14) -val CompactSmallTypography = - Typography( - headlineLarge = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Black, - fontStyle = FontStyle.Normal, - fontSize = 22.sp), - headlineMedium = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Bold, - fontStyle = FontStyle.Normal, - fontSize = 16.sp), - titleMedium = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Medium, - fontStyle = FontStyle.Normal, - fontSize = 10.sp), - labelMedium = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Normal, - fontStyle = FontStyle.Normal, - fontSize = 10.sp)) +val CompactLargeTypography = + createTypography( + headlineLargeSize = 48, + titleMediumSize = 14, + bodyLargeSize = 24, + bodyMediumSize = 20, + labelMediumSize = 18, + labelSmallSize = 16) val MediumTypography = - Typography( - headlineLarge = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Black, - fontStyle = FontStyle.Normal, - fontSize = 38.sp), - headlineMedium = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Bold, - fontStyle = FontStyle.Normal, - fontSize = 30.sp), - titleMedium = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Medium, - fontStyle = FontStyle.Normal, - fontSize = 16.sp), - labelMedium = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Normal, - fontStyle = FontStyle.Normal, - fontSize = 16.sp)) + createTypography( + headlineLargeSize = 56, + titleMediumSize = 16, + bodyLargeSize = 24, + bodyMediumSize = 22, + labelMediumSize = 20, + labelSmallSize = 18) val ExpandedTypography = - Typography( - headlineLarge = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Black, - fontStyle = FontStyle.Normal, - fontSize = 42.sp), - headlineMedium = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Bold, - fontStyle = FontStyle.Normal, - fontSize = 34.sp), - titleMedium = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Medium, - fontStyle = FontStyle.Normal, - fontSize = 18.sp), - labelMedium = - TextStyle( - fontFamily = Nunito_Sans, - fontWeight = FontWeight.Normal, - fontStyle = FontStyle.Normal, - fontSize = 18.sp)) + createTypography( + headlineLargeSize = 64, + titleMediumSize = 18, + bodyLargeSize = 24, + bodyMediumSize = 22, + labelMediumSize = 20, + labelSmallSize = 18)