send figma
This commit is contained in:
parent
6b2538c7f8
commit
2c4c6ecd0d
122
README.md
122
README.md
@ -1,121 +1 @@
|
||||
[](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/<LOGIN>/auth` (подробное описание представлено в техническом задании серверной части).
|
||||
5. В случае отсутствия логина или любой другой неполадки - необходимо вывести ошибку, пока пользователь не изменит текстовое поле или повторно не нажмёт на кнопку.
|
||||
6. После нажатия на кнопку - логин должен быть сохранён и при следующем открытии приложения экран авторизации не должен быть показан.
|
||||
7. После нажатия на кнопку - при нажатии стрелки назад - экран авторизации не должен быть показан повторно.
|
||||
8. Экран авторизации показывается только в случае, если пользователь неавторизован.
|
||||
|
||||
|
||||
|
||||
|
||||
### 2. Главный экран
|
||||
|
||||
> Данный экран содержит общую информацию о пользователе:
|
||||
>- ФИО
|
||||
>- Фото
|
||||
>- Должность
|
||||
>- Время последнего входа
|
||||
|
||||
#### Элементы, которые должны присутствовать на экране:
|
||||
- Текстовое поле (`id/fullname`), в котором написано имя пользователя.
|
||||
- Изображение (`id/photo`), на котором отображено фото пользователя.
|
||||
- Текстовое поле (`id/position`), в котором написана должность пользователя.
|
||||
- Текстовое поле (`id/lastEntry`), в котором написана дата и время последнего входа пользователя.
|
||||
- Кнопка (`id/logout`) для выхода пользователя из аккаунта.
|
||||
- Кнопка (`id/refresh`) для обновления данных.
|
||||
- Кнопка (`id/scan`) для сканирования QR кода.
|
||||
- По умолчанию скрытое текстовое поле с ошибкой (`id/error`).
|
||||
|
||||
#### Требования к компонентам:
|
||||
- В случае любой ошибки необходимо скрыть все элементы, кроме текстового поля с ошибкой и кнопки обновления данных.
|
||||
- Для получения данных необходимо использовать сетевой запрос `/api/<LOGIN>/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/<LOGIN>/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
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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<Void> amIAdmin(@Header("Authorization") String auth);
|
||||
|
||||
@POST("/api/admin/panel/get-employee-info")
|
||||
Call<Void> getEmployeeInfo(@Header("Authorization") String auth, @Query("employee-login") String login);
|
||||
}
|
@ -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<Void> auth(@Path("login") String login);
|
||||
@POST("/api/employee/auth")
|
||||
Call<Void> auth(@Header("Authorization") String auth);
|
||||
|
||||
@GET("/api/{login}/info")
|
||||
Call<Employee> info(@Path("login") String login);
|
||||
@POST("/api/employee/info")
|
||||
Call<Employee> info(@Header("Authorization") String auth);
|
||||
|
||||
@PATCH("/api/{login}/open")
|
||||
Call<Void> open(@Path("login") String login, @Body Code code);
|
||||
@POST("/api/employee/open")
|
||||
Call<Void> open(@Header("Authorization") String auth, @Body Code code);
|
||||
}
|
||||
|
@ -26,8 +26,8 @@ public class LoginRepositoryImpl implements LoginRepository {
|
||||
private EmployeeApi employeeApi = RetrofitFactory.getInstance().getEmployeeApi();
|
||||
|
||||
@Override
|
||||
public void auth(@NonNull String login, @NonNull Consumer<Status<Void>> callback) {
|
||||
employeeApi.auth(login).enqueue(new Callback<Void>() {
|
||||
public void auth(@NonNull String auth, @NonNull Consumer<Status<Void>> callback) {
|
||||
employeeApi.auth(auth).enqueue(new Callback<Void>() {
|
||||
@Override
|
||||
public void onResponse(Call<Void> call, Response<Void> response) {
|
||||
callback.accept(new Status<>(response.code(), null, null));
|
||||
|
@ -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<Status<Void>> callback);
|
||||
void getEmployeeInfo(@NonNull String auth, @NonNull String login, @NonNull Consumer<Status<EmployeeDataDto>> callback);
|
||||
void setBlockCondition(@NonNull String auth, @NonNull String login, @NonNull Boolean condition, @NonNull Consumer<Status<Void>> callback);
|
||||
void getEmployeeEntryList(@NonNull String auth, @NonNull String login, @NonNull Consumer<Status<List<EntryDto>>> callback);
|
||||
void isEmployeeBlock(@NonNull String auth, @NonNull String login, @NonNull Consumer<Status<Boolean>> callback);
|
||||
}
|
@ -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<Status<Void>> callback) {
|
||||
repository.amIAdmin(auth, callback);
|
||||
}
|
||||
}
|
@ -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<Status<List<EntryDto>>> callback) {
|
||||
repository.getEmployeeEntryList(auth, login, callback);
|
||||
}
|
||||
}
|
@ -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<Status<EmployeeDataDto>> callback) {
|
||||
repository.getEmployeeInfo(auth, login, callback);
|
||||
}
|
||||
}
|
@ -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<Status<Boolean>> callback) {
|
||||
repository.isEmployeeBlock(auth, login, callback);
|
||||
}
|
||||
}
|
@ -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<Status<Void>> callback) {
|
||||
repository.setBlockCondition(auth, login, condition, callback);
|
||||
}
|
||||
}
|
@ -13,8 +13,8 @@ public class AuthUseCase {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public void execute(@NonNull String login, @NonNull Consumer<Status<Boolean>> callback) {
|
||||
repository.auth(login, status -> {
|
||||
public void execute(@NonNull String auth, @NonNull Consumer<Status<Boolean>> callback) {
|
||||
repository.auth(auth, status -> {
|
||||
callback.accept(new Status<>(
|
||||
status.getStatusCode(),
|
||||
(status.getStatusCode() == 200 || status.getStatusCode() == 401) ? status.getStatusCode() == 200 : null,
|
||||
|
@ -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<Status<Void>> callback);
|
||||
void auth(@NonNull String auth, @NonNull Consumer<Status<Void>> callback);
|
||||
}
|
||||
|
@ -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?) {
|
||||
|
@ -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(
|
||||
|
@ -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) */ {
|
||||
|
12
app/src/main/res/drawable/admin_image.xml
Normal file
12
app/src/main/res/drawable/admin_image.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1920"
|
||||
android:viewportHeight="1920"
|
||||
android:tint="#03A9F4"
|
||||
android:alpha="0.8">
|
||||
<path
|
||||
android:pathData="M276.9,440.6v565.7c0,422.4 374.2,625.5 674.7,788.7l8,4.3 8.1,-4.3c300.5,-163.2 674.7,-366.3 674.7,-788.7L1642.5,440.6l-682.8,-321.7L276.9,440.6ZM959.7,1920.1c-9.3,0 -18.5,-2.4 -27,-6.9l-34.9,-19C588.1,1726.1 164,1495.9 164,1006.3L164,404.8c0,-21.9 12.6,-41.8 32.4,-51.2L935.7,5.4c15.1,-7.2 32.9,-7.2 48,0l739.3,348.2c19.8,9.4 32.4,29.3 32.4,51.2v601.5c0,489.6 -424.2,719.8 -733.8,887.9l-34.9,19c-8.5,4.5 -17.7,6.9 -27.1,6.9ZM1426.8,1372.5h-313.4l-91.6,-91.5v-83.8L905,1197.2v-116.8h-83.7l-58.5,-58.5c-1.9,0.1 -3.8,0.1 -5.8,0.1 -176.1,0 -319.3,-143.2 -319.3,-319.3 0,-176.1 143.2,-319.4 319.3,-319.4 176.1,0 319.3,143.3 319.3,319.4 0,1.9 0,3.8 -0.1,5.6l350.6,350.7v313.4ZM1160.2,1259.5h153.7v-153.7L958.5,750.2l4,-37.3c1,-123.9 -91.6,-216.6 -205.3,-216.6S550.7,589 550.7,702.7c0,113.8 92.6,206.3 206.3,206.3l47.2,-5.3 63.8,63.7h149.9v116.8h116.8v150l25.4,25.3ZM846.8,706c0,46.8 -37.9,84.7 -84.7,84.7 -46.8,0 -84.7,-37.9 -84.7,-84.7s37.9,-84.7 84.7,-84.7c46.8,0 84.7,37.9 84.7,84.7"
|
||||
android:fillColor="#000000"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
11
app/src/main/res/drawable/login_image.xml
Normal file
11
app/src/main/res/drawable/login_image.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="273.5"
|
||||
android:viewportHeight="273.5"
|
||||
android:tint="#03A9F4"
|
||||
android:alpha="0.8">
|
||||
<path
|
||||
android:pathData="M99.43,128.2v17.1c0,2.3 -1.87,4.17 -4.17,4.17h-5.25c-2.3,0 -4.17,-1.87 -4.17,-4.17v-17.1c0,-2.3 1.87,-4.17 4.17,-4.17h5.25C97.56,124.04 99.43,125.9 99.43,128.2zM273.5,109.13v55.25c0,11.79 -9.59,21.38 -21.38,21.38H21.38C9.59,185.75 0,176.16 0,164.38v-55.25C0,97.34 9.59,87.75 21.38,87.75h230.75C263.91,87.75 273.5,97.34 273.5,109.13zM68.16,156.96c0,-4.14 -3.36,-7.5 -7.5,-7.5H42.43v-32.93c0,-4.14 -3.36,-7.5 -7.5,-7.5s-7.5,3.36 -7.5,7.5v40.43c0,4.14 3.36,7.5 7.5,7.5h25.73C64.8,164.46 68.16,161.11 68.16,156.96zM114.43,128.2c0,-10.57 -8.6,-19.17 -19.17,-19.17h-5.25c-10.57,0 -19.17,8.6 -19.17,19.17v17.1c0,10.57 8.6,19.17 19.17,19.17h5.25c10.57,0 19.17,-8.6 19.17,-19.17V128.2zM165.45,145.3c0,-4.14 -3.36,-7.5 -7.5,-7.5h-6.82c-4.14,0 -7.5,3.36 -7.5,7.5c0,1.54 0.47,2.97 1.26,4.17h-3.86c-2.3,0 -4.17,-1.87 -4.17,-4.17v-17.1c0,-2.3 1.87,-4.17 4.17,-4.17h5.25c1.3,0 2.22,0.56 2.75,1.04c3.11,2.74 7.84,2.45 10.59,-0.66c2.74,-3.11 2.45,-7.84 -0.66,-10.59c-3.5,-3.09 -8.01,-4.79 -12.68,-4.79h-5.25c-10.57,0 -19.17,8.6 -19.17,19.17v17.1c0,10.57 8.6,19.17 19.17,19.17h5.25C156.85,164.46 165.45,155.87 165.45,145.3zM187.68,116.54c0,-4.14 -3.36,-7.5 -7.5,-7.5s-7.5,3.36 -7.5,7.5v40.43c0,4.14 3.36,7.5 7.5,7.5s7.5,-3.36 7.5,-7.5V116.54zM243.43,116.54c0,-4.14 -3.36,-7.5 -7.5,-7.5s-7.5,3.36 -7.5,7.5v18.6l-18.08,-23.21c-1.97,-2.53 -5.32,-3.53 -8.35,-2.48c-3.03,1.04 -5.06,3.89 -5.06,7.09v40.43c0,4.14 3.36,7.5 7.5,7.5s7.5,-3.36 7.5,-7.5v-18.6l18.08,23.21c1.45,1.86 3.65,2.89 5.92,2.89c0.81,0 1.64,-0.13 2.44,-0.41c3.03,-1.04 5.06,-3.89 5.06,-7.09V116.54z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
6
app/src/main/res/drawable/rounded_button.xml
Normal file
6
app/src/main/res/drawable/rounded_button.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="16dp" />
|
||||
<solid android:color="#03A9F4" />
|
||||
</shape>
|
14
app/src/main/res/drawable/user_image.xml
Normal file
14
app/src/main/res/drawable/user_image.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="32"
|
||||
android:viewportHeight="32"
|
||||
android:tint="#03A9F4"
|
||||
android:alpha="0.8">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M16,14c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7s7,3.14 7,7S19.86,14 16,14zM16,2c-2.757,0 -5,2.243 -5,5s2.243,5 5,5s5,-2.243 5,-5S18.757,2 16,2z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M23.942,32H8.058C5.82,32 4,30.18 4,27.942c0,-6.617 5.383,-12 12,-12s12,5.383 12,12C28,30.18 26.18,32 23.942,32zM16,17.942c-5.514,0 -10,4.486 -10,10C6,29.077 6.923,30 8.058,30h15.885C25.077,30 26,29.077 26,27.942C26,22.428 21.514,17.942 16,17.942z"/>
|
||||
</vector>
|
59
app/src/main/res/layout/fragment_admin.xml
Normal file
59
app/src/main/res/layout/fragment_admin.xml
Normal file
@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_marginTop="100dp"
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="250dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="50dp"
|
||||
android:src="@drawable/admin_image"/>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/employee_login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@color/white"
|
||||
|
||||
android:hint="Еnter the employee's username" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/view_employee_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/rounded_button"
|
||||
android:text="Viewing employee information"
|
||||
android:textColor="#FFFFFF"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/error"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@android:color/holo_red_dark"
|
||||
android:textStyle="bold"
|
||||
android:text="Error"
|
||||
android:visibility="invisible"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
</LinearLayout>
|
@ -11,48 +11,134 @@
|
||||
android:id="@+id/fullname"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="fullname" />
|
||||
android:layout_marginBottom="8dp"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
tools:text="Full Name" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/photo"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="200dp" />
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="250dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:src="@drawable/user_image"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/position"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="position" />
|
||||
android:textSize="18sp"
|
||||
tools:text="Position"
|
||||
android:textColor="@color/black"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginBottom="4dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/lastEntry"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="lastEntry" />
|
||||
android:textSize="16sp"
|
||||
tools:text="Last Entry"
|
||||
android:textColor="@color/black"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/isLog"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/black"
|
||||
tools:text="Is Log"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginBottom="1dp"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:clipToPadding="true"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:paddingBottom="16dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/isAdmin"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/black"
|
||||
tools:text="Is Admin"
|
||||
android:visibility="invisible"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginBottom="1dp"/>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/error"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
tools:text="error" />
|
||||
android:textColor="@android:color/holo_red_dark"
|
||||
android:textStyle="bold"
|
||||
tools:text="Error"
|
||||
android:visibility="invisible"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/admin_panel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/rounded_button"
|
||||
android:text="Admin Panel"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:visibility="invisible"
|
||||
android:textColor="#FFFFFF" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/logout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="logout" />
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/rounded_button"
|
||||
android:text="Logout"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:textColor="#FFFFFF" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/refresh"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="refresh" />
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/rounded_button"
|
||||
android:text="Refresh"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:textColor="#FFFFFF" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/scan"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="scan" />
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/rounded_button"
|
||||
android:text="Scan"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:textColor="#FFFFFF" />
|
||||
|
||||
</LinearLayout>
|
88
app/src/main/res/layout/fragment_info_for_admin.xml
Normal file
88
app/src/main/res/layout/fragment_info_for_admin.xml
Normal file
@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/employee_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:text="Full Name" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/employee_photo"
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="250dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:src="@drawable/user_image"/>
|
||||
<TextView
|
||||
android:id="@+id/position"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="18sp"
|
||||
android:text="Position"
|
||||
android:textColor="@color/black"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginBottom="4dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/lastEntry"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="16sp"
|
||||
android:text="Last Entry"
|
||||
android:textColor="@color/black"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/error"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@android:color/holo_red_dark"
|
||||
android:textStyle="bold"
|
||||
android:text="Error"
|
||||
android:visibility="invisible"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginBottom="200dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/block_pass"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/rounded_button"
|
||||
android:text="Block pass"
|
||||
android:textColor="#FFFFFF"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/unlock_pass"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/rounded_button"
|
||||
android:text="Unlock pass"
|
||||
android:textColor="#FFFFFF" />
|
||||
|
||||
|
||||
</LinearLayout>
|
@ -5,22 +5,65 @@
|
||||
android:orientation="vertical"
|
||||
android:padding="20dp">
|
||||
|
||||
<EditText
|
||||
<ImageView
|
||||
android:layout_marginTop="100dp"
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="250dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="50dp"
|
||||
android:src="@drawable/login_image"/>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="40dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="hint" />
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@color/white"
|
||||
android:hint="Enter your username" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@color/white"
|
||||
android:hint="Enter your password" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="login" />
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/rounded_button"
|
||||
android:text="Login"
|
||||
android:textColor="#FFFFFF" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/error"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
@ -9,12 +9,19 @@
|
||||
android:id="@+id/result"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="400dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="result" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/close"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="close" />
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/rounded_button"
|
||||
android:text="Close"
|
||||
android:textColor="#FFFFFF" />
|
||||
|
||||
</LinearLayout>
|
@ -1,6 +1,7 @@
|
||||
<?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/nav_graph.xml"
|
||||
app:startDestination="@id/login_fragment">
|
||||
|
||||
|
@ -3,4 +3,6 @@
|
||||
<string name="operation_was_cancelled">Operation was cancelled</string>
|
||||
<string name="success">Success</string>
|
||||
<string name="something_wrong">Something wrong</string>
|
||||
<!-- TODO: Remove or change this placeholder text -->
|
||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||
</resources>
|
Loading…
x
Reference in New Issue
Block a user