Skip to content

Commit

Permalink
Merge pull request #12278 from nextcloud/feature/new_grid-layout
Browse files Browse the repository at this point in the history
New Grid Layout
  • Loading branch information
alperozturk96 authored Dec 21, 2023
2 parents 2df8096 + d3ab706 commit 251ef24
Show file tree
Hide file tree
Showing 15 changed files with 514 additions and 273 deletions.
46 changes: 46 additions & 0 deletions app/src/main/java/com/nextcloud/utils/extensions/ViewExtensions.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Nextcloud Android client application
*
* @author Alper Ozturk
* Copyright (C) 2023 Alper Ozturk
* Copyright (C) 2023 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.nextcloud.utils.extensions

import android.content.Context
import android.graphics.Outline
import android.util.TypedValue
import android.view.View
import android.view.ViewOutlineProvider

fun createRoundedOutline(context: Context, cornerRadiusValue: Float): ViewOutlineProvider {
return object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
val left = 0
val top = 0
val right = view.width
val bottom = view.height
val cornerRadius = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
cornerRadiusValue,
context.resources.displayMetrics
).toInt()

outline.setRoundRect(left, top, right, bottom, cornerRadius.toFloat())
}
}
}
1 change: 0 additions & 1 deletion app/src/main/java/com/owncloud/android/MainApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@
* Contains methods to build the "static" strings. These strings were before constants in different classes
*/
public class MainApp extends MultiDexApplication implements HasAndroidInjector {

public static final OwnCloudVersion OUTDATED_SERVER_VERSION = NextcloudVersion.nextcloud_23;
public static final OwnCloudVersion MINIMUM_SUPPORTED_SERVER_VERSION = OwnCloudVersion.nextcloud_16;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
package com.owncloud.android.ui.adapter

import android.view.View
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import com.elyeproj.loaderviewlibrary.LoaderImageView

Expand All @@ -32,12 +34,14 @@ interface ListGridImageViewHolder {
val shimmerThumbnail: LoaderImageView
val favorite: ImageView
val localFileIndicator: ImageView
val imageFileName: TextView?
val shared: ImageView
val checkbox: ImageView
val itemLayout: View
val unreadComments: ImageView

val gridLivePhotoIndicator: TextView?
val more: ImageButton?
val fileFeaturesLayout: LinearLayout?
val gridLivePhotoIndicator: ImageView?
val livePhotoIndicator: TextView?
val livePhotoIndicatorSeparator: TextView?
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import android.widget.LinearLayout;
import android.widget.TextView;

import com.nextcloud.android.common.ui.theme.utils.ColorRole;
import com.nextcloud.client.preferences.AppPreferences;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
Expand All @@ -54,6 +55,7 @@

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;

/**
Expand Down Expand Up @@ -186,11 +188,10 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi
} else {
gridViewHolder.checkbox.setVisibility(View.VISIBLE);
if (isCheckedFile(file)) {
gridViewHolder.itemLayout.setBackgroundColor(mContext.getResources()
.getColor(R.color.selected_item_background));
gridViewHolder.itemLayout.setBackgroundColor(ContextCompat.getColor(mContext, R.color.selected_item_background));

gridViewHolder.checkbox.setImageDrawable(
viewThemeUtils.platform.tintPrimaryDrawable(mContext, R.drawable.ic_checkbox_marked));
viewThemeUtils.platform.tintDrawable(mContext, R.drawable.ic_checkbox_marked, ColorRole.PRIMARY));
} else {
gridViewHolder.itemLayout.setBackgroundColor(mContext.getResources().getColor(R.color.bg_default));
gridViewHolder.checkbox.setImageResource(R.drawable.ic_checkbox_blank_outline);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.elyeproj.loaderviewlibrary.LoaderImageView;
import com.nextcloud.android.common.ui.theme.utils.ColorRole;
Expand Down Expand Up @@ -300,6 +302,7 @@ public long getItemId(int position) {
return headerId;
}


// skip header
position--;
}
Expand Down Expand Up @@ -365,8 +368,7 @@ public boolean isEmpty() {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
switch (viewType) {
default:
case VIEWTYPE_ITEM:
default -> {
if (gridView) {
return new OCFileListGridItemViewHolder(
GridItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
Expand All @@ -376,8 +378,8 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int
ListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
);
}

case VIEWTYPE_IMAGE:
}
case VIEWTYPE_IMAGE -> {
if (gridView) {
return new OCFileListGridImageViewHolder(
GridImageBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
Expand All @@ -387,23 +389,22 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int
ListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
);
}

case VIEWTYPE_FOOTER:
}
case VIEWTYPE_FOOTER -> {
return new OCFileListFooterViewHolder(
ListFooterBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)
);

case VIEWTYPE_HEADER:
}
case VIEWTYPE_HEADER -> {
ListHeaderBinding binding = ListHeaderBinding.inflate(
LayoutInflater.from(parent.getContext()),
parent,
false);

ViewGroup.LayoutParams layoutParams = binding.headerView.getLayoutParams();
layoutParams.height = (int) (parent.getHeight() * 0.3);
binding.headerView.setLayoutParams(layoutParams);

return new OCFileListHeaderViewHolder(binding);
}
}
}

Expand All @@ -430,19 +431,54 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi
}

ocFileListDelegate.bindGridViewHolder(gridViewHolder, file, searchType);
checkVisibilityOfMoreButtons(gridViewHolder);
checkVisibilityOfFileFeaturesLayout(gridViewHolder);

if (holder instanceof ListItemViewHolder) {
bindListItemViewHolder((ListItemViewHolder) gridViewHolder, file);
}

if (holder instanceof ListGridItemViewHolder) {
bindListGridItemViewHolder((ListGridItemViewHolder) holder, file);
checkVisibilityOfMoreButtons((ListGridItemViewHolder) holder);
checkVisibilityOfFileFeaturesLayout((ListGridItemViewHolder) holder);
}

updateLivePhotoIndicators(gridViewHolder, file);
}
}

private void checkVisibilityOfFileFeaturesLayout(ListGridImageViewHolder holder) {
int fileFeaturesVisibility = View.GONE;
LinearLayout fileFeaturesLayout = holder.getFileFeaturesLayout();

if (fileFeaturesLayout == null) {
return;
}

for (int i = 0; i < fileFeaturesLayout.getChildCount(); i++) {
View child = fileFeaturesLayout.getChildAt(i);
if (child.getVisibility() == View.VISIBLE) {
fileFeaturesVisibility = View.VISIBLE;
}
}

fileFeaturesLayout.setVisibility(fileFeaturesVisibility);
}

private void checkVisibilityOfMoreButtons(ListGridImageViewHolder holder) {
ImageButton moreButton = holder.getMore();
if (moreButton == null) {
return;
}

if (isMultiSelect()) {
moreButton.setVisibility(View.GONE);
} else {
moreButton.setVisibility(View.VISIBLE);
}
}

private void mergeOCFilesForLivePhoto() {
List<OCFile> filesToRemove = new ArrayList<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@ import android.graphics.drawable.ColorDrawable
import android.os.AsyncTask
import android.view.View
import android.widget.ImageView
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import com.elyeproj.loaderviewlibrary.LoaderImageView
import com.nextcloud.android.common.ui.theme.utils.ColorRole
import com.nextcloud.client.account.User
import com.nextcloud.client.preferences.AppPreferences
import com.nextcloud.utils.extensions.createRoundedOutline
import com.owncloud.android.R
import com.owncloud.android.datamodel.FileDataStorageManager
import com.owncloud.android.datamodel.OCFile
Expand Down Expand Up @@ -142,7 +145,7 @@ class OCFileListDelegate(
storageManager,
asyncGalleryTasks,
file.remoteId,
context.resources.getColor(R.color.bg_default)
ContextCompat.getColor(context, R.color.bg_default)
)
var drawable = MimeTypeUtil.getFileTypeIcon(
file.mimeType,
Expand Down Expand Up @@ -204,6 +207,7 @@ class OCFileListDelegate(
searchType: SearchType?
) {
// thumbnail
gridViewHolder.imageFileName?.text = file.fileName
gridViewHolder.thumbnail.tag = file.fileId
DisplayUtils.setThumbnail(
file,
Expand All @@ -218,6 +222,7 @@ class OCFileListDelegate(
viewThemeUtils,
syncFolderProvider
)

// item layout + click listeners
bindGridItemLayout(file, gridViewHolder)

Expand All @@ -232,17 +237,20 @@ class OCFileListDelegate(
}

// download state
gridViewHolder.localFileIndicator.visibility = View.INVISIBLE // default first
gridViewHolder.localFileIndicator.visibility = View.GONE // default first

// metadata (downloaded, favorite)
bindGridMetadataViews(file, gridViewHolder)

// shares
val shouldHideShare = gridView ||
val shouldHideShare = (
hideItemOptions ||
!file.isFolder && file.isEncrypted ||
file.isEncrypted && !EncryptionUtils.supportsSecureFiledrop(file, user) ||
searchType == SearchType.FAVORITE_SEARCH
!file.isFolder &&
file.isEncrypted ||
file.isEncrypted &&
!EncryptionUtils.supportsSecureFiledrop(file, user) ||
searchType == SearchType.FAVORITE_SEARCH
)
if (shouldHideShare) {
gridViewHolder.shared.visibility = View.GONE
} else {
Expand All @@ -263,34 +271,63 @@ class OCFileListDelegate(
}

private fun bindGridItemLayout(file: OCFile, gridViewHolder: ListGridImageViewHolder) {
if (highlightedItem != null && file.fileId == highlightedItem!!.fileId) {
gridViewHolder.itemLayout.setBackgroundColor(
context.resources
.getColor(R.color.selected_item_background)
)
} else if (isCheckedFile(file)) {
gridViewHolder.itemLayout.setBackgroundColor(
context.resources
.getColor(R.color.selected_item_background)
)
gridViewHolder.checkbox.setImageDrawable(
viewThemeUtils.platform.tintPrimaryDrawable(context, R.drawable.ic_checkbox_marked)
)
} else {
gridViewHolder.itemLayout.setBackgroundColor(context.resources.getColor(R.color.bg_default))
gridViewHolder.checkbox.setImageResource(R.drawable.ic_checkbox_blank_outline)
setItemLayoutBackgroundColor(file, gridViewHolder)
setCheckBoxImage(file, gridViewHolder)
setItemLayoutOnClickListeners(file, gridViewHolder)

gridViewHolder.more?.setOnClickListener {
ocFileListFragmentInterface.onOverflowIconClicked(file, it)
}
}

private fun setItemLayoutOnClickListeners(file: OCFile, gridViewHolder: ListGridImageViewHolder) {
gridViewHolder.itemLayout.setOnClickListener { ocFileListFragmentInterface.onItemClicked(file) }

if (!hideItemOptions) {
gridViewHolder.itemLayout.isLongClickable = true
gridViewHolder.itemLayout.setOnLongClickListener {
ocFileListFragmentInterface.onLongItemClicked(
file
)
gridViewHolder.itemLayout.apply {
isLongClickable = true
setOnLongClickListener {
ocFileListFragmentInterface.onLongItemClicked(
file
)
}
}
}
}

private fun setItemLayoutBackgroundColor(file: OCFile, gridViewHolder: ListGridImageViewHolder) {
val cornerRadius = context.resources.getDimension(R.dimen.selected_grid_container_radius)

val isDarkModeActive = (syncFolderProvider?.preferences?.isDarkModeEnabled == true)
val selectedItemBackgroundColorId: Int = if (isDarkModeActive) {
R.color.action_mode_background
} else {
R.color.selected_item_background
}

val itemLayoutBackgroundColorId: Int = if (file.fileId == highlightedItem?.fileId || isCheckedFile(file)) {
selectedItemBackgroundColorId
} else {
R.color.bg_default
}

gridViewHolder.itemLayout.apply {
outlineProvider = createRoundedOutline(context, cornerRadius)
clipToOutline = true
setBackgroundColor(ContextCompat.getColor(context, itemLayoutBackgroundColorId))
}
}

private fun setCheckBoxImage(file: OCFile, gridViewHolder: ListGridImageViewHolder) {
if (isCheckedFile(file)) {
gridViewHolder.checkbox.setImageDrawable(
viewThemeUtils.platform.tintDrawable(context, R.drawable.ic_checkbox_marked, ColorRole.PRIMARY)
)
} else {
gridViewHolder.checkbox.setImageResource(R.drawable.ic_checkbox_blank_outline)
}
}

private fun bindGridMetadataViews(file: OCFile, gridViewHolder: ListGridImageViewHolder) {
if (showMetadata) {
showLocalFileIndicator(file, gridViewHolder)
Expand Down
Loading

0 comments on commit 251ef24

Please sign in to comment.