add profile fragment
This commit is contained in:
		
							parent
							
								
									9ba4ba21db
								
							
						
					
					
						commit
						45a5f9cff5
					
				| @ -1,5 +1,5 @@ | |||||||
| package ru.myitschool.work.core | package ru.myitschool.work.core | ||||||
| // БЕРИТЕ И ИЗМЕНЯЙТЕ ХОСТ ТОЛЬКО ЗДЕСЬ И НЕ БЕРИТЕ ИЗ ДРУГИХ МЕСТ. ФАЙЛ ПЕРЕМЕЩАТЬ НЕЛЬЗЯ | // БЕРИТЕ И ИЗМЕНЯЙТЕ ХОСТ ТОЛЬКО ЗДЕСЬ И НЕ БЕРИТЕ ИЗ ДРУГИХ МЕСТ. ФАЙЛ ПЕРЕМЕЩАТЬ НЕЛЬЗЯ | ||||||
| object Constants { | 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 | package ru.myitschool.work.data.auth | ||||||
| 
 | 
 | ||||||
|  | import android.util.Log | ||||||
| import io.ktor.client.call.body | import io.ktor.client.call.body | ||||||
| import io.ktor.client.request.get | import io.ktor.client.request.get | ||||||
| import io.ktor.client.request.header | import io.ktor.client.request.header | ||||||
| @ -17,22 +18,24 @@ import ru.myitschool.work.data.user.UserDto | |||||||
| 
 | 
 | ||||||
| object AuthNetworkDataSource { | object AuthNetworkDataSource { | ||||||
| 
 | 
 | ||||||
|     suspend fun isUserExist(login: String): Result<Boolean?> = withContext(Dispatchers.IO) { | //    suspend fun isUserExist(login: String): Result<Boolean?> = withContext(Dispatchers.IO) { | ||||||
|         runCatching { | //        runCatching { | ||||||
|             val result = client.get("$SERVER_ADDRESS/api/login/$login") //10.0.2.2 | //            val result = client.get("$SERVER_ADDRESS/api/login/$login") //10.0.2.2 | ||||||
|             when (result.status) { | //            when (result.status) { | ||||||
|                 HttpStatusCode.OK -> { return@runCatching true } | //                HttpStatusCode.OK -> { return@runCatching true } | ||||||
|                 HttpStatusCode.NotFound -> { return@runCatching false } | //                HttpStatusCode.NotFound -> { return@runCatching false } | ||||||
|                 else -> {return@runCatching null } | //                else -> {return@runCatching null } | ||||||
|             } | //            } | ||||||
|         } | //        } | ||||||
|     } | //    } | ||||||
| 
 | 
 | ||||||
|     suspend fun login(token: String): Result<UserDto> = withContext(Dispatchers.IO) { |     suspend fun login(token: String): Result<UserDto> = withContext(Dispatchers.IO) { | ||||||
|  | 
 | ||||||
|         runCatching { |         runCatching { | ||||||
|             val result = client.get("$SERVER_ADDRESS/api/login") { |             val result = client.get("$SERVER_ADDRESS/api/login") { | ||||||
|                 header(HttpHeaders.Authorization, token) |                 header(HttpHeaders.Authorization, token) | ||||||
|             } |             } | ||||||
|  |             Log.d("result", "${result.status}") | ||||||
|             if (result.status == HttpStatusCode.Unauthorized) { |             if (result.status == HttpStatusCode.Unauthorized) { | ||||||
|                 error("Неверный email или пароль") |                 error("Неверный email или пароль") | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -7,9 +7,9 @@ class AuthRepoImpl( | |||||||
|     private val authNetworkDataSource: AuthNetworkDataSource, |     private val authNetworkDataSource: AuthNetworkDataSource, | ||||||
|     private val authStorageDataSource: AuthStorageDataSource |     private val authStorageDataSource: AuthStorageDataSource | ||||||
| ) : AuthRepo { | ) : AuthRepo { | ||||||
|     override suspend fun isUserExist(email: String): Result<Boolean?> { | //    override suspend fun isUserExist(email: String): Result<Boolean?> { | ||||||
|         return authNetworkDataSource.isUserExist(email) | //        return authNetworkDataSource.isUserExist(email) | ||||||
|     } | //    } | ||||||
| 
 | 
 | ||||||
|     override suspend fun login(email: String, password: String): Result<UserDto> { |     override suspend fun login(email: String, password: String): Result<UserDto> { | ||||||
|         val token = authStorageDataSource.updateToken(email, password) |         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?, |     var avatarUrl: String?, | ||||||
|     @SerialName("position") |     @SerialName("position") | ||||||
|     val position: String, |     val position: String, | ||||||
|     @SerialName("lastEntry") |     @SerialName("lastEnter") | ||||||
|     val lastEntry : String, |     val lastEntry : String? = null, | ||||||
|     @SerialName("authorities") |     @SerialName("authorities") | ||||||
|     val authorities : String |     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 | import ru.myitschool.work.data.user.UserDto | ||||||
| 
 | 
 | ||||||
| interface AuthRepo { | interface AuthRepo { | ||||||
|     suspend fun isUserExist(email: String): Result<Boolean?> |     //suspend fun isUserExist(email: String): Result<Boolean?> | ||||||
|     suspend fun login(email: String, password: String) : Result <UserDto> |     suspend fun login(login: String, password: String) : Result <UserDto> | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,10 +3,10 @@ package ru.myitschool.work.domain.auth | |||||||
| import javax.inject.Inject | import javax.inject.Inject | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class IsUserExistUseCase ( | /*class IsUserExistUseCase ( | ||||||
|     private val authRepo : AuthRepo |     private val authRepo : AuthRepo | ||||||
| ) { | ) { | ||||||
|     suspend operator fun invoke(email : String) : Result<Boolean?> { |     suspend operator fun invoke(email : String) : Result<Boolean?> { | ||||||
|         return authRepo.isUserExist(email) |         return authRepo.isUserExist(email) | ||||||
|     } |     } | ||||||
| } | }*/ | ||||||
| @ -5,7 +5,7 @@ import ru.myitschool.work.data.user.UserDto | |||||||
| class LoginUseCase( | class LoginUseCase( | ||||||
|     private val authRepo : AuthRepo |     private val authRepo : AuthRepo | ||||||
| ){ | ){ | ||||||
|     suspend operator fun invoke(email : String, password : String) : Result<UserDto> { |     suspend operator fun invoke(login : String, password : String) : Result<UserDto> { | ||||||
|         return authRepo.login(email, password) |         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 name: String, | ||||||
|     var avatarUrl: String?, |     var avatarUrl: String?, | ||||||
|     val position : String, |     val position : String, | ||||||
|     var lastEntry : String, |     var lastEntry : String?, | ||||||
|     val authorities : 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 | package ru.myitschool.work.ui | ||||||
| 
 | 
 | ||||||
|  | import android.annotation.SuppressLint | ||||||
| import android.os.Bundle | import android.os.Bundle | ||||||
| import androidx.activity.OnBackPressedCallback | import androidx.activity.OnBackPressedCallback | ||||||
| import androidx.appcompat.app.AppCompatActivity | import androidx.appcompat.app.AppCompatActivity | ||||||
| @ -17,22 +18,28 @@ import ru.myitschool.work.ui.qr.scan.QrScanFragment | |||||||
| // НЕ ИЗМЕНЯЙТЕ НАЗВАНИЕ КЛАССА! | // НЕ ИЗМЕНЯЙТЕ НАЗВАНИЕ КЛАССА! | ||||||
| @AndroidEntryPoint | @AndroidEntryPoint | ||||||
| class RootActivity : AppCompatActivity() { | class RootActivity : AppCompatActivity() { | ||||||
|  |     @SuppressLint("ResourceType") | ||||||
|     override fun onCreate(savedInstanceState: Bundle?) { |     override fun onCreate(savedInstanceState: Bundle?) { | ||||||
|         super.onCreate(savedInstanceState) |         super.onCreate(savedInstanceState) | ||||||
|         setContentView(R.layout.activity_root) |         setContentView(R.layout.fragment_profile) | ||||||
|  |         val userRole = intent.getStringExtra("USER_ROLE") | ||||||
| 
 | 
 | ||||||
|         /*val navHostFragment = supportFragmentManager |         /*val navHostFragment = supportFragmentManager | ||||||
|             .findFragmentById(R.id.nav_host_fragment) as NavHostFragment? |             .findFragmentById(R.id.nav_host_fragment) as NavHostFragment? | ||||||
|  |         val navController = navHostFragment.navController*/ | ||||||
| 
 | 
 | ||||||
|         if (navHostFragment != null) { | 
 | ||||||
|             val navController = navHostFragment.navController | 
 | ||||||
|             navController.graph = navController.createGraph( |         /*if (userRole == "ROLE_ADMIN") { | ||||||
|                 startDestination = LoginDestination |             bottomNavigationView.menu.clear() | ||||||
|             ) { |             bottomNavigationView.inflateMenu(R.menu.bottom_menu_admin) | ||||||
|                 fragment<LoginFragment, LoginDestination>() |             navController.setGraph(R.navigation.main_admin_nav_graph) | ||||||
|                 fragment<QrScanFragment, QrScanDestination>() | 
 | ||||||
|             } |         } else { | ||||||
|         } |             bottomNavigationView.menu.clear() | ||||||
|  |             bottomNavigationView.inflateMenu(R.menu.bottom_menu) | ||||||
|  |             navController.setGraph(R.navigation.main_nav_graph) | ||||||
|  |         }*/ | ||||||
| 
 | 
 | ||||||
|         onBackPressedDispatcher.addCallback( |         onBackPressedDispatcher.addCallback( | ||||||
|             this, |             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 navController = findNavController(R.id.nav_host_fragment) | ||||||
|         val popBackResult = if (navController.previousBackStackEntry != null) { |         val popBackResult = if (navController.previousBackStackEntry != null) { | ||||||
|             navController.popBackStack() |             navController.popBackStack() | ||||||
| @ -53,5 +60,5 @@ class RootActivity : AppCompatActivity() { | |||||||
|         } |         } | ||||||
|         return popBackResult || super.onSupportNavigateUp() |         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 beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) = Unit | ||||||
|             override fun onTextChanged(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?) { |             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.AuthNetworkDataSource | ||||||
| import ru.myitschool.work.data.auth.AuthRepoImpl | import ru.myitschool.work.data.auth.AuthRepoImpl | ||||||
| import ru.myitschool.work.data.auth.AuthStorageDataSource | 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 ru.myitschool.work.domain.auth.LoginUseCase | ||||||
| import javax.inject.Inject | import javax.inject.Inject | ||||||
| import kotlin.reflect.KClass | import kotlin.reflect.KClass | ||||||
| 
 | 
 | ||||||
| class LoginViewModel constructor( | class LoginViewModel constructor( | ||||||
|     @ApplicationContext private val context: Context, |     @ApplicationContext private val context: Context, | ||||||
|     private val isUserExistUseCase: IsUserExistUseCase, |  | ||||||
|     private  val loginUseCase: LoginUseCase |     private  val loginUseCase: LoginUseCase | ||||||
| ) : ViewModel() { | ) : ViewModel() { | ||||||
|     private val _state = MutableStateFlow<State>(getStateShow()) |     private val _state = MutableStateFlow<State>(getStateShow()) | ||||||
| @ -49,44 +48,23 @@ class LoginViewModel constructor( | |||||||
|     ) |     ) | ||||||
|     { |     { | ||||||
|         viewModelScope.launch { |         viewModelScope.launch { | ||||||
|             when (checkUserExistence(login)) { |             loginUser(login, password) | ||||||
|                 true -> { | 
 | ||||||
|                     loginUser(login, password) |  | ||||||
|                 } |  | ||||||
|                 false -> { |  | ||||||
|                     updateState(context.getString(R.string.error_invalid_credentials)) |  | ||||||
|                 } |  | ||||||
|                 null -> updateState(context.getString(R.string.error_unknown)) |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     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) { |     private suspend fun loginUser(email: String, password: String) { | ||||||
|         loginUseCase(email, password).fold( |         loginUseCase(email, password).fold( | ||||||
|             onSuccess = { user -> |             onSuccess = { user -> | ||||||
|                 println("Login successful") |                 Log.d("loginViewModel","Login successful") | ||||||
|                 _userRole.emit(user.authorities) |                 _userRole.emit(user.authorities) | ||||||
|                 _navigateToMain.emit(user.authorities) |                 _navigateToMain.emit(user.authorities) | ||||||
|             }, |             }, | ||||||
|             onFailure = { error -> |             onFailure = { error -> | ||||||
|                 updateState(error.message ?: context.getString(R.string.error_unknown)) |                 updateState(error.message ?: context.getString(R.string.error_unknown)) | ||||||
|  |                 Log.d("errorLoginViewModel","${error.message}") | ||||||
|             } |             } | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
| @ -125,7 +103,6 @@ class LoginViewModel constructor( | |||||||
|                 ) |                 ) | ||||||
|                 return LoginViewModel( |                 return LoginViewModel( | ||||||
|                     application, |                     application, | ||||||
|                     isUserExistUseCase = IsUserExistUseCase(authRepoImpl), |  | ||||||
|                     loginUseCase = LoginUseCase(authRepoImpl) |                     loginUseCase = LoginUseCase(authRepoImpl) | ||||||
|                 ) as T |                 ) 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="Иванова Вера Павловна" /> |             tools:text="Иванова Вера Павловна" /> | ||||||
| 
 | 
 | ||||||
|         <TextView |         <TextView | ||||||
|             android:id="@+id/textView" |             android:id="@+id/position" | ||||||
|             android:layout_width="wrap_content" |             android:layout_width="wrap_content" | ||||||
|             android:layout_height="wrap_content" |             android:layout_height="wrap_content" | ||||||
|             android:layout_marginStart="24dp" |             android:layout_marginStart="24dp" | ||||||
| @ -118,6 +118,7 @@ | |||||||
|             tools:text="Должность: Разработчик" /> |             tools:text="Должность: Разработчик" /> | ||||||
| 
 | 
 | ||||||
|         <TextView |         <TextView | ||||||
|  |             android:id="@+id/lastEntry" | ||||||
|             android:layout_width="wrap_content" |             android:layout_width="wrap_content" | ||||||
|             android:layout_height="wrap_content" |             android:layout_height="wrap_content" | ||||||
|             android:layout_marginStart="24dp" |             android:layout_marginStart="24dp" | ||||||
| @ -125,7 +126,7 @@ | |||||||
|             android:textColor="@color/black" |             android:textColor="@color/black" | ||||||
|             android:textSize="16dp" |             android:textSize="16dp" | ||||||
|             app:layout_constraintStart_toStartOf="parent" |             app:layout_constraintStart_toStartOf="parent" | ||||||
|             app:layout_constraintTop_toBottomOf="@+id/textView" |             app:layout_constraintTop_toBottomOf="@+id/position" | ||||||
|             tools:text="Время последнего входа: 12:00 16.09" /> |             tools:text="Время последнего входа: 12:00 16.09" /> | ||||||
| 
 | 
 | ||||||
|         <com.google.android.material.button.MaterialButton |         <com.google.android.material.button.MaterialButton | ||||||
| @ -167,6 +168,7 @@ | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         <View |         <View | ||||||
|  |             android:id="@+id/view" | ||||||
|             android:layout_width="1dp" |             android:layout_width="1dp" | ||||||
|             android:layout_height="35dp" |             android:layout_height="35dp" | ||||||
|             android:layout_marginTop="7dp" |             android:layout_marginTop="7dp" | ||||||
| @ -189,25 +191,70 @@ | |||||||
|             app:layout_constraintStart_toStartOf="parent" /> |             app:layout_constraintStart_toStartOf="parent" /> | ||||||
| 
 | 
 | ||||||
|         <TextView |         <TextView | ||||||
|  |             android:id="@+id/textView" | ||||||
|             android:layout_width="wrap_content" |             android:layout_width="wrap_content" | ||||||
|             android:layout_height="20dp" |             android:layout_height="20dp" | ||||||
|             android:layout_marginTop="15dp" |             android:layout_marginTop="8dp" | ||||||
|  |             android:elevation="10dp" | ||||||
|             android:gravity="center" |             android:gravity="center" | ||||||
|             android:text="@string/entry_time" |             android:text="@string/entry_time" | ||||||
|             android:textColor="@color/white" |             android:textColor="@color/white" | ||||||
|             android:textSize="14sp" |             android:textSize="14sp" | ||||||
|             app:layout_constraintBottom_toBottomOf="@+id/view2" |  | ||||||
|             app:layout_constraintEnd_toStartOf="@+id/view3" |             app:layout_constraintEnd_toStartOf="@+id/view3" | ||||||
|             app:layout_constraintHorizontal_bias="0.51" |             app:layout_constraintHorizontal_bias="0.51" | ||||||
|             app:layout_constraintStart_toStartOf="@+id/view2" |             app:layout_constraintStart_toStartOf="@+id/view2" | ||||||
|             app:layout_constraintTop_toTopOf="@+id/view2" |             app:layout_constraintTop_toTopOf="@+id/view2" /> | ||||||
|             app:layout_constraintVertical_bias="0.0" /> | 
 | ||||||
|  | 
 | ||||||
|  |         <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 |         <androidx.recyclerview.widget.RecyclerView | ||||||
|             android:id="@+id/recyclerView" |             android:id="@+id/recyclerView" | ||||||
|             android:layout_width="match_parent" |             android:layout_width="match_parent" | ||||||
|             android:layout_height="wrap_content" |             android:layout_height="wrap_content" | ||||||
| 
 |  | ||||||
|             android:layout_marginBottom="16dp" |             android:layout_marginBottom="16dp" | ||||||
|             app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" |             app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" | ||||||
|             app:layout_constraintBottom_toBottomOf="parent" |             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="error_unknown">Непредвиденная ошибка</string> | ||||||
|     <string name="entry_history">История входов\n</string> |     <string name="entry_history">История входов\n</string> | ||||||
|     <string name="entry_time">Время входа\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> | </resources> | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user