fix profile update

This commit is contained in:
Ксении 2025-02-19 18:47:22 +03:00
parent 45a5f9cff5
commit a926afbd3d
15 changed files with 182 additions and 70 deletions

View File

@ -18,16 +18,6 @@ import ru.myitschool.work.data.user.UserDto
object AuthNetworkDataSource { 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 login(token: String): Result<UserDto> = withContext(Dispatchers.IO) { suspend fun login(token: String): Result<UserDto> = withContext(Dispatchers.IO) {

View File

@ -7,9 +7,6 @@ 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?> {
// 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)

View File

@ -1,14 +1,16 @@
package ru.myitschool.work.data.user package ru.myitschool.work.data.user
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class EntranceDto( data class EntranceDto(
@SerialName("login") @SerialName("login")
val login : String, val login : String,
@SerialName("name") @SerialName("name")
var name: String, var name: String,
@SerialName("enterAt") @SerialName("enteredAt")
var enterAt: String, var enteredAt: String,
@SerialName("enterType") @SerialName("enterType")
var enterType: String, var enterType: String,
) { ) {

View File

@ -20,18 +20,9 @@ data class UserDto(
val position: String, val position: String,
@SerialName("lastEnter") @SerialName("lastEnter")
val lastEntry : String? = null, val lastEntry : String? = null,
@SerialName("access")
val access : String,
@SerialName("authorities") @SerialName("authorities")
val authorities : String val authorities : String
) { ) {
fun toEntity(): UserEntity {
return UserEntity(
id = id ?: throw IllegalArgumentException("User ID cannot be null"),
login,
name = name,
avatarUrl = avatarUrl,
position = position,
lastEntry = lastEntry,
authorities = authorities
)
}
} }

View File

@ -1,11 +1,9 @@
package ru.sicampus.bootcamp2025.data.user package ru.myitschool.work.data.user
import android.util.Log 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
import io.ktor.client.request.put
import io.ktor.client.request.setBody
import io.ktor.client.statement.bodyAsText import io.ktor.client.statement.bodyAsText
import io.ktor.http.HttpHeaders import io.ktor.http.HttpHeaders
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
@ -14,26 +12,25 @@ import kotlinx.coroutines.withContext
import ru.myitschool.work.core.Constants.SERVER_ADDRESS import ru.myitschool.work.core.Constants.SERVER_ADDRESS
import ru.myitschool.work.data.auth.AuthStorageDataSource.token import ru.myitschool.work.data.auth.AuthStorageDataSource.token
import ru.myitschool.work.data.auth.Network.client import ru.myitschool.work.data.auth.Network.client
import ru.myitschool.work.data.user.EntranceDto
import ru.myitschool.work.data.user.UserDto
class UserNetworkDataSource { class UserNetworkDataSource {
suspend fun getUser(login : String): Result<UserDto> = withContext(Dispatchers.IO) { suspend fun getUser(login : String): Result<UserDto> = withContext(Dispatchers.IO) {
runCatching { //runCatching {
val result = client.get("http://$SERVER_ADDRESS/api/${login}/info") { val result = client.get("$SERVER_ADDRESS/api/${login}/info") {
header(HttpHeaders.Authorization, token) 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()
} }
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){ suspend fun getEntrancesList(login : String) : Result<List<EntranceDto>> = withContext(Dispatchers.IO){

View File

@ -1,7 +1,4 @@
package ru.sicampus.bootcamp2025.data.user package ru.myitschool.work.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.EntranceEntity
import ru.myitschool.work.domain.user.UserEntity import ru.myitschool.work.domain.user.UserEntity
import ru.myitschool.work.domain.user.UserRepo import ru.myitschool.work.domain.user.UserRepo
@ -35,7 +32,7 @@ class UserRepoImpl (
return EntranceEntity( return EntranceEntity(
login = login, login = login,
name = this.name, name = this.name,
enterAt = this.enterAt, enteredAt = this.enteredAt,
enterType = this.enterType enterType = this.enterType
) )
} }

View File

@ -1,11 +1,13 @@
package ru.myitschool.work.domain.user package ru.myitschool.work.domain.user
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class EntranceEntity( data class EntranceEntity(
val login : String, val login : String,
var name: String, var name: String,
var enterAt: String, var enteredAt: String,
var enterType: String, var enterType: String,
) { ) {

View File

@ -1,7 +1,7 @@
package ru.myitschool.work.domain.user package ru.myitschool.work.domain.user
import java.sql.Timestamp import kotlinx.serialization.Serializable
@Serializable
data class UserEntity( data class UserEntity(
val id : Long, val id : Long,
var login: String, var login: String,

View File

@ -21,34 +21,42 @@ class RootActivity : AppCompatActivity() {
@SuppressLint("ResourceType") @SuppressLint("ResourceType")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.fragment_profile) setContentView(R.layout.activity_root)
val userRole = intent.getStringExtra("USER_ROLE") 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*/
val navController = navHostFragment?.navController ?: throw IllegalStateException("NavHostFragment not found")
navController.setGraph(R.navigation.main_nav_graph)
navController.navigate(R.id.fragment_profile)
/*if (userRole == "ROLE_ADMIN") { /*if (userRole == "ROLE_ADMIN") {
bottomNavigationView.menu.clear() //bottomNavigationView.menu.clear()
bottomNavigationView.inflateMenu(R.menu.bottom_menu_admin) //bottomNavigationView.inflateMenu(R.menu.bottom_menu_admin)
navController.setGraph(R.navigation.main_admin_nav_graph) navController.setGraph(R.navigation.main_admin_nav_graph)
} else { } else {
bottomNavigationView.menu.clear()
bottomNavigationView.inflateMenu(R.menu.bottom_menu)
navController.setGraph(R.navigation.main_nav_graph) navController.setGraph(R.navigation.main_nav_graph)
navController.navigate(R.id.fragment_profile)
}*/ }*/
onBackPressedDispatcher.addCallback(
/*onBackPressedDispatcher.addCallback(
this, this,
object : OnBackPressedCallback(true) { object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() { override fun handleOnBackPressed() {
onSupportNavigateUp() onSupportNavigateUp()
} }
} }
) )*/
} }
/*override fun onSupportNavigateUp(): Boolean { /*override fun onSupportNavigateUp(): Boolean {

View File

@ -0,0 +1,53 @@
package ru.sicampus.bootcamp2025.ui.centerList
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import ru.myitschool.work.databinding.OneEntryListViewBinding
import ru.myitschool.work.domain.user.EntranceEntity
class EntranceAdapter(
//private val onCenterClick: (CenterEntity) -> Unit
) : ListAdapter<EntranceEntity, EntranceAdapter.ViewHolder>(EntranceDiff) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
OneEntryListViewBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
}
class ViewHolder(
private val binding: OneEntryListViewBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item : EntranceEntity) {
binding.time.text = item.enteredAt
binding.type.text = item.enterType
binding.entry.text = item.name
}
}
object EntranceDiff : DiffUtil.ItemCallback<EntranceEntity>() {
override fun areItemsTheSame(oldItem: EntranceEntity, newItem: EntranceEntity): Boolean {
return oldItem.enteredAt == newItem.enteredAt
}
override fun areContentsTheSame(oldItem: EntranceEntity, newItem: EntranceEntity): Boolean {
return oldItem == newItem
}
}
}

View File

@ -10,6 +10,7 @@ import com.squareup.picasso.Picasso
import ru.myitschool.work.R import ru.myitschool.work.R
import ru.myitschool.work.databinding.FragmentProfileBinding import ru.myitschool.work.databinding.FragmentProfileBinding
import ru.myitschool.work.ui.login.EntryActivity import ru.myitschool.work.ui.login.EntryActivity
import ru.myitschool.work.ui.qr.scan.QrScanFragment
import ru.myitschool.work.utils.collectWithLifecycle import ru.myitschool.work.utils.collectWithLifecycle
class ProfileFragment : Fragment(R.layout.fragment_profile) { class ProfileFragment : Fragment(R.layout.fragment_profile) {
@ -31,6 +32,14 @@ class ProfileFragment : Fragment(R.layout.fragment_profile) {
startActivity(intent) startActivity(intent)
requireActivity().finish() requireActivity().finish()
} }
viewBinding.qrScan.setOnClickListener{
val qrScanFragment = QrScanFragment()
val fragmentManager = parentFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.replace(R.id.fragment_container, qrScanFragment)
fragmentTransaction.addToBackStack(null)
fragmentTransaction.commit()
}
viewModel.state.collectWithLifecycle(this) { state -> viewModel.state.collectWithLifecycle(this) { state ->
@ -42,25 +51,27 @@ class ProfileFragment : Fragment(R.layout.fragment_profile) {
when(state) { when(state) {
is ProfileViewModel.State.Loading -> Unit is ProfileViewModel.State.Loading -> Unit
is ProfileViewModel.State.Show -> { is ProfileViewModel.State.Show -> {
viewBinding.noData.visibility = View.GONE
viewBinding.name.text = state.profileInfo.name viewBinding.name.text = state.profileInfo.name
viewBinding.position.text = "Должность: ${state.profileInfo.name}" viewBinding.position.text = "Должность: ${state.profileInfo.name}"
if (state.profileInfo.lastEntry == null) viewBinding.lastEntry.text = "Время последнего входа: Нет данных" if (state.profileInfo.lastEntry == null) viewBinding.lastEntry.text = "Время последнего входа: Нет данных"
else viewBinding.lastEntry.text = "Время последнего входа: ${state.profileInfo.lastEntry}" else viewBinding.lastEntry.text = "Время последнего входа: ${state.profileInfo.lastEntry}"
Picasso.get().load(state.profileInfo.avatarUrl).resize(100, 100).centerCrop().into(viewBinding.imageView) Picasso.get().load(state.profileInfo.avatarUrl).resize(100, 100).centerCrop().into(viewBinding.imageView)
//if (state.entrancesList == emptyList()) if (state.entrancesList.size == 0) {
//viewBinding.recyclerView.visibility = View.GONE viewBinding.noData.visibility = View.VISIBLE
}
} }
is ProfileViewModel.State.Error -> { is ProfileViewModel.State.Error -> {
viewBinding.errorText.text = state.text viewBinding.errorText.text = state.text
//viewBinding.noData.visibility = View.VISIBLE
} }
} }
} }
} }
override fun onDestroyView() { override fun onDestroyView() {
_viewBinding = null _viewBinding = null
super.onDestroyView() super.onDestroyView()

View File

@ -8,11 +8,12 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import ru.myitschool.work.data.auth.AuthStorageDataSource import ru.myitschool.work.data.auth.AuthStorageDataSource
import ru.myitschool.work.data.user.UserNetworkDataSource
import ru.myitschool.work.data.user.UserRepoImpl
import ru.myitschool.work.domain.user.EntranceEntity import ru.myitschool.work.domain.user.EntranceEntity
import ru.myitschool.work.domain.user.GetUserUseCase import ru.myitschool.work.domain.user.GetUserUseCase
import ru.myitschool.work.domain.user.UserEntity import ru.myitschool.work.domain.user.UserEntity
import ru.sicampus.bootcamp2025.data.user.UserNetworkDataSource
import ru.sicampus.bootcamp2025.data.user.UserRepoImpl
class ProfileViewModel( class ProfileViewModel(
private val getUserUseCase: GetUserUseCase private val getUserUseCase: GetUserUseCase

View File

@ -130,7 +130,7 @@
tools:text="Время последнего входа: 12:00 16.09" /> tools:text="Время последнего входа: 12:00 16.09" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/materialButton" android:id="@+id/qrScan"
android:layout_width="80dp" android:layout_width="80dp"
android:layout_height="90dp" android:layout_height="90dp"
android:layout_marginTop="148dp" android:layout_marginTop="148dp"
@ -262,7 +262,8 @@
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/view2" app:layout_constraintTop_toBottomOf="@+id/view2"
app:layout_constraintVertical_bias="0.0" /> app:layout_constraintVertical_bias="0.0"
tools:listitem="@layout/one_entry_list_view"/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,6 +1,54 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp"> android:layout_height="60dp"
xmlns:tools="http://schemas.android.com/tools">
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:layout_marginTop="20dp"
android:textColor="@color/black"
android:textSize="14sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="12:00" />
<TextView
android:id="@+id/entry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textColor="@color/black"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Вход А" />
<TextView
android:id="@+id/type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textColor="@color/black"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.889"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="По карте" />
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@color/grey"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,14 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_nav_graph"
app:startDestination="@id/fragment_profile">
<fragment
android:id="@+id/fragment_profile"
android:name="ru.myitschool.work.ui.profile.ProfileFragment"
android:label="Profile"
tools:layout="@layout/fragment_profile" />
</navigation>