From 0c79a6eb2cd1db93506aec66b529d9651ec799ae Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Fri, 30 Aug 2024 14:05:30 +0200 Subject: [PATCH 1/9] Improved the progress bar implementation --- .../androidshared/ui/ObviousProgressBar.kt | 15 +++++++++++---- .../src/main/res/layout/app_bar_layout.xml | 7 +------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/androidshared/src/main/java/org/odk/collect/androidshared/ui/ObviousProgressBar.kt b/androidshared/src/main/java/org/odk/collect/androidshared/ui/ObviousProgressBar.kt index 00fa7d6d6d5..b5fe3939271 100644 --- a/androidshared/src/main/java/org/odk/collect/androidshared/ui/ObviousProgressBar.kt +++ b/androidshared/src/main/java/org/odk/collect/androidshared/ui/ObviousProgressBar.kt @@ -3,23 +3,30 @@ package org.odk.collect.androidshared.ui import android.content.Context import android.os.Handler import android.util.AttributeSet -import android.widget.ProgressBar +import com.google.android.material.progressindicator.LinearProgressIndicator /** * A progress bar that shows for a minimum amount fo time so it's obvious to the user that * something has happened. */ -class ObviousProgressBar(context: Context, attrs: AttributeSet?) : ProgressBar(context, attrs) { +class ObviousProgressBar( + context: Context, + attrs: AttributeSet? +) : LinearProgressIndicator(context, attrs) { private val handler = Handler() private var shownAt: Long? = null - fun show() { + init { + super.setVisibility(GONE) + } + + override fun show() { handler.removeCallbacksAndMessages(null) shownAt = System.currentTimeMillis() super.setVisibility(VISIBLE) } - fun hide() { + override fun hide() { if (shownAt != null) { val timeShown = System.currentTimeMillis() - shownAt!! diff --git a/androidshared/src/main/res/layout/app_bar_layout.xml b/androidshared/src/main/res/layout/app_bar_layout.xml index 9491eb32aeb..fa4e022dd2e 100644 --- a/androidshared/src/main/res/layout/app_bar_layout.xml +++ b/androidshared/src/main/res/layout/app_bar_layout.xml @@ -13,11 +13,6 @@ + android:layout_height="wrap_content" /> From f0bfc8d5030e55a6fa8e6daf2b9a728aea37435c Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Sat, 31 Aug 2024 21:44:52 +0200 Subject: [PATCH 2/9] Fixed the problem with flashing app bar in form entry --- .../odk/collect/android/activities/FormFillingActivity.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/collect_app/src/main/java/org/odk/collect/android/activities/FormFillingActivity.java b/collect_app/src/main/java/org/odk/collect/android/activities/FormFillingActivity.java index 751b787aec2..db817fc8d02 100644 --- a/collect_app/src/main/java/org/odk/collect/android/activities/FormFillingActivity.java +++ b/collect_app/src/main/java/org/odk/collect/android/activities/FormFillingActivity.java @@ -65,6 +65,7 @@ import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.ViewModelProvider; +import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import org.javarosa.core.model.FormDef; @@ -263,6 +264,7 @@ public class FormFillingActivity extends LocalizedActivity implements AnimationL private Animation inAnimation; private Animation outAnimation; + private AppBarLayout appBarLayout; private FrameLayout questionHolder; private SwipeHandler.View currentView; @@ -468,6 +470,7 @@ public void onCreate(Bundle savedInstanceState) { formError = null; + appBarLayout = findViewById(org.odk.collect.androidshared.R.id.appBarLayout); questionHolder = findViewById(R.id.questionholder); initToolbar(); @@ -1417,6 +1420,7 @@ public void showView(SwipeHandler.View next, FormAnimationType from) { } else { animationCompletionSet = 2; } + appBarLayout.setLiftOnScrollTargetViewId(R.id.odk_view_container); // start InAnimation for transition... currentView.startAnimation(inAnimation); From e4f213a9902247397695eeecc88634cd7fbcce78 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Fri, 30 Aug 2024 16:34:32 +0200 Subject: [PATCH 3/9] Fixed flashing app bar in form lists --- androidshared/src/main/res/layout/app_bar_layout.xml | 4 +++- .../org/odk/collect/android/activities/AppListActivity.java | 2 +- .../instancemanagement/send/InstanceUploaderListActivity.java | 2 +- collect_app/src/main/res/layout/form_chooser_list.xml | 2 +- collect_app/src/main/res/layout/form_download_list.xml | 2 +- collect_app/src/main/res/layout/instance_uploader_list.xml | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/androidshared/src/main/res/layout/app_bar_layout.xml b/androidshared/src/main/res/layout/app_bar_layout.xml index fa4e022dd2e..861a0acc11d 100644 --- a/androidshared/src/main/res/layout/app_bar_layout.xml +++ b/androidshared/src/main/res/layout/app_bar_layout.xml @@ -1,9 +1,11 @@ + android:layout_height="wrap_content" + app:liftOnScrollTargetViewId="@+id/scrollable_container"> Date: Sat, 31 Aug 2024 21:52:50 +0200 Subject: [PATCH 4/9] Added a comment --- androidshared/src/main/res/layout/app_bar_layout.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/androidshared/src/main/res/layout/app_bar_layout.xml b/androidshared/src/main/res/layout/app_bar_layout.xml index 861a0acc11d..2d7c029ce20 100644 --- a/androidshared/src/main/res/layout/app_bar_layout.xml +++ b/androidshared/src/main/res/layout/app_bar_layout.xml @@ -1,4 +1,16 @@ + Date: Mon, 2 Sep 2024 14:13:33 +0200 Subject: [PATCH 5/9] Improved the appbar layout to avoid jumping views --- .../src/main/res/layout/app_bar_layout.xml | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/androidshared/src/main/res/layout/app_bar_layout.xml b/androidshared/src/main/res/layout/app_bar_layout.xml index 2d7c029ce20..e832d66e73f 100644 --- a/androidshared/src/main/res/layout/app_bar_layout.xml +++ b/androidshared/src/main/res/layout/app_bar_layout.xml @@ -19,14 +19,23 @@ android:layout_height="wrap_content" app:liftOnScrollTargetViewId="@+id/scrollable_container"> - + android:layout_height="wrap_content"> - + + + + From 550892d3ef3e573193b5fa2162d1f7f596bbc421 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Mon, 2 Sep 2024 14:21:13 +0200 Subject: [PATCH 6/9] Fixed other layouts that could not work properly with the appbar --- .../src/main/res/layout/manual_project_creator_dialog_layout.xml | 1 + .../main/res/layout/qr_code_project_creator_dialog_layout.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/collect_app/src/main/res/layout/manual_project_creator_dialog_layout.xml b/collect_app/src/main/res/layout/manual_project_creator_dialog_layout.xml index 5002b5f96b8..0e5a8d7a52d 100644 --- a/collect_app/src/main/res/layout/manual_project_creator_dialog_layout.xml +++ b/collect_app/src/main/res/layout/manual_project_creator_dialog_layout.xml @@ -15,6 +15,7 @@ app:layout_behavior="@string/appbar_scrolling_view_behavior"> Date: Mon, 2 Sep 2024 16:46:50 +0200 Subject: [PATCH 7/9] Fixed updating appbar color in viewpager --- .../src/main/res/layout/app_bar_layout.xml | 7 ++++--- .../blankformlist/DeleteBlankFormFragment.kt | 13 ++++++++++++- .../savedformlist/DeleteSavedFormFragment.kt | 13 ++++++++++++- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/androidshared/src/main/res/layout/app_bar_layout.xml b/androidshared/src/main/res/layout/app_bar_layout.xml index e832d66e73f..f9ad565a70c 100644 --- a/androidshared/src/main/res/layout/app_bar_layout.xml +++ b/androidshared/src/main/res/layout/app_bar_layout.xml @@ -7,9 +7,10 @@ whether it should lift by setting `app:liftOnScrollTargetViewId` to the ID of the scrolling view. Since this `AppBarLayout` is used throughout the app with various scrolling views, it’s best to use a shared ID like `scrollable_container`. - If the scrollable view is added programmatically, it may not work as expected anyway, and - `app:liftOnScrollTargetViewId` might need to be updated programmatically after adding such a view. - The `ODKView` and its `odk_view_container` is a good example of this scenario. + If the scrollable view is added programmatically or it is displayed in a `ViewPager` with a + shared id, it may not work as expected anyway, and `app:liftOnScrollTargetViewId` might + need to be updated programmatically after adding such a view. + The `ODKView` and its `odk_view_container` or `DeleteFormsActivity` are good examples of this scenario. --> Date: Thu, 5 Sep 2024 13:24:59 +0200 Subject: [PATCH 8/9] Make sure ObviousProgressBar is indeterminate --- .../java/org/odk/collect/androidshared/ui/ObviousProgressBar.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/androidshared/src/main/java/org/odk/collect/androidshared/ui/ObviousProgressBar.kt b/androidshared/src/main/java/org/odk/collect/androidshared/ui/ObviousProgressBar.kt index b5fe3939271..44315dc6a47 100644 --- a/androidshared/src/main/java/org/odk/collect/androidshared/ui/ObviousProgressBar.kt +++ b/androidshared/src/main/java/org/odk/collect/androidshared/ui/ObviousProgressBar.kt @@ -18,6 +18,7 @@ class ObviousProgressBar( init { super.setVisibility(GONE) + super.setIndeterminate(true) } override fun show() { From e1f735f81339390efaa7f6ed9b2522e619ed7ac2 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Wed, 11 Sep 2024 20:03:22 +0200 Subject: [PATCH 9/9] Moved calling #setLiftOnScrollTargetView to MultiSelectListFragment --- .../blankformlist/DeleteBlankFormFragment.kt | 13 +------------ .../savedformlist/DeleteSavedFormFragment.kt | 13 +------------ .../lists/selects/MultiSelectListFragment.kt | 18 ++++++++++++++++-- 3 files changed, 18 insertions(+), 26 deletions(-) diff --git a/collect_app/src/main/java/org/odk/collect/android/formlists/blankformlist/DeleteBlankFormFragment.kt b/collect_app/src/main/java/org/odk/collect/android/formlists/blankformlist/DeleteBlankFormFragment.kt index 6eeaed8f88c..a56beebaa52 100644 --- a/collect_app/src/main/java/org/odk/collect/android/formlists/blankformlist/DeleteBlankFormFragment.kt +++ b/collect_app/src/main/java/org/odk/collect/android/formlists/blankformlist/DeleteBlankFormFragment.kt @@ -12,8 +12,6 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle.State import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.map -import androidx.recyclerview.widget.RecyclerView -import com.google.android.material.appbar.AppBarLayout import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.odk.collect.android.R import org.odk.collect.androidshared.ui.FragmentFactoryBuilder @@ -44,8 +42,6 @@ class DeleteBlankFormFragment( } ) } - private var appBarLayout: AppBarLayout? = null - private lateinit var list: RecyclerView override fun onAttach(context: Context) { super.onAttach(context) @@ -61,8 +57,7 @@ class DeleteBlankFormFragment( it.empty.setTitle(getString(string.empty_list_of_forms_to_delete_title)) it.empty.setSubtitle(getString(string.empty_list_of_blank_forms_to_delete_subtitle)) - list = it.list - list.addItemDecoration(RecyclerViewUtils.verticalLineDivider(context)) + it.list.addItemDecoration(RecyclerViewUtils.verticalLineDivider(context)) } } .build() @@ -85,17 +80,11 @@ class DeleteBlankFormFragment( } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - appBarLayout = requireActivity().findViewById(org.odk.collect.androidshared.R.id.appBarLayout) val blankFormListMenuProvider = BlankFormListMenuProvider(requireActivity(), blankFormListViewModel) menuHost.addMenuProvider(blankFormListMenuProvider, viewLifecycleOwner, State.RESUMED) } - override fun onResume() { - super.onResume() - appBarLayout?.setLiftOnScrollTargetView(list) - } - private fun onDeleteSelected(selected: LongArray) { MaterialAlertDialogBuilder(requireContext()) .setTitle(string.delete_file) diff --git a/collect_app/src/main/java/org/odk/collect/android/formlists/savedformlist/DeleteSavedFormFragment.kt b/collect_app/src/main/java/org/odk/collect/android/formlists/savedformlist/DeleteSavedFormFragment.kt index 0985f178f1e..8271ddb9650 100644 --- a/collect_app/src/main/java/org/odk/collect/android/formlists/savedformlist/DeleteSavedFormFragment.kt +++ b/collect_app/src/main/java/org/odk/collect/android/formlists/savedformlist/DeleteSavedFormFragment.kt @@ -11,8 +11,6 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.map -import androidx.recyclerview.widget.RecyclerView -import com.google.android.material.appbar.AppBarLayout import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.odk.collect.analytics.Analytics import org.odk.collect.android.R @@ -48,8 +46,6 @@ class DeleteSavedFormFragment( } ) } - private var appBarLayout: AppBarLayout? = null - private lateinit var list: RecyclerView override fun onAttach(context: Context) { super.onAttach(context) @@ -65,8 +61,7 @@ class DeleteSavedFormFragment( it.empty.setTitle(getString(string.empty_list_of_forms_to_delete_title)) it.empty.setSubtitle(getString(string.empty_list_of_saved_forms_to_delete_subtitle)) - list = it.list - list.addItemDecoration(RecyclerViewUtils.verticalLineDivider(context)) + it.list.addItemDecoration(RecyclerViewUtils.verticalLineDivider(context)) } } .build() @@ -93,7 +88,6 @@ class DeleteSavedFormFragment( } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - appBarLayout = requireActivity().findViewById(org.odk.collect.androidshared.R.id.appBarLayout) menuHost?.addMenuProvider( SavedFormListListMenuProvider(requireContext(), savedFormListViewModel), viewLifecycleOwner, @@ -111,11 +105,6 @@ class DeleteSavedFormFragment( } } - override fun onResume() { - super.onResume() - appBarLayout?.setLiftOnScrollTargetView(list) - } - private fun onDeleteSelected(selected: LongArray) { MaterialAlertDialogBuilder(requireContext()) .setTitle(string.delete_file) diff --git a/lists/src/main/java/org/odk/collect/lists/selects/MultiSelectListFragment.kt b/lists/src/main/java/org/odk/collect/lists/selects/MultiSelectListFragment.kt index 389cc356d21..00f0e4b66d4 100644 --- a/lists/src/main/java/org/odk/collect/lists/selects/MultiSelectListFragment.kt +++ b/lists/src/main/java/org/odk/collect/lists/selects/MultiSelectListFragment.kt @@ -8,6 +8,8 @@ import android.view.ViewGroup import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.appbar.AppBarLayout import org.odk.collect.androidshared.ui.FragmentFactoryBuilder import org.odk.collect.lists.R import org.odk.collect.lists.databinding.MultiSelectListBinding @@ -19,6 +21,9 @@ class MultiSelectListFragment>( private val onViewCreated: (MultiSelectListBinding) -> Unit = {} ) : Fragment() { + private var appBarLayout: AppBarLayout? = null + private lateinit var list: RecyclerView + override fun onAttach(context: Context) { super.onAttach(context) @@ -50,15 +55,19 @@ class MultiSelectListFragment>( } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + appBarLayout = requireActivity().findViewById(org.odk.collect.androidshared.R.id.appBarLayout) + val binding = MultiSelectListBinding.bind(view) onViewCreated(binding) - binding.list.layoutManager = LinearLayoutManager(requireContext()) + list = binding.list + list.layoutManager = LinearLayoutManager(requireContext()) val adapter = MultiSelectAdapter( multiSelectViewModel, viewHolderFactory ) - binding.list.adapter = adapter + list.adapter = adapter + multiSelectViewModel.getData().observe(viewLifecycleOwner) { adapter.data = it binding.empty.isVisible = it.isEmpty() @@ -68,4 +77,9 @@ class MultiSelectListFragment>( adapter.selected = it } } + + override fun onResume() { + super.onResume() + appBarLayout?.setLiftOnScrollTargetView(list) + } }