From b14f883e3e8cb879205cbf28f71d9bae34efc4fe Mon Sep 17 00:00:00 2001 From: AndyChen1024 Date: Fri, 11 Sep 2026 13:05:10 +0800 Subject: [PATCH] =?UTF-8?q?feat(auth):=20=E6=89=8B=E6=9C=BA=E5=8F=B7?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E7=A0=81=E7=99=BB=E5=BD=95=EF=BC=88=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D=E6=A8=A1=E5=9E=8B=20+=20=E7=99=BB=E5=BD=95=E9=A1=B5?= =?UTF-8?q?=20+=20=E5=AF=BC=E8=88=AA=E6=8E=A5=E5=85=A5=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mingyuan/android_client/AppNavHost.kt | 16 ++- .../android_client/core/data/di/DataModule.kt | 14 ++ .../data/repository/FakeSessionRepository.kt | 64 +++++++-- core/datastore/build.gradle.kts | 2 +- .../domain/repository/SessionRepository.kt | 21 ++- .../android_client/core/model/AuthModels.kt | 11 ++ .../android_client/feature/auth/AuthScreen.kt | 124 +++++++++++++++++- .../feature/auth/AuthViewModel.kt | 68 +++++++++- .../feature/checkin/CheckinScreen.kt | 4 +- .../android_client/feature/home/HomeScreen.kt | 4 +- .../android_client/feature/plan/PlanScreen.kt | 4 +- .../feature/profile/ProfileScreen.kt | 3 +- .../feature/profile/ProfileViewModel.kt | 6 - 13 files changed, 308 insertions(+), 33 deletions(-) create mode 100644 core/model/src/main/kotlin/com/mingyuan/android_client/core/model/AuthModels.kt diff --git a/app/src/main/java/com/mingyuan/android_client/AppNavHost.kt b/app/src/main/java/com/mingyuan/android_client/AppNavHost.kt index c14f43c..5fa3247 100644 --- a/app/src/main/java/com/mingyuan/android_client/AppNavHost.kt +++ b/app/src/main/java/com/mingyuan/android_client/AppNavHost.kt @@ -21,6 +21,8 @@ import androidx.navigation.navArgument import com.mingyuan.android_client.core.designsystem.theme.TabActive import com.mingyuan.android_client.core.designsystem.theme.TabBackground import com.mingyuan.android_client.core.designsystem.theme.TabInactive +import com.mingyuan.android_client.feature.auth.AUTH_ROUTE +import com.mingyuan.android_client.feature.auth.AuthScreen import com.mingyuan.android_client.feature.checkin.CHECKIN_ROUTE import com.mingyuan.android_client.feature.checkin.CheckinScreen import com.mingyuan.android_client.feature.home.HOME_ROUTE @@ -74,18 +76,18 @@ fun AppNavHost() { HomeScreen( onNavigateToCheckin = { navigateToTab(CHECKIN_ROUTE) }, onNavigateToPlan = { navigateToTab(PLAN_ROUTE) }, - onNavigateToProfile = { navigateToTab(PROFILE_ROUTE) }, + onNavigateToAuth = { navController.navigate(AUTH_ROUTE) }, ) } composable(CHECKIN_ROUTE) { - CheckinScreen(onNavigateToProfile = { navigateToTab(PROFILE_ROUTE) }) + CheckinScreen(onNavigateToAuth = { navController.navigate(AUTH_ROUTE) }) } composable(PLAN_ROUTE) { PlanScreen( onNavigateToPlanSubmit = { type, periodKey -> navController.navigate(planSubmitRoute(type, periodKey)) }, - onNavigateToProfile = { navigateToTab(PROFILE_ROUTE) }, + onNavigateToAuth = { navController.navigate(AUTH_ROUTE) }, ) } composable( @@ -100,8 +102,14 @@ fun AppNavHost() { ) { PlanSubmitScreen(onBack = { navController.popBackStack() }) } + composable(AUTH_ROUTE) { + AuthScreen(onLoggedIn = { navController.popBackStack() }) + } composable(PROFILE_ROUTE) { - ProfileScreen(onLoggedOut = { navigateToTab(HOME_ROUTE) }) + ProfileScreen( + onNavigateToAuth = { navController.navigate(AUTH_ROUTE) }, + onLoggedOut = { navigateToTab(HOME_ROUTE) }, + ) } } } diff --git a/core/data/src/main/kotlin/com/mingyuan/android_client/core/data/di/DataModule.kt b/core/data/src/main/kotlin/com/mingyuan/android_client/core/data/di/DataModule.kt index 7e8b81f..160fb23 100644 --- a/core/data/src/main/kotlin/com/mingyuan/android_client/core/data/di/DataModule.kt +++ b/core/data/src/main/kotlin/com/mingyuan/android_client/core/data/di/DataModule.kt @@ -1,5 +1,10 @@ package com.mingyuan.android_client.core.data.di +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.PreferenceDataStoreFactory +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.preferencesDataStoreFile import com.mingyuan.android_client.core.data.repository.FakeCheckinRepository import com.mingyuan.android_client.core.data.repository.FakeHomeRepository import com.mingyuan.android_client.core.data.repository.FakePlanRepository @@ -12,7 +17,9 @@ import com.mingyuan.android_client.core.domain.repository.ProfileRepository import com.mingyuan.android_client.core.domain.repository.SessionRepository import dagger.Binds import dagger.Module +import dagger.Provides import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import javax.inject.Singleton @@ -39,4 +46,11 @@ abstract class DataModule { @Binds @Singleton abstract fun bindSessionRepository(impl: FakeSessionRepository): SessionRepository + + companion object { + @Provides + @Singleton + fun provideSessionDataStore(@ApplicationContext context: Context): DataStore = + PreferenceDataStoreFactory.create { context.preferencesDataStoreFile("session") } + } } diff --git a/core/data/src/main/kotlin/com/mingyuan/android_client/core/data/repository/FakeSessionRepository.kt b/core/data/src/main/kotlin/com/mingyuan/android_client/core/data/repository/FakeSessionRepository.kt index 61fc6da..6e59682 100644 --- a/core/data/src/main/kotlin/com/mingyuan/android_client/core/data/repository/FakeSessionRepository.kt +++ b/core/data/src/main/kotlin/com/mingyuan/android_client/core/data/repository/FakeSessionRepository.kt @@ -1,25 +1,71 @@ package com.mingyuan.android_client.core.data.repository +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.stringPreferencesKey +import com.mingyuan.android_client.core.domain.repository.LoginResult import com.mingyuan.android_client.core.domain.repository.SessionRepository +import com.mingyuan.android_client.core.domain.repository.SmsCodeResult +import com.mingyuan.android_client.core.model.Session import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.map import javax.inject.Inject import javax.inject.Singleton +/** + * Local-mock session implementation. It simulates the "phone + SMS code" login flow and persists + * the token via DataStore so the login survives process restarts (mirroring the mini-program's + * `wx.getStorageSync('token')`). Swap this for a network-backed implementation when the backend + * endpoints are ready. + * + * Mock credentials: phone `13812341234`, code `123456`. + */ @Singleton -class FakeSessionRepository @Inject constructor() : SessionRepository { +class FakeSessionRepository @Inject constructor( + private val dataStore: DataStore, +) : SessionRepository { - private val _isLoggedIn = MutableStateFlow(true) - override val isLoggedIn: Flow = _isLoggedIn + private companion object { + val TOKEN_KEY = stringPreferencesKey("token") + const val MOCK_SMS_CODE = "123456" + val PHONE_PATTERN = Regex("^1\\d{10}$") + // Mirrors the backend's "phone must be pre-provisioned" constraint. + val PHONE_WHITELIST = setOf("13812341234") + } + + private var pendingCode: String? = null + private var pendingPhone: String? = null + + override val session: Flow = dataStore.data + .map { prefs -> prefs[TOKEN_KEY]?.let(::Session) } + + override suspend fun requestSmsCode(phone: String): SmsCodeResult { + if (!PHONE_PATTERN.matches(phone)) { + return SmsCodeResult.Failure("请输入正确的手机号") + } + delay(500) + pendingPhone = phone + pendingCode = MOCK_SMS_CODE + return SmsCodeResult.Success + } - override suspend fun login() { - delay(300) - _isLoggedIn.value = true + override suspend fun login(phone: String, code: String): LoginResult { + if (phone != pendingPhone || code != pendingCode) { + return LoginResult.Failure("验证码错误") + } + if (phone !in PHONE_WHITELIST) { + return LoginResult.Failure("手机号未匹配,无法登录") + } + delay(500) + dataStore.edit { it[TOKEN_KEY] = "mock-token-$phone" } + pendingPhone = null + pendingCode = null + return LoginResult.Success } override suspend fun logout() { - delay(300) - _isLoggedIn.value = false + dataStore.edit { it.remove(TOKEN_KEY) } } } diff --git a/core/datastore/build.gradle.kts b/core/datastore/build.gradle.kts index a004782..2479323 100644 --- a/core/datastore/build.gradle.kts +++ b/core/datastore/build.gradle.kts @@ -8,5 +8,5 @@ android { dependencies { implementation(project(":core:model")) - implementation(libs.androidx.datastore.preferences) + api(libs.androidx.datastore.preferences) } diff --git a/core/domain/src/main/kotlin/com/mingyuan/android_client/core/domain/repository/SessionRepository.kt b/core/domain/src/main/kotlin/com/mingyuan/android_client/core/domain/repository/SessionRepository.kt index 6a56a86..2f9a514 100644 --- a/core/domain/src/main/kotlin/com/mingyuan/android_client/core/domain/repository/SessionRepository.kt +++ b/core/domain/src/main/kotlin/com/mingyuan/android_client/core/domain/repository/SessionRepository.kt @@ -1,11 +1,30 @@ package com.mingyuan.android_client.core.domain.repository +import com.mingyuan.android_client.core.model.Session import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +sealed interface SmsCodeResult { + data object Success : SmsCodeResult + data class Failure(val message: String) : SmsCodeResult +} + +sealed interface LoginResult { + data object Success : LoginResult + data class Failure(val message: String) : LoginResult +} interface SessionRepository { + /** The current session, or `null` when logged out. */ + val session: Flow + + /** Derived convenience kept for the existing feature ViewModels (home/checkin/plan/profile). */ val isLoggedIn: Flow + get() = session.map { it != null } + + suspend fun requestSmsCode(phone: String): SmsCodeResult - suspend fun login() + suspend fun login(phone: String, code: String): LoginResult suspend fun logout() } diff --git a/core/model/src/main/kotlin/com/mingyuan/android_client/core/model/AuthModels.kt b/core/model/src/main/kotlin/com/mingyuan/android_client/core/model/AuthModels.kt new file mode 100644 index 0000000..c811abe --- /dev/null +++ b/core/model/src/main/kotlin/com/mingyuan/android_client/core/model/AuthModels.kt @@ -0,0 +1,11 @@ +package com.mingyuan.android_client.core.model + +/** + * A logged-in session. Deliberately minimal for now: the token is the only thing needed to decide + * whether the user is logged in, and the user profile is still provided by [ProfileRepository]. + * When the real backend lands, this grows a `user: AuthUser` field and the local data source grows + * a user cache. + */ +data class Session( + val token: String, +) diff --git a/feature/auth/src/main/kotlin/com/mingyuan/android_client/feature/auth/AuthScreen.kt b/feature/auth/src/main/kotlin/com/mingyuan/android_client/feature/auth/AuthScreen.kt index f4e5b5f..7ecb3e2 100644 --- a/feature/auth/src/main/kotlin/com/mingyuan/android_client/feature/auth/AuthScreen.kt +++ b/feature/auth/src/main/kotlin/com/mingyuan/android_client/feature/auth/AuthScreen.kt @@ -1,18 +1,134 @@ package com.mingyuan.android_client.feature.auth -import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.background +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.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Checkbox +import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +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.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.mingyuan.android_client.core.designsystem.component.MingyuanButton +import com.mingyuan.android_client.core.designsystem.theme.Danger +import com.mingyuan.android_client.core.designsystem.theme.FaintText +import com.mingyuan.android_client.core.designsystem.theme.PageBackground +import com.mingyuan.android_client.core.designsystem.theme.PrimaryText /** Navigation route for this feature, referenced by the app-level NavHost. */ const val AUTH_ROUTE = "auth" +private val PHONE_PATTERN = Regex("^1\\d{10}$") + @Composable -fun AuthScreen(modifier: Modifier = Modifier) { - Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - Text(text = "Auth") +fun AuthScreen( + onLoggedIn: () -> Unit, + modifier: Modifier = Modifier, + viewModel: AuthViewModel = hiltViewModel(), +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + var phone by remember { mutableStateOf("") } + var code by remember { mutableStateOf("") } + var privacyAgreed by remember { mutableStateOf(false) } + + LaunchedEffect(Unit) { + viewModel.loginSuccess.collect { onLoggedIn() } + } + + val phoneValid = PHONE_PATTERN.matches(phone) + val canSendCode = phoneValid && uiState.countdownSeconds == 0 && !uiState.isSendingCode + val canSubmit = phoneValid && code.isNotBlank() && privacyAgreed && !uiState.isSubmitting + + Column( + modifier = modifier + .fillMaxSize() + .background(PageBackground) + .verticalScroll(rememberScrollState()) + .padding(24.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Spacer(Modifier.height(48.dp)) + Text("手机号登录", color = PrimaryText, fontSize = 22.sp, fontWeight = FontWeight.Bold) + Spacer(Modifier.height(8.dp)) + Text("手机号仅用于账号绑定,不会公开展示", color = FaintText, fontSize = 13.sp) + Spacer(Modifier.height(32.dp)) + + OutlinedTextField( + value = phone, + onValueChange = { phone = it.filter(Char::isDigit).take(11) }, + label = { Text("手机号") }, + singleLine = true, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Phone), + modifier = Modifier.fillMaxWidth(), + ) + Spacer(Modifier.height(16.dp)) + + Row(verticalAlignment = Alignment.CenterVertically) { + OutlinedTextField( + value = code, + onValueChange = { code = it.filter(Char::isDigit).take(6) }, + label = { Text("验证码") }, + singleLine = true, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + modifier = Modifier.weight(1f), + ) + Spacer(Modifier.width(12.dp)) + MingyuanButton( + text = when { + uiState.countdownSeconds > 0 -> "${uiState.countdownSeconds}s 后重发" + uiState.isSendingCode -> "发送中" + else -> "获取验证码" + }, + onClick = { viewModel.requestSmsCode(phone) }, + enabled = canSendCode, + ) + } + Spacer(Modifier.height(16.dp)) + + Row(verticalAlignment = Alignment.CenterVertically) { + Checkbox( + checked = privacyAgreed, + onCheckedChange = { privacyAgreed = it }, + ) + Text( + text = "我已阅读并同意《用户协议》和《隐私政策》", + color = FaintText, + fontSize = 12.sp, + ) + } + Spacer(Modifier.height(8.dp)) + + uiState.errorMessage?.let { message -> + Text(message, color = Danger, fontSize = 13.sp) + Spacer(Modifier.height(8.dp)) + } + + Spacer(Modifier.height(16.dp)) + MingyuanButton( + text = if (uiState.isSubmitting) "登录中..." else "登录", + onClick = { viewModel.login(phone, code) }, + enabled = canSubmit, + fullWidth = true, + ) } } diff --git a/feature/auth/src/main/kotlin/com/mingyuan/android_client/feature/auth/AuthViewModel.kt b/feature/auth/src/main/kotlin/com/mingyuan/android_client/feature/auth/AuthViewModel.kt index a229a6a..54f6149 100644 --- a/feature/auth/src/main/kotlin/com/mingyuan/android_client/feature/auth/AuthViewModel.kt +++ b/feature/auth/src/main/kotlin/com/mingyuan/android_client/feature/auth/AuthViewModel.kt @@ -1,8 +1,74 @@ package com.mingyuan.android_client.feature.auth import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.mingyuan.android_client.core.domain.repository.LoginResult +import com.mingyuan.android_client.core.domain.repository.SessionRepository +import com.mingyuan.android_client.core.domain.repository.SmsCodeResult import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch + +data class AuthUiState( + val isSendingCode: Boolean = false, + val countdownSeconds: Int = 0, + val isSubmitting: Boolean = false, + val errorMessage: String? = null, +) @HiltViewModel -class AuthViewModel @Inject constructor() : ViewModel() +class AuthViewModel @Inject constructor( + private val sessionRepository: SessionRepository, +) : ViewModel() { + + private val _uiState = MutableStateFlow(AuthUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _loginSuccess = MutableSharedFlow() + val loginSuccess: SharedFlow = _loginSuccess + + private var countdownJob: Job? = null + + fun requestSmsCode(phone: String) { + if (_uiState.value.isSendingCode || _uiState.value.countdownSeconds > 0) return + viewModelScope.launch { + _uiState.update { it.copy(isSendingCode = true, errorMessage = null) } + when (val result = sessionRepository.requestSmsCode(phone)) { + is SmsCodeResult.Success -> startCountdown() + is SmsCodeResult.Failure -> _uiState.update { it.copy(errorMessage = result.message) } + } + _uiState.update { it.copy(isSendingCode = false) } + } + } + + fun login(phone: String, code: String) { + if (_uiState.value.isSubmitting) return + viewModelScope.launch { + _uiState.update { it.copy(isSubmitting = true, errorMessage = null) } + when (val result = sessionRepository.login(phone, code)) { + is LoginResult.Success -> _loginSuccess.emit(Unit) + is LoginResult.Failure -> _uiState.update { it.copy(errorMessage = result.message) } + } + _uiState.update { it.copy(isSubmitting = false) } + } + } + + private fun startCountdown() { + countdownJob?.cancel() + countdownJob = viewModelScope.launch { + for (seconds in 60 downTo 1) { + _uiState.update { it.copy(countdownSeconds = seconds) } + delay(1000) + } + _uiState.update { it.copy(countdownSeconds = 0) } + } + } +} diff --git a/feature/checkin/src/main/kotlin/com/mingyuan/android_client/feature/checkin/CheckinScreen.kt b/feature/checkin/src/main/kotlin/com/mingyuan/android_client/feature/checkin/CheckinScreen.kt index e157157..134b202 100644 --- a/feature/checkin/src/main/kotlin/com/mingyuan/android_client/feature/checkin/CheckinScreen.kt +++ b/feature/checkin/src/main/kotlin/com/mingyuan/android_client/feature/checkin/CheckinScreen.kt @@ -58,7 +58,7 @@ const val CHECKIN_ROUTE = "checkin" @Composable fun CheckinScreen( - onNavigateToProfile: () -> Unit, + onNavigateToAuth: () -> Unit, modifier: Modifier = Modifier, viewModel: CheckinViewModel = hiltViewModel(), ) { @@ -68,7 +68,7 @@ fun CheckinScreen( LaunchedEffect(uiState) { if (uiState is CheckinUiState.LoggedOut) { - onNavigateToProfile() + onNavigateToAuth() } } diff --git a/feature/home/src/main/kotlin/com/mingyuan/android_client/feature/home/HomeScreen.kt b/feature/home/src/main/kotlin/com/mingyuan/android_client/feature/home/HomeScreen.kt index a29dcd8..d2bc0a3 100644 --- a/feature/home/src/main/kotlin/com/mingyuan/android_client/feature/home/HomeScreen.kt +++ b/feature/home/src/main/kotlin/com/mingyuan/android_client/feature/home/HomeScreen.kt @@ -56,7 +56,7 @@ const val HOME_ROUTE = "home" fun HomeScreen( onNavigateToCheckin: () -> Unit, onNavigateToPlan: () -> Unit, - onNavigateToProfile: () -> Unit, + onNavigateToAuth: () -> Unit, modifier: Modifier = Modifier, viewModel: HomeViewModel = hiltViewModel(), ) { @@ -97,7 +97,7 @@ fun HomeScreen( TextButton( onClick = { showLoginDialog = false - onNavigateToProfile() + onNavigateToAuth() }, ) { Text("去登录") diff --git a/feature/plan/src/main/kotlin/com/mingyuan/android_client/feature/plan/PlanScreen.kt b/feature/plan/src/main/kotlin/com/mingyuan/android_client/feature/plan/PlanScreen.kt index 738058b..f95b998 100644 --- a/feature/plan/src/main/kotlin/com/mingyuan/android_client/feature/plan/PlanScreen.kt +++ b/feature/plan/src/main/kotlin/com/mingyuan/android_client/feature/plan/PlanScreen.kt @@ -68,7 +68,7 @@ const val PLAN_ROUTE = "plan" @Composable fun PlanScreen( onNavigateToPlanSubmit: (PlanType, String) -> Unit, - onNavigateToProfile: () -> Unit, + onNavigateToAuth: () -> Unit, modifier: Modifier = Modifier, viewModel: PlanViewModel = hiltViewModel(), ) { @@ -77,7 +77,7 @@ fun PlanScreen( LaunchedEffect(uiState) { if (uiState is PlanUiState.LoggedOut) { - onNavigateToProfile() + onNavigateToAuth() } } diff --git a/feature/profile/src/main/kotlin/com/mingyuan/android_client/feature/profile/ProfileScreen.kt b/feature/profile/src/main/kotlin/com/mingyuan/android_client/feature/profile/ProfileScreen.kt index 8a1fc6f..bcdeec3 100644 --- a/feature/profile/src/main/kotlin/com/mingyuan/android_client/feature/profile/ProfileScreen.kt +++ b/feature/profile/src/main/kotlin/com/mingyuan/android_client/feature/profile/ProfileScreen.kt @@ -55,6 +55,7 @@ const val PROFILE_ROUTE = "profile" @Composable fun ProfileScreen( + onNavigateToAuth: () -> Unit, onLoggedOut: () -> Unit, modifier: Modifier = Modifier, viewModel: ProfileViewModel = hiltViewModel(), @@ -68,7 +69,7 @@ fun ProfileScreen( when (val state = uiState) { is ProfileUiState.Loading -> ProfileSkeleton(modifier) - is ProfileUiState.LoggedOut -> LoggedOutState(onLogin = viewModel::login, modifier = modifier) + is ProfileUiState.LoggedOut -> LoggedOutState(onLogin = onNavigateToAuth, modifier = modifier) is ProfileUiState.Error -> ErrorState( message = state.message, onRetry = {}, diff --git a/feature/profile/src/main/kotlin/com/mingyuan/android_client/feature/profile/ProfileViewModel.kt b/feature/profile/src/main/kotlin/com/mingyuan/android_client/feature/profile/ProfileViewModel.kt index 87c299c..ab15c59 100644 --- a/feature/profile/src/main/kotlin/com/mingyuan/android_client/feature/profile/ProfileViewModel.kt +++ b/feature/profile/src/main/kotlin/com/mingyuan/android_client/feature/profile/ProfileViewModel.kt @@ -52,12 +52,6 @@ class ProfileViewModel @Inject constructor( private val _logoutEvents = MutableSharedFlow() val logoutEvents: SharedFlow = _logoutEvents - fun login() { - viewModelScope.launch { - sessionRepository.login() - } - } - fun logout() { viewModelScope.launch { sessionRepository.logout()