From 59cb935fed839c48850922db2149fc11aeb6bc68 Mon Sep 17 00:00:00 2001 From: Marten Rebane <54431068+martenrebane@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:50:06 +0300 Subject: [PATCH 1/2] Added invisible element --- .../crypto/create/CryptoCreateScreen.java | 9 +++- .../crypto/create/CryptoRecipientsScreen.java | 10 +++- .../DigiDoc/android/eid/CodeUpdateView.java | 5 +- .../android/main/about/AboutAdapter.java | 8 ++- .../main/accessibility/AccessibilityView.java | 9 +++- .../main/diagnostics/DiagnosticsView.java | 7 ++- .../android/main/home/HomeMenuView.java | 5 +- .../DigiDoc/android/main/home/HomeView.java | 9 +++- .../android/main/settings/SettingsView.java | 5 +- .../signature/create/SignatureCreateView.java | 5 +- .../detail/CertificateDetailView.java | 5 +- .../signature/detail/SignatureDetailView.java | 5 +- .../SignatureUpdateSignatureAddDialog.java | 9 +++- .../signature/update/SignatureUpdateView.java | 9 +++- .../ria/DigiDoc/android/utils/TextUtil.java | 21 ++++++++ .../ria/DigiDoc/android/utils/ViewUtil.java | 51 +++++++++++++++++++ .../android/utils/navigator/ContentView.java | 31 +++++++++++ .../utils/widget/ConfirmationDialog.java | 3 +- .../main/res/layout/signature_list_screen.xml | 5 ++ app/src/main/res/values/donottranslate.xml | 3 ++ app/src/main/res/values/ids.xml | 1 + 21 files changed, 200 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/ee/ria/DigiDoc/android/utils/ViewUtil.java create mode 100644 app/src/main/java/ee/ria/DigiDoc/android/utils/navigator/ContentView.java diff --git a/app/src/main/java/ee/ria/DigiDoc/android/crypto/create/CryptoCreateScreen.java b/app/src/main/java/ee/ria/DigiDoc/android/crypto/create/CryptoCreateScreen.java index 728c1f69f..f1ccfdf9a 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/crypto/create/CryptoCreateScreen.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/crypto/create/CryptoCreateScreen.java @@ -7,6 +7,7 @@ import static ee.ria.DigiDoc.android.utils.BundleUtils.putFile; import static ee.ria.DigiDoc.android.utils.Predicates.duplicates; import static ee.ria.DigiDoc.android.utils.TintUtils.tintCompoundDrawables; +import static ee.ria.DigiDoc.android.utils.ViewUtil.moveView; import static ee.ria.DigiDoc.android.utils.rxbinding.app.RxDialog.cancels; import android.content.Context; @@ -42,6 +43,7 @@ import ee.ria.DigiDoc.android.utils.files.EmptyFileException; import ee.ria.DigiDoc.android.utils.mvi.MviView; import ee.ria.DigiDoc.android.utils.mvi.State; +import ee.ria.DigiDoc.android.utils.navigator.ContentView; import ee.ria.DigiDoc.android.utils.navigator.Screen; import ee.ria.DigiDoc.android.utils.widget.ConfirmationDialog; import ee.ria.DigiDoc.android.utils.widget.ErrorDialog; @@ -54,7 +56,7 @@ import io.reactivex.rxjava3.subjects.PublishSubject; import io.reactivex.rxjava3.subjects.Subject; -public final class CryptoCreateScreen extends Controller implements Screen, +public final class CryptoCreateScreen extends Controller implements Screen, ContentView, MviView { private static final String KEY_CONTAINER_FILE = "containerFile"; @@ -420,6 +422,11 @@ protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup disposables.add(viewModel.viewStates().subscribe(this::render)); viewModel.process(intents()); + addInvisibleElement(getApplicationContext(), view); + + View lastElementView = view.findViewById(R.id.lastInvisibleElement); + moveView(lastElementView); + return view; } diff --git a/app/src/main/java/ee/ria/DigiDoc/android/crypto/create/CryptoRecipientsScreen.java b/app/src/main/java/ee/ria/DigiDoc/android/crypto/create/CryptoRecipientsScreen.java index 3f18815e1..16c0aa2b2 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/crypto/create/CryptoRecipientsScreen.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/crypto/create/CryptoRecipientsScreen.java @@ -8,6 +8,7 @@ import static com.jakewharton.rxbinding4.widget.RxToolbar.navigationClicks; import static ee.ria.DigiDoc.android.Constants.MAXIMUM_PERSONAL_CODE_LENGTH; import static ee.ria.DigiDoc.android.Constants.VOID; +import static ee.ria.DigiDoc.android.utils.ViewUtil.moveView; import android.content.Context; import android.graphics.Color; @@ -47,6 +48,7 @@ import ee.ria.DigiDoc.android.utils.display.DisplayUtil; import ee.ria.DigiDoc.android.utils.mvi.MviView; import ee.ria.DigiDoc.android.utils.mvi.State; +import ee.ria.DigiDoc.android.utils.navigator.ContentView; import ee.ria.DigiDoc.android.utils.navigator.Navigator; import ee.ria.DigiDoc.android.utils.navigator.Screen; import ee.ria.DigiDoc.android.utils.validator.PersonalCodeValidator; @@ -56,7 +58,7 @@ import io.reactivex.rxjava3.subjects.PublishSubject; import io.reactivex.rxjava3.subjects.Subject; -public final class CryptoRecipientsScreen extends Controller implements Screen, +public final class CryptoRecipientsScreen extends Controller implements Screen, ContentView, MviView, Navigator.BackButtonClickListener { private static final String KEY_CRYPTO_CREATE_SCREEN_ID = "cryptoCreateScreenId"; @@ -335,6 +337,12 @@ public void afterTextChanged(Editable s) {} doneButton = view.findViewById(R.id.cryptoRecipientsDoneButton); activityOverlayView = view.findViewById(R.id.activityOverlay); activityIndicatorView = view.findViewById(R.id.activityIndicator); + + addInvisibleElement(getApplicationContext(), doneButton); + + View lastElementView = view.findViewById(R.id.lastInvisibleElement); + moveView(lastElementView); + return view; } diff --git a/app/src/main/java/ee/ria/DigiDoc/android/eid/CodeUpdateView.java b/app/src/main/java/ee/ria/DigiDoc/android/eid/CodeUpdateView.java index 31e303601..b21da79de 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/eid/CodeUpdateView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/eid/CodeUpdateView.java @@ -32,13 +32,14 @@ import ee.ria.DigiDoc.android.eid.CodeUpdateError.CodeTooEasyError; import ee.ria.DigiDoc.android.utils.TextUtil; import ee.ria.DigiDoc.android.utils.mvi.State; +import ee.ria.DigiDoc.android.utils.navigator.ContentView; import io.reactivex.rxjava3.core.Observable; import static com.jakewharton.rxbinding4.widget.RxToolbar.navigationClicks; import static com.jakewharton.rxbinding4.view.RxView.clicks; import static ee.ria.DigiDoc.android.utils.InputMethodUtils.hideSoftKeyboard; -public final class CodeUpdateView extends CoordinatorLayout { +public final class CodeUpdateView extends CoordinatorLayout implements ContentView { private final Toolbar toolbarView; private final TextView successMessageView; @@ -82,6 +83,8 @@ public CodeUpdateView(Context context, @Nullable AttributeSet attrs, int defStyl activityOverlayView = findViewById(R.id.activityOverlay); activityIndicatorView = findViewById(R.id.activityIndicator); scrollView = findViewById(R.id.eidHomeCodeUpdateScroll); + + addInvisibleElement(context, this); } public void render(@State String state, CodeUpdateAction action, diff --git a/app/src/main/java/ee/ria/DigiDoc/android/main/about/AboutAdapter.java b/app/src/main/java/ee/ria/DigiDoc/android/main/about/AboutAdapter.java index d54abaea6..8f2fae8e2 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/main/about/AboutAdapter.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/main/about/AboutAdapter.java @@ -15,9 +15,10 @@ import ee.ria.DigiDoc.BuildConfig; import ee.ria.DigiDoc.R; +import ee.ria.DigiDoc.android.utils.navigator.ContentView; import ee.ria.DigiDoc.common.TextUtil; -final class AboutAdapter extends RecyclerView.Adapter { +final class AboutAdapter extends RecyclerView.Adapter implements ContentView { private final ImmutableList components = ImmutableList.builder() .add(Component.create( @@ -258,6 +259,11 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi componentViewHolder.licenseUrlView.setText(component.licenseUrl()); componentViewHolder.licenseUrlView.setContentDescription(getAccessibilityText( resources.getString(component.licenseUrl())) + " link"); + + int lastComponent = components.size() - 1; + if (component.equals(components.get(lastComponent))) { + addInvisibleElement(holder.itemView.getContext(), holder.itemView); + } } } diff --git a/app/src/main/java/ee/ria/DigiDoc/android/main/accessibility/AccessibilityView.java b/app/src/main/java/ee/ria/DigiDoc/android/main/accessibility/AccessibilityView.java index 8d161d97d..f485c2e2e 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/main/accessibility/AccessibilityView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/main/accessibility/AccessibilityView.java @@ -1,9 +1,13 @@ package ee.ria.DigiDoc.android.main.accessibility; import static com.jakewharton.rxbinding4.widget.RxToolbar.navigationClicks; +import static ee.ria.DigiDoc.android.utils.TextUtil.getInvisibleElementTextView; +import static ee.ria.DigiDoc.android.utils.ViewUtil.findLastElement; import android.content.Context; import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; import android.widget.Toolbar; import androidx.coordinatorlayout.widget.CoordinatorLayout; @@ -11,10 +15,11 @@ import ee.ria.DigiDoc.R; import ee.ria.DigiDoc.android.Application; import ee.ria.DigiDoc.android.utils.ViewDisposables; +import ee.ria.DigiDoc.android.utils.navigator.ContentView; import ee.ria.DigiDoc.android.utils.navigator.Navigator; import ee.ria.DigiDoc.android.utils.navigator.Transaction; -public class AccessibilityView extends CoordinatorLayout { +public class AccessibilityView extends CoordinatorLayout implements ContentView { private final Toolbar toolbarView; @@ -40,6 +45,8 @@ public AccessibilityView(Context context, AttributeSet attrs, int defStyleAttr) toolbarView.setTitle(R.string.main_accessibility_title); toolbarView.setNavigationIcon(androidx.appcompat.R.drawable.abc_ic_ab_back_material); toolbarView.setNavigationContentDescription(R.string.back); + + addInvisibleElement(getContext(), this); } @Override diff --git a/app/src/main/java/ee/ria/DigiDoc/android/main/diagnostics/DiagnosticsView.java b/app/src/main/java/ee/ria/DigiDoc/android/main/diagnostics/DiagnosticsView.java index 0ffe7d156..4f61aee37 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/main/diagnostics/DiagnosticsView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/main/diagnostics/DiagnosticsView.java @@ -7,6 +7,7 @@ import static ee.ria.DigiDoc.android.main.diagnostics.DiagnosticsScreen.diagnosticsFileSaveClicksSubject; import android.content.Context; +import android.graphics.Color; import android.graphics.Typeface; import android.net.Uri; import android.os.Build; @@ -52,6 +53,8 @@ import ee.ria.DigiDoc.android.utils.TSLException; import ee.ria.DigiDoc.android.utils.TSLUtil; import ee.ria.DigiDoc.android.utils.ViewDisposables; +import ee.ria.DigiDoc.android.utils.ViewUtil; +import ee.ria.DigiDoc.android.utils.navigator.ContentView; import ee.ria.DigiDoc.android.utils.navigator.Navigator; import ee.ria.DigiDoc.android.utils.navigator.Transaction; import ee.ria.DigiDoc.android.utils.widget.ConfirmationDialog; @@ -69,7 +72,7 @@ import okhttp3.Response; import timber.log.Timber; -public final class DiagnosticsView extends CoordinatorLayout { +public final class DiagnosticsView extends CoordinatorLayout implements ContentView { private final Navigator navigator; private final SimpleDateFormat dateFormat; @@ -94,6 +97,8 @@ public DiagnosticsView(Context context) { View saveDiagnosticsButton = findViewById(R.id.configurationSaveButton); navigator = Application.component(context).navigator(); + addInvisibleElement(getContext(), this); + diagnosticsRestartConfirmationDialog = new ConfirmationDialog(navigator.activity(), R.string.main_diagnostics_restart_message, R.id.mainDiagnosticsRestartConfirmationDialog); diff --git a/app/src/main/java/ee/ria/DigiDoc/android/main/home/HomeMenuView.java b/app/src/main/java/ee/ria/DigiDoc/android/main/home/HomeMenuView.java index 7472b0816..dfbed20ee 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/main/home/HomeMenuView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/main/home/HomeMenuView.java @@ -28,6 +28,7 @@ import ee.ria.DigiDoc.R; import ee.ria.DigiDoc.android.utils.display.DisplayUtil; +import ee.ria.DigiDoc.android.utils.navigator.ContentView; import ee.ria.DigiDoc.common.TextUtil; import io.reactivex.rxjava3.core.Observable; @@ -35,7 +36,7 @@ import static com.jakewharton.rxbinding4.widget.RxRadioGroup.checkedChanges; import static ee.ria.DigiDoc.android.utils.TintUtils.tintCompoundDrawables; -public final class HomeMenuView extends NestedScrollView { +public final class HomeMenuView extends NestedScrollView implements ContentView { private final View closeButton; @@ -139,6 +140,8 @@ public HomeMenuView(@NonNull Context context, @Nullable AttributeSet attrs, int }, 2000); setFontSize(); + + addInvisibleElement(getContext(), this); } @Override diff --git a/app/src/main/java/ee/ria/DigiDoc/android/main/home/HomeView.java b/app/src/main/java/ee/ria/DigiDoc/android/main/home/HomeView.java index 72a08caf1..c430f2031 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/main/home/HomeView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/main/home/HomeView.java @@ -24,16 +24,18 @@ import ee.ria.DigiDoc.android.utils.TextUtil; import ee.ria.DigiDoc.android.utils.ViewDisposables; import ee.ria.DigiDoc.android.utils.mvi.MviView; +import ee.ria.DigiDoc.android.utils.navigator.ContentView; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; import io.reactivex.rxjava3.subjects.Subject; import static com.jakewharton.rxbinding4.material.RxBottomNavigationView.itemSelections; import static ee.ria.DigiDoc.android.utils.Predicates.duplicates; +import static ee.ria.DigiDoc.android.utils.ViewUtil.moveView; import static ee.ria.DigiDoc.android.utils.rxbinding.app.RxDialog.cancels; @SuppressLint("ViewConstructor") -public final class HomeView extends LinearLayout implements MviView { +public final class HomeView extends LinearLayout implements ContentView, MviView { public interface HomeViewChild { @@ -93,6 +95,11 @@ public HomeView(Context context, android.content.Intent intent, String screenId) viewModel = Application.component(context).navigator().viewModel(screenId, HomeViewModel.class); viewModel.eidScreenId(eidScreenId); + + addInvisibleElement(context, navigationContainerView); + + View lastElementView = findViewById(R.id.lastInvisibleElement); + moveView(lastElementView); } private void setCustomAccessibilityFeedback(BottomNavigationItemView bottomNavigationItemView) { diff --git a/app/src/main/java/ee/ria/DigiDoc/android/main/settings/SettingsView.java b/app/src/main/java/ee/ria/DigiDoc/android/main/settings/SettingsView.java index 9f824b882..25057a3ce 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/main/settings/SettingsView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/main/settings/SettingsView.java @@ -16,12 +16,13 @@ import ee.ria.DigiDoc.android.Activity; import ee.ria.DigiDoc.android.Application; import ee.ria.DigiDoc.android.utils.ViewDisposables; +import ee.ria.DigiDoc.android.utils.navigator.ContentView; import ee.ria.DigiDoc.android.utils.navigator.Navigator; import ee.ria.DigiDoc.android.utils.navigator.Transaction; import static com.jakewharton.rxbinding4.widget.RxToolbar.navigationClicks; -public final class SettingsView extends CoordinatorLayout { +public final class SettingsView extends CoordinatorLayout implements ContentView { private final Toolbar toolbarView; private final TextView toolbarTitleView; @@ -74,6 +75,8 @@ public SettingsView(Context context, AttributeSet attrs, int defStyleAttr) { restartIntent(); }); } + + addInvisibleElement(getContext(), this); } private TextView getToolbarViewTitle() { diff --git a/app/src/main/java/ee/ria/DigiDoc/android/signature/create/SignatureCreateView.java b/app/src/main/java/ee/ria/DigiDoc/android/signature/create/SignatureCreateView.java index 847d3a761..57af05eb5 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/signature/create/SignatureCreateView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/signature/create/SignatureCreateView.java @@ -10,10 +10,11 @@ import ee.ria.DigiDoc.android.Application; import ee.ria.DigiDoc.android.utils.ViewDisposables; import ee.ria.DigiDoc.android.utils.mvi.MviView; +import ee.ria.DigiDoc.android.utils.navigator.ContentView; import io.reactivex.rxjava3.core.Observable; @SuppressLint("ViewConstructor") -public final class SignatureCreateView extends FrameLayout implements MviView { +public final class SignatureCreateView extends FrameLayout implements ContentView, MviView { @Nullable private final android.content.Intent intent; @@ -27,6 +28,8 @@ public SignatureCreateView(@NonNull Context context, String screenId, viewModel = Application.component(context).navigator() .viewModel(screenId, SignatureCreateViewModel.class); inflate(context, R.layout.signature_create, this); + + addInvisibleElement(getContext(), this); } private Observable initialIntent() { diff --git a/app/src/main/java/ee/ria/DigiDoc/android/signature/detail/CertificateDetailView.java b/app/src/main/java/ee/ria/DigiDoc/android/signature/detail/CertificateDetailView.java index 38a1ffb24..83d167620 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/signature/detail/CertificateDetailView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/signature/detail/CertificateDetailView.java @@ -51,12 +51,13 @@ import ee.ria.DigiDoc.android.utils.TextUtil; import ee.ria.DigiDoc.android.utils.ViewDisposables; import ee.ria.DigiDoc.android.utils.ViewSavedState; +import ee.ria.DigiDoc.android.utils.navigator.ContentView; import ee.ria.DigiDoc.android.utils.navigator.Navigator; import ee.ria.DigiDoc.android.utils.navigator.Transaction; import timber.log.Timber; @SuppressLint("ViewConstructor") -public final class CertificateDetailView extends CoordinatorLayout { +public final class CertificateDetailView extends CoordinatorLayout implements ContentView { private final Navigator navigator; private final Toolbar toolbarView; @@ -77,6 +78,8 @@ public CertificateDetailView(Context context, X509Certificate certificate) { toolbarView.setNavigationContentDescription(R.string.back); setData(certificate); + + addInvisibleElement(context, this); } diff --git a/app/src/main/java/ee/ria/DigiDoc/android/signature/detail/SignatureDetailView.java b/app/src/main/java/ee/ria/DigiDoc/android/signature/detail/SignatureDetailView.java index f4cc0a30f..d8fe33f2f 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/signature/detail/SignatureDetailView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/signature/detail/SignatureDetailView.java @@ -25,6 +25,7 @@ import ee.ria.DigiDoc.android.utils.TextUtil; import ee.ria.DigiDoc.android.utils.ViewDisposables; import ee.ria.DigiDoc.android.utils.ViewSavedState; +import ee.ria.DigiDoc.android.utils.navigator.ContentView; import ee.ria.DigiDoc.android.utils.navigator.Navigator; import ee.ria.DigiDoc.android.utils.navigator.Transaction; import ee.ria.DigiDoc.sign.Signature; @@ -33,7 +34,7 @@ import timber.log.Timber; @SuppressLint("ViewConstructor") -public final class SignatureDetailView extends CoordinatorLayout { +public final class SignatureDetailView extends CoordinatorLayout implements ContentView { private final Navigator navigator; private final Toolbar toolbarView; @@ -66,6 +67,8 @@ public SignatureDetailView(Context context, Signature signature, SignedContainer } setData(signature, signedContainer); + + addInvisibleElement(context, this); } private String getContainerMimeType(SignedContainer signedContainer) { diff --git a/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateSignatureAddDialog.java b/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateSignatureAddDialog.java index bf25c476f..20e5dba27 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateSignatureAddDialog.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateSignatureAddDialog.java @@ -16,6 +16,7 @@ import ee.ria.DigiDoc.android.accessibility.AccessibilityUtils; import ee.ria.DigiDoc.android.utils.SecureUtil; import ee.ria.DigiDoc.android.utils.ViewDisposables; +import ee.ria.DigiDoc.android.utils.navigator.ContentView; import ee.ria.DigiDoc.android.utils.rxbinding.app.ObservableDialogClickListener; import io.reactivex.rxjava3.core.Observable; @@ -27,7 +28,7 @@ import static ee.ria.DigiDoc.android.utils.display.DisplayUtil.getDialogLandscapeWidth; import static ee.ria.DigiDoc.android.utils.display.DisplayUtil.getDialogPortraitWidth; -public final class SignatureUpdateSignatureAddDialog extends AlertDialog { +public final class SignatureUpdateSignatureAddDialog extends AlertDialog implements ContentView { private final SignatureUpdateSignatureAddView view; private final ObservableDialogClickListener positiveButtonClicks; @@ -74,6 +75,12 @@ public void show() { WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); setCustomLayoutChangeListener(window); view.addOnLayoutChangeListener(getCustomLayoutChangeListener()); + + View parentPanel = findViewById(R.id.parentPanel); + int lastInvisibleElement = R.id.lastInvisibleElement; + if (parentPanel != null && parentPanel.findViewById(lastInvisibleElement) == null) { + ContentView.addInvisibleElementToObject(getContext(), findViewById(R.id.parentPanel)); + } } } diff --git a/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateView.java b/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateView.java index 4dec8b8ab..076a9f03e 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateView.java @@ -5,6 +5,7 @@ import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; import static ee.ria.DigiDoc.android.utils.TintUtils.tintCompoundDrawables; +import static ee.ria.DigiDoc.android.utils.ViewUtil.moveView; import static ee.ria.DigiDoc.android.utils.rxbinding.app.RxDialog.cancels; import android.annotation.SuppressLint; @@ -49,6 +50,7 @@ import ee.ria.DigiDoc.android.utils.files.FileSystem; import ee.ria.DigiDoc.android.utils.mvi.MviView; import ee.ria.DigiDoc.android.utils.mvi.State; +import ee.ria.DigiDoc.android.utils.navigator.ContentView; import ee.ria.DigiDoc.android.utils.navigator.Navigator; import ee.ria.DigiDoc.android.utils.navigator.Transaction; import ee.ria.DigiDoc.android.utils.widget.ConfirmationDialog; @@ -66,7 +68,7 @@ import static com.jakewharton.rxbinding4.widget.RxToolbar.navigationClicks; @SuppressLint("ViewConstructor") -public final class SignatureUpdateView extends LinearLayout implements MviView { +public final class SignatureUpdateView extends LinearLayout implements ContentView, MviView { private final ImmutableList ASICS_TIMESTAMP_CONTAINERS = ImmutableList.of("asics", "scs"); private static final ImmutableSet UNSIGNABLE_CONTAINER_EXTENSIONS = ImmutableSet.builder().add("asics", "scs", "ddoc").build(); @@ -203,6 +205,11 @@ public SignatureUpdateView(Context context, String screenId, boolean isExistingC setupAccessibilityTabs(); setActionButtonsTextSize(); + + addInvisibleElement(getContext(), this); + + View lastElementView = findViewById(R.id.lastInvisibleElement); + moveView(lastElementView); } @Override diff --git a/app/src/main/java/ee/ria/DigiDoc/android/utils/TextUtil.java b/app/src/main/java/ee/ria/DigiDoc/android/utils/TextUtil.java index 9aa5f0133..33ac49c97 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/utils/TextUtil.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/utils/TextUtil.java @@ -1,9 +1,12 @@ package ee.ria.DigiDoc.android.utils; import static android.view.View.GONE; +import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO; +import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import android.content.Context; +import android.graphics.Color; import android.text.Layout; import android.text.SpannableString; import android.text.style.AlignmentSpan; @@ -21,6 +24,8 @@ import com.google.android.material.textfield.TextInputLayout; +import ee.ria.DigiDoc.R; + public class TextUtil { public static AppCompatEditText getTextView(View view) { @@ -96,4 +101,20 @@ public static int convertPxToDp(float size, Context context) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, context.getResources().getDisplayMetrics()); } + + public static TextView getInvisibleElementTextView(Context context) { + TextView textView = new TextView(context); + textView.setText(R.string.last_invisible_element_name); + textView.setTextColor(Color.GRAY); + textView.setId(R.id.lastInvisibleElement); + textView.setTag(R.string.last_invisible_element_tag); + textView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); + textView.setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT)); + textView.setEnabled(false); + textView.setAlpha(0.001f); + + return textView; + } } diff --git a/app/src/main/java/ee/ria/DigiDoc/android/utils/ViewUtil.java b/app/src/main/java/ee/ria/DigiDoc/android/utils/ViewUtil.java new file mode 100644 index 000000000..9749717c2 --- /dev/null +++ b/app/src/main/java/ee/ria/DigiDoc/android/utils/ViewUtil.java @@ -0,0 +1,51 @@ +package ee.ria.DigiDoc.android.utils; + +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; + +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.recyclerview.widget.RecyclerView; + +public class ViewUtil { + + public static View findLastElement(View view) { + if (view instanceof ViewGroup) { + ViewGroup viewGroup = (ViewGroup) view; + int subviews = viewGroup.getChildCount(); + if (subviews > 0) { + return findLastElement(viewGroup.getChildAt(subviews - 1)); + } + } + + return view; + } + + public static View findMainLayoutElement(View view) { + View mainView = findLastElement(view); + + if (mainView != null) { + ViewParent parent = mainView.getParent(); + if (parent != null) { + while ((parent instanceof LinearLayout || + parent instanceof RelativeLayout || + parent instanceof RecyclerView)) { + mainView = (View) parent; + parent = mainView.getParent(); + } + } + + } + return mainView; + } + + public static void moveView(View view) { + if (view != null) { + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) view.getLayoutParams(); + layoutParams.setMargins(layoutParams.leftMargin, -100, layoutParams.rightMargin, layoutParams.bottomMargin); + view.setLayoutParams(layoutParams); + } + } +} diff --git a/app/src/main/java/ee/ria/DigiDoc/android/utils/navigator/ContentView.java b/app/src/main/java/ee/ria/DigiDoc/android/utils/navigator/ContentView.java new file mode 100644 index 000000000..9b2e6adb1 --- /dev/null +++ b/app/src/main/java/ee/ria/DigiDoc/android/utils/navigator/ContentView.java @@ -0,0 +1,31 @@ +package ee.ria.DigiDoc.android.utils.navigator; + +import static ee.ria.DigiDoc.android.utils.TextUtil.getInvisibleElementTextView; +import static ee.ria.DigiDoc.android.utils.ViewUtil.findLastElement; +import static ee.ria.DigiDoc.android.utils.ViewUtil.findMainLayoutElement; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; + +public interface ContentView { + + // Adds an invisible label element to the bottom of the view. + // Used for autotests by testers + default void addInvisibleElement(Context context, View view) { + View mainLayoutElement = findMainLayoutElement(view); + if (mainLayoutElement instanceof ViewGroup) { + ((ViewGroup) mainLayoutElement).addView(getInvisibleElementTextView(context)); + } else if (mainLayoutElement != null && mainLayoutElement.getParent() instanceof ViewGroup) { + ((ViewGroup) mainLayoutElement.getParent()).addView(getInvisibleElementTextView(context)); + } + } + + static void addInvisibleElementToObject(Context context, View view) { + if (view instanceof ViewGroup) { + ((ViewGroup) view).addView(getInvisibleElementTextView(context)); + } else if (view != null && view.getParent() instanceof ViewGroup) { + ((ViewGroup) view.getParent()).addView(getInvisibleElementTextView(context)); + } + } +} diff --git a/app/src/main/java/ee/ria/DigiDoc/android/utils/widget/ConfirmationDialog.java b/app/src/main/java/ee/ria/DigiDoc/android/utils/widget/ConfirmationDialog.java index 0e08d3a05..ad4c687ba 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/utils/widget/ConfirmationDialog.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/utils/widget/ConfirmationDialog.java @@ -14,6 +14,7 @@ import ee.ria.DigiDoc.R; import ee.ria.DigiDoc.android.Constants; import ee.ria.DigiDoc.android.utils.SecureUtil; +import ee.ria.DigiDoc.android.utils.navigator.ContentView; import ee.ria.DigiDoc.android.utils.rxbinding.app.RxDialog; import ee.ria.DigiDoc.sign.utils.UrlMessage; @@ -21,7 +22,7 @@ import io.reactivex.rxjava3.subjects.PublishSubject; import io.reactivex.rxjava3.subjects.Subject; -public final class ConfirmationDialog extends AlertDialog implements +public final class ConfirmationDialog extends AlertDialog implements ContentView, DialogInterface.OnClickListener { private final Subject buttonClicksSubject = PublishSubject.create(); diff --git a/app/src/main/res/layout/signature_list_screen.xml b/app/src/main/res/layout/signature_list_screen.xml index ea91e92a1..1a3a61c65 100644 --- a/app/src/main/res/layout/signature_list_screen.xml +++ b/app/src/main/res/layout/signature_list_screen.xml @@ -30,6 +30,10 @@ app:layout_behavior="@string/appbar_scrolling_view_behavior" android:scrollbars="vertical" /> + + diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index ca34cad88..66a9f0f67 100644 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -5,6 +5,9 @@ ee.ria.digidoc.fileprovider + Invisible element + lastInvisibleElement + Eesti keel Русский язык English diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index 62ed4ea0f..81c5dba35 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -9,6 +9,7 @@ + From 2ac1ef2dafedb7dbc6c8abd8143dbebdddddf4e1 Mon Sep 17 00:00:00 2001 From: Marten Rebane <54431068+martenrebane@users.noreply.github.com> Date: Tue, 8 Aug 2023 10:26:46 +0300 Subject: [PATCH 2/2] Show invisible element on scroll --- .../crypto/create/CryptoCreateScreen.java | 20 +++--- .../crypto/create/CryptoRecipientsScreen.java | 9 ++- .../DigiDoc/android/eid/CodeUpdateView.java | 2 +- .../android/main/about/AboutAdapter.java | 5 -- .../android/main/about/AboutScreen.java | 16 ++++- .../main/accessibility/AccessibilityView.java | 2 +- .../main/diagnostics/DiagnosticsView.java | 2 +- .../android/main/home/HomeMenuView.java | 2 +- .../DigiDoc/android/main/home/HomeView.java | 2 +- .../android/main/settings/SettingsView.java | 2 +- .../signature/create/SignatureCreateView.java | 2 +- .../detail/CertificateDetailView.java | 2 +- .../signature/detail/SignatureDetailView.java | 2 +- .../signature/list/SignatureListScreen.java | 31 +++++--- .../update/SignatureUpdateAdapter.java | 6 -- .../SignatureUpdateSignatureAddDialog.java | 5 -- .../signature/update/SignatureUpdateView.java | 15 ++-- .../ria/DigiDoc/android/utils/ViewUtil.java | 11 +-- .../android/utils/navigator/ContentView.java | 35 ++++++---- .../utils/navigator/InvisibleView.java | 70 +++++++++++++++++++ app/src/main/res/layout/main_about_screen.xml | 21 +++++- .../main/res/layout/signature_list_screen.xml | 16 +++-- app/src/main/res/values/ids.xml | 2 + 23 files changed, 198 insertions(+), 82 deletions(-) create mode 100644 app/src/main/java/ee/ria/DigiDoc/android/utils/navigator/InvisibleView.java diff --git a/app/src/main/java/ee/ria/DigiDoc/android/crypto/create/CryptoCreateScreen.java b/app/src/main/java/ee/ria/DigiDoc/android/crypto/create/CryptoCreateScreen.java index f1ccfdf9a..095f48e1f 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/crypto/create/CryptoCreateScreen.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/crypto/create/CryptoCreateScreen.java @@ -1,5 +1,6 @@ package ee.ria.DigiDoc.android.crypto.create; +import static android.view.View.GONE; import static android.view.accessibility.AccessibilityEvent.TYPE_ANNOUNCEMENT; import static com.jakewharton.rxbinding4.view.RxView.clicks; import static com.jakewharton.rxbinding4.widget.RxToolbar.navigationClicks; @@ -7,7 +8,6 @@ import static ee.ria.DigiDoc.android.utils.BundleUtils.putFile; import static ee.ria.DigiDoc.android.utils.Predicates.duplicates; import static ee.ria.DigiDoc.android.utils.TintUtils.tintCompoundDrawables; -import static ee.ria.DigiDoc.android.utils.ViewUtil.moveView; import static ee.ria.DigiDoc.android.utils.rxbinding.app.RxDialog.cancels; import android.content.Context; @@ -295,12 +295,12 @@ public void render(ViewState state) { sivaConfirmationDialog.dismiss(); } - encryptButton.setVisibility(state.encryptButtonVisible() ? View.VISIBLE : View.GONE); - decryptButton.setVisibility(state.decryptButtonVisible() ? View.VISIBLE : View.GONE); - sendButton.setVisibility(state.sendButtonVisible() ? View.VISIBLE : View.GONE); + encryptButton.setVisibility(state.encryptButtonVisible() ? View.VISIBLE : GONE); + decryptButton.setVisibility(state.decryptButtonVisible() ? View.VISIBLE : GONE); + sendButton.setVisibility(state.sendButtonVisible() ? View.VISIBLE : GONE); buttonSpaceView.setVisibility(state.sendButtonVisible() && (state.encryptButtonVisible() || state.decryptButtonVisible()) - ? View.VISIBLE : View.GONE); + ? View.VISIBLE : GONE); decryptionIdCardDataResponse = state.decryptionIdCardDataResponse(); boolean decryptionPin1Locked = false; @@ -364,8 +364,8 @@ private void showSuccessNotification() { } private void setActivity(boolean activity) { - activityOverlayView.setVisibility(activity ? View.VISIBLE : View.GONE); - activityIndicatorView.setVisibility(activity ? View.VISIBLE : View.GONE); + activityOverlayView.setVisibility(activity ? View.VISIBLE : GONE); + activityIndicatorView.setVisibility(activity ? View.VISIBLE : GONE); encryptButton.setEnabled(!activity); decryptButton.setEnabled(!activity); sendButton.setEnabled(!activity); @@ -422,10 +422,11 @@ protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup disposables.add(viewModel.viewStates().subscribe(this::render)); viewModel.process(intents()); - addInvisibleElement(getApplicationContext(), view); + ContentView.addInvisibleElement(getApplicationContext(), view); View lastElementView = view.findViewById(R.id.lastInvisibleElement); - moveView(lastElementView); + + ContentView.addInvisibleElementScrollListener(listView, lastElementView); return view; } @@ -435,6 +436,7 @@ protected void onDestroyView(@NonNull View view) { decryptDialog.dismiss(); errorDialog.dismiss(); sivaConfirmationDialog.dismiss(); + ContentView.removeInvisibleElementScrollListener(listView); disposables.detach(); super.onDestroyView(view); } diff --git a/app/src/main/java/ee/ria/DigiDoc/android/crypto/create/CryptoRecipientsScreen.java b/app/src/main/java/ee/ria/DigiDoc/android/crypto/create/CryptoRecipientsScreen.java index 16c0aa2b2..20ceb8064 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/crypto/create/CryptoRecipientsScreen.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/crypto/create/CryptoRecipientsScreen.java @@ -80,6 +80,7 @@ public static CryptoRecipientsScreen create(String cryptoCreateScreenId) { private Toolbar toolbarView; private SearchView searchView; private EditText searchViewInnerText; + private RecyclerView listView; private CryptoCreateAdapter adapter; private View doneButton; private View activityOverlayView; @@ -330,7 +331,7 @@ public void afterTextChanged(Editable s) {} searchView.setSubmitButtonEnabled(true); searchView.setEnabled(true); - RecyclerView listView = view.findViewById(R.id.cryptoRecipientsList); + listView = view.findViewById(R.id.cryptoRecipientsList); listView.setLayoutManager(new LinearLayoutManager(container.getContext())); listView.setAdapter(adapter = new CryptoCreateAdapter()); listView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); @@ -338,10 +339,11 @@ public void afterTextChanged(Editable s) {} activityOverlayView = view.findViewById(R.id.activityOverlay); activityIndicatorView = view.findViewById(R.id.activityIndicator); - addInvisibleElement(getApplicationContext(), doneButton); + ContentView.addInvisibleElement(getApplicationContext(), view); View lastElementView = view.findViewById(R.id.lastInvisibleElement); - moveView(lastElementView); + + ContentView.addInvisibleElementScrollListener(listView, lastElementView); return view; } @@ -375,6 +377,7 @@ protected void onDetach(@NonNull View view) { disposables.detach(); navigator.removeBackButtonClickListener(this); searchView.setOnCloseListener(null); + ContentView.removeInvisibleElementScrollListener(listView); super.onDetach(view); } diff --git a/app/src/main/java/ee/ria/DigiDoc/android/eid/CodeUpdateView.java b/app/src/main/java/ee/ria/DigiDoc/android/eid/CodeUpdateView.java index b21da79de..c563ffa07 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/eid/CodeUpdateView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/eid/CodeUpdateView.java @@ -84,7 +84,7 @@ public CodeUpdateView(Context context, @Nullable AttributeSet attrs, int defStyl activityIndicatorView = findViewById(R.id.activityIndicator); scrollView = findViewById(R.id.eidHomeCodeUpdateScroll); - addInvisibleElement(context, this); + ContentView.addInvisibleElement(context, this); } public void render(@State String state, CodeUpdateAction action, diff --git a/app/src/main/java/ee/ria/DigiDoc/android/main/about/AboutAdapter.java b/app/src/main/java/ee/ria/DigiDoc/android/main/about/AboutAdapter.java index 8f2fae8e2..cc7b24be7 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/main/about/AboutAdapter.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/main/about/AboutAdapter.java @@ -259,11 +259,6 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi componentViewHolder.licenseUrlView.setText(component.licenseUrl()); componentViewHolder.licenseUrlView.setContentDescription(getAccessibilityText( resources.getString(component.licenseUrl())) + " link"); - - int lastComponent = components.size() - 1; - if (component.equals(components.get(lastComponent))) { - addInvisibleElement(holder.itemView.getContext(), holder.itemView); - } } } diff --git a/app/src/main/java/ee/ria/DigiDoc/android/main/about/AboutScreen.java b/app/src/main/java/ee/ria/DigiDoc/android/main/about/AboutScreen.java index 148833c11..180b068a4 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/main/about/AboutScreen.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/main/about/AboutScreen.java @@ -1,5 +1,10 @@ package ee.ria.DigiDoc.android.main.about; +import static com.jakewharton.rxbinding4.widget.RxToolbar.navigationClicks; +import static ee.ria.DigiDoc.android.utils.navigator.ContentView.addInvisibleElement; +import static ee.ria.DigiDoc.android.utils.navigator.ContentView.addInvisibleElementScrollListener; +import static ee.ria.DigiDoc.android.utils.navigator.ContentView.removeInvisibleElementScrollListener; + import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -20,14 +25,14 @@ import ee.ria.DigiDoc.android.utils.navigator.Screen; import ee.ria.DigiDoc.android.utils.navigator.Transaction; -import static com.jakewharton.rxbinding4.widget.RxToolbar.navigationClicks; - public final class AboutScreen extends Controller implements Screen { public static AboutScreen create() { return new AboutScreen(); } + private RecyclerView listView; + private final ViewDisposables disposables = new ViewDisposables(); @SuppressWarnings("WeakerAccess") @@ -45,10 +50,14 @@ protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup toolbarView.setTitle(R.string.main_about_title); toolbarView.setNavigationIcon(androidx.appcompat.R.drawable.abc_ic_ab_back_material); toolbarView.setNavigationContentDescription(R.string.back); - RecyclerView listView = view.findViewById(R.id.mainAboutList); + listView = view.findViewById(R.id.mainAboutList); listView.setLayoutManager(new LinearLayoutManager(container.getContext())); listView.setAdapter(new AboutAdapter()); + addInvisibleElement(getApplicationContext(), view); + View lastElementView = view.findViewById(R.id.lastInvisibleElement); + addInvisibleElementScrollListener(listView, lastElementView); + disposables.attach(); disposables.add(navigationClicks(toolbarView).subscribe(ignored -> Application.component(container.getContext()).navigator().execute(Transaction.pop()))); @@ -59,6 +68,7 @@ protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup @Override protected void onDestroyView(@NonNull View view) { disposables.detach(); + removeInvisibleElementScrollListener(listView); super.onDestroyView(view); } } diff --git a/app/src/main/java/ee/ria/DigiDoc/android/main/accessibility/AccessibilityView.java b/app/src/main/java/ee/ria/DigiDoc/android/main/accessibility/AccessibilityView.java index f485c2e2e..2ec8ea5c1 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/main/accessibility/AccessibilityView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/main/accessibility/AccessibilityView.java @@ -46,7 +46,7 @@ public AccessibilityView(Context context, AttributeSet attrs, int defStyleAttr) toolbarView.setNavigationIcon(androidx.appcompat.R.drawable.abc_ic_ab_back_material); toolbarView.setNavigationContentDescription(R.string.back); - addInvisibleElement(getContext(), this); + ContentView.addInvisibleElement(getContext(), this); } @Override diff --git a/app/src/main/java/ee/ria/DigiDoc/android/main/diagnostics/DiagnosticsView.java b/app/src/main/java/ee/ria/DigiDoc/android/main/diagnostics/DiagnosticsView.java index 4f61aee37..4f19d8106 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/main/diagnostics/DiagnosticsView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/main/diagnostics/DiagnosticsView.java @@ -97,7 +97,7 @@ public DiagnosticsView(Context context) { View saveDiagnosticsButton = findViewById(R.id.configurationSaveButton); navigator = Application.component(context).navigator(); - addInvisibleElement(getContext(), this); + ContentView.addInvisibleElement(getContext(), this); diagnosticsRestartConfirmationDialog = new ConfirmationDialog(navigator.activity(), R.string.main_diagnostics_restart_message, R.id.mainDiagnosticsRestartConfirmationDialog); diff --git a/app/src/main/java/ee/ria/DigiDoc/android/main/home/HomeMenuView.java b/app/src/main/java/ee/ria/DigiDoc/android/main/home/HomeMenuView.java index dfbed20ee..53116e8b6 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/main/home/HomeMenuView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/main/home/HomeMenuView.java @@ -141,7 +141,7 @@ public HomeMenuView(@NonNull Context context, @Nullable AttributeSet attrs, int setFontSize(); - addInvisibleElement(getContext(), this); + ContentView.addInvisibleElement(getContext(), this); } @Override diff --git a/app/src/main/java/ee/ria/DigiDoc/android/main/home/HomeView.java b/app/src/main/java/ee/ria/DigiDoc/android/main/home/HomeView.java index c430f2031..466b1bb83 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/main/home/HomeView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/main/home/HomeView.java @@ -96,7 +96,7 @@ public HomeView(Context context, android.content.Intent intent, String screenId) HomeViewModel.class); viewModel.eidScreenId(eidScreenId); - addInvisibleElement(context, navigationContainerView); + ContentView.addInvisibleElement(getContext(), navigationContainerView); View lastElementView = findViewById(R.id.lastInvisibleElement); moveView(lastElementView); diff --git a/app/src/main/java/ee/ria/DigiDoc/android/main/settings/SettingsView.java b/app/src/main/java/ee/ria/DigiDoc/android/main/settings/SettingsView.java index 25057a3ce..97cbf1ef4 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/main/settings/SettingsView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/main/settings/SettingsView.java @@ -76,7 +76,7 @@ public SettingsView(Context context, AttributeSet attrs, int defStyleAttr) { }); } - addInvisibleElement(getContext(), this); + ContentView.addInvisibleElement(getContext(), this); } private TextView getToolbarViewTitle() { diff --git a/app/src/main/java/ee/ria/DigiDoc/android/signature/create/SignatureCreateView.java b/app/src/main/java/ee/ria/DigiDoc/android/signature/create/SignatureCreateView.java index 57af05eb5..c64cb23c4 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/signature/create/SignatureCreateView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/signature/create/SignatureCreateView.java @@ -29,7 +29,7 @@ public SignatureCreateView(@NonNull Context context, String screenId, .viewModel(screenId, SignatureCreateViewModel.class); inflate(context, R.layout.signature_create, this); - addInvisibleElement(getContext(), this); + ContentView.addInvisibleElement(getContext(), this); } private Observable initialIntent() { diff --git a/app/src/main/java/ee/ria/DigiDoc/android/signature/detail/CertificateDetailView.java b/app/src/main/java/ee/ria/DigiDoc/android/signature/detail/CertificateDetailView.java index 83d167620..ae29846e6 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/signature/detail/CertificateDetailView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/signature/detail/CertificateDetailView.java @@ -79,7 +79,7 @@ public CertificateDetailView(Context context, X509Certificate certificate) { setData(certificate); - addInvisibleElement(context, this); + ContentView.addInvisibleElement(context, this); } diff --git a/app/src/main/java/ee/ria/DigiDoc/android/signature/detail/SignatureDetailView.java b/app/src/main/java/ee/ria/DigiDoc/android/signature/detail/SignatureDetailView.java index d8fe33f2f..adaf907db 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/signature/detail/SignatureDetailView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/signature/detail/SignatureDetailView.java @@ -68,7 +68,7 @@ public SignatureDetailView(Context context, Signature signature, SignedContainer setData(signature, signedContainer); - addInvisibleElement(context, this); + ContentView.addInvisibleElement(context, this); } private String getContainerMimeType(SignedContainer signedContainer) { diff --git a/app/src/main/java/ee/ria/DigiDoc/android/signature/list/SignatureListScreen.java b/app/src/main/java/ee/ria/DigiDoc/android/signature/list/SignatureListScreen.java index 9bd8b7f0a..267524eb0 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/signature/list/SignatureListScreen.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/signature/list/SignatureListScreen.java @@ -1,17 +1,26 @@ package ee.ria.DigiDoc.android.signature.list; -import android.content.Context; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; +import static android.view.View.GONE; +import static android.view.View.VISIBLE; +import static android.view.accessibility.AccessibilityEvent.TYPE_ANNOUNCEMENT; +import static com.jakewharton.rxbinding4.widget.RxToolbar.navigationClicks; +import static ee.ria.DigiDoc.android.utils.navigator.ContentView.addInvisibleElementScrollListener; +import static ee.ria.DigiDoc.android.utils.navigator.ContentView.addInvisibleElementToObject; +import static ee.ria.DigiDoc.android.utils.navigator.ContentView.removeInvisibleElementScrollListener; +import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.LinearLayout; import android.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import com.bluelinelabs.conductor.Controller; import com.google.common.io.Files; @@ -28,11 +37,6 @@ import ee.ria.DigiDoc.sign.SignedContainer; import io.reactivex.rxjava3.core.Observable; -import static android.view.View.GONE; -import static android.view.View.VISIBLE; -import static android.view.accessibility.AccessibilityEvent.TYPE_ANNOUNCEMENT; -import static com.jakewharton.rxbinding4.widget.RxToolbar.navigationClicks; - public final class SignatureListScreen extends Controller implements Screen, MviView { @@ -183,6 +187,12 @@ protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup emptyView = view.findViewById(R.id.listEmpty); activityIndicatorView = view.findViewById(R.id.activityIndicator); activityOverlayView = view.findViewById(R.id.activityOverlay); + + LinearLayout signatureLayout = view.findViewById(R.id.signatureListLayout); + addInvisibleElementToObject(getApplicationContext(), signatureLayout); + View lastElementView = view.findViewById(R.id.lastInvisibleElement); + addInvisibleElementScrollListener(listView, lastElementView); + return view; } @@ -190,6 +200,7 @@ protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup protected void onDestroyView(@NonNull View view) { removeConfirmationDialog.dismiss(); sivaConfirmationDialog.dismiss(); + removeInvisibleElementScrollListener(listView); super.onDestroyView(view); } diff --git a/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateAdapter.java b/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateAdapter.java index 101af97ea..a7b5e14bc 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateAdapter.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateAdapter.java @@ -3,13 +3,10 @@ import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; -import android.os.Handler; -import android.os.Looper; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.accessibility.AccessibilityEvent; import android.widget.Button; import android.widget.ImageButton; import android.widget.TextView; @@ -30,9 +27,6 @@ import java.lang.annotation.RetentionPolicy; import java.time.Instant; import java.time.Month; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; import ee.ria.DigiDoc.R; import ee.ria.DigiDoc.android.Activity; diff --git a/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateSignatureAddDialog.java b/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateSignatureAddDialog.java index 20e5dba27..9ec0501c8 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateSignatureAddDialog.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateSignatureAddDialog.java @@ -1,7 +1,6 @@ package ee.ria.DigiDoc.android.signature.update; import android.content.Context; -import android.content.res.Configuration; import android.content.res.TypedArray; import android.view.View; import android.view.Window; @@ -23,10 +22,6 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static ee.ria.DigiDoc.android.Constants.VOID; import static ee.ria.DigiDoc.android.utils.display.DisplayUtil.getDeviceLayoutWidth; -import static ee.ria.DigiDoc.android.utils.display.DisplayUtil.getDeviceOrientation; -import static ee.ria.DigiDoc.android.utils.display.DisplayUtil.getDeviceWidth; -import static ee.ria.DigiDoc.android.utils.display.DisplayUtil.getDialogLandscapeWidth; -import static ee.ria.DigiDoc.android.utils.display.DisplayUtil.getDialogPortraitWidth; public final class SignatureUpdateSignatureAddDialog extends AlertDialog implements ContentView { diff --git a/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateView.java b/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateView.java index 076a9f03e..c8b1b9cab 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateView.java @@ -3,9 +3,9 @@ import static android.util.TypedValue.COMPLEX_UNIT_SP; import static android.view.accessibility.AccessibilityEvent.TYPE_ANNOUNCEMENT; import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; - +import static com.jakewharton.rxbinding4.view.RxView.clicks; +import static com.jakewharton.rxbinding4.widget.RxToolbar.navigationClicks; import static ee.ria.DigiDoc.android.utils.TintUtils.tintCompoundDrawables; -import static ee.ria.DigiDoc.android.utils.ViewUtil.moveView; import static ee.ria.DigiDoc.android.utils.rxbinding.app.RxDialog.cancels; import android.annotation.SuppressLint; @@ -16,7 +16,6 @@ import android.os.Parcelable; import android.util.TypedValue; import android.view.View; -import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.widget.Button; import android.widget.LinearLayout; @@ -64,9 +63,6 @@ import io.reactivex.rxjava3.subjects.PublishSubject; import io.reactivex.rxjava3.subjects.Subject; -import static com.jakewharton.rxbinding4.view.RxView.clicks; -import static com.jakewharton.rxbinding4.widget.RxToolbar.navigationClicks; - @SuppressLint("ViewConstructor") public final class SignatureUpdateView extends LinearLayout implements ContentView, MviView { @@ -206,10 +202,12 @@ public SignatureUpdateView(Context context, String screenId, boolean isExistingC setActionButtonsTextSize(); - addInvisibleElement(getContext(), this); + ContentView.addInvisibleElement(getContext(), this); View lastElementView = findViewById(R.id.lastInvisibleElement); - moveView(lastElementView); + lastElementView.setVisibility(VISIBLE); + + ContentView.addInvisibleElementScrollListener(listView, lastElementView); } @Override @@ -684,6 +682,7 @@ public void onDetachedFromWindow() { isTitleViewFocused = false; SignatureUpdateProgressBar.stopProgressBar(mobileIdProgressBar); SignatureUpdateProgressBar.stopProgressBar(smartIdProgressBar); + ContentView.removeInvisibleElementScrollListener(listView); super.onDetachedFromWindow(); } diff --git a/app/src/main/java/ee/ria/DigiDoc/android/utils/ViewUtil.java b/app/src/main/java/ee/ria/DigiDoc/android/utils/ViewUtil.java index 9749717c2..8fb4ce0cb 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/utils/ViewUtil.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/utils/ViewUtil.java @@ -6,7 +6,6 @@ import android.widget.LinearLayout; import android.widget.RelativeLayout; -import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.recyclerview.widget.RecyclerView; public class ViewUtil { @@ -43,9 +42,13 @@ public static View findMainLayoutElement(View view) { public static void moveView(View view) { if (view != null) { - LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) view.getLayoutParams(); - layoutParams.setMargins(layoutParams.leftMargin, -100, layoutParams.rightMargin, layoutParams.bottomMargin); - view.setLayoutParams(layoutParams); + ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); + + if (layoutParams instanceof ViewGroup.MarginLayoutParams) { + ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) layoutParams; + marginLayoutParams.setMargins(marginLayoutParams.leftMargin, -100, marginLayoutParams.rightMargin, marginLayoutParams.bottomMargin); + view.setLayoutParams(layoutParams); + } } } } diff --git a/app/src/main/java/ee/ria/DigiDoc/android/utils/navigator/ContentView.java b/app/src/main/java/ee/ria/DigiDoc/android/utils/navigator/ContentView.java index 9b2e6adb1..5f555ef96 100644 --- a/app/src/main/java/ee/ria/DigiDoc/android/utils/navigator/ContentView.java +++ b/app/src/main/java/ee/ria/DigiDoc/android/utils/navigator/ContentView.java @@ -1,31 +1,40 @@ package ee.ria.DigiDoc.android.utils.navigator; -import static ee.ria.DigiDoc.android.utils.TextUtil.getInvisibleElementTextView; -import static ee.ria.DigiDoc.android.utils.ViewUtil.findLastElement; import static ee.ria.DigiDoc.android.utils.ViewUtil.findMainLayoutElement; import android.content.Context; import android.view.View; -import android.view.ViewGroup; + +import androidx.recyclerview.widget.RecyclerView; + +import ee.ria.DigiDoc.BuildConfig; public interface ContentView { // Adds an invisible label element to the bottom of the view. // Used for autotests by testers - default void addInvisibleElement(Context context, View view) { - View mainLayoutElement = findMainLayoutElement(view); - if (mainLayoutElement instanceof ViewGroup) { - ((ViewGroup) mainLayoutElement).addView(getInvisibleElementTextView(context)); - } else if (mainLayoutElement != null && mainLayoutElement.getParent() instanceof ViewGroup) { - ((ViewGroup) mainLayoutElement.getParent()).addView(getInvisibleElementTextView(context)); + static void addInvisibleElement(Context context, View view) { + if (BuildConfig.DEBUG) { + View mainLayoutElement = findMainLayoutElement(view); + InvisibleView.addInvisibleElement(context, mainLayoutElement); } } static void addInvisibleElementToObject(Context context, View view) { - if (view instanceof ViewGroup) { - ((ViewGroup) view).addView(getInvisibleElementTextView(context)); - } else if (view != null && view.getParent() instanceof ViewGroup) { - ((ViewGroup) view.getParent()).addView(getInvisibleElementTextView(context)); + if (BuildConfig.DEBUG) { + InvisibleView.addInvisibleElementToObject(context, view); + } + } + + static void addInvisibleElementScrollListener(RecyclerView recyclerView, View lastElementView) { + if (BuildConfig.DEBUG) { + InvisibleView.addInvisibleElementScrollListener(recyclerView, lastElementView); + } + } + + static void removeInvisibleElementScrollListener(RecyclerView recyclerView) { + if (BuildConfig.DEBUG) { + InvisibleView.removeInvisibleElementScrollListener(recyclerView); } } } diff --git a/app/src/main/java/ee/ria/DigiDoc/android/utils/navigator/InvisibleView.java b/app/src/main/java/ee/ria/DigiDoc/android/utils/navigator/InvisibleView.java new file mode 100644 index 000000000..6a789f35d --- /dev/null +++ b/app/src/main/java/ee/ria/DigiDoc/android/utils/navigator/InvisibleView.java @@ -0,0 +1,70 @@ +package ee.ria.DigiDoc.android.utils.navigator; + +import static android.view.View.GONE; +import static android.view.View.VISIBLE; +import static ee.ria.DigiDoc.android.utils.TextUtil.getInvisibleElementTextView; +import static ee.ria.DigiDoc.android.utils.ViewUtil.moveView; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +public class InvisibleView implements ContentView { + + private static boolean hasInvisibleElementMoved = false; + private static RecyclerView.OnScrollListener recyclerViewOnScrollListener; + + protected static void addInvisibleElementToObject(Context context, View view) { + if (view instanceof ViewGroup) { + ((ViewGroup) view).addView(getInvisibleElementTextView(context)); + } else if (view != null && view.getParent() instanceof ViewGroup) { + ((ViewGroup) view.getParent()).addView(getInvisibleElementTextView(context)); + } + } + + protected static void addInvisibleElement(Context context, View mainLayout) { + if (mainLayout instanceof ViewGroup) { + ((ViewGroup) mainLayout).addView(getInvisibleElementTextView(context)); + } else if (mainLayout != null && mainLayout.getParent() instanceof ViewGroup) { + ((ViewGroup) mainLayout.getParent()).addView(getInvisibleElementTextView(context)); + } + } + + protected static void addInvisibleElementScrollListener(RecyclerView recyclerView, View lastElementView) { + if (!hasInvisibleElementMoved) { + moveView(lastElementView); + hasInvisibleElementMoved = true; + } + + recyclerView.addOnScrollListener( + recyclerViewOnScrollListener = new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + + LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); + int totalItemCount; + if (layoutManager != null) { + totalItemCount = layoutManager.getItemCount(); + + int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition(); + + if (lastVisibleItemPosition == totalItemCount - 1) { + lastElementView.setVisibility(VISIBLE); + } else { + lastElementView.setVisibility(GONE); + } + } + } + }); + } + + public static void removeInvisibleElementScrollListener(RecyclerView recyclerView) { + recyclerView.removeOnScrollListener(recyclerViewOnScrollListener); + hasInvisibleElementMoved = false; + } +} diff --git a/app/src/main/res/layout/main_about_screen.xml b/app/src/main/res/layout/main_about_screen.xml index fe2d66189..479dbfcb7 100644 --- a/app/src/main/res/layout/main_about_screen.xml +++ b/app/src/main/res/layout/main_about_screen.xml @@ -22,10 +22,25 @@ - + android:fillViewport="true" + app:layout_behavior="@string/appbar_scrolling_view_behavior"> + + + + + + + diff --git a/app/src/main/res/layout/signature_list_screen.xml b/app/src/main/res/layout/signature_list_screen.xml index 1a3a61c65..63e09c584 100644 --- a/app/src/main/res/layout/signature_list_screen.xml +++ b/app/src/main/res/layout/signature_list_screen.xml @@ -23,12 +23,20 @@ - + android:orientation="vertical"> + + + + @@ -113,6 +114,7 @@ +