From 2c4c6ecd0dbdbeaf3b048ce213c2e30dd121a99b Mon Sep 17 00:00:00 2001 From: mister Date: Thu, 20 Feb 2025 14:43:59 +0300 Subject: [PATCH] send figma --- README.md | 122 +----------------- .../work/data/dto/EmployeeDataDto.java | 43 ++++++ .../ru/myitschool/work/data/dto/EntryDto.java | 9 ++ .../work/data/network/api/AdminApi.java | 19 +++ .../work/data/network/api/EmployeeApi.java | 14 +- .../data/repository/LoginRepositoryImpl.java | 4 +- .../work/domain/admin/AdminRepository.java | 18 +++ .../work/domain/admin/AmIAdminUseCase.java | 20 +++ .../admin/GetEmployeeEntryListUseCase.java | 21 +++ .../domain/admin/GetEmployeeInfoUseCase.java | 20 +++ .../domain/admin/IsEmployeeBlockUseCase.java | 19 +++ .../admin/SetBlockConditionUseCase.java | 19 +++ .../work/domain/login/AuthUseCase.java | 4 +- .../work/domain/login/LoginRepository.java | 2 +- .../ru/myitschool/work/ui/RootActivity.kt | 1 - .../work/ui/login/LoginFragment.java | 42 ++++-- .../work/ui/login/LoginViewModel.java | 20 ++- app/src/main/res/drawable/admin_image.xml | 12 ++ app/src/main/res/drawable/login_image.xml | 11 ++ app/src/main/res/drawable/rounded_button.xml | 6 + app/src/main/res/drawable/user_image.xml | 14 ++ app/src/main/res/layout/fragment_admin.xml | 59 +++++++++ app/src/main/res/layout/fragment_employee.xml | 118 ++++++++++++++--- .../res/layout/fragment_info_for_admin.xml | 88 +++++++++++++ app/src/main/res/layout/fragment_login.xml | 53 +++++++- app/src/main/res/layout/fragment_result.xml | 13 +- app/src/main/res/navigation/nav_graph.xml | 1 + app/src/main/res/values/strings.xml | 2 + 28 files changed, 602 insertions(+), 172 deletions(-) create mode 100644 app/src/main/java/ru/myitschool/work/data/dto/EmployeeDataDto.java create mode 100644 app/src/main/java/ru/myitschool/work/data/dto/EntryDto.java create mode 100644 app/src/main/java/ru/myitschool/work/data/network/api/AdminApi.java create mode 100644 app/src/main/java/ru/myitschool/work/domain/admin/AdminRepository.java create mode 100644 app/src/main/java/ru/myitschool/work/domain/admin/AmIAdminUseCase.java create mode 100644 app/src/main/java/ru/myitschool/work/domain/admin/GetEmployeeEntryListUseCase.java create mode 100644 app/src/main/java/ru/myitschool/work/domain/admin/GetEmployeeInfoUseCase.java create mode 100644 app/src/main/java/ru/myitschool/work/domain/admin/IsEmployeeBlockUseCase.java create mode 100644 app/src/main/java/ru/myitschool/work/domain/admin/SetBlockConditionUseCase.java create mode 100644 app/src/main/res/drawable/admin_image.xml create mode 100644 app/src/main/res/drawable/login_image.xml create mode 100644 app/src/main/res/drawable/rounded_button.xml create mode 100644 app/src/main/res/drawable/user_image.xml create mode 100644 app/src/main/res/layout/fragment_admin.xml create mode 100644 app/src/main/res/layout/fragment_info_for_admin.xml diff --git a/README.md b/README.md index 7bbbba0..a0b8a62 100644 --- a/README.md +++ b/README.md @@ -1,121 +1 @@ -[![Android Studio version](https://img.shields.io/endpoint?url=https%3A%2F%2Fsicampus.ru%2Fgitea%2Fcore%2Fdocs%2Fraw%2Fbranch%2Fmain%2Fandroid-studio-label.json)](https://sicampus.ru/gitea/core/docs/src/branch/main/how-upload-project.md) - -# НТО 2024. II отборочный этап. Командные задани — клиентская часть - -## 📖 Предыстория -В компании S контроль доступа в офис осуществляется с помощью СКУД (системы контроля управления доступом). На данный момент у каждого сотрудника компании есть карта-пропуск с NFC меткой. А у каждой входной двери есть считыватель с обеих сторон. При поднесении карты к считывателю, дверь открывается, а информация о времени входа или выхода сотрудника фиксируется в базе данных. -Администрации компании S требуется мобильное приложение, как для рядовых сотрудников, так и для администрации с возможностью просмотра посещений и работой электронного пропуска как временной замены обычного (при помощи сканировании QR кода, который находится на считывателе). Поскольку в приложении есть возможность использовать телефон как пропуск - то к данному приложению повышенные требования к безопасности всех данных, находящихся внутри него. - - - -## 📋 Системные требования - -| **Параметр** | **Требование** | -|-----------------------------|---------------------------------------| -| **Минимальная версия Android** | 9.0 (API 28) | -| **Целевая версия Android** | 14 (API 34) | -| **Поддерживаемые устройства** | смартфоны, планшеты | -| **Ориентация экранов** | портретная | -| **Языки** | русский, английский | -| **Разрешения** | доступ к интернету, камера (при необходимости) | - - - -## 📱 Техническое задание -Требуется разработать нативное мобильное приложение, которое будет содержать следующие экраны. - - -### 1. Экран авторизации - -> Данный экран должен быть показан при первом входе в приложение, а также в ситуациях, когда пользователь не зарегистрировался в приложении. - -#### Элементы, которые должны присутствовать на экране: -- Поле ввода (`id/username`), в котором пользователю необходимо ввести свой логин. -- Кнопка входа (`id/login`), по нажатию на которую пользователь авторизуется в системе. -- По умолчанию скрытое текстовое поле с ошибкой (`id/error`). - -#### Требования к компонентам: -1. В пустом поле ввода должна отображаться подсказка, что требуется ввести пользователю. -2. Если хотя бы одно из условий ниже соблюдено - кнопка должна быть неактивной: - - Поле ввода пустое. - - Количество символов менее 3х. - - Логин начинается с цифры. - - Логин содержит символы, отличные от латинского алфавита и цифр. -3. Поле ввода и кнопку должно быть видно при раскрытии клавиатуры. -4. - При нажатии на кнопку входа необходимо проверить, что данный пользователь существует с помощью запроса `api//auth` (подробное описание представлено в техническом задании серверной части). -5. В случае отсутствия логина или любой другой неполадки - необходимо вывести ошибку, пока пользователь не изменит текстовое поле или повторно не нажмёт на кнопку. -6. После нажатия на кнопку - логин должен быть сохранён и при следующем открытии приложения экран авторизации не должен быть показан. -7. После нажатия на кнопку - при нажатии стрелки назад - экран авторизации не должен быть показан повторно. -8. Экран авторизации показывается только в случае, если пользователь неавторизован. - - - - -### 2. Главный экран - -> Данный экран содержит общую информацию о пользователе: ->- ФИО ->- Фото ->- Должность ->- Время последнего входа - -#### Элементы, которые должны присутствовать на экране: -- Текстовое поле (`id/fullname`), в котором написано имя пользователя. -- Изображение (`id/photo`), на котором отображено фото пользователя. -- Текстовое поле (`id/position`), в котором написана должность пользователя. -- Текстовое поле (`id/lastEntry`), в котором написана дата и время последнего входа пользователя. -- Кнопка (`id/logout`) для выхода пользователя из аккаунта. -- Кнопка (`id/refresh`) для обновления данных. -- Кнопка (`id/scan`) для сканирования QR кода. -- По умолчанию скрытое текстовое поле с ошибкой (`id/error`). - -#### Требования к компонентам: -- В случае любой ошибки необходимо скрыть все элементы, кроме текстового поля с ошибкой и кнопки обновления данных. -- Для получения данных необходимо использовать сетевой запрос `/api//info`. -- Формат даты и времени последнего входа пользователя: `yyyy-MM-dd HH:mm` (например: 2024-02-31 08:31). Время необходимо отображать с сервера, без поправок на часовой пояс или локальное смещение. -- При нажатии на кнопку выход все данные (если есть) пользователя должны быть очищены, а приложение должно открыть экран авторизации. -- При нажатии кнопки сканирования необходимо открыть экран сканирования QR кода. -- При нажатии на кнопку обновления данных - необходимо повторно вызывать сетевой запрос для получения актуальных данных. - - - -### 3. Экран сканирования QR-кода - -> Данный экран позволяет отсканировать код на турникете и войти с помощью смартфона. В данном случае данный экран будет уже написан и представлен dам в готовом виде в заготовке. Вам необходимо только подписаться на его результат с помощью **Result API** и обработать считанные данные из QR кода. **Данный экран нельзя модифицировать. Он поставляется как есть.** - - - -### 4. Экран с результатом сканирования QR кода - -> На данном экране необходимо вывести успешность или неуспешность входа с помощью метода QR кода. - -#### Элементы, которые должны присутствовать на экране: -- Текстовое поле (`id/result`), где содержится текст об успешности или неуспешности входа. -- Кнопка (`id/close`) для закрытия данного экрана. - -#### Требования к компонентам: -- В случае, если результат пришёл пустым или со статусом “Отмена” - необходимо вывести пользователю текст: - *"Вход был отменён/Operation was cancelled"* -- В случае, если данные пришли, то необходимо их отправить на сервер с запросом `api//open`, добавив данные из результата и получить ответ. -- Если сервер ответил успешно - то отображаем текст: - *"Успешно/Success"* -- Если сервер ответил любой ошибкой - то отображаем текст: - *"Что-то пошло не так/Something wrong"* -- Кнопка закрытия всегда открывает главный экран. - - - -## 🛠 Решение - -Необходимо загрузить свое решение в систему [по ссылке](https://innovationcampus.ru/lms/mod/quiz/view.php?id=2149). - -Отметим, что работу необходимо осуществлять в представленных проектах-заготовках (шаблонах). - - - -## ✅ Особенности оценивания - -Оценивание происходит с помощью автоматической системы тестирования, которая в автоматическом режиме находит элементы и взаимодействует с ними (именно для этого у каждого элемента указан уникальный идентификатор, по которому будет производится поиск). Каждый тест происходит с чистой установки приложения. -В случае тестирования сервера на него поочередно отправляются команды, описанные в API и ожидаются определенные корректные ответы. -Сервер и приложение тестируются независимо. - +https://www.figma.com/design/m7vk9KAi8KYr8oPF1lB3Dg/Untitled?node-id=2-263&m=dev&t=CBaQLwRrOyOK2s2Z-1 \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/data/dto/EmployeeDataDto.java b/app/src/main/java/ru/myitschool/work/data/dto/EmployeeDataDto.java new file mode 100644 index 0000000..6758f44 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/data/dto/EmployeeDataDto.java @@ -0,0 +1,43 @@ +package ru.myitschool.work.data.dto; + +import java.time.LocalDateTime; + +public class EmployeeDataDto { + private String name; + private String photo; + private String employeePosition; + + public LocalDateTime getLastVisit() { + return lastVisit; + } + + public void setLastVisit(LocalDateTime lastVisit) { + this.lastVisit = lastVisit; + } + + public String getEmployeePosition() { + return employeePosition; + } + + public void setEmployeePosition(String employeePosition) { + this.employeePosition = employeePosition; + } + + public String getPhoto() { + return photo; + } + + public void setPhoto(String photo) { + this.photo = photo; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + private LocalDateTime lastVisit; +} diff --git a/app/src/main/java/ru/myitschool/work/data/dto/EntryDto.java b/app/src/main/java/ru/myitschool/work/data/dto/EntryDto.java new file mode 100644 index 0000000..ff9936e --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/data/dto/EntryDto.java @@ -0,0 +1,9 @@ +package ru.myitschool.work.data.dto; + +import java.time.LocalDateTime; + +public class EntryDto { + private long codeId; + private LocalDateTime entryTime; + private boolean isCard; +} diff --git a/app/src/main/java/ru/myitschool/work/data/network/api/AdminApi.java b/app/src/main/java/ru/myitschool/work/data/network/api/AdminApi.java new file mode 100644 index 0000000..acc5206 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/data/network/api/AdminApi.java @@ -0,0 +1,19 @@ +package ru.myitschool.work.data.network.api; + +import com.google.android.gms.common.internal.safeparcel.SafeParcelable; + +import retrofit2.Call; +import retrofit2.http.Body; +import retrofit2.http.Header; +import retrofit2.http.POST; +import retrofit2.http.Query; +import ru.myitschool.work.data.dto.Code; +import ru.myitschool.work.data.dto.Employee; + +public interface AdminApi { + @POST("/api/admin/am-i-admin") + Call amIAdmin(@Header("Authorization") String auth); + + @POST("/api/admin/panel/get-employee-info") + Call getEmployeeInfo(@Header("Authorization") String auth, @Query("employee-login") String login); +} diff --git a/app/src/main/java/ru/myitschool/work/data/network/api/EmployeeApi.java b/app/src/main/java/ru/myitschool/work/data/network/api/EmployeeApi.java index 8197a5c..b8f9a07 100644 --- a/app/src/main/java/ru/myitschool/work/data/network/api/EmployeeApi.java +++ b/app/src/main/java/ru/myitschool/work/data/network/api/EmployeeApi.java @@ -3,18 +3,20 @@ package ru.myitschool.work.data.network.api; import retrofit2.Call; import retrofit2.http.Body; import retrofit2.http.GET; +import retrofit2.http.Header; import retrofit2.http.PATCH; +import retrofit2.http.POST; import retrofit2.http.Path; import ru.myitschool.work.data.dto.Code; import ru.myitschool.work.data.dto.Employee; public interface EmployeeApi { - @GET("/api/{login}/auth") - Call auth(@Path("login") String login); + @POST("/api/employee/auth") + Call auth(@Header("Authorization") String auth); - @GET("/api/{login}/info") - Call info(@Path("login") String login); + @POST("/api/employee/info") + Call info(@Header("Authorization") String auth); - @PATCH("/api/{login}/open") - Call open(@Path("login") String login, @Body Code code); + @POST("/api/employee/open") + Call open(@Header("Authorization") String auth, @Body Code code); } diff --git a/app/src/main/java/ru/myitschool/work/data/repository/LoginRepositoryImpl.java b/app/src/main/java/ru/myitschool/work/data/repository/LoginRepositoryImpl.java index 7c1db7c..265ac1a 100644 --- a/app/src/main/java/ru/myitschool/work/data/repository/LoginRepositoryImpl.java +++ b/app/src/main/java/ru/myitschool/work/data/repository/LoginRepositoryImpl.java @@ -26,8 +26,8 @@ public class LoginRepositoryImpl implements LoginRepository { private EmployeeApi employeeApi = RetrofitFactory.getInstance().getEmployeeApi(); @Override - public void auth(@NonNull String login, @NonNull Consumer> callback) { - employeeApi.auth(login).enqueue(new Callback() { + public void auth(@NonNull String auth, @NonNull Consumer> callback) { + employeeApi.auth(auth).enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { callback.accept(new Status<>(response.code(), null, null)); diff --git a/app/src/main/java/ru/myitschool/work/domain/admin/AdminRepository.java b/app/src/main/java/ru/myitschool/work/domain/admin/AdminRepository.java new file mode 100644 index 0000000..00df522 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/domain/admin/AdminRepository.java @@ -0,0 +1,18 @@ +package ru.myitschool.work.domain.admin; + +import androidx.annotation.NonNull; + +import java.util.List; +import java.util.function.Consumer; + +import ru.myitschool.work.data.dto.EmployeeDataDto; +import ru.myitschool.work.data.dto.EntryDto; +import ru.myitschool.work.domain.entities.Status; + +public interface AdminRepository { + void amIAdmin(@NonNull String auth, @NonNull Consumer> callback); + void getEmployeeInfo(@NonNull String auth, @NonNull String login, @NonNull Consumer> callback); + void setBlockCondition(@NonNull String auth, @NonNull String login, @NonNull Boolean condition, @NonNull Consumer> callback); + void getEmployeeEntryList(@NonNull String auth, @NonNull String login, @NonNull Consumer>> callback); + void isEmployeeBlock(@NonNull String auth, @NonNull String login, @NonNull Consumer> callback); +} diff --git a/app/src/main/java/ru/myitschool/work/domain/admin/AmIAdminUseCase.java b/app/src/main/java/ru/myitschool/work/domain/admin/AmIAdminUseCase.java new file mode 100644 index 0000000..ad20fc5 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/domain/admin/AmIAdminUseCase.java @@ -0,0 +1,20 @@ +package ru.myitschool.work.domain.admin; + +import androidx.annotation.NonNull; + +import java.util.function.Consumer; + +import ru.myitschool.work.data.dto.Employee; +import ru.myitschool.work.domain.entities.Status; + +public class AmIAdminUseCase { + private final AdminRepository repository; + + public AmIAdminUseCase(AdminRepository repository) { + this.repository = repository; + } + + public void execute(@NonNull String auth, @NonNull Consumer> callback) { + repository.amIAdmin(auth, callback); + } +} diff --git a/app/src/main/java/ru/myitschool/work/domain/admin/GetEmployeeEntryListUseCase.java b/app/src/main/java/ru/myitschool/work/domain/admin/GetEmployeeEntryListUseCase.java new file mode 100644 index 0000000..8bd84ea --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/domain/admin/GetEmployeeEntryListUseCase.java @@ -0,0 +1,21 @@ +package ru.myitschool.work.domain.admin; + +import androidx.annotation.NonNull; + +import java.util.List; +import java.util.function.Consumer; + +import ru.myitschool.work.data.dto.EntryDto; +import ru.myitschool.work.domain.entities.Status; + +public class GetEmployeeEntryListUseCase { + private final AdminRepository repository; + + public GetEmployeeEntryListUseCase(AdminRepository repository) { + this.repository = repository; + } + + public void execute(@NonNull String auth, @NonNull String login, @NonNull Consumer>> callback) { + repository.getEmployeeEntryList(auth, login, callback); + } +} diff --git a/app/src/main/java/ru/myitschool/work/domain/admin/GetEmployeeInfoUseCase.java b/app/src/main/java/ru/myitschool/work/domain/admin/GetEmployeeInfoUseCase.java new file mode 100644 index 0000000..58681b4 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/domain/admin/GetEmployeeInfoUseCase.java @@ -0,0 +1,20 @@ +package ru.myitschool.work.domain.admin; + +import androidx.annotation.NonNull; + +import java.util.function.Consumer; + +import ru.myitschool.work.data.dto.EmployeeDataDto; +import ru.myitschool.work.domain.entities.Status; + +public class GetEmployeeInfoUseCase { + private final AdminRepository repository; + + public GetEmployeeInfoUseCase(AdminRepository repository) { + this.repository = repository; + } + + public void execute(@NonNull String auth, @NonNull String login, @NonNull Consumer> callback) { + repository.getEmployeeInfo(auth, login, callback); + } +} diff --git a/app/src/main/java/ru/myitschool/work/domain/admin/IsEmployeeBlockUseCase.java b/app/src/main/java/ru/myitschool/work/domain/admin/IsEmployeeBlockUseCase.java new file mode 100644 index 0000000..cef4315 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/domain/admin/IsEmployeeBlockUseCase.java @@ -0,0 +1,19 @@ +package ru.myitschool.work.domain.admin; + +import androidx.annotation.NonNull; + +import java.util.function.Consumer; + +import ru.myitschool.work.domain.entities.Status; + +public class IsEmployeeBlockUseCase { + private final AdminRepository repository; + + public IsEmployeeBlockUseCase(AdminRepository repository) { + this.repository = repository; + } + + public void execute(@NonNull String auth, @NonNull String login, @NonNull Consumer> callback) { + repository.isEmployeeBlock(auth, login, callback); + } +} diff --git a/app/src/main/java/ru/myitschool/work/domain/admin/SetBlockConditionUseCase.java b/app/src/main/java/ru/myitschool/work/domain/admin/SetBlockConditionUseCase.java new file mode 100644 index 0000000..8445a01 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/domain/admin/SetBlockConditionUseCase.java @@ -0,0 +1,19 @@ +package ru.myitschool.work.domain.admin; + +import androidx.annotation.NonNull; + +import java.util.function.Consumer; + +import ru.myitschool.work.domain.entities.Status; + +public class SetBlockConditionUseCase { + private final AdminRepository repository; + + public SetBlockConditionUseCase(AdminRepository repository) { + this.repository = repository; + } + + public void execute(@NonNull String auth, @NonNull String login, @NonNull Boolean condition, @NonNull Consumer> callback) { + repository.setBlockCondition(auth, login, condition, callback); + } +} diff --git a/app/src/main/java/ru/myitschool/work/domain/login/AuthUseCase.java b/app/src/main/java/ru/myitschool/work/domain/login/AuthUseCase.java index 5eac42a..869f2e7 100644 --- a/app/src/main/java/ru/myitschool/work/domain/login/AuthUseCase.java +++ b/app/src/main/java/ru/myitschool/work/domain/login/AuthUseCase.java @@ -13,8 +13,8 @@ public class AuthUseCase { this.repository = repository; } - public void execute(@NonNull String login, @NonNull Consumer> callback) { - repository.auth(login, status -> { + public void execute(@NonNull String auth, @NonNull Consumer> callback) { + repository.auth(auth, status -> { callback.accept(new Status<>( status.getStatusCode(), (status.getStatusCode() == 200 || status.getStatusCode() == 401) ? status.getStatusCode() == 200 : null, diff --git a/app/src/main/java/ru/myitschool/work/domain/login/LoginRepository.java b/app/src/main/java/ru/myitschool/work/domain/login/LoginRepository.java index de09f3b..77a9763 100644 --- a/app/src/main/java/ru/myitschool/work/domain/login/LoginRepository.java +++ b/app/src/main/java/ru/myitschool/work/domain/login/LoginRepository.java @@ -7,5 +7,5 @@ import java.util.function.Consumer; import ru.myitschool.work.domain.entities.Status; public interface LoginRepository { - void auth(@NonNull String login, @NonNull Consumer> callback); + void auth(@NonNull String auth, @NonNull Consumer> callback); } 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 51115f5..750f680 100644 --- a/app/src/main/java/ru/myitschool/work/ui/RootActivity.kt +++ b/app/src/main/java/ru/myitschool/work/ui/RootActivity.kt @@ -5,7 +5,6 @@ import androidx.appcompat.app.AppCompatActivity import dagger.hilt.android.AndroidEntryPoint import ru.myitschool.work.R -// НЕ ИЗМЕНЯЙТЕ НАЗВАНИЕ КЛАССА! @AndroidEntryPoint class RootActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/ru/myitschool/work/ui/login/LoginFragment.java b/app/src/main/java/ru/myitschool/work/ui/login/LoginFragment.java index 6a81498..717cd2b 100644 --- a/app/src/main/java/ru/myitschool/work/ui/login/LoginFragment.java +++ b/app/src/main/java/ru/myitschool/work/ui/login/LoginFragment.java @@ -1,10 +1,12 @@ package ru.myitschool.work.ui.login; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; +import android.util.Base64; import android.view.View; import androidx.annotation.NonNull; @@ -14,14 +16,19 @@ import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; import androidx.navigation.Navigation; +import java.nio.charset.StandardCharsets; + import ru.myitschool.work.R; import ru.myitschool.work.databinding.FragmentLoginBinding; +import ru.myitschool.work.ui.employee.EmployeeFragment; public class LoginFragment extends Fragment { private static final String SHARED_PREFERENCES_LOGIN_PREFERENCES = "l01"; private static final String SHARED_PREFERENCES_LOGIN_STRING = "l02"; + private String log = "", pas = ""; + private FragmentLoginBinding binding; private LoginViewModel viewModel; @@ -42,34 +49,51 @@ public class LoginFragment extends Fragment { } binding = FragmentLoginBinding.bind(view); + viewModel = new ViewModelProvider(this).get(LoginViewModel.class); binding.username.addTextChangedListener(new TextWatcher() { @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } + public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) { - viewModel.onChangeLogin(s.toString()); + log = s.toString(); + viewModel.onChangeLoginPassword(log, pas); binding.error.setVisibility(View.GONE); } }); + binding.password.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + pas = s.toString(); + viewModel.onChangeLoginPassword(log, pas); + binding.error.setVisibility(View.GONE); + } + }); + binding.login.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - viewModel.startQuery(); + binding.username.setText(""); + binding.password.setText(""); + Navigation.findNavController(getView()).navigate( + R.id.action_login_fragment_to_employee_fragment + ); binding.error.setVisibility(View.GONE); } }); subscribe(viewModel); - viewModel.onChangeLogin(binding.username.toString()); + viewModel.onChangeLoginPassword(binding.username.toString(), binding.password.toString()); } @@ -87,7 +111,7 @@ public class LoginFragment extends Fragment { if (s.equals("Correct Login")) { SharedPreferences sharedPreferences = getContext().getSharedPreferences(SHARED_PREFERENCES_LOGIN_PREFERENCES, Context.MODE_PRIVATE); sharedPreferences.edit() - .putString(SHARED_PREFERENCES_LOGIN_STRING, binding.username.getText().toString()) + .putString(SHARED_PREFERENCES_LOGIN_STRING, "Basic " + Base64.encodeToString((binding.username.toString() + ":" + binding.password.toString()).getBytes(StandardCharsets.UTF_8), Base64.DEFAULT)) .apply(); Navigation.findNavController(getView()).navigate( diff --git a/app/src/main/java/ru/myitschool/work/ui/login/LoginViewModel.java b/app/src/main/java/ru/myitschool/work/ui/login/LoginViewModel.java index 5c18f1b..54e7e20 100644 --- a/app/src/main/java/ru/myitschool/work/ui/login/LoginViewModel.java +++ b/app/src/main/java/ru/myitschool/work/ui/login/LoginViewModel.java @@ -1,9 +1,15 @@ package ru.myitschool.work.ui.login; +import android.util.Base64; + import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; +import androidx.navigation.Navigation; +import java.nio.charset.StandardCharsets; + +import ru.myitschool.work.R; import ru.myitschool.work.data.repository.LoginRepositoryImpl; import ru.myitschool.work.domain.login.AuthUseCase; @@ -20,14 +26,16 @@ public class LoginViewModel extends ViewModel { private String login; + private String password; - public void onChangeLogin(String login) { + public void onChangeLoginPassword(String login, String password) { this.login = login; - onChangeButtonState(login); + this.password = password; + onChangeButtonState(login, password); } - private void onChangeButtonState(String login) { - if (login.length() >= 3 && !Character.isDigit(login.charAt(0)) && login.matches("^[a-zA-Z0-9]*$")) { + private void onChangeButtonState(String login, String password) { + if (login.length() >= 3 && !Character.isDigit(login.charAt(0)) && login.matches("^[a-zA-Z0-9]*$") && password.length() >= 3) { mutableButtonStateLiveData.postValue(true); } else { mutableButtonStateLiveData.postValue(false); @@ -35,8 +43,8 @@ public class LoginViewModel extends ViewModel { } public void startQuery() { - final String currentLogin = login; - authUseCase.execute(currentLogin, status -> { + final String currentLogin = login, currentPassword = password; + authUseCase.execute("Basic " + Base64.encodeToString((currentLogin + ":" + currentPassword).getBytes(StandardCharsets.UTF_8), Base64.DEFAULT), status -> { if (status.getStatusCode() == 200) { mutableLoginStateLiveData.postValue("Correct Login"); } else /*(status.getStatusCode() == 401) */ { diff --git a/app/src/main/res/drawable/admin_image.xml b/app/src/main/res/drawable/admin_image.xml new file mode 100644 index 0000000..00ec8f5 --- /dev/null +++ b/app/src/main/res/drawable/admin_image.xml @@ -0,0 +1,12 @@ + + + diff --git a/app/src/main/res/drawable/login_image.xml b/app/src/main/res/drawable/login_image.xml new file mode 100644 index 0000000..4e25a54 --- /dev/null +++ b/app/src/main/res/drawable/login_image.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable/rounded_button.xml b/app/src/main/res/drawable/rounded_button.xml new file mode 100644 index 0000000..4f5b4ba --- /dev/null +++ b/app/src/main/res/drawable/rounded_button.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/user_image.xml b/app/src/main/res/drawable/user_image.xml new file mode 100644 index 0000000..0f13d13 --- /dev/null +++ b/app/src/main/res/drawable/user_image.xml @@ -0,0 +1,14 @@ + + + + diff --git a/app/src/main/res/layout/fragment_admin.xml b/app/src/main/res/layout/fragment_admin.xml new file mode 100644 index 0000000..94951ac --- /dev/null +++ b/app/src/main/res/layout/fragment_admin.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + +