auth to server-V2
This commit is contained in:
parent
ff86c28ee0
commit
8c26b4c5a1
8 changed files with 74 additions and 119 deletions
|
|
@ -1,30 +0,0 @@
|
||||||
package com.example.login_v3.auth
|
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import com.example.login_v3.data.api.api_class.LoginResponse
|
|
||||||
import com.example.login_v3.data.repository.basic.ITecnologiaRepository
|
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
|
|
||||||
@HiltViewModel
|
|
||||||
class LoginViewModel @Inject constructor(
|
|
||||||
private val repository: ITecnologiaRepository
|
|
||||||
) : ViewModel() {
|
|
||||||
|
|
||||||
// 使用 StateFlow 或 LiveData 來傳遞結果給 UI
|
|
||||||
private val _loginResult = MutableStateFlow<Result<LoginResponse>?>(null)
|
|
||||||
val loginResult = _loginResult.asStateFlow()
|
|
||||||
|
|
||||||
fun performLogin(username: String, password: String) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
// 直接呼叫 repository,ViewModel 不關心資料是從網路還是資料庫來的
|
|
||||||
val result = repository.login(username, password)
|
|
||||||
_loginResult.value = result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.example.login_v3.auth
|
package com.example.login_v3.auth.login
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
|
|
@ -13,7 +13,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.rounded.AccountCircle
|
import androidx.compose.material.icons.rounded.AccountCircle
|
||||||
|
|
@ -47,8 +46,6 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
import androidx.compose.ui.text.input.VisualTransformation
|
import androidx.compose.ui.text.input.VisualTransformation
|
||||||
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 androidx.hilt.navigation.compose.hiltViewModel
|
|
||||||
import androidx.navigation.NavBackStackEntry
|
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import coil.decode.SvgDecoder
|
import coil.decode.SvgDecoder
|
||||||
|
|
@ -159,7 +156,7 @@ fun LoginScreen(
|
||||||
label = {
|
label = {
|
||||||
Text(
|
Text(
|
||||||
emailError.ifEmpty { "Email" },
|
emailError.ifEmpty { "Email" },
|
||||||
color = if (emailError.isNotEmpty()) Red else androidx.compose.ui.graphics.Color.Unspecified
|
color = if (emailError.isNotEmpty()) Red else Color.Unspecified
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -190,7 +187,7 @@ fun LoginScreen(
|
||||||
label = {
|
label = {
|
||||||
Text(
|
Text(
|
||||||
passwordError.ifEmpty { "Password" },
|
passwordError.ifEmpty { "Password" },
|
||||||
color = if (passwordError.isNotEmpty()) Red else androidx.compose.ui.graphics.Color.Unspecified
|
color = if (passwordError.isNotEmpty()) Red else Color.Unspecified
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
leadingIcon = {
|
leadingIcon = {
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package com.example.login_v3.auth.login
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.example.login_v3.auth
|
package com.example.login_v3.auth.reg
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
|
|
@ -11,7 +11,6 @@ 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.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.rounded.AccountCircle
|
import androidx.compose.material.icons.rounded.AccountCircle
|
||||||
|
|
@ -45,8 +44,6 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
import androidx.compose.ui.text.input.VisualTransformation
|
import androidx.compose.ui.text.input.VisualTransformation
|
||||||
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 androidx.hilt.navigation.compose.hiltViewModel
|
|
||||||
import com.example.login_v3.data.health.HealthCheckViewModel
|
|
||||||
import com.example.login_v3.ui.theme.main_orange
|
import com.example.login_v3.ui.theme.main_orange
|
||||||
import kotlin.text.ifEmpty
|
import kotlin.text.ifEmpty
|
||||||
|
|
||||||
|
|
@ -137,7 +134,7 @@ fun Register_Screen(
|
||||||
label = {
|
label = {
|
||||||
Text(
|
Text(
|
||||||
user_name_Error.ifEmpty { "username" },
|
user_name_Error.ifEmpty { "username" },
|
||||||
color = if (user_name_Error.isNotEmpty()) Red else androidx.compose.ui.graphics.Color.Unspecified
|
color = if (user_name_Error.isNotEmpty()) Red else Color.Unspecified
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -168,7 +165,7 @@ fun Register_Screen(
|
||||||
label = {
|
label = {
|
||||||
Text(
|
Text(
|
||||||
emailError.ifEmpty { "Email" },
|
emailError.ifEmpty { "Email" },
|
||||||
color = if (emailError.isNotEmpty()) Red else androidx.compose.ui.graphics.Color.Unspecified
|
color = if (emailError.isNotEmpty()) Red else Color.Unspecified
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -199,7 +196,7 @@ fun Register_Screen(
|
||||||
label = {
|
label = {
|
||||||
Text(
|
Text(
|
||||||
passwordError.ifEmpty { "Password" },
|
passwordError.ifEmpty { "Password" },
|
||||||
color = if (passwordError.isNotEmpty()) Red else androidx.compose.ui.graphics.Color.Unspecified
|
color = if (passwordError.isNotEmpty()) Red else Color.Unspecified
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
leadingIcon = {
|
leadingIcon = {
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.example.login_v3.auth.reg
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.example.login_v3.data.api.api_class.RegisterRequest
|
||||||
|
import com.example.login_v3.data.repository.basic.AuthRepository
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class RegisterViewModel @Inject constructor(
|
||||||
|
private val repository: AuthRepository
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
|
fun handleRegister() {
|
||||||
|
val request = RegisterRequest(
|
||||||
|
display_name = "測試員",
|
||||||
|
email = "test@example.com",
|
||||||
|
password = "password123",
|
||||||
|
username = "tester01"
|
||||||
|
)
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
val response = repository.register(request)
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
// 註冊成功,處理 response.body()
|
||||||
|
val successMsg = response.body()?.message
|
||||||
|
println("註冊成功: $successMsg")
|
||||||
|
} else {
|
||||||
|
// 註冊失敗,處理錯誤訊息 (例如 400 重複註冊)
|
||||||
|
val errorJson = response.errorBody()?.string()
|
||||||
|
println("註冊失敗: $errorJson")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// 處理網路連線異常
|
||||||
|
println("網路錯誤: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.example.login_v3.data.repository.basic
|
||||||
|
|
||||||
|
import com.example.login_v3.data.api.TecnologiaApi
|
||||||
|
import com.example.login_v3.data.api.api_class.ApiResponse
|
||||||
|
import com.example.login_v3.data.api.api_class.RegisterRequest
|
||||||
|
import retrofit2.Response
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class AuthRepository @Inject constructor(
|
||||||
|
private val api: TecnologiaApi
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* 處理用戶註冊
|
||||||
|
* 回傳 Response<ApiResponse>,讓 ViewModel 可以根據 isSuccessful 判斷結果
|
||||||
|
*/
|
||||||
|
suspend fun register(request: RegisterRequest): Response<ApiResponse> {
|
||||||
|
return api.register(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 你也可以在這裡加入其他的 Auth 相關功能,例如登入
|
||||||
|
// suspend fun login(request: LoginRequest) = api.login(request)
|
||||||
|
}
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
package com.example.login_v3.data.repository.basic
|
|
||||||
|
|
||||||
import com.example.login_v3.data.api.TecnologiaApi
|
|
||||||
import com.example.login_v3.data.api.api_class.ApiResponse
|
|
||||||
import com.example.login_v3.data.api.api_class.FriendRequest
|
|
||||||
import com.example.login_v3.data.api.api_class.LoginRequest
|
|
||||||
import com.example.login_v3.data.api.api_class.LoginResponse
|
|
||||||
import com.example.login_v3.data.api.api_class.User
|
|
||||||
import dagger.Binds
|
|
||||||
import dagger.Module
|
|
||||||
import dagger.hilt.InstallIn
|
|
||||||
import dagger.hilt.components.SingletonComponent
|
|
||||||
import java.lang.Exception
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
class TecnologiaRepositoryImpl @Inject constructor(
|
|
||||||
private val api: TecnologiaApi // Hilt 會從 NetworkModule 找這個 API
|
|
||||||
) : ITecnologiaRepository {
|
|
||||||
|
|
||||||
override suspend fun login(username: String, password: String): Result<LoginResponse> {
|
|
||||||
return try {
|
|
||||||
val response = api.login(LoginRequest(username, password))
|
|
||||||
Result.success(response)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Result.failure(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getMe(token: String): Result<User> {
|
|
||||||
return try {
|
|
||||||
val response = api.getMe("Bearer $token")
|
|
||||||
Result.success(response)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Result.failure(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun sendFriendRequest(token: String, friendId: String): Result<ApiResponse> {
|
|
||||||
return try {
|
|
||||||
val response = api.sendFriendRequest("Bearer $token", FriendRequest(friendId))
|
|
||||||
Result.success(response)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Result.failure(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Module
|
|
||||||
@InstallIn(SingletonComponent::class)
|
|
||||||
abstract class RepositoryModule {
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
@Singleton
|
|
||||||
abstract fun bindTecnologiaRepository(
|
|
||||||
repositoryImpl: TecnologiaRepositoryImpl // 這裡要對應實作類別的名稱
|
|
||||||
): ITecnologiaRepository
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ITecnologiaRepository {
|
|
||||||
suspend fun login(username: String, password: String): Result<LoginResponse>
|
|
||||||
suspend fun getMe(token: String): Result<User>
|
|
||||||
suspend fun sendFriendRequest(token: String, friendId: String): Result<ApiResponse>
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +1,15 @@
|
||||||
package com.example.login_v3.navigation
|
package com.example.login_v3.navigation
|
||||||
|
|
||||||
import android.R.attr.padding
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavHostController
|
import com.example.login_v3.auth.login.LoginScreen
|
||||||
import androidx.navigation.compose.NavHost
|
|
||||||
import androidx.navigation.compose.composable
|
|
||||||
import androidx.navigation.compose.rememberNavController
|
|
||||||
import com.example.login_v3.auth.LoginScreen
|
|
||||||
import com.example.login_v3.auth.LoginViewModel
|
|
||||||
import com.example.login_v3.auth.Login_or_Reg_page
|
import com.example.login_v3.auth.Login_or_Reg_page
|
||||||
import com.example.login_v3.auth.Register_Screen
|
import com.example.login_v3.auth.reg.Register_Screen
|
||||||
import com.example.login_v3.home.HomeScreen
|
import com.example.login_v3.home.HomeScreen
|
||||||
import com.example.login_v3.home.Tg_MarketPlace
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AppNavGraph(
|
fun AppNavGraph(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue