add profile fragment
This commit is contained in:
		
							parent
							
								
									9ba4ba21db
								
							
						
					
					
						commit
						45a5f9cff5
					
				| @ -1,5 +1,5 @@ | ||||
| package ru.myitschool.work.core | ||||
| // БЕРИТЕ И ИЗМЕНЯЙТЕ ХОСТ ТОЛЬКО ЗДЕСЬ И НЕ БЕРИТЕ ИЗ ДРУГИХ МЕСТ. ФАЙЛ ПЕРЕМЕЩАТЬ НЕЛЬЗЯ | ||||
| object Constants { | ||||
|     const val SERVER_ADDRESS = "http://localhost:8090" | ||||
|     const val SERVER_ADDRESS = "http://10.0.2.2:8080" | ||||
| } | ||||
| @ -1,5 +1,6 @@ | ||||
| package ru.myitschool.work.data.auth | ||||
| 
 | ||||
| import android.util.Log | ||||
| import io.ktor.client.call.body | ||||
| import io.ktor.client.request.get | ||||
| import io.ktor.client.request.header | ||||
| @ -17,22 +18,24 @@ import ru.myitschool.work.data.user.UserDto | ||||
| 
 | ||||
| object AuthNetworkDataSource { | ||||
| 
 | ||||
|     suspend fun isUserExist(login: String): Result<Boolean?> = withContext(Dispatchers.IO) { | ||||
|         runCatching { | ||||
|             val result = client.get("$SERVER_ADDRESS/api/login/$login") //10.0.2.2 | ||||
|             when (result.status) { | ||||
|                 HttpStatusCode.OK -> { return@runCatching true } | ||||
|                 HttpStatusCode.NotFound -> { return@runCatching false } | ||||
|                 else -> {return@runCatching null } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| //    suspend fun isUserExist(login: String): Result<Boolean?> = withContext(Dispatchers.IO) { | ||||
| //        runCatching { | ||||
| //            val result = client.get("$SERVER_ADDRESS/api/login/$login") //10.0.2.2 | ||||
| //            when (result.status) { | ||||
| //                HttpStatusCode.OK -> { return@runCatching true } | ||||
| //                HttpStatusCode.NotFound -> { return@runCatching false } | ||||
| //                else -> {return@runCatching null } | ||||
| //            } | ||||
| //        } | ||||
| //    } | ||||
| 
 | ||||
|     suspend fun login(token: String): Result<UserDto> = withContext(Dispatchers.IO) { | ||||
| 
 | ||||
|         runCatching { | ||||
|             val result = client.get("$SERVER_ADDRESS/api/login") { | ||||
|                 header(HttpHeaders.Authorization, token) | ||||
|             } | ||||
|             Log.d("result", "${result.status}") | ||||
|             if (result.status == HttpStatusCode.Unauthorized) { | ||||
|                 error("Неверный email или пароль") | ||||
|             } | ||||
|  | ||||
| @ -7,9 +7,9 @@ class AuthRepoImpl( | ||||
|     private val authNetworkDataSource: AuthNetworkDataSource, | ||||
|     private val authStorageDataSource: AuthStorageDataSource | ||||
| ) : AuthRepo { | ||||
|     override suspend fun isUserExist(email: String): Result<Boolean?> { | ||||
|         return authNetworkDataSource.isUserExist(email) | ||||
|     } | ||||
| //    override suspend fun isUserExist(email: String): Result<Boolean?> { | ||||
| //        return authNetworkDataSource.isUserExist(email) | ||||
| //    } | ||||
| 
 | ||||
|     override suspend fun login(email: String, password: String): Result<UserDto> { | ||||
|         val token = authStorageDataSource.updateToken(email, password) | ||||
|  | ||||
| @ -0,0 +1,16 @@ | ||||
| package ru.myitschool.work.data.user | ||||
| 
 | ||||
| import kotlinx.serialization.SerialName | ||||
| 
 | ||||
| data class EntranceDto( | ||||
|     @SerialName("login") | ||||
|     val login : String, | ||||
|     @SerialName("name") | ||||
|     var name: String, | ||||
|     @SerialName("enterAt") | ||||
|     var enterAt: String, | ||||
|     @SerialName("enterType") | ||||
|     var enterType: String, | ||||
| ) { | ||||
| 
 | ||||
| } | ||||
| @ -18,8 +18,8 @@ data class UserDto( | ||||
|     var avatarUrl: String?, | ||||
|     @SerialName("position") | ||||
|     val position: String, | ||||
|     @SerialName("lastEntry") | ||||
|     val lastEntry : String, | ||||
|     @SerialName("lastEnter") | ||||
|     val lastEntry : String? = null, | ||||
|     @SerialName("authorities") | ||||
|     val authorities : String | ||||
| ) { | ||||
|  | ||||
| @ -0,0 +1,52 @@ | ||||
| package ru.sicampus.bootcamp2025.data.user | ||||
| 
 | ||||
| import android.util.Log | ||||
| import io.ktor.client.call.body | ||||
| import io.ktor.client.request.get | ||||
| import io.ktor.client.request.header | ||||
| import io.ktor.client.request.put | ||||
| import io.ktor.client.request.setBody | ||||
| import io.ktor.client.statement.bodyAsText | ||||
| import io.ktor.http.HttpHeaders | ||||
| import io.ktor.http.HttpStatusCode | ||||
| import kotlinx.coroutines.Dispatchers | ||||
| import kotlinx.coroutines.withContext | ||||
| import ru.myitschool.work.core.Constants.SERVER_ADDRESS | ||||
| import ru.myitschool.work.data.auth.AuthStorageDataSource.token | ||||
| import ru.myitschool.work.data.auth.Network.client | ||||
| import ru.myitschool.work.data.user.EntranceDto | ||||
| import ru.myitschool.work.data.user.UserDto | ||||
| 
 | ||||
| class UserNetworkDataSource { | ||||
|     suspend fun getUser(login : String): Result<UserDto> = withContext(Dispatchers.IO) { | ||||
|         runCatching { | ||||
| 
 | ||||
|             val result = client.get("http://$SERVER_ADDRESS/api/${login}/info") { | ||||
|                 header(HttpHeaders.Authorization, token) | ||||
|             } | ||||
|             Log.d("tututuut", "${result.status}") | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|             if (result.status != HttpStatusCode.OK) { | ||||
|                 error("Status ${result.status}") | ||||
|             } | ||||
|             Log.d("result", result.bodyAsText()) | ||||
|             result.body() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     suspend fun getEntrancesList(login : String) : Result<List<EntranceDto>> = withContext(Dispatchers.IO){ | ||||
|         runCatching { | ||||
|             val result = client.get("http://$SERVER_ADDRESS/api/$login/entrances") { | ||||
|                 header(HttpHeaders.Authorization, token) | ||||
|             } | ||||
|             Log.d("serverCode", "${result.status}") | ||||
|             if (result.status != HttpStatusCode.OK) { | ||||
|                 error("Status ${result.status}") | ||||
|             } | ||||
|             result.body() | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,42 @@ | ||||
| package ru.sicampus.bootcamp2025.data.user | ||||
| 
 | ||||
| import ru.myitschool.work.data.user.EntranceDto | ||||
| import ru.myitschool.work.data.user.UserDto | ||||
| import ru.myitschool.work.domain.user.EntranceEntity | ||||
| import ru.myitschool.work.domain.user.UserEntity | ||||
| import ru.myitschool.work.domain.user.UserRepo | ||||
| 
 | ||||
| 
 | ||||
| class UserRepoImpl ( | ||||
|     private val userNetworkDataSource: UserNetworkDataSource | ||||
| ) : UserRepo { | ||||
|     override suspend fun getUser(login: String): Result<UserEntity> { | ||||
|         return userNetworkDataSource.getUser(login).map { dto -> | ||||
|             UserEntity( | ||||
|                 id = dto.id ?: -1, | ||||
|                 name = dto.name, | ||||
|                 avatarUrl = dto.avatarUrl ?: "", | ||||
|                 authorities = dto.authorities, | ||||
|                 login = login, | ||||
|                 position = dto.position, | ||||
|                 lastEntry = dto.lastEntry ?: "", | ||||
|             ) | ||||
| 
 | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|     override suspend fun getEntrancesList(login : String): Result<List<EntranceEntity>> { | ||||
|         return userNetworkDataSource.getEntrancesList(login).map { userList -> | ||||
|             userList.map { it.toEntity() } | ||||
|         } | ||||
|     } | ||||
|     fun EntranceDto.toEntity(): EntranceEntity { | ||||
|         return EntranceEntity( | ||||
|             login = login, | ||||
|             name = this.name, | ||||
|             enterAt = this.enterAt, | ||||
|             enterType = this.enterType | ||||
|         ) | ||||
|     } | ||||
| } | ||||
| @ -3,6 +3,6 @@ package ru.myitschool.work.domain.auth | ||||
| import ru.myitschool.work.data.user.UserDto | ||||
| 
 | ||||
| interface AuthRepo { | ||||
|     suspend fun isUserExist(email: String): Result<Boolean?> | ||||
|     suspend fun login(email: String, password: String) : Result <UserDto> | ||||
|     //suspend fun isUserExist(email: String): Result<Boolean?> | ||||
|     suspend fun login(login: String, password: String) : Result <UserDto> | ||||
| } | ||||
|  | ||||
| @ -3,10 +3,10 @@ package ru.myitschool.work.domain.auth | ||||
| import javax.inject.Inject | ||||
| 
 | ||||
| 
 | ||||
| class IsUserExistUseCase ( | ||||
| /*class IsUserExistUseCase ( | ||||
|     private val authRepo : AuthRepo | ||||
| ) { | ||||
|     suspend operator fun invoke(email : String) : Result<Boolean?> { | ||||
|         return authRepo.isUserExist(email) | ||||
|     } | ||||
| } | ||||
| }*/ | ||||
| @ -5,7 +5,7 @@ import ru.myitschool.work.data.user.UserDto | ||||
| class LoginUseCase( | ||||
|     private val authRepo : AuthRepo | ||||
| ){ | ||||
|     suspend operator fun invoke(email : String, password : String) : Result<UserDto> { | ||||
|         return authRepo.login(email, password) | ||||
|     suspend operator fun invoke(login : String, password : String) : Result<UserDto> { | ||||
|         return authRepo.login(login, password) | ||||
|     } | ||||
| } | ||||
| @ -1,18 +0,0 @@ | ||||
| package ru.sicampus.bootcamp2025.data | ||||
| 
 | ||||
| import io.ktor.client.HttpClient | ||||
| import io.ktor.client.engine.cio.CIO | ||||
| import io.ktor.client.plugins.contentnegotiation.ContentNegotiation | ||||
| import io.ktor.serialization.kotlinx.json.json | ||||
| import kotlinx.serialization.json.Json | ||||
| 
 | ||||
| object Network { | ||||
|     val client = HttpClient(CIO) { | ||||
|         install(ContentNegotiation) { | ||||
|             json(Json { | ||||
|                 isLenient = true | ||||
|                 ignoreUnknownKeys = true | ||||
|             }) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,12 @@ | ||||
| package ru.myitschool.work.domain.user | ||||
| 
 | ||||
| import kotlinx.serialization.SerialName | ||||
| 
 | ||||
| data class EntranceEntity( | ||||
|     val login : String, | ||||
|     var name: String, | ||||
|     var enterAt: String, | ||||
|     var enterType: String, | ||||
| ) { | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,16 @@ | ||||
| package ru.myitschool.work.domain.user | ||||
| 
 | ||||
| import ru.myitschool.work.data.auth.AuthStorageDataSource | ||||
| import ru.myitschool.work.data.user.UserDto | ||||
| 
 | ||||
| class GetUserUseCase( | ||||
|     private val repo: UserRepo, | ||||
|     private val authStorageDataSource: AuthStorageDataSource | ||||
| ) { | ||||
|     suspend fun getUserFromStorage() : UserDto? { | ||||
|         return authStorageDataSource.userInfo | ||||
|     } | ||||
|     suspend operator fun invoke() = repo.getUser(getUserFromStorage()?.login!!) | ||||
|     suspend fun getEntrancesList() = repo.getEntrancesList(getUserFromStorage()?.login!!) | ||||
| 
 | ||||
| } | ||||
| @ -8,7 +8,7 @@ data class UserEntity( | ||||
|     var name: String, | ||||
|     var avatarUrl: String?, | ||||
|     val position : String, | ||||
|     var lastEntry : String, | ||||
|     var lastEntry : String?, | ||||
|     val authorities : String | ||||
| 
 | ||||
| ) | ||||
|  | ||||
| @ -0,0 +1,7 @@ | ||||
| package ru.myitschool.work.domain.user | ||||
| 
 | ||||
| 
 | ||||
| interface UserRepo { | ||||
|     suspend fun getUser(login: String) : Result<UserEntity> | ||||
|     suspend fun getEntrancesList(login : String) : Result<List<EntranceEntity>> | ||||
| } | ||||
| @ -1,5 +1,6 @@ | ||||
| package ru.myitschool.work.ui | ||||
| 
 | ||||
| import android.annotation.SuppressLint | ||||
| import android.os.Bundle | ||||
| import androidx.activity.OnBackPressedCallback | ||||
| import androidx.appcompat.app.AppCompatActivity | ||||
| @ -17,22 +18,28 @@ import ru.myitschool.work.ui.qr.scan.QrScanFragment | ||||
| // НЕ ИЗМЕНЯЙТЕ НАЗВАНИЕ КЛАССА! | ||||
| @AndroidEntryPoint | ||||
| class RootActivity : AppCompatActivity() { | ||||
|     @SuppressLint("ResourceType") | ||||
|     override fun onCreate(savedInstanceState: Bundle?) { | ||||
|         super.onCreate(savedInstanceState) | ||||
|         setContentView(R.layout.activity_root) | ||||
|         setContentView(R.layout.fragment_profile) | ||||
|         val userRole = intent.getStringExtra("USER_ROLE") | ||||
| 
 | ||||
|         /*val navHostFragment = supportFragmentManager | ||||
|             .findFragmentById(R.id.nav_host_fragment) as NavHostFragment? | ||||
|         val navController = navHostFragment.navController*/ | ||||
| 
 | ||||
|         if (navHostFragment != null) { | ||||
|             val navController = navHostFragment.navController | ||||
|             navController.graph = navController.createGraph( | ||||
|                 startDestination = LoginDestination | ||||
|             ) { | ||||
|                 fragment<LoginFragment, LoginDestination>() | ||||
|                 fragment<QrScanFragment, QrScanDestination>() | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         /*if (userRole == "ROLE_ADMIN") { | ||||
|             bottomNavigationView.menu.clear() | ||||
|             bottomNavigationView.inflateMenu(R.menu.bottom_menu_admin) | ||||
|             navController.setGraph(R.navigation.main_admin_nav_graph) | ||||
| 
 | ||||
|         } else { | ||||
|             bottomNavigationView.menu.clear() | ||||
|             bottomNavigationView.inflateMenu(R.menu.bottom_menu) | ||||
|             navController.setGraph(R.navigation.main_nav_graph) | ||||
|         }*/ | ||||
| 
 | ||||
|         onBackPressedDispatcher.addCallback( | ||||
|             this, | ||||
| @ -44,7 +51,7 @@ class RootActivity : AppCompatActivity() { | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun onSupportNavigateUp(): Boolean { | ||||
|     /*override fun onSupportNavigateUp(): Boolean { | ||||
|         val navController = findNavController(R.id.nav_host_fragment) | ||||
|         val popBackResult = if (navController.previousBackStackEntry != null) { | ||||
|             navController.popBackStack() | ||||
| @ -53,5 +60,5 @@ class RootActivity : AppCompatActivity() { | ||||
|         } | ||||
|         return popBackResult || super.onSupportNavigateUp() | ||||
|     }*/ | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -65,7 +65,7 @@ class LoginFragment : Fragment(R.layout.fragment_login) { | ||||
|             override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) = Unit | ||||
|             override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) = Unit | ||||
|             override fun afterTextChanged(p0: Editable?) { | ||||
| 
 | ||||
|                 viewModel.changeLogin() | ||||
|             } | ||||
| 
 | ||||
|         }) | ||||
|  | ||||
| @ -17,14 +17,13 @@ import ru.myitschool.work.R | ||||
| import ru.myitschool.work.data.auth.AuthNetworkDataSource | ||||
| import ru.myitschool.work.data.auth.AuthRepoImpl | ||||
| import ru.myitschool.work.data.auth.AuthStorageDataSource | ||||
| import ru.myitschool.work.domain.auth.IsUserExistUseCase | ||||
| //import ru.myitschool.work.domain.auth.IsUserExistUseCase | ||||
| import ru.myitschool.work.domain.auth.LoginUseCase | ||||
| import javax.inject.Inject | ||||
| import kotlin.reflect.KClass | ||||
| 
 | ||||
| class LoginViewModel constructor( | ||||
|     @ApplicationContext private val context: Context, | ||||
|     private val isUserExistUseCase: IsUserExistUseCase, | ||||
|     private  val loginUseCase: LoginUseCase | ||||
| ) : ViewModel() { | ||||
|     private val _state = MutableStateFlow<State>(getStateShow()) | ||||
| @ -49,44 +48,23 @@ class LoginViewModel constructor( | ||||
|     ) | ||||
|     { | ||||
|         viewModelScope.launch { | ||||
|             when (checkUserExistence(login)) { | ||||
|                 true -> { | ||||
|                     loginUser(login, password) | ||||
|                 } | ||||
|                 false -> { | ||||
|                     updateState(context.getString(R.string.error_invalid_credentials)) | ||||
|                 } | ||||
|                 null -> updateState(context.getString(R.string.error_unknown)) | ||||
|             } | ||||
|             loginUser(login, password) | ||||
| 
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private suspend fun checkUserExistence(email: String):Boolean?{ | ||||
|         return try { | ||||
|             val result = isUserExistUseCase(email) | ||||
|             result.fold( | ||||
|                 onSuccess = {isExist -> isExist}, | ||||
|                 onFailure = { | ||||
|                     Log.e("LoginViewModel", "Error checking user existence", it) | ||||
|                     null | ||||
|                 } | ||||
|             ) | ||||
|         } catch (e: Exception) { | ||||
|             Log.e("LoginViewModel", "Error during user existence check", e) | ||||
|             null | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     private suspend fun loginUser(email: String, password: String) { | ||||
|         loginUseCase(email, password).fold( | ||||
|             onSuccess = { user -> | ||||
|                 println("Login successful") | ||||
|                 Log.d("loginViewModel","Login successful") | ||||
|                 _userRole.emit(user.authorities) | ||||
|                 _navigateToMain.emit(user.authorities) | ||||
|             }, | ||||
|             onFailure = { error -> | ||||
|                 updateState(error.message ?: context.getString(R.string.error_unknown)) | ||||
|                 Log.d("errorLoginViewModel","${error.message}") | ||||
|             } | ||||
|         ) | ||||
|     } | ||||
| @ -125,7 +103,6 @@ class LoginViewModel constructor( | ||||
|                 ) | ||||
|                 return LoginViewModel( | ||||
|                     application, | ||||
|                     isUserExistUseCase = IsUserExistUseCase(authRepoImpl), | ||||
|                     loginUseCase = LoginUseCase(authRepoImpl) | ||||
|                 ) as T | ||||
|             } | ||||
|  | ||||
| @ -0,0 +1,68 @@ | ||||
| package ru.myitschool.work.ui.profile | ||||
| 
 | ||||
| import android.content.Intent | ||||
| import android.os.Bundle | ||||
| import android.util.Log | ||||
| import android.view.View | ||||
| import androidx.fragment.app.Fragment | ||||
| import androidx.fragment.app.viewModels | ||||
| import com.squareup.picasso.Picasso | ||||
| import ru.myitschool.work.R | ||||
| import ru.myitschool.work.databinding.FragmentProfileBinding | ||||
| import ru.myitschool.work.ui.login.EntryActivity | ||||
| import ru.myitschool.work.utils.collectWithLifecycle | ||||
| 
 | ||||
| class ProfileFragment : Fragment(R.layout.fragment_profile) { | ||||
|     private var _viewBinding: FragmentProfileBinding? = null | ||||
|     private val viewBinding: FragmentProfileBinding get() = _viewBinding!! | ||||
| 
 | ||||
|     private val viewModel by viewModels<ProfileViewModel> { ProfileViewModel.Factory } | ||||
| 
 | ||||
| 
 | ||||
|     override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | ||||
|         _viewBinding = FragmentProfileBinding.bind(view) | ||||
|         super.onViewCreated(view, savedInstanceState) | ||||
| 
 | ||||
| 
 | ||||
|         viewBinding.refresh.setOnClickListener { viewModel.clickRefresh() } | ||||
|         viewBinding.refreshForProfile.setOnClickListener { viewModel.clickRefresh() } | ||||
|         viewBinding.logout.setOnClickListener { | ||||
|             val intent = Intent(requireContext(), EntryActivity::class.java) | ||||
|             startActivity(intent) | ||||
|             requireActivity().finish() | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         viewModel.state.collectWithLifecycle(this) { state -> | ||||
| 
 | ||||
|             viewBinding.error.visibility = if (state is ProfileViewModel.State.Error) View.VISIBLE else View.GONE | ||||
|             viewBinding.loading.visibility = if (state is ProfileViewModel.State.Loading) View.VISIBLE else View.GONE | ||||
|             viewBinding.profile.visibility = if (state is ProfileViewModel.State.Show) View.VISIBLE else View.GONE | ||||
| 
 | ||||
|             when(state) { | ||||
|                 is ProfileViewModel.State.Loading -> Unit | ||||
|                 is ProfileViewModel.State.Show -> { | ||||
|                     viewBinding.name.text = state.profileInfo.name | ||||
|                     viewBinding.position.text = "Должность: ${state.profileInfo.name}" | ||||
|                     if (state.profileInfo.lastEntry == null) viewBinding.lastEntry.text = "Время последнего входа: Нет данных" | ||||
|                     else viewBinding.lastEntry.text = "Время последнего входа: ${state.profileInfo.lastEntry}" | ||||
|                     Picasso.get().load(state.profileInfo.avatarUrl).resize(100, 100).centerCrop().into(viewBinding.imageView) | ||||
| 
 | ||||
|                     //if (state.entrancesList == emptyList()) | ||||
|                     //viewBinding.recyclerView.visibility = View.GONE | ||||
|                 } | ||||
|                 is ProfileViewModel.State.Error -> { | ||||
|                     viewBinding.errorText.text = state.text | ||||
|                     //viewBinding.noData.visibility = View.VISIBLE | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     override fun onDestroyView() { | ||||
|         _viewBinding = null | ||||
|         super.onDestroyView() | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,86 @@ | ||||
| package ru.myitschool.work.ui.profile | ||||
| 
 | ||||
| import android.util.Log | ||||
| import androidx.lifecycle.ViewModel | ||||
| import androidx.lifecycle.ViewModelProvider | ||||
| import androidx.lifecycle.viewModelScope | ||||
| import kotlinx.coroutines.flow.MutableStateFlow | ||||
| import kotlinx.coroutines.flow.asStateFlow | ||||
| import kotlinx.coroutines.launch | ||||
| import ru.myitschool.work.data.auth.AuthStorageDataSource | ||||
| import ru.myitschool.work.domain.user.EntranceEntity | ||||
| import ru.myitschool.work.domain.user.GetUserUseCase | ||||
| import ru.myitschool.work.domain.user.UserEntity | ||||
| import ru.sicampus.bootcamp2025.data.user.UserNetworkDataSource | ||||
| import ru.sicampus.bootcamp2025.data.user.UserRepoImpl | ||||
| 
 | ||||
| class ProfileViewModel( | ||||
|     private val getUserUseCase: GetUserUseCase | ||||
| ) : ViewModel() { | ||||
|     private val _state = MutableStateFlow<State>(State.Loading) | ||||
|     val state = _state.asStateFlow() | ||||
| 
 | ||||
|     init { | ||||
|         updateStateGet() | ||||
|     } | ||||
| 
 | ||||
|     fun clickRefresh() { | ||||
|         updateStateGet() | ||||
|     } | ||||
| 
 | ||||
|     fun updateStateGet() { | ||||
|         viewModelScope.launch { | ||||
|             _state.emit(State.Loading) | ||||
|             val entranceList : List<EntranceEntity> = getUserUseCase.getEntrancesList().fold( | ||||
|                 onSuccess = { list -> | ||||
|                     list | ||||
|                 }, | ||||
|                 onFailure = { | ||||
|                     emptyList() | ||||
|                 } | ||||
|             ) | ||||
|             _state.emit( | ||||
|                 getUserUseCase.invoke().fold( | ||||
|                     onSuccess = { data -> | ||||
|                         Log.d("uraa", "успех успех ${data.toString()}") | ||||
|                         State.Show(data, entranceList) | ||||
|                     }, | ||||
|                     onFailure = { error -> | ||||
|                         Log.d("kaput", error.message.toString()) | ||||
|                         State.Error(error.message.toString()) | ||||
|                     } | ||||
|                 ) | ||||
|             ) | ||||
|             //_state.emit(State.Error("о нет ошибка ошибка помогите")) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     sealed interface State { | ||||
|         data object Loading: State | ||||
|         data class Show( | ||||
|             val profileInfo: UserEntity, | ||||
|             val entrancesList : List<EntranceEntity> | ||||
|         ) : State | ||||
|         data class Error( | ||||
|             val text: String | ||||
|         ) : State | ||||
|     } | ||||
|     companion object { | ||||
|         val Factory : ViewModelProvider.Factory = object : ViewModelProvider.Factory { | ||||
|             @Suppress("UNCHECKED_CAST") | ||||
|             override fun <T : ViewModel> create(modelClass: Class<T>): T { | ||||
|                 return ProfileViewModel( | ||||
|                     getUserUseCase = GetUserUseCase( | ||||
|                         repo = UserRepoImpl( | ||||
|                             userNetworkDataSource = UserNetworkDataSource() | ||||
|                         ), | ||||
|                         authStorageDataSource = AuthStorageDataSource | ||||
|                     ) | ||||
|                 ) as T | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -106,7 +106,7 @@ | ||||
|             tools:text="Иванова Вера Павловна" /> | ||||
| 
 | ||||
|         <TextView | ||||
|             android:id="@+id/textView" | ||||
|             android:id="@+id/position" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginStart="24dp" | ||||
| @ -118,6 +118,7 @@ | ||||
|             tools:text="Должность: Разработчик" /> | ||||
| 
 | ||||
|         <TextView | ||||
|             android:id="@+id/lastEntry" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginStart="24dp" | ||||
| @ -125,7 +126,7 @@ | ||||
|             android:textColor="@color/black" | ||||
|             android:textSize="16dp" | ||||
|             app:layout_constraintStart_toStartOf="parent" | ||||
|             app:layout_constraintTop_toBottomOf="@+id/textView" | ||||
|             app:layout_constraintTop_toBottomOf="@+id/position" | ||||
|             tools:text="Время последнего входа: 12:00 16.09" /> | ||||
| 
 | ||||
|         <com.google.android.material.button.MaterialButton | ||||
| @ -167,6 +168,7 @@ | ||||
| 
 | ||||
| 
 | ||||
|         <View | ||||
|             android:id="@+id/view" | ||||
|             android:layout_width="1dp" | ||||
|             android:layout_height="35dp" | ||||
|             android:layout_marginTop="7dp" | ||||
| @ -189,25 +191,70 @@ | ||||
|             app:layout_constraintStart_toStartOf="parent" /> | ||||
| 
 | ||||
|         <TextView | ||||
|             android:id="@+id/textView" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="20dp" | ||||
|             android:layout_marginTop="15dp" | ||||
|             android:layout_marginTop="8dp" | ||||
|             android:elevation="10dp" | ||||
|             android:gravity="center" | ||||
|             android:text="@string/entry_time" | ||||
|             android:textColor="@color/white" | ||||
|             android:textSize="14sp" | ||||
|             app:layout_constraintBottom_toBottomOf="@+id/view2" | ||||
|             app:layout_constraintEnd_toStartOf="@+id/view3" | ||||
|             app:layout_constraintHorizontal_bias="0.51" | ||||
|             app:layout_constraintStart_toStartOf="@+id/view2" | ||||
|             app:layout_constraintTop_toTopOf="@+id/view2" | ||||
|             app:layout_constraintVertical_bias="0.0" /> | ||||
|             app:layout_constraintTop_toTopOf="@+id/view2" /> | ||||
| 
 | ||||
| 
 | ||||
|         <TextView | ||||
|             android:id="@+id/textView2" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="20dp" | ||||
|             android:layout_marginTop="8dp" | ||||
|             android:elevation="10dp" | ||||
|             android:gravity="center" | ||||
|             android:text="@string/entry" | ||||
|             android:textColor="@color/white" | ||||
| 
 | ||||
|             android:textSize="14sp" | ||||
|             app:layout_constraintEnd_toStartOf="@+id/view" | ||||
| 
 | ||||
|             app:layout_constraintHorizontal_bias="0.5" | ||||
|             app:layout_constraintStart_toEndOf="@+id/view3" | ||||
|             app:layout_constraintTop_toTopOf="@+id/view2" /> | ||||
| 
 | ||||
|         <TextView | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="20dp" | ||||
|             android:layout_marginTop="8dp" | ||||
|             android:elevation="10dp" | ||||
|             android:gravity="center" | ||||
|             android:text="@string/type_of_entrance" | ||||
|             android:textColor="@color/white" | ||||
|             android:textSize="14sp" | ||||
| 
 | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintStart_toEndOf="@+id/view" | ||||
|             app:layout_constraintTop_toTopOf="@+id/view2" /> | ||||
| 
 | ||||
|         <TextView | ||||
|             android:id="@+id/no_data" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginTop="28dp" | ||||
|             android:text="@string/no_data" | ||||
|             android:textColor="@color/black" | ||||
|             android:textSize="16sp" | ||||
|             android:visibility="gone" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintHorizontal_bias="0.498" | ||||
|             app:layout_constraintStart_toStartOf="parent" | ||||
|             app:layout_constraintTop_toBottomOf="@+id/view2" /> | ||||
| 
 | ||||
|         <androidx.recyclerview.widget.RecyclerView | ||||
|             android:id="@+id/recyclerView" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
| 
 | ||||
|             android:layout_marginBottom="16dp" | ||||
|             app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" | ||||
|             app:layout_constraintBottom_toBottomOf="parent" | ||||
|  | ||||
							
								
								
									
										17
									
								
								app/src/main/res/navigation/main_admin_nav_graph.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								app/src/main/res/navigation/main_admin_nav_graph.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <navigation xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     android:id="@+id/admin_main_nav_graph"> | ||||
| 
 | ||||
|     <!--<fragment | ||||
|         android:id="@+id/fragment_profile" | ||||
|         android:name="" | ||||
|         android:label="Profile" | ||||
|         tools:layout="@layout/fragment_profile" /> | ||||
|     <fragment | ||||
|         android:id="@+id/fragment_user_list" | ||||
|         android:name="ru.sicampus.bootcamp2025.ui.userList.FreeVolunteersListFragment" | ||||
|         android:label="UserList" | ||||
|         tools:layout="@layout/fragment_free_volunteers_list" />--> | ||||
| 
 | ||||
| </navigation> | ||||
| @ -10,4 +10,7 @@ | ||||
|     <string name="error_unknown">Непредвиденная ошибка</string> | ||||
|     <string name="entry_history">История входов\n</string> | ||||
|     <string name="entry_time">Время входа\n</string> | ||||
|     <string name="entry">Вход</string> | ||||
|     <string name="type_of_entrance">Тип прохода</string> | ||||
|     <string name="no_data">Нет данных\n</string> | ||||
| </resources> | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user