Merge remote-tracking branch 'origin/main'

# Conflicts:
#	app/src/main/res/layout/fragment_profile.xml
This commit is contained in:
SunZar 2025-02-20 16:56:19 +03:00
commit 116eb2f04b
9 changed files with 106 additions and 156 deletions

@ -2,6 +2,11 @@
# НТО 2024. II отборочный этап. Командные задани — клиентская часть
## Визуализация дизайна приложения в Figma
- https://www.figma.com/design/JEGV0KLTYC3925JlsQds06/Pass-sistem?node-id=0-1&p=f&t=dDFutSZxZRnxQmEy-0
## 📖 Предыстория
В компании S контроль доступа в офис осуществляется с помощью СКУД (системы контроля управления доступом). На данный момент у каждого сотрудника компании есть карта-пропуск с NFC меткой. А у каждой входной двери есть считыватель с обеих сторон. При поднесении карты к считывателю, дверь открывается, а информация о времени входа или выхода сотрудника фиксируется в базе данных.
Администрации компании S требуется мобильное приложение, как для рядовых сотрудников, так и для администрации с возможностью просмотра посещений и работой электронного пропуска как временной замены обычного (при помощи сканировании QR кода, который находится на считывателе). Поскольку в приложении есть возможность использовать телефон как пропуск - то к данному приложению повышенные требования к безопасности всех данных, находящихся внутри него.

@ -34,6 +34,7 @@ public class LoginFragment extends Fragment {
private FragmentLoginBinding binding;
private PreferenceManager preferenceManager;
private LoginViewModel viewModel;
@Nullable
@ -47,10 +48,9 @@ public class LoginFragment extends Fragment {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//binding.log.setText("created");
preferenceManager = new PreferenceManager(this.getContext());
viewModel = new ViewModelProvider(this).get(LoginViewModel.class);
//sharedPreferences.edit().putString(ru.myitschool.work.ui.Constants.KEY_LOGIN, "5user").apply();
binding.login.setEnabled(false);
binding.username.addTextChangedListener(new OnChangeText() {
@ -58,7 +58,7 @@ public class LoginFragment extends Fragment {
public void afterTextChanged(Editable s) {
super.afterTextChanged(s);
viewModel.changeUsername(s.toString());
if (binding.username.getText().length() >= 3 && binding.username.getText().toString().matches("[0-9a-zA-Z]+") && (binding.username.getText().toString().charAt(0) + "").matches("[0-9]+")) {
if (binding.password.getText().length() >= 5 && binding.username.getText().length() >= 3 && binding.username.getText().toString().matches("[0-9a-zA-Z]+") && (binding.username.getText().toString().charAt(0) + "").matches("[0-9]+")) {
binding.login.setEnabled(true);
} else {
binding.login.setEnabled(false);
@ -69,32 +69,7 @@ public class LoginFragment extends Fragment {
}
});
binding.username.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (binding.username.getText().length() >= 3 && binding.username.getText().toString().matches("[0-9a-zA-Z]+") && (binding.username.getText().toString().charAt(0) + "").matches("[0-9]+")) {
binding.login.setEnabled(true);
//binding.log.setText("changed true");
} else {
binding.login.setEnabled(false);
//binding.log.setText("changed false");
}
//Log.d("tagg", "changed");
if (binding.error.getVisibility() == View.VISIBLE) {
binding.error.setVisibility(View.GONE);
}
}
@Override
public void afterTextChanged(Editable editable) {
}
});
binding.password.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
@ -104,7 +79,7 @@ public class LoginFragment extends Fragment {
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
viewModel.changePassword(charSequence.toString());
if (binding.password.getText().length() >= 5) {
if (binding.password.getText().length() >= 5 && binding.username.getText().length() >= 3 && binding.username.getText().toString().matches("[0-9a-zA-Z]+") && (binding.username.getText().toString().charAt(0) + "").matches("[0-9]+")) {
binding.login.setEnabled(true);
} else {
binding.login.setEnabled(false);
@ -122,66 +97,19 @@ public class LoginFragment extends Fragment {
binding.login.setOnClickListener(view1 -> {
viewModel.confirm();
/*if (binding.login.isEnabled()) {
if (binding.error.getVisibility() == View.VISIBLE) {
binding.error.setVisibility(View.GONE);
//binding.log.setText("click enabled");
}
//binding.log.setText("click");
onClickLogin(view);
}*/
});
subscribe(viewModel);
}
/*private void onClickLogin(View view) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.SERVER_ADDRESS)
.addConverterFactory(GsonConverterFactory.create())
.build();
StoreAPI storeApi = retrofit.create(StoreAPI.class);
String login = binding.username.getText().toString();
Call<Boolean> call = storeApi.authenticateUser(login);
call.enqueue(new Callback<Boolean>() {
@Override
public void onResponse(Call<Boolean> call, Response<Boolean> response) {
if (response.isSuccessful()) {
if (response.body() != null && response.body()) {
preferenceManager.putString(ru.myitschool.work.utils.Constants.KEY_LOGIN, binding.username.getText().toString());
Navigation.findNavController(view).navigate(R.id.action_loginFragment_to_informationFragment);
//getFragmentManager().beginTransaction().replace(R.id.nav_host_fragment, new InformationFragment()).commit();
} else {
binding.error.setVisibility(View.VISIBLE);
}
} else if (response.code() == 401) {
binding.error.setVisibility(View.VISIBLE);
} else if (response.code() == 400) {
binding.error.setVisibility(View.VISIBLE);
} else {
binding.error.setVisibility(View.VISIBLE);
}
}
@Override
public void onFailure(Call<Boolean> call, Throwable t) {
binding.error.setVisibility(View.VISIBLE);
}
});
}*/
private void subscribe(LoginViewModel viewModel) {
viewModel.errorLiveData.observe(getViewLifecycleOwner(), error -> {
//Toast.makeText(getContext(), error, Toast.LENGTH_SHORT).show();
});
/*viewModel.stateLiveData.observe(getViewLifecycleOwner(), state -> {
binding.confirm.setText(state.getButton());
binding.title.setText(state.getTitle());
binding.password.setVisibility(Utils.visibleOrGone(state.isPasswordEnabled()));
});*/
viewModel.openListLiveData.observe(getViewLifecycleOwner(), username -> {
final View view = getView();
//Toast.makeText(getContext(), "FFFFFFFFF", Toast.LENGTH_SHORT).show();

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
</selector>

Binary file not shown.

After

(image error) Size: 18 KiB

@ -5,11 +5,21 @@
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools">
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/iconmain"
app:layout_constraintEnd_toEndOf="@id/root_fragment"
app:layout_constraintHorizontal_bias="0.17"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<fragment
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/nav_view"
app:layout_constraintTop_toBottomOf="@id/image"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:id="@+id/root_fragment"
android:layout_width="match_parent"
android:layout_height="0dp"

@ -11,77 +11,40 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/fullname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<ImageView
android:id="@+id/photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/fullname"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
android:id="@+id/position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/photo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
android:id="@+id/lastEntry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/position"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/logout"
android:text="@string/logout"
<ScrollView
android:id="@+id/scrollView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/lastEntry"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
app:layout_constraintTop_toTopOf="parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/historylist"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/error"
tools:listitem="@layout/item_history" />
</ScrollView>
<TextView
android:id="@+id/error"
android:visibility="gone"
android:text="@string/error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/logout"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/error"
app:layout_constraintStart_toStartOf="parent"
android:text="@string/error"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="@+id/scrollView2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="@+id/historylist"
tools:listitem="@layout/item_history"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toBottomOf="@id/error"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</ScrollView>
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -9,7 +9,8 @@
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/username"/>
android:hint="@string/username" />
<EditText
android:id="@+id/password"

@ -3,41 +3,79 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/photo"
android:text="Профиль"
android:textStyle="bold"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textSize="40sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/username"
app:layout_constraintTop_toTopOf="parent"/>
app:layout_constraintTop_toTopOf="parent"
android:id="@+id/text"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Логин"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:textSize="15sp"
android:id="@+id/text1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/username"
app:layout_constraintTop_toBottomOf="@id/photo"
app:layout_constraintTop_toBottomOf="@id/text1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/name"
android:text="ФИО"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/username"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
app:layout_constraintEnd_toEndOf="parent"
android:textSize="15sp"
android:id="@+id/text2"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/position"
app:layout_constraintTop_toBottomOf="@id/name"
app:layout_constraintTop_toBottomOf="@id/text2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Должность"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/position"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:textSize="15sp"
android:id="@+id/text3"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/lastTime"
app:layout_constraintTop_toBottomOf="@id/text3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/exit"
android:text="выход"
app:layout_constraintTop_toBottomOf="@id/position"
app:layout_constraintTop_toBottomOf="@id/lastTime"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>

@ -2,6 +2,7 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
@ -13,7 +14,7 @@
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_width="140dp"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textSize="16sp"
@ -37,7 +38,7 @@
app:layout_constraintTop_toBottomOf="@id/layout_time">
<TextView
android:layout_width="wrap_content"
android:layout_width="140dp"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textSize="16sp"
@ -61,7 +62,7 @@
app:layout_constraintTop_toBottomOf="@id/layout_code">
<TextView
android:layout_width="wrap_content"
android:layout_width="140dp"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textSize="16sp"