auth to server-V2

This commit is contained in:
Eric85710 2026-04-27 18:24:00 +08:00
parent ff86c28ee0
commit 8c26b4c5a1
8 changed files with 74 additions and 119 deletions

View file

@ -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
}
}
}

View file

@ -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 = {

View file

@ -0,0 +1 @@
package com.example.login_v3.auth.login

View file

@ -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 = {

View file

@ -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}")
}
}
}
}

View file

@ -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)
}

View file

@ -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>
}

View file

@ -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(