mirror of
https://github.com/nextcloud/android.git
synced 2024-11-23 13:45:35 +03:00
Merge pull request #10050 from nextcloud/mediaTimeline
Group photos as timeline by month
This commit is contained in:
commit
c944203d93
29 changed files with 1627 additions and 798 deletions
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2022 Tobias Kaminsky
|
||||
* Copyright (C) 2022 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.owncloud.android.datamodel
|
||||
|
||||
data class GalleryItems(val date: Long, val files: List<OCFile>)
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2022 Tobias Kaminsky
|
||||
* Copyright (C) 2022 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.owncloud.android.ui.adapter
|
||||
|
||||
import com.nextcloud.client.account.User
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager
|
||||
import com.owncloud.android.datamodel.OCFile
|
||||
import com.owncloud.android.utils.FileSortOrder
|
||||
|
||||
interface CommonOCFileListAdapterInterface {
|
||||
fun isMultiSelect(): Boolean
|
||||
fun cancelAllPendingTasks()
|
||||
fun getItemPosition(file: OCFile): Int
|
||||
fun swapDirectory(
|
||||
user: User,
|
||||
directory: OCFile,
|
||||
storageManager: FileDataStorageManager,
|
||||
onlyOnDevice: Boolean,
|
||||
mLimitToMimeType: String
|
||||
)
|
||||
|
||||
fun setHighlightedItem(file: OCFile)
|
||||
fun setSortOrder(mFile: OCFile, sortOrder: FileSortOrder)
|
||||
fun addCheckedFile(file: OCFile)
|
||||
fun isCheckedFile(file: OCFile): Boolean
|
||||
fun getCheckedItems(): Set<OCFile>
|
||||
fun removeCheckedFile(file: OCFile)
|
||||
fun notifyItemChanged(file: OCFile)
|
||||
fun getFilesCount(): Int
|
||||
fun setMultiSelect(boolean: Boolean)
|
||||
fun clearCheckedItems()
|
||||
}
|
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2022 Tobias Kaminsky
|
||||
* Copyright (C) 2022 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.owncloud.android.ui.adapter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.afollestad.sectionedrecyclerview.SectionedRecyclerViewAdapter
|
||||
import com.afollestad.sectionedrecyclerview.SectionedViewHolder
|
||||
import com.nextcloud.client.account.User
|
||||
import com.nextcloud.client.preferences.AppPreferences
|
||||
import com.owncloud.android.databinding.GalleryHeaderBinding
|
||||
import com.owncloud.android.databinding.GridImageBinding
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager
|
||||
import com.owncloud.android.datamodel.GalleryItems
|
||||
import com.owncloud.android.datamodel.OCFile
|
||||
import com.owncloud.android.ui.activity.ComponentsGetter
|
||||
import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface
|
||||
import com.owncloud.android.utils.DisplayUtils
|
||||
import com.owncloud.android.utils.FileSortOrder
|
||||
import com.owncloud.android.utils.FileStorageUtils
|
||||
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView.SectionedAdapter
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
|
||||
class GalleryAdapter(
|
||||
val context: Context,
|
||||
user: User,
|
||||
ocFileListFragmentInterface: OCFileListFragmentInterface,
|
||||
preferences: AppPreferences,
|
||||
transferServiceGetter: ComponentsGetter
|
||||
) : SectionedRecyclerViewAdapter<SectionedViewHolder>(), CommonOCFileListAdapterInterface, SectionedAdapter {
|
||||
private var files: List<GalleryItems> = mutableListOf()
|
||||
private var ocFileListDelegate: OCFileListDelegate
|
||||
private var storageManager: FileDataStorageManager
|
||||
|
||||
init {
|
||||
storageManager = transferServiceGetter.storageManager
|
||||
|
||||
ocFileListDelegate = OCFileListDelegate(
|
||||
context,
|
||||
ocFileListFragmentInterface,
|
||||
user,
|
||||
storageManager,
|
||||
false,
|
||||
preferences,
|
||||
true,
|
||||
transferServiceGetter,
|
||||
showMetadata = false,
|
||||
showShareAvatar = false
|
||||
)
|
||||
}
|
||||
|
||||
override fun showFooters(): Boolean = false
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SectionedViewHolder {
|
||||
return if (viewType == VIEW_TYPE_HEADER) {
|
||||
GalleryHeaderViewHolder(
|
||||
GalleryHeaderBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
} else {
|
||||
GalleryItemViewHolder(
|
||||
GridImageBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(
|
||||
holder: SectionedViewHolder?,
|
||||
section: Int,
|
||||
relativePosition: Int,
|
||||
absolutePosition: Int
|
||||
) {
|
||||
if (holder != null) {
|
||||
val itemViewHolder = holder as GalleryItemViewHolder
|
||||
val ocFile = files[section].files[relativePosition]
|
||||
|
||||
ocFileListDelegate.bindGridViewHolder(itemViewHolder, ocFile)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(section: Int): Int {
|
||||
return files[section].files.size
|
||||
}
|
||||
|
||||
override fun getSectionCount(): Int {
|
||||
return files.size
|
||||
}
|
||||
|
||||
override fun getSectionName(position: Int): String {
|
||||
return DisplayUtils.getDateByPattern(
|
||||
files[getRelativePosition(position).section()].date,
|
||||
context,
|
||||
DisplayUtils.MONTH_YEAR_PATTERN
|
||||
)
|
||||
}
|
||||
|
||||
override fun onBindHeaderViewHolder(holder: SectionedViewHolder?, section: Int, expanded: Boolean) {
|
||||
if (holder != null) {
|
||||
val headerViewHolder = holder as GalleryHeaderViewHolder
|
||||
val galleryItem = files[section]
|
||||
|
||||
headerViewHolder.binding.month.text = DisplayUtils.getDateByPattern(
|
||||
galleryItem.date,
|
||||
context,
|
||||
DisplayUtils.MONTH_PATTERN
|
||||
)
|
||||
headerViewHolder.binding.year.text = DisplayUtils.getDateByPattern(
|
||||
galleryItem.date,
|
||||
context, DisplayUtils.YEAR_PATTERN
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindFooterViewHolder(holder: SectionedViewHolder?, section: Int) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun showAllGalleryItems(storageManager: FileDataStorageManager) {
|
||||
val items = storageManager.allGalleryItems
|
||||
|
||||
files = items
|
||||
.groupBy { firstOfMonth(it.modificationTimestamp) }
|
||||
.map { GalleryItems(it.key, FileStorageUtils.sortOcFolderDescDateModifiedWithoutFavoritesFirst(it.value)) }
|
||||
.sortedBy { it.date }.reversed()
|
||||
|
||||
Handler(Looper.getMainLooper()).post { notifyDataSetChanged() }
|
||||
}
|
||||
|
||||
private fun firstOfMonth(timestamp: Long): Long {
|
||||
val cal = Calendar.getInstance()
|
||||
cal.time = Date(timestamp)
|
||||
cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH))
|
||||
cal.set(Calendar.HOUR_OF_DAY, 0)
|
||||
cal.set(Calendar.MINUTE, 0)
|
||||
cal.set(Calendar.SECOND, 0)
|
||||
|
||||
return cal.timeInMillis
|
||||
}
|
||||
|
||||
fun isEmpty(): Boolean {
|
||||
return files.isEmpty()
|
||||
}
|
||||
|
||||
fun getItem(position: Int): OCFile {
|
||||
val itemCoord = getRelativePosition(position)
|
||||
|
||||
return files[itemCoord.section()].files[itemCoord.relativePos()]
|
||||
}
|
||||
|
||||
override fun isMultiSelect(): Boolean {
|
||||
return ocFileListDelegate.isMultiSelect
|
||||
}
|
||||
|
||||
override fun cancelAllPendingTasks() {
|
||||
ocFileListDelegate.cancelAllPendingTasks()
|
||||
}
|
||||
|
||||
override fun getItemPosition(file: OCFile): Int {
|
||||
val item = files.find { it.files.contains(file) }
|
||||
return getAbsolutePosition(files.indexOf(item), item?.files?.indexOf(file) ?: 0)
|
||||
}
|
||||
|
||||
override fun swapDirectory(
|
||||
user: User,
|
||||
directory: OCFile,
|
||||
storageManager: FileDataStorageManager,
|
||||
onlyOnDevice: Boolean,
|
||||
mLimitToMimeType: String
|
||||
) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun setHighlightedItem(file: OCFile) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun setSortOrder(mFile: OCFile, sortOrder: FileSortOrder) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun addCheckedFile(file: OCFile) {
|
||||
ocFileListDelegate.addCheckedFile(file)
|
||||
}
|
||||
|
||||
override fun isCheckedFile(file: OCFile): Boolean {
|
||||
return ocFileListDelegate.isCheckedFile(file)
|
||||
}
|
||||
|
||||
override fun getCheckedItems(): Set<OCFile> {
|
||||
return ocFileListDelegate.checkedItems
|
||||
}
|
||||
|
||||
override fun removeCheckedFile(file: OCFile) {
|
||||
ocFileListDelegate.removeCheckedFile(file)
|
||||
}
|
||||
|
||||
override fun notifyItemChanged(file: OCFile) {
|
||||
notifyItemChanged(getItemPosition(file))
|
||||
}
|
||||
|
||||
override fun getFilesCount(): Int {
|
||||
return files.fold(0) { acc, item -> acc + item.files.size }
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun setMultiSelect(boolean: Boolean) {
|
||||
ocFileListDelegate.isMultiSelect = boolean
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun clearCheckedItems() {
|
||||
ocFileListDelegate.clearCheckedItems()
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun addFiles(items: List<GalleryItems>) {
|
||||
files = items
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2022 Tobias Kaminsky
|
||||
* Copyright (C) 2022 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.owncloud.android.ui.adapter
|
||||
|
||||
import com.afollestad.sectionedrecyclerview.SectionedViewHolder
|
||||
import com.owncloud.android.databinding.GalleryHeaderBinding
|
||||
|
||||
class GalleryHeaderViewHolder(val binding: GalleryHeaderBinding) : SectionedViewHolder(binding.root)
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2022 Tobias Kaminsky
|
||||
* Copyright (C) 2022 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.owncloud.android.ui.adapter
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import com.afollestad.sectionedrecyclerview.SectionedViewHolder
|
||||
import com.elyeproj.loaderviewlibrary.LoaderImageView
|
||||
import com.owncloud.android.databinding.GridImageBinding
|
||||
|
||||
class GalleryItemViewHolder(val binding: GridImageBinding) :
|
||||
SectionedViewHolder(binding.root), ListGridImageViewHolder {
|
||||
override val thumbnail: ImageView
|
||||
get() = binding.thumbnail
|
||||
|
||||
override val shimmerThumbnail: LoaderImageView
|
||||
get() = binding.thumbnailShimmer
|
||||
|
||||
override val favorite: ImageView
|
||||
get() = binding.favoriteAction
|
||||
|
||||
override val localFileIndicator: ImageView
|
||||
get() = binding.localFileIndicator
|
||||
|
||||
override val shared: ImageView
|
||||
get() = binding.sharedIcon
|
||||
|
||||
override val checkbox: ImageView
|
||||
get() = binding.customCheckbox
|
||||
|
||||
override val itemLayout: View
|
||||
get() = binding.ListItemLayout
|
||||
|
||||
override val unreadComments: ImageView
|
||||
get() = binding.unreadComments
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2022 Tobias Kaminsky
|
||||
* Copyright (C) 2022 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.owncloud.android.ui.adapter
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import com.elyeproj.loaderviewlibrary.LoaderImageView
|
||||
|
||||
interface ListGridImageViewHolder {
|
||||
val thumbnail: ImageView
|
||||
val shimmerThumbnail: LoaderImageView
|
||||
val favorite: ImageView
|
||||
val localFileIndicator: ImageView
|
||||
val shared: ImageView
|
||||
val checkbox: ImageView
|
||||
val itemLayout: View
|
||||
val unreadComments: ImageView
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2022 Tobias Kaminsky
|
||||
* Copyright (C) 2022 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.owncloud.android.ui.adapter
|
||||
|
||||
import android.widget.TextView
|
||||
|
||||
internal interface ListGridItemViewHolder : ListGridImageViewHolder {
|
||||
val fileName: TextView
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2022 Tobias Kaminsky
|
||||
* Copyright (C) 2022 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.owncloud.android.ui.adapter
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.owncloud.android.ui.AvatarGroupLayout
|
||||
|
||||
internal interface ListItemViewHolder : ListGridItemViewHolder {
|
||||
val fileSize: TextView
|
||||
val fileSizeSeparator: View
|
||||
val lastModification: TextView
|
||||
val overflowMenu: ImageView
|
||||
val sharedAvatars: AvatarGroupLayout
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2022 Tobias Kaminsky
|
||||
* Copyright (C) 2022 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.owncloud.android.ui.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import com.nextcloud.client.account.User
|
||||
import com.nextcloud.client.preferences.AppPreferences
|
||||
import com.owncloud.android.R
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager
|
||||
import com.owncloud.android.datamodel.OCFile
|
||||
import com.owncloud.android.datamodel.ThumbnailsCacheManager.ThumbnailGenerationTask
|
||||
import com.owncloud.android.lib.common.utils.Log_OC
|
||||
import com.owncloud.android.ui.activity.ComponentsGetter
|
||||
import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface
|
||||
import com.owncloud.android.utils.DisplayUtils
|
||||
import com.owncloud.android.utils.theme.ThemeColorUtils
|
||||
import com.owncloud.android.utils.theme.ThemeDrawableUtils
|
||||
|
||||
@Suppress("LongParameterList", "TooManyFunctions")
|
||||
class OCFileListDelegate(
|
||||
private val context: Context,
|
||||
private val ocFileListFragmentInterface: OCFileListFragmentInterface,
|
||||
private val user: User,
|
||||
private val storageManager: FileDataStorageManager,
|
||||
private val hideItemOptions: Boolean,
|
||||
private val preferences: AppPreferences,
|
||||
private val gridView: Boolean,
|
||||
private val transferServiceGetter: ComponentsGetter,
|
||||
private val showMetadata: Boolean,
|
||||
private var showShareAvatar: Boolean
|
||||
) {
|
||||
private val checkedFiles: MutableSet<OCFile> = HashSet()
|
||||
private var highlightedItem: OCFile? = null
|
||||
var isMultiSelect = false
|
||||
private val asyncTasks: MutableList<ThumbnailGenerationTask> = ArrayList()
|
||||
fun setHighlightedItem(highlightedItem: OCFile?) {
|
||||
this.highlightedItem = highlightedItem
|
||||
}
|
||||
|
||||
fun isCheckedFile(file: OCFile): Boolean {
|
||||
return checkedFiles.contains(file)
|
||||
}
|
||||
|
||||
fun addCheckedFile(file: OCFile) {
|
||||
checkedFiles.add(file)
|
||||
highlightedItem = null
|
||||
}
|
||||
|
||||
fun removeCheckedFile(file: OCFile) {
|
||||
checkedFiles.remove(file)
|
||||
}
|
||||
|
||||
fun addToCheckedFiles(files: List<OCFile>?) {
|
||||
checkedFiles.addAll(files!!)
|
||||
}
|
||||
|
||||
val checkedItems: Set<OCFile>
|
||||
get() = checkedFiles
|
||||
|
||||
fun setCheckedItem(files: Set<OCFile>?) {
|
||||
checkedFiles.clear()
|
||||
checkedFiles.addAll(files!!)
|
||||
}
|
||||
|
||||
fun clearCheckedItems() {
|
||||
checkedFiles.clear()
|
||||
}
|
||||
|
||||
fun bindGridViewHolder(gridViewHolder: ListGridImageViewHolder, file: OCFile) {
|
||||
// thumbnail
|
||||
gridViewHolder.thumbnail.tag = file.fileId
|
||||
DisplayUtils.setThumbnail(
|
||||
file,
|
||||
gridViewHolder.thumbnail,
|
||||
user,
|
||||
storageManager,
|
||||
asyncTasks,
|
||||
gridView,
|
||||
context,
|
||||
gridViewHolder.shimmerThumbnail,
|
||||
preferences
|
||||
)
|
||||
// item layout + click listeners
|
||||
bindGridItemLayout(file, gridViewHolder)
|
||||
|
||||
// unread comments
|
||||
bindUnreadComments(file, gridViewHolder)
|
||||
|
||||
// multiSelect (Checkbox)
|
||||
if (isMultiSelect) {
|
||||
gridViewHolder.checkbox.visibility = View.VISIBLE
|
||||
} else {
|
||||
gridViewHolder.checkbox.visibility = View.GONE
|
||||
}
|
||||
|
||||
// download state
|
||||
gridViewHolder.localFileIndicator.visibility = View.INVISIBLE // default first
|
||||
|
||||
// metadata (downloaded, favorite)
|
||||
bindGridMetadataViews(file, gridViewHolder)
|
||||
|
||||
// shares
|
||||
val shouldHideShare = gridView || hideItemOptions || file.isFolder && !file.canReshare()
|
||||
if (shouldHideShare) {
|
||||
gridViewHolder.shared.visibility = View.GONE
|
||||
} else {
|
||||
showShareIcon(gridViewHolder, file)
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindUnreadComments(file: OCFile, gridViewHolder: ListGridImageViewHolder) {
|
||||
if (file.unreadCommentsCount > 0) {
|
||||
gridViewHolder.unreadComments.visibility = View.VISIBLE
|
||||
gridViewHolder.unreadComments.setOnClickListener {
|
||||
ocFileListFragmentInterface
|
||||
.showActivityDetailView(file)
|
||||
}
|
||||
} else {
|
||||
gridViewHolder.unreadComments.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
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(
|
||||
ThemeDrawableUtils.tintDrawable(
|
||||
R.drawable.ic_checkbox_marked,
|
||||
ThemeColorUtils.primaryColor(context)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
gridViewHolder.itemLayout.setBackgroundColor(context.resources.getColor(R.color.bg_default))
|
||||
gridViewHolder.checkbox.setImageResource(R.drawable.ic_checkbox_blank_outline)
|
||||
}
|
||||
gridViewHolder.itemLayout.setOnClickListener { ocFileListFragmentInterface.onItemClicked(file) }
|
||||
if (!hideItemOptions) {
|
||||
gridViewHolder.itemLayout.isLongClickable = true
|
||||
gridViewHolder.itemLayout.setOnLongClickListener {
|
||||
ocFileListFragmentInterface.onLongItemClicked(
|
||||
file
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindGridMetadataViews(file: OCFile, gridViewHolder: ListGridImageViewHolder) {
|
||||
if (showMetadata) {
|
||||
showLocalFileIndicator(file, gridViewHolder)
|
||||
gridViewHolder.favorite.visibility = if (file.isFavorite) View.VISIBLE else View.GONE
|
||||
} else {
|
||||
gridViewHolder.localFileIndicator.visibility = View.GONE
|
||||
gridViewHolder.favorite.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLocalFileIndicator(file: OCFile, gridViewHolder: ListGridImageViewHolder) {
|
||||
val operationsServiceBinder = transferServiceGetter.operationsServiceBinder
|
||||
val fileDownloaderBinder = transferServiceGetter.fileDownloaderBinder
|
||||
val fileUploaderBinder = transferServiceGetter.fileUploaderBinder
|
||||
when {
|
||||
operationsServiceBinder?.isSynchronizing(user, file) == true ||
|
||||
fileDownloaderBinder?.isDownloading(user, file) == true ||
|
||||
fileUploaderBinder?.isUploading(user, file) == true -> {
|
||||
// synchronizing, downloading or uploading
|
||||
gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synchronizing)
|
||||
gridViewHolder.localFileIndicator.visibility = View.VISIBLE
|
||||
}
|
||||
file.etagInConflict != null -> {
|
||||
// conflict
|
||||
gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synchronizing_error)
|
||||
gridViewHolder.localFileIndicator.visibility = View.VISIBLE
|
||||
}
|
||||
file.isDown -> {
|
||||
// downloaded
|
||||
gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synced)
|
||||
gridViewHolder.localFileIndicator.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showShareIcon(gridViewHolder: ListGridImageViewHolder, file: OCFile) {
|
||||
val sharedIconView = gridViewHolder.shared
|
||||
if (gridViewHolder is OCFileListItemViewHolder || file.unreadCommentsCount == 0) {
|
||||
sharedIconView.visibility = View.VISIBLE
|
||||
if (file.isSharedWithSharee || file.isSharedWithMe) {
|
||||
if (showShareAvatar) {
|
||||
sharedIconView.visibility = View.GONE
|
||||
} else {
|
||||
sharedIconView.visibility = View.VISIBLE
|
||||
sharedIconView.setImageResource(R.drawable.shared_via_users)
|
||||
sharedIconView.contentDescription = context.getString(R.string.shared_icon_shared)
|
||||
}
|
||||
} else if (file.isSharedViaLink) {
|
||||
sharedIconView.setImageResource(R.drawable.shared_via_link)
|
||||
sharedIconView.contentDescription = context.getString(R.string.shared_icon_shared_via_link)
|
||||
} else {
|
||||
sharedIconView.setImageResource(R.drawable.ic_unshared)
|
||||
sharedIconView.contentDescription = context.getString(R.string.shared_icon_share)
|
||||
}
|
||||
sharedIconView.setOnClickListener { ocFileListFragmentInterface.onShareIconClick(file) }
|
||||
} else {
|
||||
sharedIconView.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
fun cancelAllPendingTasks() {
|
||||
for (task in asyncTasks) {
|
||||
task.cancel(true)
|
||||
if (task.getMethod != null) {
|
||||
Log_OC.d(TAG, "cancel: abort get method directly")
|
||||
task.getMethod.abort()
|
||||
}
|
||||
}
|
||||
asyncTasks.clear()
|
||||
}
|
||||
|
||||
fun setShowShareAvatar(bool: Boolean) {
|
||||
showShareAvatar = bool
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = OCFileListDelegate::class.java.simpleName
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2022 Tobias Kaminsky
|
||||
* Copyright (C) 2022 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.owncloud.android.ui.adapter
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.owncloud.android.databinding.ListFooterBinding
|
||||
|
||||
internal class OCFileListFooterViewHolder(var binding: ListFooterBinding) : RecyclerView.ViewHolder(
|
||||
binding.root
|
||||
) {
|
||||
val footerText
|
||||
get() = binding.footerText
|
||||
|
||||
val loadingProgressBar
|
||||
get() = binding.loadingProgressBar
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2022 Tobias Kaminsky
|
||||
* Copyright (C) 2022 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.owncloud.android.ui.adapter
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.elyeproj.loaderviewlibrary.LoaderImageView
|
||||
import com.owncloud.android.databinding.GridImageBinding
|
||||
|
||||
internal class OCFileListGridImageViewHolder(var binding: GridImageBinding) :
|
||||
RecyclerView.ViewHolder(
|
||||
binding.root
|
||||
),
|
||||
ListGridImageViewHolder {
|
||||
override val thumbnail: ImageView
|
||||
get() = binding.thumbnail
|
||||
override val shimmerThumbnail: LoaderImageView
|
||||
get() = binding.thumbnailShimmer
|
||||
override val favorite: ImageView
|
||||
get() = binding.favoriteAction
|
||||
override val localFileIndicator: ImageView
|
||||
get() = binding.localFileIndicator
|
||||
override val shared: ImageView
|
||||
get() = binding.sharedIcon
|
||||
override val checkbox: ImageView
|
||||
get() = binding.customCheckbox
|
||||
override val itemLayout: View
|
||||
get() = binding.ListItemLayout
|
||||
override val unreadComments: ImageView
|
||||
get() = binding.unreadComments
|
||||
|
||||
init {
|
||||
binding.favoriteAction.drawable.mutate()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2022 Tobias Kaminsky
|
||||
* Copyright (C) 2022 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.owncloud.android.ui.adapter
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.elyeproj.loaderviewlibrary.LoaderImageView
|
||||
import com.owncloud.android.databinding.GridItemBinding
|
||||
|
||||
internal class OCFileListGridItemViewHolder(var binding: GridItemBinding) :
|
||||
RecyclerView.ViewHolder(
|
||||
binding.root
|
||||
),
|
||||
ListGridItemViewHolder {
|
||||
override val fileName: TextView
|
||||
get() = binding.Filename
|
||||
override val thumbnail: ImageView
|
||||
get() = binding.thumbnail
|
||||
override val shimmerThumbnail: LoaderImageView
|
||||
get() = binding.thumbnailShimmer
|
||||
override val favorite: ImageView
|
||||
get() = binding.favoriteAction
|
||||
override val localFileIndicator: ImageView
|
||||
get() = binding.localFileIndicator
|
||||
override val shared: ImageView
|
||||
get() = binding.sharedIcon
|
||||
override val checkbox: ImageView
|
||||
get() = binding.customCheckbox
|
||||
override val itemLayout: View
|
||||
get() = binding.ListItemLayout
|
||||
override val unreadComments: ImageView
|
||||
get() = binding.unreadComments
|
||||
|
||||
init {
|
||||
binding.favoriteAction.drawable.mutate()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2022 Tobias Kaminsky
|
||||
* Copyright (C) 2022 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.owncloud.android.ui.adapter
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.owncloud.android.databinding.ListHeaderBinding
|
||||
|
||||
internal class OCFileListHeaderViewHolder(var binding: ListHeaderBinding) : RecyclerView.ViewHolder(
|
||||
binding.root
|
||||
) {
|
||||
val headerText
|
||||
get() = binding.headerText
|
||||
|
||||
val headerView
|
||||
get() = binding.headerView
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2022 Tobias Kaminsky
|
||||
* Copyright (C) 2022 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.owncloud.android.ui.adapter
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.elyeproj.loaderviewlibrary.LoaderImageView
|
||||
import com.owncloud.android.databinding.ListItemBinding
|
||||
import com.owncloud.android.ui.AvatarGroupLayout
|
||||
|
||||
internal class OCFileListItemViewHolder(private var binding: ListItemBinding) :
|
||||
RecyclerView.ViewHolder(
|
||||
binding.root
|
||||
),
|
||||
ListItemViewHolder {
|
||||
override val fileSize: TextView
|
||||
get() = binding.fileSize
|
||||
override val fileSizeSeparator: View
|
||||
get() = binding.fileSeparator
|
||||
override val lastModification: TextView
|
||||
get() = binding.lastMod
|
||||
override val overflowMenu: ImageView
|
||||
get() = binding.overflowMenu
|
||||
override val sharedAvatars: AvatarGroupLayout
|
||||
get() = binding.sharedAvatars
|
||||
override val fileName: TextView
|
||||
get() = binding.Filename
|
||||
override val thumbnail: ImageView
|
||||
get() = binding.thumbnail
|
||||
override val shimmerThumbnail: LoaderImageView
|
||||
get() = binding.thumbnailShimmer
|
||||
override val favorite: ImageView
|
||||
get() = binding.favoriteAction
|
||||
override val localFileIndicator: ImageView
|
||||
get() = binding.localFileIndicator
|
||||
override val shared: ImageView
|
||||
get() = binding.sharedIcon
|
||||
override val checkbox: ImageView
|
||||
get() = binding.customCheckbox
|
||||
override val itemLayout: View
|
||||
get() = binding.ListItemLayout
|
||||
override val unreadComments: ImageView
|
||||
get() = binding.unreadComments
|
||||
|
||||
init {
|
||||
binding.favoriteAction.drawable.mutate()
|
||||
}
|
||||
}
|
|
@ -100,7 +100,7 @@ public class GallerySearchTask extends AsyncTask<Void, Void, GallerySearchTask.R
|
|||
boolean emptySearch = parseMedia(startDate, endDate, result.getData());
|
||||
long lastTimeStamp = findLastTimestamp(result.getData());
|
||||
|
||||
photoFragment.getAdapter().showAllGalleryItems(storageManager);
|
||||
photoFragment.showAllGalleryItems();
|
||||
|
||||
return new Result(result.isSuccess(), emptySearch, lastTimeStamp);
|
||||
} else {
|
||||
|
|
|
@ -37,7 +37,6 @@ import com.owncloud.android.datamodel.OCFile;
|
|||
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.ui.adapter.LocalFileListAdapter;
|
||||
import com.owncloud.android.ui.adapter.OCFileListAdapter;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.theme.ThemeButtonUtils;
|
||||
import com.owncloud.android.utils.theme.ThemeCheckableUtils;
|
||||
|
@ -197,7 +196,7 @@ public class ConflictsResolveDialog extends DialogFragment {
|
|||
existingFile.getModificationTimestamp()));
|
||||
|
||||
binding.existingThumbnail.setTag(existingFile.getFileId());
|
||||
OCFileListAdapter.setThumbnail(existingFile,
|
||||
DisplayUtils.setThumbnail(existingFile,
|
||||
binding.existingThumbnail,
|
||||
user,
|
||||
new FileDataStorageManager(user,
|
||||
|
|
|
@ -31,6 +31,8 @@ import com.owncloud.android.R;
|
|||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.ui.activity.FileDisplayActivity;
|
||||
import com.owncloud.android.ui.adapter.CommonOCFileListAdapterInterface;
|
||||
import com.owncloud.android.ui.adapter.GalleryAdapter;
|
||||
import com.owncloud.android.ui.asynctasks.GallerySearchTask;
|
||||
import com.owncloud.android.ui.events.ChangeMenuEvent;
|
||||
|
||||
|
@ -50,6 +52,7 @@ public class GalleryFragment extends OCFileListFragment {
|
|||
private long endDate;
|
||||
private long daySpan = 30;
|
||||
private int limit = 300;
|
||||
private GalleryAdapter mAdapter;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -87,18 +90,45 @@ public class GalleryFragment extends OCFileListFragment {
|
|||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
mAdapter.setShowMetadata(false);
|
||||
|
||||
currentSearchType = SearchType.GALLERY_SEARCH;
|
||||
|
||||
switchToGridView();
|
||||
|
||||
menuItemAddRemoveValue = MenuItemAddRemove.REMOVE_GRID_AND_SORT;
|
||||
requireActivity().invalidateOptionsMenu();
|
||||
|
||||
handleSearchEvent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setAdapter(Bundle args) {
|
||||
mAdapter = new GalleryAdapter(requireContext(),
|
||||
accountManager.getUser(),
|
||||
this,
|
||||
preferences,
|
||||
mContainerActivity);
|
||||
|
||||
// val spacing = resources.getDimensionPixelSize(R.dimen.media_grid_spacing)
|
||||
// binding.list.addItemDecoration(MediaGridItemDecoration(spacing))
|
||||
setRecyclerViewAdapter(mAdapter);
|
||||
|
||||
|
||||
GridLayoutManager layoutManager = new GridLayoutManager(getContext(), getColumnsCount());
|
||||
// ((GridLayoutManager) layoutManager).setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
|
||||
// @Override
|
||||
// public int getSpanSize(int position) {
|
||||
// if (position == getAdapter().getItemCount() - 1 ||
|
||||
// position == 0 && getAdapter().shouldShowHeader()) {
|
||||
// return ((GridLayoutManager) layoutManager).getSpanCount();
|
||||
// } else {
|
||||
// return 1;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
mAdapter.setLayoutManager(layoutManager);
|
||||
getRecyclerView().setLayoutManager(layoutManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
super.onRefresh();
|
||||
|
@ -106,6 +136,11 @@ public class GalleryFragment extends OCFileListFragment {
|
|||
handleSearchEvent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonOCFileListAdapterInterface getCommonAdapter() {
|
||||
return mAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
@ -161,7 +196,7 @@ public class GalleryFragment extends OCFileListFragment {
|
|||
setEmptyListMessage(SearchType.GALLERY_SEARCH);
|
||||
}
|
||||
|
||||
if (emptySearch && getAdapter().getItemCount() > 0) {
|
||||
if (emptySearch && mAdapter.getItemCount() > 0) {
|
||||
Log_OC.d(this, "End gallery search");
|
||||
return;
|
||||
}
|
||||
|
@ -234,8 +269,7 @@ public class GalleryFragment extends OCFileListFragment {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGalleryFragment() {
|
||||
return true;
|
||||
public void showAllGalleryItems() {
|
||||
mAdapter.showAllGalleryItems(mContainerActivity.getStorageManager());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ import com.owncloud.android.ui.activity.FileDisplayActivity;
|
|||
import com.owncloud.android.ui.activity.FolderPickerActivity;
|
||||
import com.owncloud.android.ui.activity.OnEnforceableRefreshListener;
|
||||
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.dialog.ChooseRichDocumentsTemplateDialogFragment;
|
||||
import com.owncloud.android.ui.dialog.ChooseTemplateDialogFragment;
|
||||
|
@ -189,7 +190,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
protected FileFragment.ContainerActivity mContainerActivity;
|
||||
|
||||
protected OCFile mFile;
|
||||
protected OCFileListAdapter mAdapter;
|
||||
private OCFileListAdapter mAdapter;
|
||||
protected boolean mOnlyFoldersClickable;
|
||||
protected boolean mFileSelectable;
|
||||
|
||||
|
@ -326,7 +327,9 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
if (mAdapter != null) {
|
||||
mAdapter.cancelAllPendingTasks();
|
||||
}
|
||||
|
||||
if (getActivity() != null) {
|
||||
getActivity().getIntent().removeExtra(OCFileListFragment.SEARCH_EVENT);
|
||||
|
@ -349,18 +352,8 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
mOnlyFoldersClickable = args != null && args.getBoolean(ARG_ONLY_FOLDERS_CLICKABLE, false);
|
||||
mFileSelectable = args != null && args.getBoolean(ARG_FILE_SELECTABLE, false);
|
||||
mLimitToMimeType = args != null ? args.getString(ARG_MIMETYPE, "") : "";
|
||||
boolean hideItemOptions = args != null && args.getBoolean(ARG_HIDE_ITEM_OPTIONS, false);
|
||||
|
||||
mAdapter = new OCFileListAdapter(
|
||||
getActivity(),
|
||||
accountManager.getUser(),
|
||||
preferences,
|
||||
mContainerActivity,
|
||||
this,
|
||||
hideItemOptions,
|
||||
isGridViewPreferred(mFile)
|
||||
);
|
||||
setRecyclerViewAdapter(mAdapter);
|
||||
setAdapter(args);
|
||||
|
||||
mHideFab = args != null && args.getBoolean(ARG_HIDE_FAB, false);
|
||||
|
||||
|
@ -406,6 +399,22 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
listDirectory(false, false);
|
||||
}
|
||||
|
||||
protected void setAdapter(Bundle args) {
|
||||
boolean hideItemOptions = args != null && args.getBoolean(ARG_HIDE_ITEM_OPTIONS, false);
|
||||
|
||||
mAdapter = new OCFileListAdapter(
|
||||
getActivity(),
|
||||
accountManager.getUser(),
|
||||
preferences,
|
||||
mContainerActivity,
|
||||
this,
|
||||
hideItemOptions,
|
||||
isGridViewPreferred(mFile)
|
||||
);
|
||||
|
||||
setRecyclerViewAdapter(mAdapter);
|
||||
}
|
||||
|
||||
protected void prepareCurrentSearch(SearchEvent event) {
|
||||
if (isSearchEventSet(event)) {
|
||||
|
||||
|
@ -691,7 +700,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
// hide FAB in multi selection mode
|
||||
setFabVisible(false);
|
||||
|
||||
mAdapter.setMultiSelect(true);
|
||||
getCommonAdapter().setMultiSelect(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -700,12 +709,12 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
*/
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
final int checkedCount = mAdapter.getCheckedItems().size();
|
||||
Set<OCFile> checkedFiles = mAdapter.getCheckedItems();
|
||||
Set<OCFile> checkedFiles = getCommonAdapter().getCheckedItems();
|
||||
final int checkedCount = checkedFiles.size();
|
||||
String title = getResources().getQuantityString(R.plurals.items_selected_count, checkedCount, checkedCount);
|
||||
mode.setTitle(title);
|
||||
FileMenuFilter mf = new FileMenuFilter(
|
||||
mAdapter.getFiles().size(),
|
||||
getCommonAdapter().getFilesCount(),
|
||||
checkedFiles,
|
||||
mContainerActivity,
|
||||
getActivity(),
|
||||
|
@ -728,7 +737,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
*/
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
Set<OCFile> checkedFiles = mAdapter.getCheckedItems();
|
||||
Set<OCFile> checkedFiles = getCommonAdapter().getCheckedItems();
|
||||
return onFileActionChosen(item, checkedFiles);
|
||||
}
|
||||
|
||||
|
@ -744,8 +753,8 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
setFabVisible(true);
|
||||
}
|
||||
|
||||
mAdapter.setMultiSelect(false);
|
||||
mAdapter.clearCheckedItems();
|
||||
getCommonAdapter().setMultiSelect(false);
|
||||
getCommonAdapter().clearCheckedItems();
|
||||
}
|
||||
|
||||
public void storeStateIn(Bundle outState) {
|
||||
|
@ -865,10 +874,10 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
* @param file The concerned OCFile by the selection/deselection
|
||||
*/
|
||||
private void toggleItemToCheckedList(OCFile file) {
|
||||
if (getAdapter().isCheckedFile(file)) {
|
||||
getAdapter().removeCheckedFile(file);
|
||||
if (getCommonAdapter().isCheckedFile(file)) {
|
||||
getCommonAdapter().removeCheckedFile(file);
|
||||
} else {
|
||||
getAdapter().addCheckedFile(file);
|
||||
getCommonAdapter().addCheckedFile(file);
|
||||
}
|
||||
updateActionModeFile(file);
|
||||
}
|
||||
|
@ -881,7 +890,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
mIsActionModeNew = false;
|
||||
if (mActiveActionMode != null) {
|
||||
mActiveActionMode.invalidate();
|
||||
mAdapter.notifyItemChanged(getAdapter().getItemPosition(file));
|
||||
getCommonAdapter().notifyItemChanged(file);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -894,7 +903,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
toggleItemToCheckedList(file);
|
||||
} else {
|
||||
actionBarActivity.startActionMode(mMultiChoiceModeListener);
|
||||
getAdapter().addCheckedFile(file);
|
||||
getCommonAdapter().addCheckedFile(file);
|
||||
}
|
||||
updateActionModeFile(file);
|
||||
}
|
||||
|
@ -904,11 +913,11 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
|
||||
@Override
|
||||
public void onItemClicked(OCFile file) {
|
||||
if (getAdapter().isMultiSelect()) {
|
||||
if (getCommonAdapter().isMultiSelect()) {
|
||||
toggleItemToCheckedList(file);
|
||||
} else {
|
||||
if (file != null) {
|
||||
int position = mAdapter.getItemPosition(file);
|
||||
int position = getCommonAdapter().getItemPosition(file);
|
||||
|
||||
if (file.isFolder()) {
|
||||
resetHeaderScrollingState();
|
||||
|
@ -1229,6 +1238,10 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
if (!directory.isFolder()) {
|
||||
Log_OC.w(TAG, "You see, that is not a directory -> " + directory);
|
||||
directory = storageManager.getFileById(directory.getParentId());
|
||||
|
||||
if (directory == null) {
|
||||
return; // no files, wait for sync
|
||||
}
|
||||
}
|
||||
|
||||
if (searchView != null && !searchView.isIconified() && !fromSearch) {
|
||||
|
@ -1379,6 +1392,10 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public CommonOCFileListAdapterInterface getCommonAdapter() {
|
||||
return mAdapter;
|
||||
}
|
||||
|
||||
public OCFileListAdapter getAdapter() {
|
||||
return mAdapter;
|
||||
}
|
||||
|
@ -1587,7 +1604,11 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
|
||||
|
||||
FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
|
||||
int position = mAdapter.getItemPosition(storageManager.getFileByRemoteId(event.remoteId));
|
||||
OCFile file = storageManager.getFileByRemoteId(event.remoteId);
|
||||
int position = -1;
|
||||
if (file != null) {
|
||||
position = mAdapter.getItemPosition(file);
|
||||
}
|
||||
SetupEncryptionDialogFragment dialog = SetupEncryptionDialogFragment.newInstance(user, position);
|
||||
dialog.setTargetFragment(this, SetupEncryptionDialogFragment.SETUP_ENCRYPTION_REQUEST_CODE);
|
||||
dialog.show(getParentFragmentManager(), SetupEncryptionDialogFragment.SETUP_ENCRYPTION_DIALOG_TAG);
|
||||
|
@ -1656,11 +1677,6 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
return searchFragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGalleryFragment() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* De-/select all elements in the current list view.
|
||||
*
|
||||
|
@ -1672,7 +1688,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
if (select) {
|
||||
ocFileListAdapter.addAllFilesToCheckedFiles();
|
||||
} else {
|
||||
ocFileListAdapter.removeAllFilesFromCheckedFiles();
|
||||
ocFileListAdapter.clearCheckedItems();
|
||||
}
|
||||
|
||||
for (int i = 0; i < mAdapter.getItemCount(); i++) {
|
||||
|
|
|
@ -69,7 +69,7 @@ class OCFileListSearchAsyncTask(
|
|||
if (remoteOperationResult.resultData.isNullOrEmpty()) {
|
||||
fragment.setEmptyView(event)
|
||||
} else {
|
||||
fragment.mAdapter.setData(
|
||||
fragment.adapter.setData(
|
||||
remoteOperationResult.resultData,
|
||||
fragment.currentSearchType,
|
||||
fileDataStorageManager,
|
||||
|
@ -85,7 +85,7 @@ class OCFileListSearchAsyncTask(
|
|||
fragmentReference.get()?.let { fragment ->
|
||||
fragment.isLoading = false
|
||||
if (!isCancelled) {
|
||||
fragment.mAdapter.notifyDataSetChanged()
|
||||
fragment.adapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ class SharedListFragment : OCFileListFragment(), Injectable {
|
|||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
mAdapter.setShowMetadata(false)
|
||||
adapter.setShowMetadata(false)
|
||||
currentSearchType = SearchType.SHARED_FILTER
|
||||
searchEvent = SearchEvent("", SearchRemoteOperation.SearchType.SHARED_FILTER)
|
||||
menuItemAddRemoveValue = MenuItemAddRemove.REMOVE_GRID_AND_SORT
|
||||
|
|
|
@ -48,8 +48,4 @@ public interface OCFileListFragmentInterface {
|
|||
boolean isLoading();
|
||||
|
||||
void onHeaderClicked();
|
||||
|
||||
boolean isSearchFragment();
|
||||
|
||||
boolean isGalleryFragment();
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ import java.security.SecureRandom;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
|
||||
/**
|
||||
* Data holder utility to store & retrieve stuff
|
||||
*/
|
||||
|
@ -39,6 +41,7 @@ public class DataHolderUtil {
|
|||
@SuppressLint("TrulyRandom")
|
||||
private SecureRandom random = new SecureRandom();
|
||||
|
||||
@SuppressFBWarnings("MS_EXPOSE_REP")
|
||||
public static synchronized DataHolderUtil getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new DataHolderUtil();
|
||||
|
|
|
@ -46,6 +46,9 @@ import android.text.style.StyleSpan;
|
|||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.bumptech.glide.GenericRequestBuilder;
|
||||
|
@ -56,13 +59,16 @@ import com.bumptech.glide.load.resource.file.FileToStreamDecoder;
|
|||
import com.bumptech.glide.request.target.SimpleTarget;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
import com.caverock.androidsvg.SVG;
|
||||
import com.elyeproj.loaderviewlibrary.LoaderImageView;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.nextcloud.client.account.CurrentAccountProvider;
|
||||
import com.nextcloud.client.account.User;
|
||||
import com.nextcloud.client.network.ClientFactory;
|
||||
import com.nextcloud.client.preferences.AppPreferences;
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.ArbitraryDataProvider;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
|
||||
import com.owncloud.android.lib.common.OwnCloudAccount;
|
||||
|
@ -89,17 +95,19 @@ import java.math.BigDecimal;
|
|||
import java.net.IDN;
|
||||
import java.nio.charset.Charset;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.widget.AppCompatDrawableManager;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
|
@ -130,6 +138,10 @@ public final class DisplayUtils {
|
|||
private static final double BYTE_SIZE_DIVIDER_DOUBLE = 1024.0;
|
||||
private static final int DATE_TIME_PARTS_SIZE = 2;
|
||||
|
||||
public static final String MONTH_YEAR_PATTERN = "MMMM yyyy";
|
||||
public static final String MONTH_PATTERN = "MMMM";
|
||||
public static final String YEAR_PATTERN = "yyyy";
|
||||
|
||||
private static Map<String, String> mimeType2HumanReadable;
|
||||
|
||||
static {
|
||||
|
@ -820,4 +832,178 @@ public final class DisplayUtils {
|
|||
return R.string.menu_item_sort_by_name_a_z;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getDateByPattern(long timestamp, Context context, String pattern) {
|
||||
DateFormat df = new SimpleDateFormat(pattern, context.getResources().getConfiguration().locale);
|
||||
df.setTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getID()));
|
||||
|
||||
return df.format(timestamp);
|
||||
}
|
||||
|
||||
public static void setThumbnail(OCFile file,
|
||||
ImageView thumbnailView,
|
||||
User user,
|
||||
FileDataStorageManager storageManager,
|
||||
List<ThumbnailsCacheManager.ThumbnailGenerationTask> asyncTasks,
|
||||
boolean gridView,
|
||||
Context context) {
|
||||
setThumbnail(file,
|
||||
thumbnailView,
|
||||
user,
|
||||
storageManager,
|
||||
asyncTasks,
|
||||
gridView,
|
||||
context,
|
||||
null,
|
||||
null);
|
||||
}
|
||||
|
||||
public static void setThumbnail(OCFile file,
|
||||
ImageView thumbnailView,
|
||||
User user,
|
||||
FileDataStorageManager storageManager,
|
||||
List<ThumbnailsCacheManager.ThumbnailGenerationTask> asyncTasks,
|
||||
boolean gridView,
|
||||
Context context,
|
||||
LoaderImageView shimmerThumbnail,
|
||||
AppPreferences preferences) {
|
||||
if (file.isFolder()) {
|
||||
stopShimmer(shimmerThumbnail, thumbnailView);
|
||||
thumbnailView.setImageDrawable(MimeTypeUtil
|
||||
.getFolderTypeIcon(file.isSharedWithMe() || file.isSharedWithSharee(),
|
||||
file.isSharedViaLink(), file.isEncrypted(),
|
||||
file.getMountType(), context));
|
||||
} else {
|
||||
if (file.getRemoteId() != null && file.isPreviewAvailable()) {
|
||||
// Thumbnail in cache?
|
||||
Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
|
||||
ThumbnailsCacheManager.PREFIX_THUMBNAIL + file.getRemoteId()
|
||||
);
|
||||
|
||||
if (thumbnail != null && !file.isUpdateThumbnailNeeded()) {
|
||||
stopShimmer(shimmerThumbnail, thumbnailView);
|
||||
|
||||
if (MimeTypeUtil.isVideo(file)) {
|
||||
Bitmap withOverlay = ThumbnailsCacheManager.addVideoOverlay(thumbnail);
|
||||
thumbnailView.setImageBitmap(withOverlay);
|
||||
} else {
|
||||
if (gridView) {
|
||||
BitmapUtils.setRoundedBitmapForGridMode(thumbnail, thumbnailView);
|
||||
} else {
|
||||
BitmapUtils.setRoundedBitmap(thumbnail, thumbnailView);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// generate new thumbnail
|
||||
if (ThumbnailsCacheManager.cancelPotentialThumbnailWork(file, thumbnailView)) {
|
||||
try {
|
||||
final ThumbnailsCacheManager.ThumbnailGenerationTask task =
|
||||
new ThumbnailsCacheManager.ThumbnailGenerationTask(thumbnailView,
|
||||
storageManager,
|
||||
user,
|
||||
asyncTasks,
|
||||
gridView);
|
||||
if (thumbnail == null) {
|
||||
Drawable drawable = MimeTypeUtil.getFileTypeIcon(file.getMimeType(),
|
||||
file.getFileName(),
|
||||
user,
|
||||
context);
|
||||
if (drawable == null) {
|
||||
drawable = ResourcesCompat.getDrawable(context.getResources(),
|
||||
R.drawable.file_image,
|
||||
null);
|
||||
}
|
||||
int px = ThumbnailsCacheManager.getThumbnailDimension();
|
||||
thumbnail = BitmapUtils.drawableToBitmap(drawable, px, px);
|
||||
}
|
||||
final ThumbnailsCacheManager.AsyncThumbnailDrawable asyncDrawable =
|
||||
new ThumbnailsCacheManager.AsyncThumbnailDrawable(context.getResources(),
|
||||
thumbnail, task);
|
||||
|
||||
if (shimmerThumbnail != null && shimmerThumbnail.getVisibility() == View.GONE) {
|
||||
if (gridView) {
|
||||
configShimmerGridImageSize(shimmerThumbnail, preferences.getGridColumns());
|
||||
}
|
||||
startShimmer(shimmerThumbnail, thumbnailView);
|
||||
}
|
||||
|
||||
task.setListener(new ThumbnailsCacheManager.ThumbnailGenerationTask.Listener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
stopShimmer(shimmerThumbnail, thumbnailView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
stopShimmer(shimmerThumbnail, thumbnailView);
|
||||
}
|
||||
});
|
||||
|
||||
thumbnailView.setImageDrawable(asyncDrawable);
|
||||
asyncTasks.add(task);
|
||||
task.execute(new ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file,
|
||||
file.getRemoteId()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log_OC.d(TAG, "ThumbnailGenerationTask : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ("image/png".equalsIgnoreCase(file.getMimeType())) {
|
||||
thumbnailView.setBackgroundColor(context.getResources().getColor(R.color.bg_default));
|
||||
}
|
||||
} else {
|
||||
stopShimmer(shimmerThumbnail, thumbnailView);
|
||||
thumbnailView.setImageDrawable(MimeTypeUtil.getFileTypeIcon(file.getMimeType(),
|
||||
file.getFileName(),
|
||||
user,
|
||||
context));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void startShimmer(LoaderImageView thumbnailShimmer, ImageView thumbnailView) {
|
||||
thumbnailShimmer.setImageResource(R.drawable.background);
|
||||
thumbnailShimmer.resetLoader();
|
||||
thumbnailView.setVisibility(View.GONE);
|
||||
thumbnailShimmer.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
private static void stopShimmer(@Nullable LoaderImageView thumbnailShimmer, ImageView thumbnailView) {
|
||||
if (thumbnailShimmer != null) {
|
||||
thumbnailShimmer.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
thumbnailView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
private static void configShimmerGridImageSize(LoaderImageView thumbnailShimmer, float gridColumns) {
|
||||
FrameLayout.LayoutParams targetLayoutParams = (FrameLayout.LayoutParams) thumbnailShimmer.getLayoutParams();
|
||||
|
||||
try {
|
||||
final Point screenSize = getScreenSize(thumbnailShimmer.getContext());
|
||||
final int marginLeftAndRight = targetLayoutParams.leftMargin + targetLayoutParams.rightMargin;
|
||||
final int size = Math.round(screenSize.x / gridColumns - marginLeftAndRight);
|
||||
|
||||
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(size, size);
|
||||
params.setMargins(targetLayoutParams.leftMargin,
|
||||
targetLayoutParams.topMargin,
|
||||
targetLayoutParams.rightMargin,
|
||||
targetLayoutParams.bottomMargin);
|
||||
thumbnailShimmer.setLayoutParams(params);
|
||||
} catch (Exception exception) {
|
||||
Log_OC.e("ConfigShimmer", exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static Point getScreenSize(Context context) throws Exception {
|
||||
final WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
if (windowManager != null) {
|
||||
final Point displaySize = new Point();
|
||||
windowManager.getDefaultDisplay().getSize(displaySize);
|
||||
return displaySize;
|
||||
} else {
|
||||
throw new Exception("WindowManager not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
48
app/src/main/res/layout/gallery_header.xml
Normal file
48
app/src/main/res/layout/gallery_header.xml
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~
|
||||
~ Nextcloud Android client application
|
||||
~
|
||||
~ @author Tobias Kaminsky
|
||||
~ Copyright (C) 2022 Tobias Kaminsky
|
||||
~ Copyright (C) 2022 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/>.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="@dimen/alternate_half_padding"
|
||||
android:paddingTop="@dimen/alternate_half_padding"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/month"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/standard_margin"
|
||||
android:layout_marginTop="@dimen/standard_margin"
|
||||
android:layout_marginEnd="@dimen/standard_half_margin"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textStyle="bold"
|
||||
tools:text="July" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/year"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/standard_margin"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
tools:text="2016" />
|
||||
</LinearLayout>
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2022 Tobias Kaminsky
|
||||
* Copyright (C) 2022 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.owncloud.android.ui.adapter
|
||||
|
||||
import android.content.Context
|
||||
import com.nextcloud.client.account.User
|
||||
import com.nextcloud.client.preferences.AppPreferences
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager
|
||||
import com.owncloud.android.datamodel.GalleryItems
|
||||
import com.owncloud.android.datamodel.OCFile
|
||||
import com.owncloud.android.ui.activity.ComponentsGetter
|
||||
import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface
|
||||
import junit.framework.Assert.assertEquals
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
class GalleryAdapterTest {
|
||||
@Mock
|
||||
lateinit var context: Context
|
||||
|
||||
@Mock
|
||||
lateinit var user: User
|
||||
|
||||
@Mock
|
||||
lateinit var ocFileListFragmentInterface: OCFileListFragmentInterface
|
||||
|
||||
@Mock
|
||||
lateinit var preferences: AppPreferences
|
||||
|
||||
@Mock
|
||||
lateinit var transferServiceGetter: ComponentsGetter
|
||||
|
||||
@Mock
|
||||
lateinit var storageManager: FileDataStorageManager
|
||||
|
||||
private lateinit var mocks: AutoCloseable
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
mocks = MockitoAnnotations.openMocks(this)
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
mocks.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testItemCount() {
|
||||
whenever(transferServiceGetter.storageManager) doReturn storageManager
|
||||
|
||||
val sut = GalleryAdapter(
|
||||
context,
|
||||
user,
|
||||
ocFileListFragmentInterface,
|
||||
preferences,
|
||||
transferServiceGetter
|
||||
)
|
||||
|
||||
val list = listOf(
|
||||
GalleryItems(1649317247, listOf(OCFile("/1.md"), OCFile("/2.md"))),
|
||||
GalleryItems(1649317247, listOf(OCFile("/1.md"), OCFile("/2.md")))
|
||||
)
|
||||
|
||||
sut.addFiles(list)
|
||||
|
||||
assertEquals(4, sut.getFilesCount())
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
592
|
||||
536
|
|
@ -1,2 +1,2 @@
|
|||
DO NOT TOUCH; GENERATED BY DRONE
|
||||
<span class="mdl-layout-title">Lint Report: 92 warnings</span>
|
||||
<span class="mdl-layout-title">Lint Report: 89 warnings</span>
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
<Bug pattern="ANDROID_EXTERNAL_FILE_ACCESS" />
|
||||
<Bug pattern="BAS_BLOATED_ASSIGNMENT_SCOPE" />
|
||||
<Bug pattern="IMC_IMMATURE_CLASS_BAD_SERIALVERSIONUID" />
|
||||
<Bug pattern="EI_EXPOSE_REP" />
|
||||
<Bug pattern="EI_EXPOSE_REP2" />
|
||||
|
||||
<!-- This is unmanageable for now due to large amount of interconnected static state -->
|
||||
|
|
Loading…
Reference in a new issue