Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ interface FileDao {
)
fun getGalleryItems(startDate: Long, endDate: Long, fileOwner: String): List<FileEntity>

@Query(
"SELECT * FROM filelist WHERE modified >= :startDate" +
" AND modified < :endDate" +
" AND (content_type LIKE 'image/%' OR content_type LIKE 'video/%')" +
" AND file_owner = :fileOwner" +
" ORDER BY ${ProviderTableMeta.FILE_DEFAULT_SORT_ORDER}"
)
suspend fun getGalleryItemsSuspended(startDate: Long, endDate: Long, fileOwner: String): List<FileEntity>

@Query("SELECT * FROM filelist WHERE file_owner = :fileOwner ORDER BY ${ProviderTableMeta.FILE_DEFAULT_SORT_ORDER}")
fun getAllFiles(fileOwner: String): List<FileEntity>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ suspend fun FileDataStorageManager.saveShares(shares: List<OCShare>, accountName
}
}

suspend fun FileDataStorageManager.getAllGalleryItemsSuspended(): List<OCFile> {
val fileEntities = fileDao.getGalleryItemsSuspended(0, Long.MAX_VALUE, user.accountName)
return fileEntities.map { createFileInstance(it) }
}

fun FileDataStorageManager.searchFilesByName(file: OCFile, accountName: String, query: String): List<OCFile> =
fileDao.searchFilesInFolder(file.fileId, accountName, query).map {
createFileInstance(it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
package com.nextcloud.utils.extensions

import com.owncloud.android.MainApp
import com.owncloud.android.datamodel.GalleryItems
import com.owncloud.android.datamodel.GalleryRow
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.datamodel.OCFileDepth
import com.owncloud.android.datamodel.OCFileDepth.DeepLevel
import com.owncloud.android.datamodel.OCFileDepth.FirstLevel
import com.owncloud.android.datamodel.OCFileDepth.Root
import com.owncloud.android.utils.FileStorageUtils
import java.util.Calendar
import java.util.Date

fun List<OCFile>.filterFilenames(): List<OCFile> = distinctBy { it.fileName }

Expand Down Expand Up @@ -50,3 +54,31 @@ fun OCFile?.getDepth(): OCFileDepth? {
// Otherwise, it's a subdirectory of a subdirectory
return DeepLevel
}

fun List<OCFile>.toGalleryItems(columns: Int, defaultSize: Int): List<GalleryItems> {
if (isEmpty()) return emptyList()

val calendar = Calendar.getInstance()
return groupBy {
calendar.timeInMillis = it.modificationTimestamp
calendar.set(Calendar.DAY_OF_MONTH, 1)
calendar.set(Calendar.HOUR_OF_DAY, 0)
calendar.set(Calendar.MINUTE, 0)
calendar.set(Calendar.SECOND, 0)
calendar.set(Calendar.MILLISECOND, 0)
calendar.timeInMillis
}
.map { (date, filesList) ->
GalleryItems(date, transformToRows(filesList, columns, defaultSize))
}
.sortedByDescending { it.date }
}

private fun transformToRows(list: List<OCFile>, columns: Int, defaultSize: Int): List<GalleryRow> {
if (list.isEmpty()) return emptyList()

return list
.sortedByDescending { it.modificationTimestamp }
.chunked(columns)
.map { chunk -> GalleryRow(chunk, defaultSize, defaultSize) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,19 @@ import com.afollestad.sectionedrecyclerview.SectionedRecyclerViewAdapter
import com.afollestad.sectionedrecyclerview.SectionedViewHolder
import com.nextcloud.client.account.User
import com.nextcloud.client.preferences.AppPreferences
import com.nextcloud.utils.extensions.toGalleryItems
import com.owncloud.android.databinding.GalleryHeaderBinding
import com.owncloud.android.databinding.GalleryRowBinding
import com.owncloud.android.datamodel.FileDataStorageManager
import com.owncloud.android.datamodel.GalleryItems
import com.owncloud.android.datamodel.GalleryRow
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.ui.activity.ComponentsGetter
import com.owncloud.android.ui.fragment.GalleryFragment
import com.owncloud.android.ui.fragment.GalleryFragmentBottomSheetDialog
import com.owncloud.android.ui.fragment.SearchType
import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface
import com.owncloud.android.utils.DisplayUtils
import com.owncloud.android.utils.FileSortOrder
import com.owncloud.android.utils.MimeTypeUtil
import com.owncloud.android.utils.theme.ViewThemeUtils
import me.zhanghai.android.fastscroll.PopupTextProvider
import java.util.Calendar
import java.util.Date

@Suppress("LongParameterList", "TooManyFunctions")
class GalleryAdapter(
Expand Down Expand Up @@ -210,72 +204,17 @@ class GalleryAdapter(
}

@SuppressLint("NotifyDataSetChanged")
fun showAllGalleryItems(
remotePath: String,
mediaState: GalleryFragmentBottomSheetDialog.MediaState,
photoFragment: GalleryFragment
) {
val items = storageManager.allGalleryItems

val filteredList = items.filter { it != null && it.remotePath.startsWith(remotePath) }

setMediaFilter(
filteredList,
mediaState,
photoFragment
)
}

// Set Image/Video List According to Selection of Hide/Show Image/Video
@SuppressLint("NotifyDataSetChanged")
private fun setMediaFilter(
items: List<OCFile>,
mediaState: GalleryFragmentBottomSheetDialog.MediaState,
photoFragment: GalleryFragment
) {
val finalSortedList: List<OCFile> = when (mediaState) {
GalleryFragmentBottomSheetDialog.MediaState.MEDIA_STATE_PHOTOS_ONLY -> {
items.filter { MimeTypeUtil.isImage(it.mimeType) }.distinct()
}

GalleryFragmentBottomSheetDialog.MediaState.MEDIA_STATE_VIDEOS_ONLY -> {
items.filter { MimeTypeUtil.isVideo(it.mimeType) }.distinct()
}

else -> items
}

if (finalSortedList.isEmpty()) {
photoFragment.setEmptyListMessage(SearchType.GALLERY_SEARCH)
}

files = finalSortedList.toGalleryItems()
fun updateList(items: List<GalleryItems>) {
files = items
notifyDataSetChanged()
}

private fun transformToRows(list: List<OCFile>): List<GalleryRow> {
if (list.isEmpty()) return emptyList()

return list
.sortedByDescending { it.modificationTimestamp }
.chunked(columns)
.map { chunk -> GalleryRow(chunk, defaultThumbnailSize, defaultThumbnailSize) }
}

@SuppressLint("NotifyDataSetChanged")
fun clear() {
files = emptyList()
notifyDataSetChanged()
}

private fun firstOfMonth(timestamp: Long): Long = Calendar.getInstance().apply {
time = Date(timestamp)
set(Calendar.DAY_OF_MONTH, getActualMinimum(Calendar.DAY_OF_MONTH))
set(Calendar.HOUR_OF_DAY, 0)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
}.timeInMillis

fun isEmpty(): Boolean = files.isEmpty()

fun getItem(position: Int): OCFile? {
Expand Down Expand Up @@ -365,21 +304,11 @@ class GalleryAdapter(
val allFiles = getAllFiles()
allFiles.firstOrNull { it.remotePath == remotePath }?.also { file ->
file.isFavorite = favorite
files = allFiles.toGalleryItems()
files = allFiles.toGalleryItems(columns, defaultThumbnailSize)
notifyItemChanged(file)
}
}

private fun List<OCFile>.toGalleryItems(): List<GalleryItems> {
if (isEmpty()) return emptyList()

return groupBy { firstOfMonth(it.modificationTimestamp) }
.map { (date, filesList) ->
GalleryItems(date, transformToRows(filesList))
}
.sortedByDescending { it.date }
}

override fun onBindFooterViewHolder(holder: SectionedViewHolder?, section: Int) = Unit

override fun swapDirectory(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.MenuHost
import androidx.core.view.MenuProvider
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.nextcloud.utils.extensions.getAllGalleryItemsSuspended
import com.nextcloud.utils.extensions.getParcelableArgument
import kotlinx.coroutines.Job
import com.nextcloud.utils.extensions.getTypedActivity
import com.nextcloud.utils.extensions.toGalleryItems
import com.owncloud.android.BuildConfig
import com.owncloud.android.R
import com.owncloud.android.datamodel.OCFile
Expand All @@ -44,13 +47,18 @@ import com.owncloud.android.ui.adapter.GalleryAdapter
import com.owncloud.android.ui.asynctasks.GallerySearchTask
import com.owncloud.android.ui.events.ChangeMenuEvent
import com.owncloud.android.ui.fragment.GalleryFragmentBottomSheetDialog.MediaState
import com.owncloud.android.utils.MimeTypeUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

@Suppress("ForbiddenComment", "ReturnCount", "MagicNumber", "MaxLineLength")
class GalleryFragment :
OCFileListFragment(),
GalleryFragmentBottomSheetActions {
var isPhotoSearchQueryRunning: Boolean = false
private var photoSearchTask: Job? = null
private var showGalleryJob: Job? = null
private var endDate: Long = 0
private val limit = 150
private var adapter: GalleryAdapter? = null
Expand Down Expand Up @@ -124,10 +132,11 @@ class GalleryFragment :
}

override fun onDestroyView() {
if (photoSearchTask != null) {
photoSearchTask?.cancel()
photoSearchTask = null
}
showGalleryJob?.cancel()
showGalleryJob = null

photoSearchTask?.cancel()
photoSearchTask = null

LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(refreshSearchEventReceiver)

Expand Down Expand Up @@ -372,12 +381,32 @@ class GalleryFragment :
fun showAllGalleryItems() {
val mediaState = bottomSheet?.currMediaState ?: return

adapter?.showAllGalleryItems(
preferences.getLastSelectedMediaFolder(),
mediaState,
this
)
updateSubtitle(mediaState)
showGalleryJob?.cancel()
showGalleryJob = lifecycleScope.launch(Dispatchers.Default) {
val remotePath = preferences.getLastSelectedMediaFolder()
val items = mContainerActivity.storageManager.getAllGalleryItemsSuspended()

val isPhotosOnly = mediaState == MediaState.MEDIA_STATE_PHOTOS_ONLY
val isVideosOnly = mediaState == MediaState.MEDIA_STATE_VIDEOS_ONLY

val filteredItems = items.filter {
if (!it.remotePath.startsWith(remotePath)) return@filter false
if (isPhotosOnly) return@filter MimeTypeUtil.isImage(it.mimeType)
if (isVideosOnly) return@filter MimeTypeUtil.isVideo(it.mimeType)
true
}

val galleryItems =
filteredItems.toGalleryItems(columnsCount, ThumbnailsCacheManager.getThumbnailDimension())

withContext(Dispatchers.Main) {
if (galleryItems.isEmpty()) {
setEmptyListMessage(SearchType.GALLERY_SEARCH)
}
adapter?.updateList(galleryItems)
updateSubtitle(mediaState)
}
}
}

private fun updateSubtitle(mediaState: MediaState?) {
Expand Down
Loading