diff --git a/app/src/main/java/com/karan/hashin/MainActivity.kt b/app/src/main/java/com/karan/hashin/MainActivity.kt index 1f92e1e..c7c6f01 100644 --- a/app/src/main/java/com/karan/hashin/MainActivity.kt +++ b/app/src/main/java/com/karan/hashin/MainActivity.kt @@ -1,9 +1,28 @@ package com.karan.hashin +import android.app.Activity +import android.graphics.Color.TRANSPARENT +import android.os.Build import android.os.Bundle +import android.view.View +import android.view.Window +import android.view.WindowInsets +import android.view.WindowInsetsController +import android.view.WindowManager import androidx.activity.ComponentActivity +import androidx.activity.SystemBarStyle +import androidx.activity.compose.LocalActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge +import androidx.annotation.RequiresApi +import androidx.compose.foundation.isSystemInDarkTheme +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.LocalView +import androidx.core.view.WindowCompat +import androidx.core.view.WindowInsetsControllerCompat import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController import com.karan.hashin.navigation.NavGraph @@ -13,12 +32,15 @@ class MainActivity : ComponentActivity() { private lateinit var navController: NavHostController + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - enableEdgeToEdge() + + WindowCompat.setDecorFitsSystemWindows(window, false) + setContent { - HashinTheme { + HashinTheme(dynamicColor = false) { navController = rememberNavController() NavGraph(navController) } diff --git a/app/src/main/java/com/karan/hashin/components/Element.kt b/app/src/main/java/com/karan/hashin/components/Element.kt index e00b6a9..b0b5478 100644 --- a/app/src/main/java/com/karan/hashin/components/Element.kt +++ b/app/src/main/java/com/karan/hashin/components/Element.kt @@ -1,9 +1,11 @@ package com.karan.hashin.components +import android.content.res.Configuration import com.karan.hashin.R import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -15,6 +17,8 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -22,6 +26,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.vectorResource +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 @@ -37,7 +42,7 @@ fun Element( Card( colors = CardDefaults.cardColors( - containerColor = Color.White + containerColor = MaterialTheme.colorScheme.surface ), elevation = CardDefaults.cardElevation( defaultElevation = 4.dp @@ -54,12 +59,13 @@ fun Element( modifier = Modifier .fillMaxSize() ) { - Image( + Icon ( imageVector = ImageVector.vectorResource(id = R.drawable.people), contentDescription = "Element Icon Image", + tint = MaterialTheme.colorScheme.primary, modifier = Modifier .padding(start = 16.dp) - .size(52.dp) + .size(36.dp) ) Column( @@ -68,7 +74,7 @@ fun Element( ) { Text( text = passKey.service.ifEmpty { "Website" }, - fontSize = 22.sp, + fontSize = 20.sp, color = getColorForLabel(passKey.label) ) @@ -76,7 +82,7 @@ fun Element( text = passKey.userName, fontSize = 14.sp, modifier = Modifier - .padding(start = 4.dp) + .padding(start = 2.dp) ) } Spacer( @@ -92,7 +98,8 @@ fun Element( ) { Text( text = passKey.label.firstOrNull()?.uppercase() ?: "", - color = Color.White, + color = MaterialTheme.colorScheme.onPrimaryContainer, + fontWeight = FontWeight.W300, fontSize = 36.sp, ) } @@ -100,11 +107,30 @@ fun Element( } } -@Preview(showBackground = true, showSystemUi = true) +@Preview( + name = "Dark Theme", + showBackground = true, + showSystemUi = false, + uiMode = Configuration.UI_MODE_NIGHT_YES +) +@Preview( + name = "Light Theme", + showBackground = true, + showSystemUi = false, + uiMode = Configuration.UI_MODE_NIGHT_NO +) @Composable private fun PreviewElement() { - HashinTheme { - Element(PassKey("", "", "", ""), Modifier.padding(top = 144.dp)) {} + HashinTheme(dynamicColor = false) { + Element(PassKey( + service = "Github", + userName = "KaranJoshi1208", + desc = "My passkey", + label = "Work" + ), + modifier = Modifier, + onClick = {} + ) } } diff --git a/app/src/main/java/com/karan/hashin/components/BottomAppBar.kt b/app/src/main/java/com/karan/hashin/components/NavigationBar.kt similarity index 80% rename from app/src/main/java/com/karan/hashin/components/BottomAppBar.kt rename to app/src/main/java/com/karan/hashin/components/NavigationBar.kt index 3d4d039..4dfc5d9 100644 --- a/app/src/main/java/com/karan/hashin/components/BottomAppBar.kt +++ b/app/src/main/java/com/karan/hashin/components/NavigationBar.kt @@ -1,26 +1,26 @@ package com.karan.hashin.components import android.content.res.Configuration -import com.karan.hashin.ui.theme.iconTintDark -import androidx.compose.ui.graphics.Color -import com.karan.hashin.R import androidx.compose.foundation.background +import androidx.compose.runtime.getValue +import com.karan.hashin.ui.theme.iconTintDark import androidx.compose.foundation.border import androidx.compose.foundation.clickable -import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Key -import androidx.compose.material.icons.outlined.Settings import androidx.compose.material.icons.rounded.Add import androidx.compose.material.icons.rounded.Settings import androidx.compose.material3.Card @@ -28,48 +28,47 @@ import androidx.compose.material3.CardDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.RectangleShape -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.res.vectorResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.karan.hashin.ui.theme.HashinTheme -import com.karan.hashin.ui.theme.PurpleA700 -import com.karan.hashin.ui.theme.iconTintLight @Composable -fun BottomAppBar( +fun NavigationBar( toVault: () -> Unit = {}, toPassKey: () -> Unit = {}, toSetting: () -> Unit = {}, selection: Int, modifier: Modifier = Modifier ) { - val iconTint = iconTintDark + val iconTint by remember { mutableStateOf(iconTintDark) } Card( shape = RectangleShape, colors = CardDefaults.cardColors( - containerColor = MaterialTheme.colorScheme.primaryContainer + containerColor = MaterialTheme.colorScheme.tertiaryContainer ), elevation = CardDefaults.cardElevation( defaultElevation = 4.dp ), modifier = modifier .fillMaxWidth() - .navigationBarsPadding() - .height(80.dp) + .wrapContentHeight() ) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceEvenly, modifier = modifier - .fillMaxSize() + .fillMaxWidth() + .padding(top = 8.dp) + .height(64.dp) + ) { Icon( imageVector =Icons.Default.Key , @@ -92,7 +91,6 @@ fun BottomAppBar( color = if(selection == 2) iconTint else MaterialTheme.colorScheme.primary, shape = RoundedCornerShape(percent = 33) ) -// ) { Icon( imageVector = Icons.Rounded.Add, @@ -119,17 +117,26 @@ fun BottomAppBar( } ) } + Spacer(Modifier.navigationBarsPadding()) } } @Preview( name = "BottomAppBar Preview Light", -// uiMode = Configuration.UI_MODE_NIGHT_NO, - showBackground = true + uiMode = Configuration.UI_MODE_NIGHT_YES, + showBackground = true, + showSystemUi = true ) @Composable -private fun p1() { +private fun P1() { HashinTheme(darkTheme = true, dynamicColor = false) { - BottomAppBar({}, {}, {}, 2) + Column( + verticalArrangement = Arrangement.Bottom, + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.background) + ) { + NavigationBar({}, {}, {}, 2) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/karan/hashin/screens/home/Home.kt b/app/src/main/java/com/karan/hashin/screens/home/Home.kt index d054293..e416dd5 100644 --- a/app/src/main/java/com/karan/hashin/screens/home/Home.kt +++ b/app/src/main/java/com/karan/hashin/screens/home/Home.kt @@ -2,14 +2,11 @@ package com.karan.hashin.screens.home import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue -import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.viewmodel.compose.viewModel @@ -19,7 +16,7 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument -import com.karan.hashin.components.BottomAppBar +import com.karan.hashin.components.NavigationBar import com.karan.hashin.navigation.Screens import com.karan.hashin.ui.theme.HashinTheme import com.karan.hashin.viewmodel.HomeViewModel @@ -32,11 +29,11 @@ fun HomeScreen( modifier: Modifier = Modifier ) { val innerNav = rememberNavController() - var selection by remember { mutableIntStateOf(1) } + var selection by rememberSaveable { mutableIntStateOf(1) } Scaffold( bottomBar = { - BottomAppBar( + NavigationBar( toVault = { selection = 1 innerNav.navigate(Screens.HomeGraph.Vault.route) { @@ -70,9 +67,6 @@ fun HomeScreen( modifier = Modifier ) }, - modifier = Modifier - .navigationBarsPadding() - .statusBarsPadding() ) { pd -> NavHost( navController = innerNav, diff --git a/app/src/main/java/com/karan/hashin/screens/home/NewProfile.kt b/app/src/main/java/com/karan/hashin/screens/home/NewProfile.kt new file mode 100644 index 0000000..220641f --- /dev/null +++ b/app/src/main/java/com/karan/hashin/screens/home/NewProfile.kt @@ -0,0 +1,2 @@ +package com.karan.hashin.screens.home + diff --git a/app/src/main/java/com/karan/hashin/screens/home/PassKey.kt b/app/src/main/java/com/karan/hashin/screens/home/PassKey.kt index 9828c47..c639363 100644 --- a/app/src/main/java/com/karan/hashin/screens/home/PassKey.kt +++ b/app/src/main/java/com/karan/hashin/screens/home/PassKey.kt @@ -22,6 +22,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextStyle @@ -31,10 +32,13 @@ import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.karan.hashin.R +import com.karan.hashin.ui.theme.Blue +import com.karan.hashin.ui.theme.Gray +import com.karan.hashin.ui.theme.Purple +import com.karan.hashin.ui.theme.Unfocused import com.karan.hashin.viewmodel.HomeViewModel import kotlinx.coroutines.launch -@OptIn(ExperimentalMaterial3Api::class) @Composable fun Passkey( viewModel: HomeViewModel, @@ -70,28 +74,26 @@ fun Passkey( verticalArrangement = Arrangement.spacedBy(16.dp), modifier = modifier .fillMaxSize() - .background(Color(0xFFF5F5F5)) + .background(MaterialTheme.colorScheme.background) .padding(16.dp) ) { Text( text = "${if (doEdit) "Update" else "Add"} Passkey ", style = MaterialTheme.typography.headlineMedium, - fontWeight = FontWeight.Bold, - color = Color(0xFF1A1A1A) + fontWeight = FontWeight.Bold ) Text( text = "${if (doEdit) "Update" else "Store"} your credentials securely", style = MaterialTheme.typography.bodyMedium, - color = Color.Gray ) Spacer(modifier = Modifier.height(16.dp)) Card( colors = CardDefaults.cardColors( - containerColor = Color.White, + containerColor = MaterialTheme.colorScheme.surface, ), elevation = CardDefaults.cardElevation( defaultElevation = 2.dp @@ -118,12 +120,15 @@ fun Passkey( } ?: false }, label = { Text("Service") }, - placeholder = { Text("eg. Github", color = Color.Black.copy(alpha = 0.4f)) }, + placeholder = { Text("eg. Github", color = MaterialTheme.colorScheme.primary.copy(alpha = 0.4f)) }, leadingIcon = { Icon(Icons.Default.Web, contentDescription = "Website name") }, modifier = Modifier.fillMaxWidth(), colors = OutlinedTextFieldDefaults.colors( - focusedBorderColor = Color(0xFF6200EE), - focusedLabelColor = Color(0xFF6200EE) + unfocusedBorderColor = Unfocused, + unfocusedLeadingIconColor = Unfocused, + focusedLeadingIconColor = MaterialTheme.colorScheme.primary, + focusedBorderColor = MaterialTheme.colorScheme.outline, + focusedLabelColor = MaterialTheme.colorScheme.primary ) ) OutlinedTextField( @@ -143,8 +148,11 @@ fun Passkey( leadingIcon = { Icon(Icons.Default.Person, contentDescription = "Username") }, modifier = Modifier.fillMaxWidth(), colors = OutlinedTextFieldDefaults.colors( - focusedBorderColor = Color(0xFF6200EE), - focusedLabelColor = Color(0xFF6200EE) + unfocusedBorderColor = Unfocused, + unfocusedLeadingIconColor = Unfocused, + focusedLeadingIconColor = MaterialTheme.colorScheme.primary, + focusedBorderColor = MaterialTheme.colorScheme.outline, + focusedLabelColor = MaterialTheme.colorScheme.primary ) ) @@ -170,8 +178,11 @@ fun Passkey( visualTransformation = if (isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(), modifier = Modifier.fillMaxWidth(), colors = OutlinedTextFieldDefaults.colors( - focusedBorderColor = Color(0xFF6200EE), - focusedLabelColor = Color(0xFF6200EE) + unfocusedBorderColor = Unfocused, + unfocusedLeadingIconColor = Unfocused, + focusedLeadingIconColor = MaterialTheme.colorScheme.primary, + focusedBorderColor = MaterialTheme.colorScheme.outline, + focusedLabelColor = MaterialTheme.colorScheme.primary ) ) } @@ -179,7 +190,7 @@ fun Passkey( Card( colors = CardDefaults.cardColors( - containerColor = Color.White + containerColor = MaterialTheme.colorScheme.surface ), elevation = CardDefaults.cardElevation( defaultElevation = 2.dp @@ -201,17 +212,22 @@ fun Passkey( ) } ?: false }, + textStyle = TextStyle( + color = MaterialTheme.colorScheme.primary, + fontSize = 16.sp + ), + cursorBrush = SolidColor(MaterialTheme.colorScheme.primary), decorationBox = { innerTextField -> Box( modifier = Modifier .fillMaxSize() - .padding(16.dp) + .padding(vertical = 16.dp, horizontal = 20.dp) ) { if (desc.isEmpty()) { Text( text = "Add a description...", style = TextStyle( - color = Color.Gray, + color = Unfocused, fontSize = 16.sp ) ) @@ -278,7 +294,7 @@ fun Passkey( .fillMaxWidth() .height(56.dp), colors = ButtonDefaults.buttonColors( - containerColor = Color(0xFF6200EE) + containerColor = Blue ), shape = RoundedCornerShape(12.dp) ) { @@ -353,7 +369,7 @@ fun LabelSelector( } .scale(scale.value), colors = CardDefaults.cardColors( - containerColor = if (isSelected) Color(0xFF9C27B0) else Color(0xFFF0F0F0) + containerColor = if (isSelected) Purple else Gray ), elevation = CardDefaults.cardElevation( defaultElevation = elevation.value diff --git a/app/src/main/java/com/karan/hashin/screens/home/PassKeyDetail.kt b/app/src/main/java/com/karan/hashin/screens/home/PassKeyDetail.kt index b9f285f..304a0b2 100644 --- a/app/src/main/java/com/karan/hashin/screens/home/PassKeyDetail.kt +++ b/app/src/main/java/com/karan/hashin/screens/home/PassKeyDetail.kt @@ -4,6 +4,7 @@ import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.graphics.drawable.Icon +import android.text.Layout import android.util.Log import android.widget.Toast import androidx.compose.animation.AnimatedVisibility @@ -109,14 +110,14 @@ fun PassKeyDetail( Column( modifier = modifier .fillMaxSize() - .background(Color(0xFFF8F9FA)) + .background(MaterialTheme.colorScheme.background) .verticalScroll(rememberScrollState()) ) { Row( horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier .fillMaxWidth() - .padding(horizontal = 16.dp) + .padding(16.dp) ) { Box( modifier = Modifier @@ -132,7 +133,7 @@ fun PassKeyDetail( Icon( Icons.Default.ArrowBackIosNew, contentDescription = "Back", - tint = Color.Black + tint = MaterialTheme.colorScheme.primary ) } @@ -150,7 +151,7 @@ fun PassKeyDetail( Icon( Icons.Default.DeleteOutline, contentDescription = "Back", - tint = Color.Black + tint = MaterialTheme.colorScheme.primary ) } } @@ -164,7 +165,8 @@ fun PassKeyDetail( // Header Card with Label Card( colors = CardDefaults.cardColors( - containerColor = Color(0xFF3F51B5) + containerColor = Color(0xFF3F51B5) // TODO(should be dynamic) + ), elevation = CardDefaults.cardElevation( defaultElevation = 8.dp @@ -178,10 +180,13 @@ fun PassKeyDetail( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier .fillMaxWidth() - .padding(24.dp) + .padding(horizontal = 24.dp) + .padding(top = 16.dp, bottom = 24.dp) ) { Row( - horizontalArrangement = Arrangement.End + horizontalArrangement = Arrangement.End, + modifier = Modifier + .fillMaxWidth() ) { IconButton( onClick = { @@ -206,7 +211,7 @@ fun PassKeyDetail( modifier = Modifier .size(80.dp) .clip(CircleShape) - .background(Color.White.copy(alpha = 0.2f)) + .background(Color.White.copy(alpha = 0.1f)) ) { Text( text = passkey.label.firstOrNull()?.uppercase() ?: "", @@ -243,7 +248,7 @@ fun PassKeyDetail( modifier = Modifier .fillMaxWidth(), colors = CardDefaults.cardColors( - containerColor = Color.White + containerColor = MaterialTheme.colorScheme.surface ), elevation = CardDefaults.cardElevation( defaultElevation = 4.dp @@ -349,7 +354,7 @@ private fun UsernameField( ) { Card( colors = CardDefaults.cardColors( - containerColor = Color(0xFFF8F9FA) + containerColor = MaterialTheme.colorScheme.surfaceVariant ), shape = RoundedCornerShape(12.dp), modifier = Modifier @@ -364,8 +369,8 @@ private fun UsernameField( Icon( imageVector = Icons.Default.Person, contentDescription = null, - tint = Color.Black, - modifier = Modifier.size(28.dp) + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(24.dp) ) Spacer(modifier = Modifier.width(12.dp)) @@ -387,7 +392,7 @@ private fun UsernameField( Icon( Icons.Default.ContentCopy, contentDescription = "Copy", - tint = Color.Black, + tint = MaterialTheme.colorScheme.primary, modifier = Modifier.size(18.dp) ) } @@ -403,11 +408,9 @@ private fun PasswordField( onValueChange: (String) -> Unit ) { - var pass by remember { mutableStateOf("") } - Card( colors = CardDefaults.cardColors( - containerColor = Color(0xFFF8F9FA) + containerColor = MaterialTheme.colorScheme.surfaceVariant ), shape = RoundedCornerShape(12.dp), modifier = Modifier @@ -422,12 +425,10 @@ private fun PasswordField( Icon( imageVector = Icons.Default.Lock, contentDescription = null, - tint = Color.Black, - modifier = Modifier.size(28.dp) + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(24.dp) ) - Spacer(modifier = Modifier.width(12.dp)) - Column( modifier = Modifier.weight(1f) ) { @@ -439,34 +440,24 @@ private fun PasswordField( readOnly = !isVisible, visualTransformation = if (isVisible) VisualTransformation.None else PasswordVisualTransformation(), colors = TextFieldDefaults.colors( - focusedContainerColor = Color(0xFFF8F9FA), - unfocusedContainerColor = Color(0xFFF8F9FA), - disabledContainerColor = Color(0xFFF8F9FA), unfocusedIndicatorColor = Color.Transparent, focusedIndicatorColor = Color.Transparent, disabledIndicatorColor = Color.Transparent - ) + ), ) } - // Visibility Toggle Button - Box( + // Visibility Button + IconButton( + onClick = onVisibilityToggle, modifier = Modifier .size(32.dp) - .semantics { role = Role.Button } - .clickable( - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) { - onVisibilityToggle() - } ) { Icon( if (isVisible) Icons.Default.Visibility else Icons.Default.VisibilityOff, contentDescription = "Toggle visibility", - tint = Color.Black, - modifier = Modifier - .size(18.dp) + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(18.dp) ) } } diff --git a/app/src/main/java/com/karan/hashin/screens/home/Settings.kt b/app/src/main/java/com/karan/hashin/screens/home/Settings.kt index 2439896..d589137 100644 --- a/app/src/main/java/com/karan/hashin/screens/home/Settings.kt +++ b/app/src/main/java/com/karan/hashin/screens/home/Settings.kt @@ -1,240 +1,116 @@ package com.karan.hashin.screens.home +import android.content.res.Configuration +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue import androidx.compose.animation.core.* import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* +import androidx.compose.material.icons.outlined.Edit import androidx.compose.material3.* import androidx.compose.runtime.* +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.scale -import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.window.Popup import androidx.lifecycle.viewmodel.compose.viewModel +import com.karan.hashin.ui.theme.Blue import com.karan.hashin.ui.theme.HashinTheme import com.karan.hashin.viewmodel.HomeViewModel @Composable fun Settings( - viewModel: HomeViewModel, +// viewModel: HomeViewModel, modifier: Modifier = Modifier ) { val context = LocalContext.current - var isDarkTheme by remember { mutableStateOf(false) } - - // Animation for profile section - val infiniteTransition = rememberInfiniteTransition(label = "profile") - val profileScale by infiniteTransition.animateFloat( - initialValue = 1f, - targetValue = 1.05f, - animationSpec = infiniteRepeatable( - animation = tween(2000), - repeatMode = RepeatMode.Reverse - ), - label = "profile" - ) + var isDarkTheme by rememberSaveable { mutableStateOf(false) } + var scrollState = rememberScrollState(0) Column( + verticalArrangement = Arrangement.spacedBy(8.dp), modifier = modifier + .statusBarsPadding() .fillMaxSize() - .background( - brush = Brush.verticalGradient( - colors = listOf( - MaterialTheme.colorScheme.background, - MaterialTheme.colorScheme.background.copy(alpha = 0.95f) - ) - ) - ) - .padding(16.dp), - verticalArrangement = Arrangement.spacedBy(20.dp) + .padding(horizontal = 16.dp) + .background(MaterialTheme.colorScheme.background) + .verticalScroll(scrollState) ) { - // Profile Section with Animation - Card( - modifier = Modifier - .fillMaxWidth() - .shadow( - elevation = 8.dp, - shape = RoundedCornerShape(24.dp) - ), - colors = CardDefaults.cardColors( - containerColor = MaterialTheme.colorScheme.surface - ), - shape = RoundedCornerShape(24.dp) - ) { - Column( - modifier = Modifier.padding(24.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Box( - modifier = Modifier - .size(100.dp) - .scale(profileScale) - .clip(CircleShape) - .background( - brush = Brush.linearGradient( - colors = listOf( - MaterialTheme.colorScheme.primary, - MaterialTheme.colorScheme.tertiary - ) - ) - ), - contentAlignment = Alignment.Center - ) { - Icon( - imageVector = Icons.Default.Person, - contentDescription = "Profile", - modifier = Modifier.size(50.dp), - tint = Color.White - ) - } - - Spacer(modifier = Modifier.height(20.dp)) - - Text( - text = "John Doe", - style = MaterialTheme.typography.headlineMedium, - fontWeight = FontWeight.Bold, - color = MaterialTheme.colorScheme.onSurface - ) - - Text( - text = "john.doe@example.com", - style = MaterialTheme.typography.bodyLarge, - color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f) - ) - - Spacer(modifier = Modifier.height(20.dp)) - - Button( - onClick = { /* TODO: Handle edit profile */ }, - modifier = Modifier - .fillMaxWidth() - .height(50.dp), - colors = ButtonDefaults.buttonColors( - containerColor = MaterialTheme.colorScheme.primary - ), - shape = RoundedCornerShape(16.dp) - ) { - Icon( - imageVector = Icons.Default.Edit, - contentDescription = null, - modifier = Modifier.size(24.dp) - ) - Spacer(modifier = Modifier.width(8.dp)) - Text( - "Edit Profile", - style = MaterialTheme.typography.titleMedium - ) - } - } - } + // Profile Card + ProfileCard() - // Settings Options with Modern Cards - Card( + // Settings Options Card + ElevatedCard( modifier = Modifier .fillMaxWidth() - .shadow( - elevation = 8.dp, - shape = RoundedCornerShape(24.dp) - ), - colors = CardDefaults.cardColors( + .padding(vertical = 8.dp), + elevation = CardDefaults.elevatedCardElevation(defaultElevation = 8.dp), + shape = RoundedCornerShape(24.dp), + colors = CardDefaults.elevatedCardColors( containerColor = MaterialTheme.colorScheme.surface - ), - shape = RoundedCornerShape(24.dp) + ) ) { - Column( - modifier = Modifier.padding(16.dp) - ) { + Column(modifier = Modifier.padding(16.dp)) { SettingsItem( icon = Icons.Default.DarkMode, title = "Dark Theme", - description = "Switch between light and dark mode", + description = "Switch to dark mode", trailing = { Switch( checked = isDarkTheme, onCheckedChange = { isDarkTheme = it }, colors = SwitchDefaults.colors( - checkedThumbColor = MaterialTheme.colorScheme.primary, - checkedTrackColor = MaterialTheme.colorScheme.primaryContainer, - uncheckedThumbColor = MaterialTheme.colorScheme.outline, - uncheckedTrackColor = MaterialTheme.colorScheme.surfaceVariant + uncheckedThumbColor = MaterialTheme.colorScheme.primary, + uncheckedTrackColor = MaterialTheme.colorScheme.surface, + uncheckedBorderColor = MaterialTheme.colorScheme.surfaceVariant, + checkedThumbColor = MaterialTheme.colorScheme.outline, + checkedTrackColor = MaterialTheme.colorScheme.surface, + checkedBorderColor = MaterialTheme.colorScheme.outline ) ) } ) - - Divider( - modifier = Modifier.padding(horizontal = 16.dp), - color = MaterialTheme.colorScheme.outline.copy(alpha = 0.1f) - ) - + Divider(color = MaterialTheme.colorScheme.outline.copy(alpha = 0.1f)) SettingsItem( icon = Icons.Default.Notifications, title = "Notifications", - description = "Manage your notification preferences", - onClick = { /* TODO: Handle notifications */ } - ) - - Divider( - modifier = Modifier.padding(horizontal = 16.dp), - color = MaterialTheme.colorScheme.outline.copy(alpha = 0.1f) + description = "Manage notifications", + onClick = { } ) - + Divider(color = MaterialTheme.colorScheme.outline.copy(alpha = 0.1f)) SettingsItem( icon = Icons.Default.Security, title = "Security", - description = "Manage your security settings", - onClick = { /* TODO: Handle security */ } - ) - - Divider( - modifier = Modifier.padding(horizontal = 16.dp), - color = MaterialTheme.colorScheme.outline.copy(alpha = 0.1f) + description = "Manage security settings", + onClick = { } ) - + Divider(color = MaterialTheme.colorScheme.outline.copy(alpha = 0.1f)) SettingsItem( - icon = Icons.Default.Help, + icon = Icons.Default.Feedback, title = "Help & Support", - description = "Get help and contact support", - onClick = { /* TODO: Handle help */ } + description = "Get help & contact support", + onClick = { } ) } } - - // Sign Out Button with Gradient - Button( - onClick = { /* TODO: Handle sign out */ }, - modifier = Modifier - .fillMaxWidth() - .height(56.dp), - colors = ButtonDefaults.buttonColors( - containerColor = MaterialTheme.colorScheme.error - ), - shape = RoundedCornerShape(16.dp) - ) { - Icon( - imageVector = Icons.Default.Logout, - contentDescription = null, - modifier = Modifier.size(24.dp) - ) - Spacer(modifier = Modifier.width(8.dp)) - Text( - "Sign Out", - style = MaterialTheme.typography.titleMedium - ) - } } } @@ -255,52 +131,170 @@ private fun SettingsItem( verticalAlignment = Alignment.CenterVertically ) { Box( + contentAlignment = Alignment.Center, modifier = Modifier .size(40.dp) .clip(RoundedCornerShape(12.dp)) - .background(MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)), - contentAlignment = Alignment.Center + .background(MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)) ) { - Icon( - imageVector = icon, - contentDescription = null, - tint = MaterialTheme.colorScheme.primary, - modifier = Modifier.size(24.dp) - ) + Icon(icon, contentDescription = null, tint = MaterialTheme.colorScheme.primary) } - Spacer(modifier = Modifier.width(16.dp)) - Column(modifier = Modifier.weight(1f)) { - Text( - text = title, - style = MaterialTheme.typography.titleMedium, - color = MaterialTheme.colorScheme.onSurface - ) - Text( - text = description, - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f) - ) + Text(title, style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurface) + Text(description, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f)) } - if (trailing != null) { trailing() } else { Icon( - imageVector = Icons.Default.ChevronRight, + Icons.Default.ChevronRight, contentDescription = null, - tint = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f), - modifier = Modifier.size(24.dp) + tint = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f) ) } } } -@Preview + +@Composable +fun ProfileCard(modifier: Modifier = Modifier) { + ElevatedCard( + elevation = CardDefaults.elevatedCardElevation(defaultElevation = 8.dp), + shape = RoundedCornerShape(24.dp), + colors = CardDefaults.elevatedCardColors( + containerColor = MaterialTheme.colorScheme.surface + ), + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp) + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .padding(top = 12.dp, bottom = 24.dp) + .padding(horizontal = 24.dp) + ) { + IconButton( + onClick = { }, + modifier = Modifier + .size(32.dp) + .align(Alignment.End) + ) { + Icon( + imageVector = Icons.Outlined.Edit, + contentDescription = "Edit info", + tint = MaterialTheme.colorScheme.primary + ) + } + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + ) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .size(80.dp) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.tertiary) + ) { + Icon( + imageVector = Icons.Default.Person, + contentDescription = "Profile", + tint = Color.White, + modifier = Modifier.size(50.dp) + ) + } + Spacer(modifier = Modifier.height(20.dp)) + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .fillMaxWidth() + ) { + Text( + text = "John Doe", + style = MaterialTheme.typography.headlineMedium, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = "john.doe@example.com", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f) + ) + } + + + } + Spacer(modifier = Modifier.height(24.dp)) + Button( + onClick = { /* Sign out */ }, + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.error + ), + shape = RoundedCornerShape(16.dp), + modifier = Modifier + .fillMaxWidth() + .height(56.dp) + ) { + Text("Sign Out", style = MaterialTheme.typography.titleMedium, color = Color.White) + } + } + } +} + +@Composable +fun AccountEditPopUp( + visible: Boolean, + onConfirm: () -> Unit, + onDismiss: () -> Unit +) { + if (visible) { + Popup() { + + } + } +} + +@Composable +fun SignOutAlert( + visible: Boolean, + onConfirm: () -> Unit, + onDismiss: () -> Unit +) { + if (visible) { + AlertDialog( + onDismissRequest = onDismiss, + title = { Text("Really !?") }, + text = { Text("Are you sure you want to sign out ?") }, + confirmButton = { + TextButton(onClick = onConfirm) { + Text("Sign Out", color = Color.Red) + } + }, + dismissButton = { + TextButton(onClick = onDismiss) { + Text("Cancel") + } + } + ) + } +} + +@Preview(showBackground = true, showSystemUi = true, uiMode = Configuration.UI_MODE_NIGHT_NO) @Composable -private fun PreviewSetting() { - HashinTheme { - Settings(viewModel()) +fun PreviewSettingsLight() { + MaterialTheme { +// Settings(viewModel()) + Settings() } -} \ No newline at end of file +} + +//@Preview(showBackground = true, showSystemUi = true) +//@Composable +//fun PreviewSettingsDark() { +// MaterialTheme(colorScheme = darkColorScheme()) { +// Settings() +// } +//} diff --git a/app/src/main/java/com/karan/hashin/screens/home/Vault.kt b/app/src/main/java/com/karan/hashin/screens/home/Vault.kt index 1cc2ab9..00cef58 100644 --- a/app/src/main/java/com/karan/hashin/screens/home/Vault.kt +++ b/app/src/main/java/com/karan/hashin/screens/home/Vault.kt @@ -3,6 +3,7 @@ package com.karan.hashin.screens.home import android.util.Log import androidx.activity.compose.BackHandler import androidx.activity.compose.LocalOnBackPressedDispatcherOwner +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize @@ -12,6 +13,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf @@ -48,15 +50,10 @@ fun Vault( Column( modifier = modifier .fillMaxSize() + .background(MaterialTheme.colorScheme.background) .statusBarsPadding() .navigationBarsPadding() ) { - // Top App Bar -// TopAppBar( -// onSearch = { -// // TODO: Implement search functionality -// } -// ) // Content Box( @@ -73,7 +70,7 @@ fun Vault( } } else { val data = viewModel.passkeys.also { - Log.d("#ined", "data: ${it.toList()}") +// Log.d("#ined", "data: ${it.toList()}") } if (data.isEmpty()) { diff --git a/app/src/main/java/com/karan/hashin/ui/theme/Color.kt b/app/src/main/java/com/karan/hashin/ui/theme/Color.kt index f60b0ce..482715f 100644 --- a/app/src/main/java/com/karan/hashin/ui/theme/Color.kt +++ b/app/src/main/java/com/karan/hashin/ui/theme/Color.kt @@ -6,10 +6,22 @@ import androidx.compose.ui.graphics.Color val iconTintLight = Color(0xFF2962FF) val iconTintDark = Color(0xFF82B1FF) -val PurpleA700 = Color(0xFF9C27B0) +val Purple = Color(0xFF9C27B0) +val Blue = Color(0xFF6200EE) +val Gray = Color(0xFFF0F0F0) + +val BlueSelectionLight = Color(0xFF6200EE) +val BlueSelectionDark = Color(0xFF82B1FF) +val Unfocused = Color(red = 147, green = 143, blue = 153) + +val SurfaceDark = Color(0xFF1E1E1E) +val SurfaceLight = Color.White +val SurfaceVariantDark = Color(0xFF2A2A2A) +val SurfaceVariantLight = Color(0xFFF2F2F2) + val PurpleGrey80 = Color(0xFFCCC2DC) val Pink80 = Color(0xFFEFB8C8) -val Purple40 = Color(0xFF6650a4) +val Purple40 = Color(0xFF6650A4) val PurpleGrey40 = Color(0xFF625b71) val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/app/src/main/java/com/karan/hashin/ui/theme/Theme.kt b/app/src/main/java/com/karan/hashin/ui/theme/Theme.kt index 2eaa3cc..ddfdaeb 100644 --- a/app/src/main/java/com/karan/hashin/ui/theme/Theme.kt +++ b/app/src/main/java/com/karan/hashin/ui/theme/Theme.kt @@ -1,7 +1,11 @@ package com.karan.hashin.ui.theme -import android.app.Activity +import android.graphics.Color.TRANSPARENT import android.os.Build +import androidx.activity.ComponentActivity +import androidx.activity.SystemBarStyle +import androidx.activity.compose.LocalActivity +import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material.ripple.LocalRippleTheme import androidx.compose.material.ripple.RippleAlpha @@ -13,35 +17,56 @@ import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.DisposableEffect import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext private val DarkColorScheme = darkColorScheme( + // Background + background = Color(0xFF121212), + // Primary Scheme primary = Color.White, // Icon color - primaryContainer = Color.Black, - onPrimaryContainer = Color.White, + primaryContainer = Color(0xFF292929), +// onPrimaryContainer = Color(0xFFEADDFF), // Secondary Scheme secondary = Color(0xFF9C27B0), onSecondary = Color.White, - secondaryContainer = Color(0xFF41484D) , + secondaryContainer = Color(0xFF41484D), onSecondaryContainer = Color.White, // Tertiary Scheme tertiary = Color(0xFFF0F0F0), onTertiary = Color(0xFF666666), - tertiaryContainer = Color(0xFF4A4458), + tertiaryContainer = Color.Black, onTertiaryContainer = Color.White, + + outline = BlueSelectionDark, + + // Surface + surface = SurfaceDark, + surfaceTint = SurfaceDark, + surfaceVariant = SurfaceVariantDark, + surfaceContainer = Color(0xFF242424), + onSurface = Color.White, + onSurfaceVariant = Color.White, +// surfaceContainerLow = Color(0xFF1B1B1B), +// surfaceContainerHigh = Color(0xFF2E2E2E) + + error = Color(0xFFCF6679), ) private val LightColorScheme = lightColorScheme( + // BackGround + background = Color(0xFFFFFBFE), + // Primary Scheme primary = Color.Black, - primaryContainer = Color.White, - onPrimaryContainer = Color.Black, + primaryContainer = Color(0xFFEADDFF), +// onPrimaryContainer = Color(0xFF21005D), // Secondary Scheme secondary = Color(0xFF9C27B0), @@ -51,21 +76,26 @@ private val LightColorScheme = lightColorScheme( // Tertiary Scheme tertiary = Color(0xFFF0F0F0), onTertiary = Color(0xFF666666), + tertiaryContainer = Color.White, + + outline = BlueSelectionLight, + + surface = SurfaceLight, + surfaceVariant = SurfaceVariantLight, + surfaceContainer = Color(0xFFF7F7F7), + surfaceTint = SurfaceLight, + onSurface = Color.Black, + onSurfaceVariant = Color.Black, + + error = Color(0xFFB3261E), - /* 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), - */ ) object NoRippleTheme : RippleTheme { - @Composable override fun defaultColor() = Color.Unspecified - @Composable override fun rippleAlpha() = RippleAlpha(0f, 0f, 0f, 0f) + @Composable + override fun defaultColor() = Color.Unspecified + @Composable + override fun rippleAlpha() = RippleAlpha(0f, 0f, 0f, 0f) } @Composable @@ -75,6 +105,7 @@ fun HashinTheme( dynamicColor: Boolean = true, content: @Composable () -> Unit ) { + val activity = LocalActivity.current as ComponentActivity val colorScheme = when { dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { val context = LocalContext.current @@ -86,11 +117,29 @@ fun HashinTheme( } + DisposableEffect(darkTheme) { + val barStyle = if (darkTheme) { + SystemBarStyle.dark( + scrim = TRANSPARENT + ) + } else { + SystemBarStyle.light( + scrim = TRANSPARENT, + darkScrim = TRANSPARENT + ) + } + activity.enableEdgeToEdge( + statusBarStyle = barStyle, + navigationBarStyle = barStyle + ) + onDispose { } + } + MaterialTheme( colorScheme = colorScheme, typography = Typography, - ) { + ) { CompositionLocalProvider( LocalRippleTheme provides NoRippleTheme, ) {