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 70fc7ea6c..c51e2c82c 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; @@ -43,6 +44,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; @@ -55,7 +57,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"; @@ -377,8 +379,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); signButton.setEnabled(!activity); @@ -440,6 +442,12 @@ protected View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup disposables.add(viewModel.viewStates().subscribe(this::render)); viewModel.process(intents()); + ContentView.addInvisibleElement(getApplicationContext(), view); + + View lastElementView = view.findViewById(R.id.lastInvisibleElement); + + ContentView.addInvisibleElementScrollListener(listView, lastElementView); + return view; } @@ -448,6 +456,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 a77160966..73040bed8 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; @@ -48,6 +49,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; @@ -57,7 +59,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"; @@ -79,6 +81,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; @@ -333,13 +336,20 @@ 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); doneButton = view.findViewById(R.id.cryptoRecipientsDoneButton); activityOverlayView = view.findViewById(R.id.activityOverlay); activityIndicatorView = view.findViewById(R.id.activityIndicator); + + ContentView.addInvisibleElement(getApplicationContext(), view); + + View lastElementView = view.findViewById(R.id.lastInvisibleElement); + + ContentView.addInvisibleElementScrollListener(listView, lastElementView); + return view; } @@ -372,6 +382,7 @@ protected void onDetach(@NonNull View view) { disposables.detach(); navigator.removeBackButtonClickListener(this); searchView.setOnCloseListener(null); + ContentView.removeInvisibleElementScrollListener(listView); ee.ria.DigiDoc.android.utils.TextUtil.removeTextWatcher(searchViewInnerText,searchViewTextWatcher); 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 61a39ba06..f6490cb74 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 @@ -31,6 +31,7 @@ import ee.ria.DigiDoc.android.eid.CodeUpdateError.CodeSameAsCurrentError; import ee.ria.DigiDoc.android.eid.CodeUpdateError.CodeTooEasyError; 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; @@ -38,7 +39,7 @@ import static ee.ria.DigiDoc.android.utils.ErrorMessageUtil.setTextViewError; 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; @@ -88,6 +89,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); + + 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 d54abaea6..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 @@ -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( 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 301bd1e45..753454d62 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 -> ApplicationApp.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 fc2314ac5..70cfeb762 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.ApplicationApp; 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); + + 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 c2a041a21..e3b4e9009 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 = ApplicationApp.component(context).navigator(); + 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 7472b0816..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 @@ -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(); + + 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 00341bea3..920433634 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 = ApplicationApp.component(context).navigator().viewModel(screenId, HomeViewModel.class); viewModel.eidScreenId(eidScreenId); + + ContentView.addInvisibleElement(getContext(), 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 a6e1e8273..d8b1c4fa3 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,10 +16,11 @@ import ee.ria.DigiDoc.android.ApplicationApp; import ee.ria.DigiDoc.android.main.settings.access.SettingsAccessScreen; 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 final class SettingsView extends CoordinatorLayout { +public final class SettingsView extends CoordinatorLayout implements ContentView { private final Toolbar toolbarView; private final Button accessCategory; 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 f2a17eb73..e4afc6bdd 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.ApplicationApp; 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 = ApplicationApp.component(context).navigator() .viewModel(screenId, SignatureCreateViewModel.class); inflate(context, R.layout.signature_create, 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 d5d9b2db1..d9e8dbbfd 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 @@ -50,12 +50,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; @@ -76,6 +77,8 @@ public CertificateDetailView(Context context, X509Certificate certificate) { toolbarView.setNavigationContentDescription(R.string.back); setData(certificate); + + 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 f65da5d0c..d85a42f23 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 @@ -38,6 +38,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; @@ -48,7 +49,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; @@ -111,6 +112,8 @@ public SignatureDetailView(Context context, Signature signature, SignedContainer setExpandedState(false); setWarningsData(signature); setData(signature, signedContainer); + + 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 137792cc0..ec13af666 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 @@ -4,12 +4,16 @@ 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; @@ -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/SignatureUpdateSignatureAddDialog.java b/app/src/main/java/ee/ria/DigiDoc/android/signature/update/SignatureUpdateSignatureAddDialog.java index f833c2aa5..a5ab6c66e 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 @@ -25,10 +25,11 @@ 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; -public final class SignatureUpdateSignatureAddDialog extends AlertDialog { +public final class SignatureUpdateSignatureAddDialog extends AlertDialog implements ContentView { private final SignatureUpdateSignatureAddView view; private final ObservableDialogClickListener positiveButtonClicks; @@ -99,6 +100,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 522766afe..1a2a1623d 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 @@ -26,7 +26,6 @@ import android.widget.Button; import android.widget.LinearLayout; import android.widget.ProgressBar; -import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toolbar; @@ -57,6 +56,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; @@ -72,7 +72,7 @@ import io.reactivex.rxjava3.subjects.Subject; @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("adoc", "asics", "scs", "ddoc").build(); @@ -209,6 +209,13 @@ public SignatureUpdateView(Context context, String screenId, boolean isExistingC setupAccessibilityTabs(); setActionButtonsTextSize(); + + ContentView.addInvisibleElement(getContext(), this); + + View lastElementView = findViewById(R.id.lastInvisibleElement); + lastElementView.setVisibility(VISIBLE); + + ContentView.addInvisibleElementScrollListener(listView, lastElementView); } @Override @@ -713,6 +720,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/TextUtil.java b/app/src/main/java/ee/ria/DigiDoc/android/utils/TextUtil.java index f4e06db34..defc84103 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 @@ -2,9 +2,11 @@ import static android.util.TypedValue.COMPLEX_UNIT_PX; import static android.view.View.GONE; +import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO; import static android.view.View.VISIBLE; import android.content.Context; +import android.graphics.Color; import android.text.Editable; import android.text.Layout; import android.text.SpannableString; @@ -26,6 +28,8 @@ import com.google.android.material.textfield.TextInputLayout; +import ee.ria.DigiDoc.R; + public class TextUtil { public static AppCompatEditText getTextView(View view) { @@ -102,6 +106,22 @@ public static int convertPxToDp(float size, Context context) { 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; + } + public static TextWatcher addTextWatcher(EditText editText) { float defaultTextSize = editText.getTextSize(); 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..8fb4ce0cb --- /dev/null +++ b/app/src/main/java/ee/ria/DigiDoc/android/utils/ViewUtil.java @@ -0,0 +1,54 @@ +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.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) { + 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 new file mode 100644 index 000000000..5f555ef96 --- /dev/null +++ b/app/src/main/java/ee/ria/DigiDoc/android/utils/navigator/ContentView.java @@ -0,0 +1,40 @@ +package ee.ria.DigiDoc.android.utils.navigator; + +import static ee.ria.DigiDoc.android.utils.ViewUtil.findMainLayoutElement; + +import android.content.Context; +import android.view.View; + +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 + 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 (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/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/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 ea91e92a1..63e09c584 100644 --- a/app/src/main/res/layout/signature_list_screen.xml +++ b/app/src/main/res/layout/signature_list_screen.xml @@ -23,13 +23,25 @@ - + android:orientation="vertical"> + + + + + diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index 117ee3413..aa59bbc13 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 e72ec7c83..43994dce9 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -9,6 +9,7 @@ + @@ -81,6 +82,7 @@ + @@ -121,6 +123,7 @@ +