From a9f2f1fd288ed3096cca8842f8c187c46ec954f0 Mon Sep 17 00:00:00 2001 From: A117870935 Date: Thu, 25 May 2023 14:18:34 +0530 Subject: [PATCH] List divider added for tablet and landscape mode. --- .../com/nmc/android/utils/DisplayUtils.kt | 18 +++ .../ui/activity/UploadListActivity.java | 40 ++++++ .../SimpleListItemDividerDecoration.java | 22 +++- .../ui/fragment/OCFileListFragment.java | 123 ++++++++++++++++++ .../android/ui/trashbin/TrashbinActivity.kt | 38 ++++++ app/src/main/res/drawable/item_divider.xml | 6 + app/src/main/res/values-night/colors.xml | 64 +++++++++ app/src/main/res/values-sw480dp/bool.xml | 4 + app/src/main/res/values/bool.xml | 4 + app/src/main/res/values/colors.xml | 89 +++++++++++++ app/src/main/res/values/dimens.xml | 31 +++++ 11 files changed, 437 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/nmc/android/utils/DisplayUtils.kt create mode 100644 app/src/main/res/drawable/item_divider.xml create mode 100644 app/src/main/res/values-sw480dp/bool.xml create mode 100644 app/src/main/res/values/bool.xml create mode 100644 app/src/main/res/values/dimens.xml diff --git a/app/src/main/java/com/nmc/android/utils/DisplayUtils.kt b/app/src/main/java/com/nmc/android/utils/DisplayUtils.kt new file mode 100644 index 000000000000..f58e93c4252a --- /dev/null +++ b/app/src/main/java/com/nmc/android/utils/DisplayUtils.kt @@ -0,0 +1,18 @@ +package com.nmc.android.utils + +import android.content.res.Configuration +import com.owncloud.android.MainApp +import com.owncloud.android.R + +object DisplayUtils { + + @JvmStatic + fun isShowDividerForList(): Boolean = isTablet() || isLandscapeOrientation() + + @JvmStatic + fun isTablet(): Boolean = MainApp.getAppContext().resources.getBoolean(R.bool.isTablet) + + @JvmStatic + fun isLandscapeOrientation(): Boolean = + MainApp.getAppContext().resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE +} \ No newline at end of file diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java index 8d5e5ac5293c..27ed23f2487f 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java @@ -30,6 +30,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; +import android.content.res.Configuration; import android.os.Bundle; import android.os.IBinder; import android.view.Menu; @@ -58,11 +59,13 @@ import com.owncloud.android.ui.adapter.UploadListAdapter; import com.owncloud.android.ui.decoration.MediaGridItemDecoration; import com.owncloud.android.utils.DisplayUtils; +import com.owncloud.android.ui.decoration.SimpleListItemDividerDecoration; import com.owncloud.android.utils.FilesSyncHelper; import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; +import androidx.annotation.NonNull; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.recyclerview.widget.GridLayoutManager; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -110,6 +113,8 @@ public class UploadListActivity extends FileActivity { private UploadListLayoutBinding binding; + private SimpleListItemDividerDecoration simpleListItemDividerDecoration; + public static Intent createIntent(OCFile file, User user, Integer flag, Context context) { Intent intent = new Intent(context, UploadListActivity.class); if (flag != null) { @@ -174,6 +179,8 @@ private void setupContent() { int spacing = getResources().getDimensionPixelSize(R.dimen.media_grid_spacing); binding.list.addItemDecoration(new MediaGridItemDecoration(spacing)); binding.list.setLayoutManager(lm); + simpleListItemDividerDecoration = new SimpleListItemDividerDecoration(this, R.drawable.item_divider, true); + addListItemDecorator(); binding.list.setAdapter(uploadListAdapter); viewThemeUtils.androidx.themeSwipeRefreshLayout(swipeListRefreshLayout); @@ -182,6 +189,23 @@ private void setupContent() { loadItems(); } + private void addListItemDecorator() { + if (com.nmc.android.utils.DisplayUtils.isShowDividerForList()) { + //check and remove divider item decorator if exist then add item decorator + removeListDividerDecorator(); + binding.list.addItemDecoration(simpleListItemDividerDecoration); + } + } + + /** + * method to remove the divider item decorator + */ + private void removeListDividerDecorator() { + if (binding.list.getItemDecorationCount() > 0) { + binding.list.removeItemDecoration(simpleListItemDividerDecoration); + } + } + private void loadItems() { uploadListAdapter.loadUploadItemsFromDb(); @@ -372,4 +396,20 @@ public void onReceive(Context context, Intent intent) { }); } } + + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + super.onConfigurationChanged(newConfig); + //this should only run when device is not tablet because we are adding dividers in tablet for both the + // orientations + if (!com.nmc.android.utils.DisplayUtils.isTablet()) { + if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { + //add the divider item decorator when orientation is landscape + addListItemDecorator(); + } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { + //remove the divider item decorator when orientation is portrait + removeListDividerDecorator(); + } + } + } } diff --git a/app/src/main/java/com/owncloud/android/ui/decoration/SimpleListItemDividerDecoration.java b/app/src/main/java/com/owncloud/android/ui/decoration/SimpleListItemDividerDecoration.java index f4f705ed095b..6dc9de8a8bff 100644 --- a/app/src/main/java/com/owncloud/android/ui/decoration/SimpleListItemDividerDecoration.java +++ b/app/src/main/java/com/owncloud/android/ui/decoration/SimpleListItemDividerDecoration.java @@ -28,6 +28,7 @@ import android.util.DisplayMetrics; import android.view.View; +import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.RecyclerView; @@ -39,7 +40,8 @@ public class SimpleListItemDividerDecoration extends DividerItemDecoration { private final Rect bounds = new Rect(); private Drawable divider; - private int leftPadding; + private int leftPadding = 0; + private boolean hasFooter; /** * Default divider will be used @@ -52,6 +54,17 @@ public SimpleListItemDividerDecoration(Context context) { styledAttributes.recycle(); } + /** + * Custom divider will be used + * + * @param hasFooter if recyclerview has footer and no divider should be shown for footer then pass true else false + */ + public SimpleListItemDividerDecoration(Context context, int resId, boolean hasFooter) { + super(context, DividerItemDecoration.VERTICAL); + this.hasFooter = hasFooter; + divider = ContextCompat.getDrawable(context, resId); + } + @Override public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) { canvas.save(); @@ -65,7 +78,12 @@ public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) right = parent.getWidth(); } - final int childCount = parent.getChildCount(); + int childCount = parent.getChildCount(); + + if (hasFooter) { + childCount = childCount - 1; + } + for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); parent.getDecoratedBoundsWithMargins(child, bounds); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index ef302fedc124..f4ec6025f108 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -29,6 +29,7 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.content.res.Configuration; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; @@ -43,6 +44,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.view.ViewTreeObserver; import android.widget.AbsListView; import android.widget.Toast; @@ -62,6 +64,7 @@ import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ClientFactory; import com.nextcloud.client.preferences.AppPreferences; +import com.nextcloud.client.preferences.AppPreferencesImpl; import com.nextcloud.client.utils.Throttler; import com.nextcloud.common.NextcloudClient; import com.nextcloud.ui.fileactions.FileActionsBottomSheet; @@ -95,6 +98,8 @@ import com.owncloud.android.ui.activity.UploadFilesActivity; import com.owncloud.android.ui.adapter.CommonOCFileListAdapterInterface; import com.owncloud.android.ui.adapter.OCFileListAdapter; +import com.owncloud.android.ui.decoration.MediaGridItemDecoration; +import com.owncloud.android.ui.decoration.SimpleListItemDividerDecoration; import com.owncloud.android.ui.dialog.ChooseRichDocumentsTemplateDialogFragment; import com.owncloud.android.ui.dialog.ChooseTemplateDialogFragment; import com.owncloud.android.ui.dialog.ConfirmationDialogFragment; @@ -237,6 +242,9 @@ public class OCFileListFragment extends ExtendedListFragment implements protected String mLimitToMimeType; private FloatingActionButton mFabMain; + private SimpleListItemDividerDecoration simpleListItemDividerDecoration; + private MediaGridItemDecoration mediaGridItemDecoration; + @Inject DeviceInfo deviceInfo; protected enum MenuItemAddRemove { @@ -250,6 +258,13 @@ protected enum MenuItemAddRemove { private List mOriginalMenuItems = new ArrayList<>(); + private int maxColumnSizeLandscape = 5; + + //this variable will help us to provide number of span count for grid view + //the width for single item is approx to 360 + private static final int GRID_ITEM_DEFAULT_WIDTH = 360; + private static final int DEFAULT_FALLBACK_SPAN_COUNT = 1; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -448,6 +463,10 @@ protected void setAdapter(Bundle args) { viewThemeUtils ); + simpleListItemDividerDecoration = new SimpleListItemDividerDecoration(getContext(), R.drawable.item_divider, true); + int spacing = getResources().getDimensionPixelSize(R.dimen.media_grid_spacing); + mediaGridItemDecoration = new MediaGridItemDecoration(spacing); + setRecyclerViewAdapter(mAdapter); fastScrollUtils.applyFastScroll(getRecyclerView()); @@ -1430,6 +1449,7 @@ public void switchToListView() { if (isGridEnabled()) { switchLayoutManager(false); } + addRemoveRecyclerViewItemDecorator(); } public void setGridAsPreferred() { @@ -1441,6 +1461,33 @@ public void switchToGridView() { if (!isGridEnabled()) { switchLayoutManager(true); } + addRemoveRecyclerViewItemDecorator(); + } + + private void addRemoveRecyclerViewItemDecorator() { + if (getRecyclerView().getLayoutManager() instanceof GridLayoutManager) { + removeItemDecorator(); + if (getRecyclerView().getItemDecorationCount() == 0) { + getRecyclerView().addItemDecoration(mediaGridItemDecoration); + int padding = getResources().getDimensionPixelSize(R.dimen.grid_recyclerview_padding); + getRecyclerView().setPadding(padding, padding, padding, padding); + } + } else { + removeItemDecorator(); + if (getRecyclerView().getItemDecorationCount() == 0 && com.nmc.android.utils.DisplayUtils.isShowDividerForList()) { + getRecyclerView().addItemDecoration(simpleListItemDividerDecoration); + getRecyclerView().setPadding(0, 0, 0, 0); + } + } + } + + /** + * method to remove the item decorator + */ + private void removeItemDecorator() { + while (getRecyclerView().getItemDecorationCount() > 0) { + getRecyclerView().removeItemDecorationAt(0); + } } public void switchLayoutManager(boolean grid) { @@ -1471,12 +1518,40 @@ public int getSpanSize(int position) { } getRecyclerView().setLayoutManager(layoutManager); + updateSpanCount(getResources().getConfiguration()); getRecyclerView().scrollToPosition(position); getAdapter().setGridView(grid); getRecyclerView().setAdapter(getAdapter()); getAdapter().notifyDataSetChanged(); } + /** + * method will calculate the number of spans required for grid item and will update the span accordingly + * + * @param isGrid + */ + private void calculateAndUpdateSpanCount(boolean isGrid) { + getRecyclerView().getViewTreeObserver().addOnGlobalLayoutListener( + new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + getRecyclerView().getViewTreeObserver().removeOnGlobalLayoutListener(this); + if (isGrid) { + int viewWidth = getRecyclerView().getMeasuredWidth(); + int newSpanCount = viewWidth / GRID_ITEM_DEFAULT_WIDTH; + RecyclerView.LayoutManager layoutManager = getRecyclerView().getLayoutManager(); + if (layoutManager instanceof GridLayoutManager) { + if (newSpanCount < 1) { + newSpanCount = DEFAULT_FALLBACK_SPAN_COUNT; + } + ((GridLayoutManager) layoutManager).setSpanCount(newSpanCount); + layoutManager.requestLayout(); + } + } + } + }); + } + public CommonOCFileListAdapterInterface getCommonAdapter() { return mAdapter; } @@ -2033,4 +2108,52 @@ public void setFabEnabled(final boolean enabled) { public boolean isEmpty() { return mAdapter == null || mAdapter.isEmpty(); } + + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (getAdapter() != null) { + getAdapter().notifyDataSetChanged(); + } + updateSpanCount(newConfig); + } + + /** + * method will update the span count on basis of device orientation for the file listing + * + * @param newConfig current configuration + */ + private void updateSpanCount(Configuration newConfig) { + //this should only run when current view is not media gallery + if (getAdapter() != null) { + int maxColumnSize = (int) AppPreferencesImpl.DEFAULT_GRID_COLUMN; + if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { + //add the divider item decorator when orientation is landscape and device is not tablet + //because we don't have to add divider again as it is already added + if (!com.nmc.android.utils.DisplayUtils.isTablet()) { + addRemoveRecyclerViewItemDecorator(); + } + maxColumnSize = maxColumnSizeLandscape; + } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { + //remove the divider item decorator when orientation is portrait and when device is not tablet + //because we have to show divider in both landscape and portrait mode + if (!com.nmc.android.utils.DisplayUtils.isTablet()) { + removeItemDecorator(); + } + maxColumnSize = (int) AppPreferencesImpl.DEFAULT_GRID_COLUMN; + } + + if (isGridEnabled()) { + //for tablet calculate size on the basis of screen width + if (com.nmc.android.utils.DisplayUtils.isTablet()) { + calculateAndUpdateSpanCount(true); + } else { + //and for phones directly show the hardcoded column size + if (getRecyclerView().getLayoutManager() instanceof GridLayoutManager) { + ((GridLayoutManager) getRecyclerView().getLayoutManager()).setSpanCount(maxColumnSize); + } + } + } + } + } } diff --git a/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt b/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt index ff99ef902406..1975e1159ecf 100644 --- a/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt @@ -24,6 +24,7 @@ package com.owncloud.android.ui.trashbin import android.content.Intent +import android.content.res.Configuration import android.os.Bundle import android.view.Menu import android.view.MenuItem @@ -45,6 +46,7 @@ import com.owncloud.android.databinding.TrashbinActivityBinding import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile import com.owncloud.android.ui.activity.DrawerActivity import com.owncloud.android.ui.adapter.TrashbinListAdapter +import com.owncloud.android.ui.decoration.SimpleListItemDividerDecoration import com.owncloud.android.ui.dialog.SortingOrderDialogFragment.OnSortingOrderListener import com.owncloud.android.ui.interfaces.TrashbinActivityInterface import com.owncloud.android.utils.DisplayUtils @@ -86,6 +88,8 @@ class TrashbinActivity : private var active = false private lateinit var binding: TrashbinActivityBinding + private var simpleListItemDividerDecoration: SimpleListItemDividerDecoration? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -158,6 +162,8 @@ class TrashbinActivity : recyclerView.setHasFixedSize(true) recyclerView.setHasFooter(true) recyclerView.layoutManager = LinearLayoutManager(this) + simpleListItemDividerDecoration = SimpleListItemDividerDecoration(this, R.drawable.item_divider, true) + addListItemDecorator() viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeContainingList) binding.swipeContainingList.setOnRefreshListener { loadFolder() } @@ -178,6 +184,23 @@ class TrashbinActivity : handleOnBackPressed() } + private fun addListItemDecorator() { + if (com.nmc.android.utils.DisplayUtils.isShowDividerForList()) { + // check and remove divider item decorator if exist then add item decorator + removeListDividerDecorator() + binding.list.addItemDecoration(simpleListItemDividerDecoration!!) + } + } + + /** + * method to remove the divider item decorator + */ + private fun removeListDividerDecorator() { + if (binding.list.itemDecorationCount > 0) { + binding.list.removeItemDecoration(simpleListItemDividerDecoration!!) + } + } + private fun handleOnBackPressed() { onBackPressedDispatcher.addCallback( this, @@ -334,6 +357,21 @@ class TrashbinActivity : } } + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + // this should only run when device is not tablet because we are adding dividers in tablet for both the + // orientations + if (!com.nmc.android.utils.DisplayUtils.isTablet()) { + if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { + // add the divider item decorator when orientation is landscape + addListItemDecorator() + } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { + // remove the divider item decorator when orientation is portrait + removeListDividerDecorator() + } + } + } + companion object { const val EMPTY_LIST_COUNT = 1 } diff --git a/app/src/main/res/drawable/item_divider.xml b/app/src/main/res/drawable/item_divider.xml new file mode 100644 index 000000000000..9f742e91d67c --- /dev/null +++ b/app/src/main/res/drawable/item_divider.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index 08bf64d552ad..e926fdcc432f 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -48,4 +48,68 @@ #1E1E1E @android:color/white + + + #FFFFFF + @color/grey_30 + @color/grey_30 + #CCCCCC + @color/grey_70 + @color/grey_80 + #2D2D2D + @color/grey_70 + @color/grey_70 + + + @color/grey_80 + @color/grey_0 + + + @color/grey_80 + @color/grey_0 + + + @color/grey_60 + @color/grey_0 + @color/grey_0 + @color/grey_30 + #FFFFFF + @color/grey_30 + @color/grey_80 + #FFFFFF + + + @color/grey_80 + @color/grey_30 + @color/grey_0 + + + @color/grey_80 + @color/grey_0 + @color/grey_80 + + + @color/grey_70 + @color/grey_60 + + + @color/grey_70 + @color/grey_70 + + + #FFFFFF + @color/grey_30 + @color/grey_0 + @color/grey_0 + @color/grey_0 + @color/grey_0 + @color/grey_60 + @color/grey_0 + #FFFFFF + + + #121212 + @color/grey_0 + @color/grey_80 + @color/grey_80 diff --git a/app/src/main/res/values-sw480dp/bool.xml b/app/src/main/res/values-sw480dp/bool.xml new file mode 100644 index 000000000000..8e66f10e898c --- /dev/null +++ b/app/src/main/res/values-sw480dp/bool.xml @@ -0,0 +1,4 @@ + + + true + diff --git a/app/src/main/res/values/bool.xml b/app/src/main/res/values/bool.xml new file mode 100644 index 000000000000..c2dcd8baf0ea --- /dev/null +++ b/app/src/main/res/values/bool.xml @@ -0,0 +1,4 @@ + + + false + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 58fcdecf1fc2..b05b582157a7 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -82,4 +82,93 @@ @android:color/white #666666 #A5A5A5 + + + #191919 + @color/primary + #191919 + #191919 + @color/grey_30 + @android:color/white + #FFFFFF + @color/grey_0 + #CCCCCC + #77c4ff + #B3FFFFFF + @color/grey_10 + + + #101010 + #F2F2F2 + #E5E5E5 + #B2B2B2 + #666666 + #4C4C4C + #333333 + + + @color/design_snackbar_background_color + @color/white + + + #FFFFFF + #191919 + + + @color/grey_0 + #191919 + @color/primary + #191919 + @color/primary + @color/grey_30 + @color/white + #191919 + + + #FFFFFF + #191919 + #191919 + + + #FFFFFF + #191919 + #FFFFFF + + + @color/primary + #F399C7 + #FFFFFF + @color/grey_30 + @color/grey_10 + @color/grey_0 + + + @color/primary + @color/grey_30 + @color/grey_30 + #CCCCCC + + + #191919 + @color/grey_30 + #191919 + #191919 + #191919 + #191919 + @color/grey_30 + #191919 + #000000 + #191919 + #F6E5EB + #C16F81 + #0D39DF + #0099ff + + + @color/grey_0 + #191919 + @color/grey_0 + @color/grey_30 + #77b6bb + #5077b6bb diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 000000000000..cc9e25255a10 --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,31 @@ + + + 4dp + 16dp + 24dp + 6dp + 18sp + 15sp + 15dp + 56dp + 86dp + 80dp + 11sp + 30dp + 55dp + 258dp + 17sp + 20dp + 160dp + 50dp + 150dp + 55dp + 48dp + 48dp + 24dp + 26dp + 20sp + 145dp + 1dp + 13sp + \ No newline at end of file