This commit is contained in:
2024-07-30 09:04:07 +08:00
parent 53c71973ae
commit 406caa3702
6 changed files with 637 additions and 21 deletions

View File

@@ -29,7 +29,10 @@ import com.aiosman.riderpro.ui.gallery.ProfileTimelineScreen
import com.aiosman.riderpro.ui.index.IndexScreen import com.aiosman.riderpro.ui.index.IndexScreen
import com.aiosman.riderpro.ui.like.LikeScreen import com.aiosman.riderpro.ui.like.LikeScreen
import com.aiosman.riderpro.ui.location.LocationDetailScreen import com.aiosman.riderpro.ui.location.LocationDetailScreen
import com.aiosman.riderpro.ui.login.EmailSignupScreen
import com.aiosman.riderpro.ui.login.LoginPage import com.aiosman.riderpro.ui.login.LoginPage
import com.aiosman.riderpro.ui.login.SignupScreen
import com.aiosman.riderpro.ui.login.UserAuthScreen
import com.aiosman.riderpro.ui.message.NotificationsScreen import com.aiosman.riderpro.ui.message.NotificationsScreen
import com.aiosman.riderpro.ui.modification.EditModificationScreen import com.aiosman.riderpro.ui.modification.EditModificationScreen
import com.aiosman.riderpro.ui.post.NewPostScreen import com.aiosman.riderpro.ui.post.NewPostScreen
@@ -54,6 +57,9 @@ sealed class NavigationRoute(
data object EditModification : NavigationRoute("EditModification") data object EditModification : NavigationRoute("EditModification")
data object Login : NavigationRoute("Login") data object Login : NavigationRoute("Login")
data object AccountProfile : NavigationRoute("AccountProfile/{id}") data object AccountProfile : NavigationRoute("AccountProfile/{id}")
data object SignUp : NavigationRoute("SignUp")
data object UserAuth : NavigationRoute("UserAuth")
data object EmailSignUp : NavigationRoute("EmailSignUp")
} }
@@ -65,7 +71,7 @@ fun NavigationController(navController: NavHostController) {
NavHost( NavHost(
navController = navController, navController = navController,
startDestination = NavigationRoute.Login.route, startDestination = NavigationRoute.Index.route,
) { ) {
composable(route = NavigationRoute.Index.route) { composable(route = NavigationRoute.Index.route) {
CompositionLocalProvider( CompositionLocalProvider(
@@ -148,6 +154,15 @@ fun NavigationController(navController: NavHostController) {
) { ) {
AccountProfile(it.arguments?.getString("id")!!) AccountProfile(it.arguments?.getString("id")!!)
} }
composable(route = NavigationRoute.SignUp.route) {
SignupScreen()
}
composable(route = NavigationRoute.UserAuth.route) {
UserAuthScreen()
}
composable(route = NavigationRoute.EmailSignUp.route) {
EmailSignupScreen()
}
} }

View File

@@ -62,7 +62,8 @@ fun CommentsScreen() {
@Composable @Composable
fun NoticeScreenHeader( fun NoticeScreenHeader(
title:String title:String,
moreIcon: Boolean = true
) { ) {
val nav = LocalNavController.current val nav = LocalNavController.current
Row( Row(
@@ -80,13 +81,16 @@ fun NoticeScreenHeader(
} }
) )
Spacer(modifier = Modifier.size(12.dp)) Spacer(modifier = Modifier.size(12.dp))
Text(title, fontWeight = FontWeight.Bold, fontSize = 17.sp) Text(title, fontWeight = FontWeight.W800, fontSize = 17.sp)
if (moreIcon) {
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
Image( Image(
painter = painterResource(id = R.drawable.rider_pro_more_horizon), painter = painterResource(id = R.drawable.rider_pro_more_horizon),
contentDescription = "More", contentDescription = "More",
modifier = Modifier.size(24.dp) modifier = Modifier.size(24.dp)
) )
}
} }
} }

View File

@@ -0,0 +1,155 @@
package com.aiosman.riderpro.ui.login
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.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Checkbox
import androidx.compose.material3.CheckboxDefaults
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.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.aiosman.riderpro.R
import com.aiosman.riderpro.ui.comment.NoticeScreenHeader
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
@Composable
fun EmailSignupScreen() {
var email by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
var rememberMe by remember { mutableStateOf(false) }
var acceptTerms by remember { mutableStateOf(false) }
var acceptPromotions by remember { mutableStateOf(false) }
StatusBarMaskLayout {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(top = 16.dp, start = 16.dp, end = 16.dp)
) {
NoticeScreenHeader("SIGNUP", moreIcon = false)
}
Spacer(modifier = Modifier.padding(68.dp))
TextInputField(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp),
text = email,
onValueChange = {
email = it
},
label = "What's your email?",
hint = "Enter your email"
)
Spacer(modifier = Modifier.padding(16.dp))
TextInputField(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp),
text = password,
onValueChange = {
password = it
},
password = true,
label = "What's your password?",
hint = "Enter your password"
)
Spacer(modifier = Modifier.padding(16.dp))
TextInputField(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp),
text = password,
onValueChange = {
password = it
},
password = true,
label = "Confirm password",
hint = "Enter your password"
)
Spacer(modifier = Modifier.height(32.dp))
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.Start,
) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
checked = rememberMe,
onCheckedChange = {
rememberMe = it
},
modifier = Modifier.padding(start = 16.dp),
colors = CheckboxDefaults.colors(
checkedColor = Color.Black
),
)
Text("Remember me", modifier = Modifier.padding(start = 4.dp))
}
Row(
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
checked = acceptTerms,
onCheckedChange = {
acceptTerms = it
},
modifier = Modifier.padding(start = 16.dp),
colors = CheckboxDefaults.colors(
checkedColor = Color.Black
),
)
Text(
"Yes, I have read and agree to RiderPros Terms of Service.",
modifier = Modifier.padding(start = 4.dp),
fontSize = 12.sp
)
}
Row(
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
checked = acceptPromotions,
onCheckedChange = {
acceptPromotions = it
},
modifier = Modifier.padding(start = 16.dp),
colors = CheckboxDefaults.colors(
checkedColor = Color.Black
),
)
Text(
"Yes, Send me news and promotional content from RiderPro.",
modifier = Modifier.padding(start = 4.dp),
fontSize = 12.sp
)
}
}
Spacer(modifier = Modifier.height(64.dp))
ActionButton(
modifier = Modifier
.width(345.dp)
.height(48.dp),
text = "LET'S RIDE".uppercase(),
backgroundImage = R.mipmap.rider_pro_signup_red_bg
)
}
}
}

View File

@@ -1,41 +1,133 @@
package com.aiosman.riderpro.ui.login package com.aiosman.riderpro.ui.login
import androidx.annotation.DrawableRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column 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.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ElevatedButton import androidx.compose.foundation.layout.width
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.aiosman.riderpro.LocalNavController import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.R
import com.aiosman.riderpro.ui.NavigationRoute import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
@Composable @Composable
fun LoginPage() { fun LoginPage() {
val navController = LocalNavController.current val navController = LocalNavController.current
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
navController.navigate(NavigationRoute.Index.route) // navController.navigate(NavigationRoute.Index.route)
} }
Scaffold { paddingValues -> Scaffold {
Column( it
modifier = Modifier.padding(paddingValues).padding(horizontal = 16.dp).fillMaxSize(), Box(
verticalArrangement = Arrangement.Center, modifier = Modifier.fillMaxSize()
horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Text("Login", fontSize = 24.sp) // to bottom
ElevatedButton( Box(
onClick = { /*TODO*/ }, contentAlignment = Alignment.TopCenter,
modifier = Modifier.padding(top = 211.dp)
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
Text("Login with Google") Image(
painter = painterResource(id = R.mipmap.rider_pro_logo),
contentDescription = "Rider Pro",
modifier = Modifier
.width(108.dp)
.height(45.dp)
)
Spacer(modifier = Modifier.height(32.dp))
Text(
"Connecting Riders".uppercase(),
fontSize = 28.sp,
fontWeight = FontWeight.Bold
)
Text("Worldwide".uppercase(), fontSize = 28.sp, fontWeight = FontWeight.Bold)
}
}
Box(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 82.dp + 162.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
) {
ActionButton(
modifier = Modifier
.width(162.dp)
.height(48.dp),
text = "Login in".uppercase(),
backgroundImage = R.mipmap.rider_pro_grey_bg_big
) {
navController.navigate(NavigationRoute.UserAuth.route)
}
ActionButton(
modifier = Modifier
.width(162.dp)
.height(48.dp),
text = "Sign In".uppercase(),
backgroundImage = R.mipmap.rider_pro_red_bg_big
){
navController.navigate(NavigationRoute.SignUp.route)
} }
} }
} }
}
}
}
@Composable
fun ActionButton(
modifier: Modifier,
text: String,
color: Color = Color.White,
@DrawableRes backgroundImage: Int,
leading: @Composable (() -> Unit)? = null,
click: () -> Unit = {}
) {
Box(
modifier = modifier.noRippleClickable {
click()
}
) {
Image(
painter = painterResource(id = backgroundImage),
contentDescription = "Rider Pro",
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.FillBounds
)
Row(
modifier = Modifier.align(Alignment.Center),
verticalAlignment = Alignment.CenterVertically
) {
leading?.invoke()
Text(text, fontSize = 16.sp, color = color, fontWeight = FontWeight.W400)
}
}
} }

View File

@@ -0,0 +1,172 @@
package com.aiosman.riderpro.ui.login
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
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.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.R
import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
@Composable
fun SignupScreen() {
val navController = LocalNavController.current
Scaffold(
modifier = Modifier
.fillMaxSize()
.background(Color(0xFFECECEC))
) {
it
Box(
modifier = Modifier.fillMaxSize()
) {
// to bottom
Box(
contentAlignment = Alignment.TopCenter,
modifier = Modifier.padding(top = 211.dp)
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
Image(
painter = painterResource(id = R.mipmap.rider_pro_logo),
contentDescription = "Rider Pro",
modifier = Modifier
.width(108.dp)
.height(45.dp)
)
Spacer(modifier = Modifier.height(32.dp))
Text(
"Connecting Riders".uppercase(),
fontSize = 28.sp,
fontWeight = FontWeight.Bold
)
Text("Worldwide".uppercase(), fontSize = 28.sp, fontWeight = FontWeight.Bold)
}
}
Box(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 82.dp, start = 24.dp, end = 24.dp)
) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
ActionButton(
modifier = Modifier
.width(345.dp)
.height(48.dp),
text = "CONTINUE WITH EMAIL".uppercase(),
backgroundImage = R.mipmap.rider_pro_signup_red_bg,
leading = {
Image(
painter = painterResource(id = R.mipmap.rider_pro_email),
contentDescription = "Email",
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(8.dp))
}
) {
navController.navigate(NavigationRoute.EmailSignUp.route)
}
Spacer(modifier = Modifier.height(16.dp))
ActionButton(
modifier = Modifier
.width(345.dp)
.height(48.dp),
text = "CONTINUE WITH FACEBOOK".uppercase(),
backgroundImage = R.mipmap.rider_pro_signup_facebook_bg,
leading = {
Image(
painter = painterResource(id = R.mipmap.rider_pro_signup_facebook),
contentDescription = "Facebook",
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(8.dp))
}
)
Spacer(modifier = Modifier.height(16.dp))
ActionButton(
modifier = Modifier
.width(345.dp)
.height(48.dp),
color = Color.Black,
leading = {
Image(
painter = painterResource(id = R.mipmap.rider_pro_signup_google),
contentDescription = "Google",
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(8.dp))
},
text = "CONTINUE WITH GOOGLE".uppercase(),
backgroundImage = R.mipmap.rider_pro_signup_white_bg
)
Spacer(modifier = Modifier.height(16.dp))
Box(
modifier = Modifier
.width(345.dp)
.height(48.dp)
.clip(RoundedCornerShape(8.dp))
.background(Color.Black)
) {
Text(
"Sign in with Apple",
color = Color.White,
modifier = Modifier.align(Alignment.Center),
fontSize = 16.sp,
fontWeight = FontWeight.Bold
)
}
Spacer(modifier = Modifier.height(40.dp))
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.noRippleClickable {
navController.popBackStack()
}
) {
Image(
painter = painterResource(id = R.drawable.rider_pro_nav_back),
contentDescription = "Back",
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text(
"BACK",
color = Color.Black,
fontSize = 16.sp,
fontWeight = FontWeight.Bold
)
}
}
}
}
}
}

View File

@@ -0,0 +1,178 @@
package com.aiosman.riderpro.ui.login
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
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.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Checkbox
import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
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.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.aiosman.riderpro.R
import com.aiosman.riderpro.ui.comment.NoticeScreenHeader
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun UserAuthScreen() {
var email by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
var rememberMe by remember { mutableStateOf(false) }
StatusBarMaskLayout {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(top = 16.dp, start = 16.dp, end = 16.dp)
) {
NoticeScreenHeader("LOGIN", moreIcon = false)
}
Spacer(modifier = Modifier.padding(68.dp))
TextInputField(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp),
text = email,
onValueChange = {
email = it
},
label = "What's your email?",
hint = "Enter your email"
)
Spacer(modifier = Modifier.padding(16.dp))
TextInputField(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp),
text = password,
onValueChange = {
password = it
},
password = true,
label = "What's your password?",
hint = "Enter your password"
)
Spacer(modifier = Modifier.height(32.dp))
Row(
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
checked = rememberMe,
onCheckedChange = {
rememberMe = it
},
modifier = Modifier.padding(start = 24.dp),
colors = CheckboxDefaults.colors(
checkedColor = Color.Black
),
)
Text("Remember me", modifier = Modifier.padding(start = 4.dp))
Spacer(modifier = Modifier.weight(1f))
Text("Forgot password?", modifier = Modifier.padding(end = 24.dp))
}
Spacer(modifier = Modifier.height(64.dp))
ActionButton(
modifier = Modifier
.width(345.dp)
.height(48.dp),
text = "LET'S RIDE".uppercase(),
backgroundImage = R.mipmap.rider_pro_signup_red_bg
)
Spacer(modifier = Modifier.height(121.dp))
Text("or login with", color = Color(0xFF999999))
}
}
}
@Composable
fun TextInputField(
modifier: Modifier = Modifier,
text: String,
onValueChange: (String) -> Unit,
password: Boolean = false,
label: String? = null,
hint: String? = null
) {
var showPassword by remember { mutableStateOf(!password) }
Column(modifier = modifier) {
label?.let {
Text(it, color = Color(0xFFCCCCCC))
Spacer(modifier = Modifier.height(16.dp))
}
Box(
contentAlignment = Alignment.CenterStart
) {
Row {
BasicTextField(
value = text,
onValueChange = onValueChange,
modifier = Modifier.weight(1f),
textStyle = TextStyle(
fontSize = 16.sp,
fontWeight = FontWeight.W500
),
keyboardOptions = KeyboardOptions(
keyboardType = if (password) KeyboardType.Password else KeyboardType.Text
),
visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(),
singleLine = true
)
if (password) {
Image(
painter = painterResource(id = R.drawable.rider_pro_eye),
contentDescription = "Password",
modifier = Modifier.size(24.dp).noRippleClickable {
showPassword = !showPassword
},
colorFilter = androidx.compose.ui.graphics.ColorFilter.tint(Color.Black)
)
}
}
if (text.isEmpty()) {
hint?.let {
Text(it, color = Color(0xFFCCCCCC), fontWeight = FontWeight.W600)
}
}
}
Spacer(modifier = Modifier.height(16.dp))
Box(
modifier = Modifier
.fillMaxWidth()
.height(1.dp)
.background(Color(0xFFF5F5F5))
)
}
}