auth to server-V95
This commit is contained in:
parent
538c018470
commit
d9f5efc680
3 changed files with 278 additions and 2 deletions
|
|
@ -0,0 +1,271 @@
|
|||
package com.example.login_v3.auth.SwitchAccount
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
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.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.AccountCircle
|
||||
import androidx.compose.material.icons.rounded.Lock
|
||||
import androidx.compose.material.icons.rounded.Visibility
|
||||
import androidx.compose.material.icons.rounded.VisibilityOff
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
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.draw.BlurredEdgeTreatment
|
||||
import androidx.compose.ui.draw.blur
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Color.Companion.Red
|
||||
import androidx.compose.ui.graphics.Color.Companion.Transparent
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
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.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import coil.ImageLoader
|
||||
import coil.compose.AsyncImage
|
||||
import coil.decode.SvgDecoder
|
||||
import coil.request.ImageRequest
|
||||
import com.example.login_v3.R
|
||||
import com.example.login_v3.auth.login.AuthViewModel
|
||||
import com.example.login_v3.auth.login.LoginUiState
|
||||
import com.example.login_v3.ui.theme.light_orange
|
||||
import com.example.login_v3.ui.theme.main_orange
|
||||
import kotlin.text.ifEmpty
|
||||
|
||||
@Composable
|
||||
fun AddAccountScreen(
|
||||
paddingValues: PaddingValues,
|
||||
viewModel: AuthViewModel = hiltViewModel()
|
||||
){
|
||||
|
||||
val uiState by viewModel.loginState.collectAsStateWithLifecycle()
|
||||
val isLoading = uiState is LoginUiState.Loading
|
||||
var username by remember { mutableStateOf("") }
|
||||
var password by remember { mutableStateOf("") }
|
||||
var passwordVisible by remember { mutableStateOf(false) }
|
||||
|
||||
var usernameError by remember { mutableStateOf("") }
|
||||
var passwordError by remember { mutableStateOf("") }
|
||||
|
||||
|
||||
|
||||
//background
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(
|
||||
brush = Brush.linearGradient(
|
||||
colors = listOf(
|
||||
Color(0xFFDA7029),
|
||||
Color(0xFF777777),
|
||||
Color(0xFFB34800)
|
||||
)
|
||||
)
|
||||
)
|
||||
.padding(paddingValues),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
|
||||
|
||||
//title
|
||||
Text(text = "Add Account",
|
||||
fontSize = 32.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = Color.White
|
||||
)
|
||||
|
||||
//login Box
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(340.dp)
|
||||
.fillMaxWidth()
|
||||
.padding(start = 24.dp, end = 24.dp, top = 20.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
){
|
||||
|
||||
|
||||
//glass effect
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.clip(RoundedCornerShape(16.dp)) // 🔥 一定要有
|
||||
.blur(
|
||||
radius = 10.dp,
|
||||
edgeTreatment = BlurredEdgeTreatment.Unbounded
|
||||
)
|
||||
.background(
|
||||
Color.White.copy(alpha = 0.18f)
|
||||
)
|
||||
.border( // ⭐ 玻璃邊框
|
||||
width = 1.dp,
|
||||
color = Color.White.copy(alpha = 0.35f),
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(8.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
|
||||
TextField(
|
||||
value = username,
|
||||
onValueChange = { username = it},
|
||||
label = {
|
||||
Text(
|
||||
usernameError.ifEmpty { "username" },
|
||||
color = if (usernameError.isNotEmpty()) Red else Color.Unspecified
|
||||
)
|
||||
},
|
||||
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Rounded.AccountCircle,
|
||||
contentDescription = ""
|
||||
)
|
||||
},
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 4.dp, horizontal = 16.dp),
|
||||
|
||||
colors = TextFieldDefaults.colors(
|
||||
focusedContainerColor = Transparent,
|
||||
unfocusedIndicatorColor = Transparent
|
||||
)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
|
||||
|
||||
TextField(
|
||||
value = password,
|
||||
onValueChange = { password = it },
|
||||
label = {
|
||||
Text(
|
||||
passwordError.ifEmpty { "Password" },
|
||||
color = if (passwordError.isNotEmpty()) Red else Color.Unspecified
|
||||
)
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(Icons.Rounded.Lock, contentDescription = "")
|
||||
},
|
||||
|
||||
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
|
||||
trailingIcon = {
|
||||
val image = if (passwordVisible) {
|
||||
Icons.Rounded.Visibility
|
||||
} else {
|
||||
Icons.Rounded.VisibilityOff
|
||||
}
|
||||
|
||||
IconButton(onClick = { passwordVisible = !passwordVisible }) {
|
||||
Icon(imageVector = image, contentDescription = if (passwordVisible) "Hide password" else "Show password")
|
||||
}
|
||||
},
|
||||
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 4.dp, horizontal = 16.dp),
|
||||
|
||||
colors = TextFieldDefaults.colors(
|
||||
focusedContainerColor = Transparent,
|
||||
unfocusedIndicatorColor = Transparent
|
||||
)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
|
||||
when (uiState) {
|
||||
is LoginUiState.Success -> {
|
||||
val user = (uiState as LoginUiState.Success).user
|
||||
Text("歡迎,${user.display_name}")
|
||||
}
|
||||
is LoginUiState.Error -> {
|
||||
Text(text = (uiState as LoginUiState.Error).message, color = Color.Red)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
|
||||
if (isLoading) {
|
||||
CircularProgressIndicator(color = Color.White)
|
||||
} else {
|
||||
Button(
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
onClick = {
|
||||
usernameError = if(username.isBlank()) "Email is required" else ""
|
||||
passwordError = if(password.isBlank()) "password is required" else ""
|
||||
if (usernameError.isEmpty() && passwordError.isEmpty()){
|
||||
viewModel.login(username, password)
|
||||
}
|
||||
},
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = main_orange, // 背景顏色
|
||||
contentColor = Color.White // 文字顏色
|
||||
)
|
||||
|
||||
) {
|
||||
Text( text = "Login")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Text( text = "forget password?",
|
||||
color = light_orange,
|
||||
modifier = Modifier
|
||||
.clickable{}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ class MainViewModel : ViewModel() {
|
|||
|
||||
//init navigation
|
||||
enum class AppScreen {
|
||||
PreReg, Login, Register, Home, ScreensTab, Loading, AccountSwitch
|
||||
PreReg, Login, Register, Home, ScreensTab, Loading, AccountSwitch, AddAccount
|
||||
}
|
||||
|
||||
@HiltViewModel
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
|||
import com.example.login_v3.auth.login.LoginScreen
|
||||
import com.example.login_v3.auth.Login_or_Reg_page
|
||||
import com.example.login_v3.auth.SwitchAccount.AccountSwitchScreen
|
||||
import com.example.login_v3.auth.SwitchAccount.AddAccountScreen
|
||||
import com.example.login_v3.auth.reg.RegisterScreen
|
||||
import com.example.login_v3.auth.reg.Register_Screen
|
||||
import com.example.login_v3.home.HomeScreen
|
||||
|
|
@ -45,6 +46,10 @@ fun AppNavGraph(
|
|||
paddingValues = paddingValues
|
||||
)
|
||||
|
||||
AppScreen.AddAccount -> AddAccountScreen(
|
||||
paddingValues = paddingValues
|
||||
)
|
||||
|
||||
AppScreen.Register -> {
|
||||
//back to pre_reg
|
||||
BackHandler {
|
||||
|
|
@ -69,7 +74,7 @@ fun AppNavGraph(
|
|||
AppScreen.AccountSwitch -> {
|
||||
AccountSwitchScreen(
|
||||
// 點擊「登入另一個帳號」就跳轉到 Login 頁面
|
||||
onAddAccountClick = { appViewModel.goTo(AppScreen.Login) },
|
||||
onAddAccountClick = { appViewModel.goTo(AppScreen.AddAccount) },
|
||||
// 點擊返回則回到原本的主分頁 (ScreensTab)
|
||||
onBack = { appViewModel.goTo(AppScreen.ScreensTab) }
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue