From f437e8a120d47d2f34a8fe8cc97243fcb5cd39cf Mon Sep 17 00:00:00 2001 From: DKaverznev Date: Thu, 20 Feb 2025 10:14:48 +0300 Subject: [PATCH 1/3] =?UTF-8?q?code:=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D0=B5=D1=82=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../myitschool/work/ui/list/ListViewHolder.kt | 2 +- .../work/ui/result/ResultFragment.kt | 2 + .../work/ui/scan/qr/QrScanFragment.kt | 40 +- .../drawable/button_beigestroke_whitefill.xml | 8 - app/src/main/res/drawable/res_error.xml | 1119 +---------------- app/src/main/res/drawable/res_success.xml | 26 - app/src/main/res/drawable/res_success_ic.xml | 9 + ...istrator_screen.xml => fragment_admin.xml} | 36 +- app/src/main/res/layout/fragment_main.xml | 2 +- .../main/res/layout/fragment_scan_result.xml | 14 +- .../item_recycler_view_entrancedata.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 12 files changed, 63 insertions(+), 1199 deletions(-) delete mode 100644 app/src/main/res/drawable/button_beigestroke_whitefill.xml delete mode 100644 app/src/main/res/drawable/res_success.xml create mode 100644 app/src/main/res/drawable/res_success_ic.xml rename app/src/main/res/layout/{fragment_administrator_screen.xml => fragment_admin.xml} (88%) diff --git a/app/src/main/java/ru/myitschool/work/ui/list/ListViewHolder.kt b/app/src/main/java/ru/myitschool/work/ui/list/ListViewHolder.kt index a04c678..50f3e45 100644 --- a/app/src/main/java/ru/myitschool/work/ui/list/ListViewHolder.kt +++ b/app/src/main/java/ru/myitschool/work/ui/list/ListViewHolder.kt @@ -9,7 +9,7 @@ class ListViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { private val binding = ItemRecyclerViewEntrancedataBinding.bind(itemView) fun bind(item: ListInfo) { - binding.text1.text = item.time + binding.text1.text = item.time.replace("T", " ") binding.text2.text = item.value binding.text3.text = item.type } diff --git a/app/src/main/java/ru/myitschool/work/ui/result/ResultFragment.kt b/app/src/main/java/ru/myitschool/work/ui/result/ResultFragment.kt index df74102..3f28f62 100644 --- a/app/src/main/java/ru/myitschool/work/ui/result/ResultFragment.kt +++ b/app/src/main/java/ru/myitschool/work/ui/result/ResultFragment.kt @@ -58,7 +58,9 @@ class ResultFragment : Fragment(R.layout.fragment_scan_result) { if (qrData != null) { authPreferences.getLogin()?.let { login -> + val currentTime = getCurrentTime() + viewModel.open(login, CodeJson( value = qrData.toString(), type = OpenType.QR_TYPE, diff --git a/app/src/main/java/ru/myitschool/work/ui/scan/qr/QrScanFragment.kt b/app/src/main/java/ru/myitschool/work/ui/scan/qr/QrScanFragment.kt index 46314dc..ba9deb7 100644 --- a/app/src/main/java/ru/myitschool/work/ui/scan/qr/QrScanFragment.kt +++ b/app/src/main/java/ru/myitschool/work/ui/scan/qr/QrScanFragment.kt @@ -22,7 +22,6 @@ import com.google.mlkit.vision.barcode.BarcodeScanning import com.google.mlkit.vision.barcode.common.Barcode import ru.myitschool.work.R import ru.myitschool.work.databinding.FragmentQrScanBinding -import ru.myitschool.work.ui.main.MainDestination import ru.myitschool.work.ui.result.ResultDestination import ru.myitschool.work.utils.QrPreferences import ru.myitschool.work.utils.collectWhenStarted @@ -41,10 +40,8 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) { private val viewModel: QrScanViewModel by viewModels() private lateinit var qrPreferences: QrPreferences - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - qrPreferences = QrPreferences(requireContext()) } @@ -77,8 +74,7 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) { goBack() } is QrScanViewModel.Action.CloseWithResult -> { - sendResult(QrScanDestination.packToBundle(action.result)) - goResult() + // Удаляем этот блок, так как мы будем обрабатывать результат в другом месте } } } @@ -108,8 +104,12 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) { executor ) { result -> result?.getValue(barcodeScanner)?.firstOrNull()?.let { value -> - viewModel.findBarcode(value) + qrPreferences.saveQr(value.displayValue ?: value.rawValue ?: "") + + sendResult(QrScanDestination.packToBundle(value.displayValue ?: value.rawValue ?: "")) + + goResult() } } ) @@ -125,31 +125,17 @@ class QrScanFragment : Fragment(R.layout.fragment_qr_scan) { super.onDestroyView() } - private fun goBack() { - val qrData = arguments?.let { QrScanDestination.getDataIfExist(it) } - qrPreferences.saveQr(qrData.toString()) - - findNavControllerOrNull()?.popBackStack() - ?: requireActivity().onBackPressedDispatcher.onBackPressed() - } - private fun goResult() { - try { - val qrData = arguments?.let { QrScanDestination.getDataIfExist(it) } - qrPreferences.saveQr(qrData.toString()) - - Log.i("ResultFragment", qrData.toString()) - - findNavController().apply { - popBackStack(ResultDestination, false) - navigate(ResultDestination) - } - } catch (e: Exception) { - Log.e("ResultFragment", "Navigation error", e) - Toast.makeText(context, getText(R.string.errorGoText).toString(), Toast.LENGTH_SHORT).show() + findNavController().apply { + popBackStack(ResultDestination, false) + navigate(ResultDestination) } } + private fun goBack() { + findNavControllerOrNull()?.popBackStack() + ?: requireActivity().onBackPressedDispatcher.onBackPressed() + } private fun sendResult(bundle: Bundle) { setFragmentResult( diff --git a/app/src/main/res/drawable/button_beigestroke_whitefill.xml b/app/src/main/res/drawable/button_beigestroke_whitefill.xml deleted file mode 100644 index 5de5240..0000000 --- a/app/src/main/res/drawable/button_beigestroke_whitefill.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/res_error.xml b/app/src/main/res/drawable/res_error.xml index f613449..6b14052 100644 --- a/app/src/main/res/drawable/res_error.xml +++ b/app/src/main/res/drawable/res_error.xml @@ -1,1117 +1,36 @@ + android:width="32dp" + android:height="32dp" + android:viewportWidth="32" + android:viewportHeight="32"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:strokeColor="#000000"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:strokeColor="#000000"/> + android:strokeColor="#000000"/> + android:strokeColor="#000000"/> + android:strokeColor="#000000"/> diff --git a/app/src/main/res/drawable/res_success.xml b/app/src/main/res/drawable/res_success.xml deleted file mode 100644 index dfefcb7..0000000 --- a/app/src/main/res/drawable/res_success.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/drawable/res_success_ic.xml b/app/src/main/res/drawable/res_success_ic.xml new file mode 100644 index 0000000..3c71223 --- /dev/null +++ b/app/src/main/res/drawable/res_success_ic.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/fragment_administrator_screen.xml b/app/src/main/res/layout/fragment_admin.xml similarity index 88% rename from app/src/main/res/layout/fragment_administrator_screen.xml rename to app/src/main/res/layout/fragment_admin.xml index 3444646..12ab792 100644 --- a/app/src/main/res/layout/fragment_administrator_screen.xml +++ b/app/src/main/res/layout/fragment_admin.xml @@ -17,7 +17,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" - app:layout_constraintGuide_percent="0.36" /> + app:layout_constraintGuide_percent="0.4" /> - - - - - - - + app:layout_constraintTop_toBottomOf="@+id/block" + app:layout_constraintVertical_bias="0.0" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml index 9f085e6..8df4958 100644 --- a/app/src/main/res/layout/fragment_main.xml +++ b/app/src/main/res/layout/fragment_main.xml @@ -10,7 +10,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" - app:layout_constraintGuide_percent="0.31" /> + app:layout_constraintGuide_percent="0.37" /> + app:layout_constraintGuide_percent="0.29" /> + app:layout_constraintGuide_percent="0.58" /> @@ -76,7 +76,7 @@ android:layout_width="320dp" android:layout_height="80dp" android:layout_marginTop="10dp" - android:background="@drawable/button_beige" + android:background="@drawable/button_grey" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/guideline_bottom" /> diff --git a/app/src/main/res/layout/item_recycler_view_entrancedata.xml b/app/src/main/res/layout/item_recycler_view_entrancedata.xml index 2f1b91b..db67975 100644 --- a/app/src/main/res/layout/item_recycler_view_entrancedata.xml +++ b/app/src/main/res/layout/item_recycler_view_entrancedata.xml @@ -1,6 +1,6 @@ - NTO Pass + DoorRock логин Добро пожаловать! Введите свой логин From 9372266f4fabc8b2a8d19d8b2f7803ee2c80b56a Mon Sep 17 00:00:00 2001 From: DKaverznev Date: Thu, 20 Feb 2025 12:54:44 +0300 Subject: [PATCH 2/3] =?UTF-8?q?code:=20=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0?= =?UTF-8?q?=D0=BB=20api=20=D0=B0=D0=B4=D0=BC=D0=B8=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 8 +++- .../ru/myitschool/work/api/NetworkModule.kt | 7 ++++ .../ru/myitschool/work/api/RetrofitClient.kt | 6 ++- .../ru/myitschool/work/api/admin/AdminJson.kt | 7 ++++ .../work/api/admin/ApiServiceAdmin.kt | 16 +++++++ .../work/api/list/ApiServiceList.kt | 2 +- .../work/api/login/ApiServiceLogin.kt | 6 +-- .../work/api/main/ApiServiceMain.kt | 2 +- .../ru/myitschool/work/api/main/UserInfo.kt | 23 +++++----- .../work/api/scan/ApiServiceScan.kt | 2 +- .../ru/myitschool/work/ui/RootActivity.kt | 1 + .../myitschool/work/ui/login/LoginFragment.kt | 2 - .../work/ui/login/LoginViewModel.kt | 2 +- .../myitschool/work/ui/main/MainFragment.kt | 42 +++++++++++++++---- .../myitschool/work/ui/main/MainViewModel.kt | 7 +++- .../baseline_admin_panel_settings_24.xml | 7 ++++ app/src/main/res/layout/fragment_main.xml | 3 +- 17 files changed, 107 insertions(+), 36 deletions(-) create mode 100644 app/src/main/java/ru/myitschool/work/api/admin/AdminJson.kt create mode 100644 app/src/main/java/ru/myitschool/work/api/admin/ApiServiceAdmin.kt create mode 100644 app/src/main/res/drawable/baseline_admin_panel_settings_24.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 492e413..2ebcf6f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -48,7 +48,13 @@ dependencies { implementation(Dependencies.Retrofit.gsonConverter) implementation("com.squareup.okhttp3:logging-interceptor:4.10.0") - implementation("com.squareup.picasso:picasso:2.8") + // Убираем Picasso + // implementation("com.squareup.picasso:picasso:2.8") + + // Добавляем Glide + implementation("com.github.bumptech.glide:glide:4.14.2") + kapt("com.github.bumptech.glide:compiler:4.14.2") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") implementation("androidx.datastore:datastore-preferences:1.1.2") implementation("com.google.mlkit:barcode-scanning:17.3.0") diff --git a/app/src/main/java/ru/myitschool/work/api/NetworkModule.kt b/app/src/main/java/ru/myitschool/work/api/NetworkModule.kt index 205c1c3..3b19c42 100644 --- a/app/src/main/java/ru/myitschool/work/api/NetworkModule.kt +++ b/app/src/main/java/ru/myitschool/work/api/NetworkModule.kt @@ -6,6 +6,7 @@ import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import dagger.hilt.android.qualifiers.ApplicationContext +import ru.myitschool.work.api.admin.ApiServiceAdmin import ru.myitschool.work.api.list.ApiServiceList import ru.myitschool.work.api.login.ApiServiceLogin import ru.myitschool.work.api.main.ApiServiceMain @@ -45,4 +46,10 @@ object NetworkModule { fun provideListApiService(retrofitClient: RetrofitClient): ApiServiceList { return retrofitClient.getApiServiceList() } + + @Provides + @Singleton + fun provideApiServiceAdmin(retrofitClient: RetrofitClient): ApiServiceAdmin { + return retrofitClient.getApiServiceAdmin() + } } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/api/RetrofitClient.kt b/app/src/main/java/ru/myitschool/work/api/RetrofitClient.kt index ce4b061..01f981e 100644 --- a/app/src/main/java/ru/myitschool/work/api/RetrofitClient.kt +++ b/app/src/main/java/ru/myitschool/work/api/RetrofitClient.kt @@ -1,11 +1,11 @@ package ru.myitschool.work.api import android.content.Context -import com.google.android.datatransport.BuildConfig import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory +import ru.myitschool.work.api.admin.ApiServiceAdmin import ru.myitschool.work.api.list.ApiServiceList import ru.myitschool.work.api.login.ApiServiceLogin import ru.myitschool.work.api.main.ApiServiceMain @@ -57,4 +57,8 @@ class RetrofitClient(context: Context) { fun getApiServiceList(): ApiServiceList { return retrofitWithAuth.create(ApiServiceList::class.java) } + fun getApiServiceAdmin(): ApiServiceAdmin { + return retrofitWithAuth.create(ApiServiceAdmin::class.java) + } + } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/api/admin/AdminJson.kt b/app/src/main/java/ru/myitschool/work/api/admin/AdminJson.kt new file mode 100644 index 0000000..34993c3 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/api/admin/AdminJson.kt @@ -0,0 +1,7 @@ +package ru.myitschool.work.api.admin + +import com.google.gson.annotations.SerializedName + +class AdminJson( + @SerializedName("authority") var authority: String? = null, +) \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/api/admin/ApiServiceAdmin.kt b/app/src/main/java/ru/myitschool/work/api/admin/ApiServiceAdmin.kt new file mode 100644 index 0000000..e31acd3 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/api/admin/ApiServiceAdmin.kt @@ -0,0 +1,16 @@ +package ru.myitschool.work.api.admin + +import retrofit2.Response +import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.PATCH +import retrofit2.http.Path +import ru.myitschool.work.api.main.UserInfo + +interface ApiServiceAdmin { + @PATCH("api/admin/authority/change/{login}") + suspend fun block( + @Path("login") login: String, + @Body data: AdminJson + ): Response +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/api/list/ApiServiceList.kt b/app/src/main/java/ru/myitschool/work/api/list/ApiServiceList.kt index c92f80e..86105a3 100644 --- a/app/src/main/java/ru/myitschool/work/api/list/ApiServiceList.kt +++ b/app/src/main/java/ru/myitschool/work/api/list/ApiServiceList.kt @@ -5,6 +5,6 @@ import retrofit2.http.GET import retrofit2.http.Path interface ApiServiceList { - @GET("api/list/{login}") + @GET("api/user/list/{login}") suspend fun getList(@Path("login") login: String): Response> } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/api/login/ApiServiceLogin.kt b/app/src/main/java/ru/myitschool/work/api/login/ApiServiceLogin.kt index 51dd1d0..451c80b 100644 --- a/app/src/main/java/ru/myitschool/work/api/login/ApiServiceLogin.kt +++ b/app/src/main/java/ru/myitschool/work/api/login/ApiServiceLogin.kt @@ -1,13 +1,9 @@ package ru.myitschool.work.api.login import retrofit2.Call -import retrofit2.http.Body import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Path -import ru.myitschool.work.api.main.UserInfo interface ApiServiceLogin { - @GET("api/login") + @GET("api/user/login") fun authenticate(): Call } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/api/main/ApiServiceMain.kt b/app/src/main/java/ru/myitschool/work/api/main/ApiServiceMain.kt index c99468c..7b3a832 100644 --- a/app/src/main/java/ru/myitschool/work/api/main/ApiServiceMain.kt +++ b/app/src/main/java/ru/myitschool/work/api/main/ApiServiceMain.kt @@ -5,6 +5,6 @@ import retrofit2.http.GET import retrofit2.http.Path interface ApiServiceMain { - @GET("api/info/{login}") + @GET("api/user/info/{login}") fun getDataUser(@Path("login") login: String): Call } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/api/main/UserInfo.kt b/app/src/main/java/ru/myitschool/work/api/main/UserInfo.kt index 31fc8d1..617cd2a 100644 --- a/app/src/main/java/ru/myitschool/work/api/main/UserInfo.kt +++ b/app/src/main/java/ru/myitschool/work/api/main/UserInfo.kt @@ -9,15 +9,16 @@ data class UserInfo( @SerializedName("photo") val photoUrl: String, @SerializedName("position") val position: String, @SerializedName("lastVisit") val lastVisit: String, -) { - companion object { - val Initial = UserInfo( - id = 0, - login = "", - name = "", - photoUrl = "", - position = "", - lastVisit = "", - ) - } + @SerializedName("authority") val authority: List +) + +data class AuthorityData( + @SerializedName("id") val id: Int, + @SerializedName("authority") val authority: String, +) + +object Authorities { + const val ROLE_ADMIN = "ROLE_ADMIN" + const val ROLE_USER = "ROLE_USER" + const val ROLE_BLOCK = "ROLE_BLOCK" } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/api/scan/ApiServiceScan.kt b/app/src/main/java/ru/myitschool/work/api/scan/ApiServiceScan.kt index e83ffd4..8eadd2d 100644 --- a/app/src/main/java/ru/myitschool/work/api/scan/ApiServiceScan.kt +++ b/app/src/main/java/ru/myitschool/work/api/scan/ApiServiceScan.kt @@ -6,6 +6,6 @@ import retrofit2.http.POST import retrofit2.http.Path interface ApiServiceScan { - @POST("api/add/{login}") + @POST("api/user/add/{login}") fun open(@Path("login") login: String, @Body data: CodeJson): Call } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/RootActivity.kt b/app/src/main/java/ru/myitschool/work/ui/RootActivity.kt index 8f1b5fe..2eadf1a 100644 --- a/app/src/main/java/ru/myitschool/work/ui/RootActivity.kt +++ b/app/src/main/java/ru/myitschool/work/ui/RootActivity.kt @@ -36,6 +36,7 @@ class RootActivity : AppCompatActivity() { fragment() fragment() fragment() + /*fragment()*/ } } diff --git a/app/src/main/java/ru/myitschool/work/ui/login/LoginFragment.kt b/app/src/main/java/ru/myitschool/work/ui/login/LoginFragment.kt index 60695ac..7894194 100644 --- a/app/src/main/java/ru/myitschool/work/ui/login/LoginFragment.kt +++ b/app/src/main/java/ru/myitschool/work/ui/login/LoginFragment.kt @@ -104,8 +104,6 @@ class LoginFragment : Fragment(R.layout.fragment_login) { text = "Ошибка авторизации" } - authPreferences.clearLoginState() - Log.d("Authentication", "Ошибка авторизации") } diff --git a/app/src/main/java/ru/myitschool/work/ui/login/LoginViewModel.kt b/app/src/main/java/ru/myitschool/work/ui/login/LoginViewModel.kt index 8996957..699e12d 100644 --- a/app/src/main/java/ru/myitschool/work/ui/login/LoginViewModel.kt +++ b/app/src/main/java/ru/myitschool/work/ui/login/LoginViewModel.kt @@ -36,7 +36,7 @@ class LoginViewModel @Inject constructor( _state.value = LoginState.InvalidCredentials } 401 -> { - _state.value = LoginState.Error + _state.value = LoginState.InvalidCredentials } else -> { _state.value = LoginState.Error diff --git a/app/src/main/java/ru/myitschool/work/ui/main/MainFragment.kt b/app/src/main/java/ru/myitschool/work/ui/main/MainFragment.kt index b4b1ede..00f0012 100644 --- a/app/src/main/java/ru/myitschool/work/ui/main/MainFragment.kt +++ b/app/src/main/java/ru/myitschool/work/ui/main/MainFragment.kt @@ -8,9 +8,9 @@ import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager -import com.squareup.picasso.Picasso import dagger.hilt.android.AndroidEntryPoint import ru.myitschool.work.R +import ru.myitschool.work.api.main.Authorities import ru.myitschool.work.databinding.FragmentMainBinding import ru.myitschool.work.ui.list.ListAdapter import ru.myitschool.work.ui.login.LoginDestination @@ -100,6 +100,16 @@ class MainFragment : Fragment(R.layout.fragment_main) { username.text = state.userInfo.name position.text = state.userInfo.position + + if (state.userInfo.authority[0].authority == Authorities.ROLE_ADMIN) { + admin.visibleOrGone(true) + } else if (state.userInfo.authority[0].authority == Authorities.ROLE_USER) { + admin.visibleOrGone(false) + } else { + admin.visibleOrGone(false) + Log.e("MainFragment", "Unknown role") + } + loadImageFromUrl(state.userInfo.photoUrl) val inputFormat = java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault()) @@ -107,7 +117,8 @@ class MainFragment : Fragment(R.layout.fragment_main) { try { val parsedDate = inputFormat.parse(state.userInfo.lastVisit) - lastEntry.text = parsedDate?.let { outputFormat.format(it) } ?: state.userInfo.lastVisit + lastEntry.text = parsedDate?.let { outputFormat.format(it) } + ?: state.userInfo.lastVisit } catch (e: Exception) { lastEntry.text = state.userInfo.lastVisit } @@ -125,13 +136,13 @@ class MainFragment : Fragment(R.layout.fragment_main) { viewModel.listState.collectWhenStarted(this) { state -> when (state) { is MainViewModel.ListState.Loading -> { - //TODO + hideAll() } is MainViewModel.ListState.Success -> { listAdapter.submitList(state.data) } is MainViewModel.ListState.Error -> { - //TODO + hideAll() binding.error.text = state.message } } @@ -139,11 +150,7 @@ class MainFragment : Fragment(R.layout.fragment_main) { } private fun loadImageFromUrl(url: String) { - Picasso - .get() - .load(url) - .error(R.drawable.icon_profile) - .into(binding.photo) + } private fun setupMainComponents() { @@ -152,6 +159,10 @@ class MainFragment : Fragment(R.layout.fragment_main) { navigateToLogin() } + binding.admin.setOnClickListener { + navigateToAdmin() + } + binding.refresh.setOnClickListener { viewModel.getUserData(authPreferences.getLogin() ?: "") } @@ -173,6 +184,19 @@ class MainFragment : Fragment(R.layout.fragment_main) { } } + + private fun navigateToAdmin() { + try {/* + authPreferences.clearLoginState() + findNavController().apply { + popBackStack(AdminDestination, false) + navigate(AdminDestination) + }*/ + } catch (e: Exception) { + Log.e("MainFragment", "Error navigating to login", e) + } + } + override fun onDestroyView() { super.onDestroyView() _binding = null diff --git a/app/src/main/java/ru/myitschool/work/ui/main/MainViewModel.kt b/app/src/main/java/ru/myitschool/work/ui/main/MainViewModel.kt index 73c6a29..286a0ed 100644 --- a/app/src/main/java/ru/myitschool/work/ui/main/MainViewModel.kt +++ b/app/src/main/java/ru/myitschool/work/ui/main/MainViewModel.kt @@ -36,12 +36,15 @@ class MainViewModel @Inject constructor( when { response.isSuccessful -> { - val userInfo = response.body() ?: UserInfo.Initial - _state.value = MainState.Success(userInfo) + val userInfo = response.body() + _state.value = userInfo?.let { MainState.Success(it) }!! } response.code() == 401 -> { _state.value = MainState.Error("Unauthorized") } + response.code() == 403 -> { + _state.value = MainState.Error("Block") + } else -> { _state.value = MainState.Error("Error") } diff --git a/app/src/main/res/drawable/baseline_admin_panel_settings_24.xml b/app/src/main/res/drawable/baseline_admin_panel_settings_24.xml new file mode 100644 index 0000000..e8b27be --- /dev/null +++ b/app/src/main/res/drawable/baseline_admin_panel_settings_24.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml index 9a5efcd..4a92509 100644 --- a/app/src/main/res/layout/fragment_main.xml +++ b/app/src/main/res/layout/fragment_main.xml @@ -33,13 +33,14 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> + From add9651561b98fdbcfaffb685fbba32c97284be5 Mon Sep 17 00:00:00 2001 From: DKaverznev Date: Thu, 20 Feb 2025 14:26:25 +0300 Subject: [PATCH 3/3] =?UTF-8?q?code:=20=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0?= =?UTF-8?q?=D0=BB=20api=20=D0=B0=D0=B4=D0=BC=D0=B8=D0=BD=D0=B0=20=D0=B8=20?= =?UTF-8?q?=D0=B5=D0=B3=D0=BE=20VM=20(=D0=B2=D1=80=D0=BE=D0=B4=D0=B5=20?= =?UTF-8?q?=D0=BA=D0=B0=D0=BA)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/myitschool/work/api/RetrofitClient.kt | 1 + .../work/api/admin/ApiServiceAdmin.kt | 2 - .../ru/myitschool/work/ui/RootActivity.kt | 4 +- .../work/ui/admin/AdminDestination.kt | 6 + .../myitschool/work/ui/admin/AdminFragment.kt | 101 +++++++++++++ .../work/ui/admin/AdminViewModel.kt | 135 ++++++++++++++++++ .../myitschool/work/ui/main/MainFragment.kt | 5 +- .../myitschool/work/ui/result/TextStatus.kt | 6 - 8 files changed, 249 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/ru/myitschool/work/ui/admin/AdminDestination.kt create mode 100644 app/src/main/java/ru/myitschool/work/ui/admin/AdminFragment.kt create mode 100644 app/src/main/java/ru/myitschool/work/ui/admin/AdminViewModel.kt delete mode 100644 app/src/main/java/ru/myitschool/work/ui/result/TextStatus.kt diff --git a/app/src/main/java/ru/myitschool/work/api/RetrofitClient.kt b/app/src/main/java/ru/myitschool/work/api/RetrofitClient.kt index 01f981e..1ceb126 100644 --- a/app/src/main/java/ru/myitschool/work/api/RetrofitClient.kt +++ b/app/src/main/java/ru/myitschool/work/api/RetrofitClient.kt @@ -57,6 +57,7 @@ class RetrofitClient(context: Context) { fun getApiServiceList(): ApiServiceList { return retrofitWithAuth.create(ApiServiceList::class.java) } + fun getApiServiceAdmin(): ApiServiceAdmin { return retrofitWithAuth.create(ApiServiceAdmin::class.java) } diff --git a/app/src/main/java/ru/myitschool/work/api/admin/ApiServiceAdmin.kt b/app/src/main/java/ru/myitschool/work/api/admin/ApiServiceAdmin.kt index e31acd3..496e179 100644 --- a/app/src/main/java/ru/myitschool/work/api/admin/ApiServiceAdmin.kt +++ b/app/src/main/java/ru/myitschool/work/api/admin/ApiServiceAdmin.kt @@ -2,10 +2,8 @@ package ru.myitschool.work.api.admin import retrofit2.Response import retrofit2.http.Body -import retrofit2.http.GET import retrofit2.http.PATCH import retrofit2.http.Path -import ru.myitschool.work.api.main.UserInfo interface ApiServiceAdmin { @PATCH("api/admin/authority/change/{login}") diff --git a/app/src/main/java/ru/myitschool/work/ui/RootActivity.kt b/app/src/main/java/ru/myitschool/work/ui/RootActivity.kt index 2eadf1a..a4baea5 100644 --- a/app/src/main/java/ru/myitschool/work/ui/RootActivity.kt +++ b/app/src/main/java/ru/myitschool/work/ui/RootActivity.kt @@ -9,6 +9,8 @@ import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.fragment import dagger.hilt.android.AndroidEntryPoint import ru.myitschool.work.R +import ru.myitschool.work.ui.admin.AdminDestination +import ru.myitschool.work.ui.admin.AdminFragment import ru.myitschool.work.ui.login.LoginDestination import ru.myitschool.work.ui.login.LoginFragment import ru.myitschool.work.ui.main.MainDestination @@ -36,7 +38,7 @@ class RootActivity : AppCompatActivity() { fragment() fragment() fragment() - /*fragment()*/ + fragment() } } diff --git a/app/src/main/java/ru/myitschool/work/ui/admin/AdminDestination.kt b/app/src/main/java/ru/myitschool/work/ui/admin/AdminDestination.kt new file mode 100644 index 0000000..4f02d97 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/ui/admin/AdminDestination.kt @@ -0,0 +1,6 @@ +package ru.myitschool.work.ui.admin + +import kotlinx.serialization.Serializable + +@Serializable +data object AdminDestination \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/admin/AdminFragment.kt b/app/src/main/java/ru/myitschool/work/ui/admin/AdminFragment.kt new file mode 100644 index 0000000..2aa2a3b --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/ui/admin/AdminFragment.kt @@ -0,0 +1,101 @@ +package ru.myitschool.work.ui.admin + +import android.os.Bundle +import android.util.Log +import android.view.View +import android.widget.Toast +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController +import dagger.hilt.android.AndroidEntryPoint +import ru.myitschool.work.R +import ru.myitschool.work.databinding.FragmentAdminBinding +import ru.myitschool.work.ui.main.MainDestination +import ru.myitschool.work.utils.AuthPreferences +import ru.myitschool.work.utils.QrPreferences +import ru.myitschool.work.utils.collectWhenStarted +import ru.myitschool.work.utils.visibleOrGone + +@AndroidEntryPoint +class AdminFragment : Fragment(R.layout.fragment_admin) { + private var _binding: FragmentAdminBinding? = null + private val binding: FragmentAdminBinding get() = _binding!! + private val viewModel: AdminViewModel by viewModels() + + private lateinit var authPreferences: AuthPreferences + private lateinit var qrPreferences: QrPreferences + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + authPreferences = AuthPreferences(requireContext()) + qrPreferences = QrPreferences(requireContext()) + + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + _binding = FragmentAdminBinding.bind(view) + + setupOpenComponents() + observeOpenState() + } + + private fun setupOpenComponents() { + binding.apply { + block.setOnClickListener { + authPreferences.getLogin().toString().let { + viewModel.block( + it, + true + ) + } + } + } + } + + private fun observeOpenState() { + viewModel.state.collectWhenStarted(this) { state -> + when (state) { + is AdminViewModel.ResultState.Loading -> { + + } + is AdminViewModel.ResultState.Success -> { + + + } + is AdminViewModel.ResultState.InvalidCredentials -> { + + } + is AdminViewModel.ResultState.Error -> { + + } + AdminViewModel.ResultState.Initial -> { + + } + } + } + } + + private fun visibleAll(isVisible: Boolean) { + binding.apply { + } + } + + private fun navigateToMainScreen() { + try { + findNavController().apply { + popBackStack(MainDestination, false) + navigate(MainDestination) + } + } catch (e: Exception) { + Log.e("ResultFragment", "Navigation error", e) + Toast.makeText(context, getText(R.string.errorGoText).toString(), Toast.LENGTH_SHORT).show() + } + } + + override fun onDestroyView() { + _binding = null + super.onDestroyView() + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/admin/AdminViewModel.kt b/app/src/main/java/ru/myitschool/work/ui/admin/AdminViewModel.kt new file mode 100644 index 0000000..3d78b19 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/ui/admin/AdminViewModel.kt @@ -0,0 +1,135 @@ +package ru.myitschool.work.ui.admin + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response +import ru.myitschool.work.api.admin.AdminJson +import ru.myitschool.work.api.admin.ApiServiceAdmin +import ru.myitschool.work.api.list.ListInfo +import ru.myitschool.work.api.main.ApiServiceMain +import ru.myitschool.work.api.main.Authorities +import ru.myitschool.work.api.main.UserInfo +import ru.myitschool.work.ui.list.ListRepository +import javax.inject.Inject + +@HiltViewModel +class AdminViewModel @Inject constructor( + private val apiService: ApiServiceAdmin, + private val apiServiceData: ApiServiceMain, + private val listRepository: ListRepository +) : ViewModel() { + + private val _state = MutableStateFlow(ResultState.Initial) + val state = _state.asStateFlow() + + private val _stateData = MutableStateFlow(ResultStateData.Initial) + val stateData = _stateData.asStateFlow() + + fun block(login: String, authority: Boolean) { + viewModelScope.launch { + _state.value = ResultState.Loading + + try { + val response = apiService.block( + login = login, + data = AdminJson( + if (authority) Authorities.ROLE_BLOCK + else Authorities.ROLE_USER + ) + ) + + when (response.code()) { + 200 -> { + _state.value = ResultState.Success + } + 403 -> { + _state.value = ResultState.InvalidCredentials + } + 401 -> { + _state.value = ResultState.Error + } + else -> { + _state.value = ResultState.Error + } + } + } catch (t: Throwable) { + _state.value = ResultState.Error + } + } + } + + fun getUserData(login: String) { + viewModelScope.launch { + _stateData.value = ResultStateData.Loading + + + apiServiceData.getDataUser(login).enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + + when { + response.isSuccessful -> { + val userInfo = response.body() + _stateData.value = userInfo?.let { ResultStateData.Success(it) }!! + } + response.code() == 401 -> { + _stateData.value = ResultStateData.Error("Unauthorized") + } + response.code() == 403 -> { + _stateData.value = ResultStateData.Error("Block") + } + else -> { + _stateData.value = ResultStateData.Error("Error") + } + } + } + + override fun onFailure(call: Call, t: Throwable) { + _stateData.value = ResultStateData.Error("Network Error") + } + }) + } + } + + private val _listState = MutableStateFlow(ListState.Loading) + val listState: StateFlow = _listState + + sealed class ListState { + data object Loading : ListState() + data class Success(val data: List) : ListState() + data class Error(val message: String) : ListState() + } + + fun loadList(login: String) { + viewModelScope.launch { + _listState.value = ListState.Loading + try { + val list = listRepository.getList(login) + _listState.value = ListState.Success(list) + } catch (e: Exception) { + _listState.value = ListState.Error(e.message ?: "Unknown error") + } + } + } + + sealed class ResultState { + data object Initial : ResultState() + data object InvalidCredentials : ResultState() + data object Loading : ResultState() + data object Success : ResultState() + data object Error : ResultState() + } + + sealed class ResultStateData { + data object Initial : ResultStateData() + data object Loading : ResultStateData() + data class Success(val userInfo: UserInfo) : ResultStateData() + data class Error(val message: String) : ResultStateData() + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/main/MainFragment.kt b/app/src/main/java/ru/myitschool/work/ui/main/MainFragment.kt index 00f0012..b207dcd 100644 --- a/app/src/main/java/ru/myitschool/work/ui/main/MainFragment.kt +++ b/app/src/main/java/ru/myitschool/work/ui/main/MainFragment.kt @@ -12,6 +12,7 @@ import dagger.hilt.android.AndroidEntryPoint import ru.myitschool.work.R import ru.myitschool.work.api.main.Authorities import ru.myitschool.work.databinding.FragmentMainBinding +import ru.myitschool.work.ui.admin.AdminDestination import ru.myitschool.work.ui.list.ListAdapter import ru.myitschool.work.ui.login.LoginDestination import ru.myitschool.work.ui.scan.qr.QrScanDestination @@ -186,12 +187,12 @@ class MainFragment : Fragment(R.layout.fragment_main) { private fun navigateToAdmin() { - try {/* + try { authPreferences.clearLoginState() findNavController().apply { popBackStack(AdminDestination, false) navigate(AdminDestination) - }*/ + } } catch (e: Exception) { Log.e("MainFragment", "Error navigating to login", e) } diff --git a/app/src/main/java/ru/myitschool/work/ui/result/TextStatus.kt b/app/src/main/java/ru/myitschool/work/ui/result/TextStatus.kt deleted file mode 100644 index cb4a621..0000000 --- a/app/src/main/java/ru/myitschool/work/ui/result/TextStatus.kt +++ /dev/null @@ -1,6 +0,0 @@ -package ru.myitschool.work.ui.result - -object TextStatus { - const val error = "Вход был отменён/Operation was cancelled" - const val success = "Успешно/Success" -}