forked from Olympic/NTO-2025-Android-TeamTask
singleton (AuthRepository) repo refactor
This commit is contained in:
@@ -20,6 +20,6 @@ class App : Application() {
|
||||
super.onCreate()
|
||||
instance = this
|
||||
|
||||
AuthRepository.init(applicationContext)
|
||||
AuthRepository.getInstance(applicationContext)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
package ru.myitschool.work.core
|
||||
|
||||
object Constants {
|
||||
|
||||
const val HOST = "http://10.0.2.2:8080"
|
||||
// const val HOST = "http://127.0.0.1:8080"
|
||||
|
||||
const val AUTH_URL = "/auth"
|
||||
const val INFO_URL = "/info"
|
||||
const val BOOKING_URL = "/booking"
|
||||
|
||||
@@ -7,42 +7,48 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import ru.myitschool.work.data.source.NetworkDataSource
|
||||
|
||||
object AuthRepository {
|
||||
private const val PREFS_NAME = "auth_prefs"
|
||||
private const val KEY_CODE = "auth_code"
|
||||
private const val KEY_NAME = "user_name"
|
||||
private const val KEY_PHOTO = "user_photo"
|
||||
class AuthRepository private constructor(context: Context) {
|
||||
|
||||
private var _context: Context? = null
|
||||
companion object {
|
||||
@Volatile
|
||||
private var INSTANCE: AuthRepository? = null
|
||||
|
||||
fun getInstance(context: Context): AuthRepository {
|
||||
return INSTANCE ?: synchronized(this) {
|
||||
INSTANCE ?: AuthRepository(context.applicationContext).also { INSTANCE = it }
|
||||
}
|
||||
}
|
||||
|
||||
fun clearInstance() {
|
||||
INSTANCE = null
|
||||
}
|
||||
}
|
||||
|
||||
private val PREFS_NAME = "auth_prefs"
|
||||
private val KEY_CODE = "auth_code"
|
||||
private val KEY_NAME = "user_name"
|
||||
private val KEY_PHOTO = "user_photo"
|
||||
|
||||
private val context: Context = context.applicationContext
|
||||
private var codeCache: String? = null
|
||||
private var userCache: UserCache? = null
|
||||
|
||||
private val _isAuthorized = MutableStateFlow(false)
|
||||
val isAuthorized: StateFlow<Boolean> = _isAuthorized.asStateFlow()
|
||||
|
||||
fun init(context: Context) {
|
||||
if (_context == null) {
|
||||
_context = context.applicationContext
|
||||
init {
|
||||
val prefs = context.getSharedPreferences(PREFS_NAME, MODE_PRIVATE)
|
||||
codeCache = prefs.getString(KEY_CODE, null)
|
||||
val name = prefs.getString(KEY_NAME, null)
|
||||
val photo = prefs.getString(KEY_PHOTO, null)
|
||||
|
||||
val prefs = _context!!.getSharedPreferences(PREFS_NAME, MODE_PRIVATE)
|
||||
codeCache = prefs.getString(KEY_CODE, null)
|
||||
val name = prefs.getString(KEY_NAME, null)
|
||||
val photo = prefs.getString(KEY_PHOTO, null)
|
||||
|
||||
if (codeCache != null && name != null) {
|
||||
userCache = UserCache(name, photo)
|
||||
_isAuthorized.value = true
|
||||
}
|
||||
if (codeCache != null && name != null) {
|
||||
userCache = UserCache(name, photo)
|
||||
_isAuthorized.value = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun requireContext(): Context {
|
||||
return _context ?: throw IllegalStateException(
|
||||
"AuthRepository not inited"
|
||||
)
|
||||
}
|
||||
|
||||
private fun getPrefs() = requireContext().getSharedPreferences(PREFS_NAME, MODE_PRIVATE)
|
||||
private fun getPrefs() = context.getSharedPreferences(PREFS_NAME, MODE_PRIVATE)
|
||||
|
||||
suspend fun checkAndSave(text: String): Result<Boolean> {
|
||||
return NetworkDataSource.checkAuth(text).onSuccess { success ->
|
||||
|
||||
@@ -4,9 +4,10 @@ import ru.myitschool.work.data.model.BookingInfoResponse
|
||||
import ru.myitschool.work.data.source.AuthException
|
||||
import ru.myitschool.work.data.source.NetworkDataSource
|
||||
|
||||
object BookRepository {
|
||||
class BookRepository(private val authRepository: AuthRepository) {
|
||||
|
||||
suspend fun getAvailableBookings(): Result<BookingInfoResponse> {
|
||||
val code = AuthRepository.getCurrentCode()
|
||||
val code = authRepository.getCurrentCode()
|
||||
return if (code != null) {
|
||||
NetworkDataSource.getBookingInfo(code)
|
||||
} else {
|
||||
@@ -15,7 +16,7 @@ object BookRepository {
|
||||
}
|
||||
|
||||
suspend fun book(date: String, placeId: Int): Result<Unit> {
|
||||
val code = AuthRepository.getCurrentCode()
|
||||
val code = authRepository.getCurrentCode()
|
||||
return if (code != null) {
|
||||
NetworkDataSource.book(code, date, placeId)
|
||||
} else {
|
||||
|
||||
@@ -4,9 +4,10 @@ import ru.myitschool.work.data.model.UserInfoResponse
|
||||
import ru.myitschool.work.data.source.AuthException
|
||||
import ru.myitschool.work.data.source.NetworkDataSource
|
||||
|
||||
object MainRepository {
|
||||
class MainRepository(private val authRepository: AuthRepository) {
|
||||
|
||||
suspend fun getUserInfo(): Result<UserInfoResponse> {
|
||||
val code = AuthRepository.getCurrentCode()
|
||||
val code = authRepository.getCurrentCode()
|
||||
return if (code != null) {
|
||||
NetworkDataSource.getInfo(code)
|
||||
} else {
|
||||
|
||||
@@ -6,7 +6,9 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
@@ -24,8 +26,10 @@ fun AppNavHost(
|
||||
modifier: Modifier = Modifier,
|
||||
navController: NavHostController = rememberNavController()
|
||||
) {
|
||||
// authorized state follow
|
||||
val isAuthorized by AuthRepository.isAuthorized.collectAsState()
|
||||
val context = LocalContext.current
|
||||
val authRepository = remember { AuthRepository.getInstance(context) }
|
||||
|
||||
val isAuthorized by authRepository.isAuthorized.collectAsState()
|
||||
|
||||
LaunchedEffect(isAuthorized) {
|
||||
if (isAuthorized) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@@ -34,7 +35,7 @@ import ru.myitschool.work.ui.nav.MainScreenDestination
|
||||
|
||||
@Composable
|
||||
fun AuthScreen(
|
||||
viewModel: AuthViewModel = viewModel(),
|
||||
viewModel: AuthViewModel = viewModel(factory = AuthViewModelFactory(LocalContext.current)),
|
||||
navController: NavController
|
||||
) {
|
||||
val state by viewModel.uiState.collectAsState()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package ru.myitschool.work.ui.screen.auth
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -12,10 +14,11 @@ import kotlinx.coroutines.launch
|
||||
import ru.myitschool.work.data.repo.AuthRepository
|
||||
import ru.myitschool.work.domain.auth.CheckAndSaveAuthCodeUseCase
|
||||
|
||||
private val authRepo = AuthRepository
|
||||
private val checkAndSaveAuthCodeUseCase = CheckAndSaveAuthCodeUseCase(authRepo)
|
||||
|
||||
class AuthViewModel : ViewModel() {
|
||||
class AuthViewModel(
|
||||
private val authRepository: AuthRepository,
|
||||
private val checkAndSaveAuthCodeUseCase: CheckAndSaveAuthCodeUseCase
|
||||
) : ViewModel() {
|
||||
private val _uiState = MutableStateFlow<AuthState>(AuthState.Data())
|
||||
val uiState: StateFlow<AuthState> = _uiState.asStateFlow()
|
||||
|
||||
@@ -68,6 +71,18 @@ class AuthViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class AuthViewModelFactory(private val context: Context) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
if (modelClass.isAssignableFrom(AuthViewModel::class.java)) {
|
||||
val authRepository = AuthRepository.getInstance(context)
|
||||
val useCase = CheckAndSaveAuthCodeUseCase(authRepository)
|
||||
return AuthViewModel(authRepository, useCase) as T
|
||||
}
|
||||
throw IllegalArgumentException("Unknown ViewModel class")
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface AuthAction {
|
||||
object NavigateToMain : AuthAction
|
||||
}
|
||||
@@ -19,13 +19,14 @@ import androidx.navigation.NavController
|
||||
import ru.myitschool.work.R
|
||||
import ru.myitschool.work.core.TestIds
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun BookScreen(
|
||||
viewModel: BookViewModel = viewModel(),
|
||||
viewModel: BookViewModel = viewModel(factory = BookViewModelFactory(LocalContext.current)),
|
||||
navController: NavController
|
||||
) {
|
||||
val state by viewModel.uiState.collectAsState()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package ru.myitschool.work.ui.screen.book
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -9,14 +11,14 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import ru.myitschool.work.data.repo.AuthRepository
|
||||
import ru.myitschool.work.data.repo.BookRepository
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
private val bookRepo = BookRepository
|
||||
|
||||
class BookViewModel : ViewModel() {
|
||||
class BookViewModel(private val bookRepo: BookRepository) : ViewModel() {
|
||||
private val _uiState = MutableStateFlow<BookState>(BookState.Loading)
|
||||
val uiState: StateFlow<BookState> = _uiState.asStateFlow()
|
||||
|
||||
@@ -180,3 +182,15 @@ sealed interface BookAction {
|
||||
object NavigateBack : BookAction
|
||||
object NavigateBackWithRefresh : BookAction
|
||||
}
|
||||
|
||||
|
||||
class BookViewModelFactory(private val context: Context) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
if (modelClass.isAssignableFrom(BookViewModel::class.java)) {
|
||||
val authRepository = AuthRepository.getInstance(context)
|
||||
val bookRepository = BookRepository(authRepository)
|
||||
return BookViewModel(bookRepository) as T
|
||||
}
|
||||
throw IllegalArgumentException("Unknown ViewModel class")
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ import ru.myitschool.work.ui.nav.BookScreenDestination
|
||||
|
||||
@Composable
|
||||
fun MainScreen(
|
||||
viewModel: MainViewModel = viewModel(),
|
||||
viewModel: MainViewModel = viewModel(factory = MainViewModelFactory(LocalContext.current)),
|
||||
navController: NavController
|
||||
) {
|
||||
val state by viewModel.uiState.collectAsState()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package ru.myitschool.work.ui.screen.main
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -14,10 +16,11 @@ import java.time.format.DateTimeFormatter
|
||||
import ru.myitschool.work.data.repo.AuthRepository
|
||||
import ru.myitschool.work.data.repo.MainRepository
|
||||
|
||||
private val authRepo = AuthRepository
|
||||
private val mainRepo = MainRepository
|
||||
|
||||
class MainViewModel : ViewModel() {
|
||||
|
||||
class MainViewModel(private val authRepo: AuthRepository,
|
||||
private val mainRepo: MainRepository)
|
||||
: ViewModel() {
|
||||
private val _uiState = MutableStateFlow<MainState>(MainState.Loading)
|
||||
val uiState: StateFlow<MainState> = _uiState.asStateFlow()
|
||||
|
||||
@@ -95,6 +98,17 @@ class MainViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
class MainViewModelFactory(private val context: Context) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
|
||||
val authRepository = AuthRepository.getInstance(context)
|
||||
val mainRepository = MainRepository(authRepository)
|
||||
return MainViewModel(authRepository, mainRepository) as T
|
||||
}
|
||||
throw IllegalArgumentException("Unknown ViewModel class")
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface MainAction {
|
||||
object NavigateToAuth : MainAction
|
||||
object NavigateToBooking : MainAction
|
||||
|
||||
Reference in New Issue
Block a user