handle media grouping at the MediaActivity

This commit is contained in:
tibbi 2018-06-22 14:54:28 +02:00
parent e759270019
commit 698f9b0c76
4 changed files with 107 additions and 99 deletions

View File

@ -283,8 +283,9 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
Thread {
val filtered = mMedia.filter { it.name.contains(text, true) } as ArrayList
filtered.sortBy { !it.name.startsWith(text, true) }
val groupedMedia = MediaFetcher(applicationContext).groupMedia(filtered, mPath)
runOnUiThread {
getMediaAdapter()?.updateMedia(filtered)
getMediaAdapter()?.updateMedia(groupedMedia)
}
}.start()
}
@ -315,12 +316,12 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
return
}
val media = mMedia.clone() as ArrayList<Medium>
val groupedMedia = MediaFetcher(applicationContext).groupMedia(mMedia.clone() as ArrayList<Medium>, mPath)
val currAdapter = media_grid.adapter
if (currAdapter == null) {
initZoomListener()
val fastscroller = if (config.scrollHorizontally) media_horizontal_fastscroller else media_vertical_fastscroller
MediaAdapter(this, media, this, mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent, mAllowPickingMultiple, media_grid, fastscroller, mPath) {
MediaAdapter(this, groupedMedia, this, mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent, mAllowPickingMultiple, media_grid, fastscroller) {
itemClicked((it as ThumbnailMedium).path)
}.apply {
setupZoomListener(mZoomListener)
@ -328,8 +329,9 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
}
setupLayoutManager()
} else {
(currAdapter as MediaAdapter).updateMedia(media)
(currAdapter as MediaAdapter).updateMedia(groupedMedia)
}
setupScrollDirection()
}
@ -359,8 +361,9 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
private fun getBubbleTextItem(index: Int, sorting: Int) = getMediaAdapter()?.getItemBubbleText(index, sorting) ?: ""
private fun checkLastMediaChanged() {
if (isActivityDestroyed())
if (isActivityDestroyed()) {
return
}
mLastMediaHandler.removeCallbacksAndMessages(null)
mLastMediaHandler.postDelayed({

View File

@ -2,7 +2,6 @@ package com.simplemobiletools.gallery.adapters
import android.os.Handler
import android.os.Looper
import android.text.format.DateFormat
import android.view.Menu
import android.view.View
import android.view.ViewGroup
@ -19,19 +18,16 @@ import com.simplemobiletools.commons.views.MyRecyclerView
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.dialogs.DeleteWithRememberDialog
import com.simplemobiletools.gallery.extensions.*
import com.simplemobiletools.gallery.helpers.*
import com.simplemobiletools.gallery.models.Medium
import com.simplemobiletools.gallery.helpers.VIEW_TYPE_LIST
import com.simplemobiletools.gallery.models.ThumbnailItem
import com.simplemobiletools.gallery.models.ThumbnailMedium
import com.simplemobiletools.gallery.models.ThumbnailSection
import kotlinx.android.synthetic.main.photo_video_item_grid.view.*
import kotlinx.android.synthetic.main.thumbnail_section.view.*
import java.util.*
import kotlin.collections.ArrayList
class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>, val listener: MediaOperationsListener?, val isAGetIntent: Boolean,
val allowMultiplePicks: Boolean, recyclerView: MyRecyclerView, fastScroller: FastScroller? = null, val path: String,
itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<ThumbnailItem>, val listener: MediaOperationsListener?, val isAGetIntent: Boolean,
val allowMultiplePicks: Boolean, recyclerView: MyRecyclerView, fastScroller: FastScroller? = null, itemClick: (Any) -> Unit) :
MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
private val INSTANT_LOAD_DURATION = 2000L
private val IMAGE_LOAD_DELAY = 100L
@ -41,13 +37,10 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
private val config = activity.config
private val isListViewType = config.viewTypeFiles == VIEW_TYPE_LIST
private var visibleItemPaths = ArrayList<String>()
private var thumbnailItems = ArrayList<ThumbnailItem>()
private var loadImageInstantly = false
private var delayHandler = Handler(Looper.getMainLooper())
private var currentMediaHash = media.hashCode()
private var currentGrouping = GROUP_BY_NONE
private val hasOTGConnected = activity.hasOTGConnected()
private var mediumGroups = LinkedHashMap<String, ArrayList<Medium>>()
private var scrollHorizontally = config.scrollHorizontally
private var animateGifs = config.animateGifs
@ -56,7 +49,6 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
init {
setupDragListener(true)
groupMedia()
enableInstantLoad()
}
@ -84,7 +76,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
}
override fun onBindViewHolder(holder: MyRecyclerViewAdapter.ViewHolder, position: Int) {
val tmbItem = thumbnailItems.getOrNull(position) ?: return
val tmbItem = media.getOrNull(position) ?: return
if (tmbItem is ThumbnailMedium) {
visibleItemPaths.add(tmbItem.path)
}
@ -99,10 +91,10 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
bindViewHolder(holder, position, view)
}
override fun getItemCount() = thumbnailItems.size
override fun getItemCount() = media.size
override fun getItemViewType(position: Int): Int {
val tmbItem = thumbnailItems[position]
val tmbItem = media[position]
return if (tmbItem is ThumbnailSection) {
ITEM_SECTION
} else {
@ -145,7 +137,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
}
}
override fun getSelectableItemCount() = thumbnailItems.filter { it is ThumbnailMedium }.size
override fun getSelectableItemCount() = media.filter { it is ThumbnailMedium }.size
override fun getIsItemSelectable(position: Int) = !isASectionTitle(position)
@ -161,7 +153,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
}
}
fun isASectionTitle(position: Int) = thumbnailItems.getOrNull(position) is ThumbnailSection
fun isASectionTitle(position: Int) = media.getOrNull(position) is ThumbnailSection
private fun checkHideBtnVisibility(menu: Menu) {
var hiddenCnt = 0
@ -199,7 +191,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
private fun showProperties() {
if (selectedPositions.size <= 1) {
PropertiesDialog(activity, (thumbnailItems[selectedPositions.first()] as ThumbnailMedium).path, config.shouldShowHidden)
PropertiesDialog(activity, (media[selectedPositions.first()] as ThumbnailMedium).path, config.shouldShowHidden)
} else {
val paths = getSelectedPaths()
PropertiesDialog(activity, paths, config.shouldShowHidden)
@ -293,7 +285,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
}
}
private fun getCurrentPath() = (thumbnailItems[selectedPositions.first()] as ThumbnailMedium).path
private fun getCurrentPath() = (media[selectedPositions.first()] as ThumbnailMedium).path
private fun deleteFiles() {
if (selectedPositions.isEmpty()) {
@ -303,22 +295,22 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
val fileDirItems = ArrayList<FileDirItem>(selectedPositions.size)
val removeMedia = ArrayList<ThumbnailMedium>(selectedPositions.size)
if (thumbnailItems.size <= selectedPositions.first()) {
if (media.size <= selectedPositions.first()) {
finishActMode()
return
}
val SAFPath = (thumbnailItems[selectedPositions.first()] as ThumbnailMedium).path
val SAFPath = (media[selectedPositions.first()] as ThumbnailMedium).path
activity.handleSAFDialog(SAFPath) {
selectedPositions.sortedDescending().forEach {
val thumbnailItem = thumbnailItems[it]
val thumbnailItem = media[it]
if (thumbnailItem is ThumbnailMedium) {
fileDirItems.add(FileDirItem(thumbnailItem.path, thumbnailItem.name))
removeMedia.add(thumbnailItem)
}
}
thumbnailItems.removeAll(removeMedia)
media.removeAll(removeMedia)
listener?.tryDeleteFiles(fileDirItems)
removeSelectedItems()
}
@ -327,19 +319,18 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
private fun getSelectedMedia(): List<ThumbnailMedium> {
val selectedMedia = ArrayList<ThumbnailMedium>(selectedPositions.size)
selectedPositions.forEach {
selectedMedia.add(thumbnailItems[it] as ThumbnailMedium)
selectedMedia.add(media[it] as ThumbnailMedium)
}
return selectedMedia
}
private fun getSelectedPaths() = getSelectedMedia().map { it.path } as ArrayList<String>
fun updateMedia(newMedia: ArrayList<Medium>) {
if (newMedia.hashCode() != currentMediaHash || currentGrouping != config.getFolderGrouping(path)) {
fun updateMedia(newMedia: ArrayList<ThumbnailItem>) {
if (newMedia.hashCode() != currentMediaHash) {
currentMediaHash = newMedia.hashCode()
Handler().postDelayed({
media = newMedia
groupMedia()
enableInstantLoad()
notifyDataSetChanged()
finishActMode()
@ -376,69 +367,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
}, INSTANT_LOAD_DURATION)
}
private fun groupMedia() {
currentGrouping = config.getFolderGrouping(path)
if (currentGrouping and GROUP_BY_NONE != 0) {
return
}
mediumGroups.clear()
media.forEach {
val key = it.getGroupingKey(currentGrouping)
if (!mediumGroups.containsKey(key)) {
mediumGroups[key] = ArrayList()
}
mediumGroups[key]!!.add(it)
}
val sortDescending = currentGrouping and GROUP_DESCENDING != 0
val sorted = mediumGroups.toSortedMap(if (sortDescending) compareByDescending { it } else compareBy { it })
mediumGroups.clear()
sorted.forEach { key, value ->
mediumGroups[key] = value
}
thumbnailItems.clear()
for ((key, value) in mediumGroups) {
thumbnailItems.add(ThumbnailSection(getFormattedKey(key, currentGrouping)))
value.forEach {
val thumbnailMedium = ThumbnailMedium(it.name, it.path, it.parentPath, it.modified, it.taken, it.size, it.type, it.isFavorite)
thumbnailItems.add(thumbnailMedium)
}
}
}
private fun getFormattedKey(key: String, grouping: Int): String {
return when {
grouping and GROUP_BY_LAST_MODIFIED != 0 || grouping and GROUP_BY_DATE_TAKEN != 0 -> formatDate(key)
grouping and GROUP_BY_FILE_TYPE != 0 -> getFileTypeString(key)
grouping and GROUP_BY_EXTENSION != 0 -> key.toUpperCase()
grouping and GROUP_BY_FOLDER != 0 -> activity.humanizePath(key)
else -> key
}
}
private fun formatDate(timestamp: String): String {
return if (timestamp.areDigitsOnly()) {
val cal = Calendar.getInstance(Locale.ENGLISH)
cal.timeInMillis = timestamp.toLong()
DateFormat.format("dd MMM yyyy", cal).toString()
} else {
""
}
}
private fun getFileTypeString(key: String): String {
val stringId = when (key.toInt()) {
TYPE_IMAGES -> R.string.images
TYPE_VIDEOS -> R.string.videos
TYPE_GIFS -> R.string.gifs
else -> R.string.raw_images
}
return activity.getString(stringId)
}
fun getItemBubbleText(position: Int, sorting: Int) = (thumbnailItems[position] as? ThumbnailMedium)?.getBubbleText(sorting)
fun getItemBubbleText(position: Int, sorting: Int) = (media[position] as? ThumbnailMedium)?.getBubbleText(sorting)
private fun setupThumbnailMedium(view: View, medium: ThumbnailMedium) {
view.apply {

View File

@ -12,13 +12,15 @@ import com.simplemobiletools.gallery.adapters.MediaAdapter
import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask
import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.extensions.getCachedMedia
import com.simplemobiletools.gallery.helpers.MediaFetcher
import com.simplemobiletools.gallery.helpers.VIEW_TYPE_GRID
import com.simplemobiletools.gallery.models.Medium
import com.simplemobiletools.gallery.models.ThumbnailItem
import kotlinx.android.synthetic.main.dialog_medium_picker.view.*
class PickMediumDialog(val activity: BaseSimpleActivity, val path: String, val callback: (path: String) -> Unit) {
var dialog: AlertDialog
var shownMedia = ArrayList<Medium>()
var shownMedia = ArrayList<ThumbnailItem>()
val view = activity.layoutInflater.inflate(R.layout.dialog_medium_picker, null)
var isGridViewType = activity.config.viewTypeFiles == VIEW_TYPE_GRID
@ -31,7 +33,7 @@ class PickMediumDialog(val activity: BaseSimpleActivity, val path: String, val c
dialog = AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.setNeutralButton(R.string.other_folder, { dialogInterface, i -> showOtherFolder() })
.setNeutralButton(R.string.other_folder) { dialogInterface, i -> showOtherFolder() }
.create().apply {
activity.setupDialogStuff(view, this, R.string.select_photo)
}
@ -61,8 +63,8 @@ class PickMediumDialog(val activity: BaseSimpleActivity, val path: String, val c
if (media.hashCode() == shownMedia.hashCode())
return
shownMedia = media
val adapter = MediaAdapter(activity, media, null, true, false, view.media_grid, null, path) {
shownMedia = MediaFetcher(activity).groupMedia(media, path)
val adapter = MediaAdapter(activity, shownMedia, null, true, false, view.media_grid, null) {
callback((it as Medium).path)
dialog.dismiss()
}

View File

@ -4,14 +4,20 @@ import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.provider.MediaStore
import android.text.format.DateFormat
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.extensions.getDistinctPath
import com.simplemobiletools.gallery.extensions.getOTGFolderChildren
import com.simplemobiletools.gallery.extensions.shouldFolderBeVisible
import com.simplemobiletools.gallery.models.Medium
import com.simplemobiletools.gallery.models.ThumbnailItem
import com.simplemobiletools.gallery.models.ThumbnailMedium
import com.simplemobiletools.gallery.models.ThumbnailSection
import java.io.File
import java.util.*
class MediaFetcher(val context: Context) {
var shouldStop = false
@ -329,4 +335,72 @@ class MediaFetcher(val context: Context) {
result
})
}
fun groupMedia(media: ArrayList<Medium>, path: String): ArrayList<ThumbnailItem> {
val thumbnailItems = ArrayList<ThumbnailItem>()
val mediumGroups = LinkedHashMap<String, ArrayList<Medium>>()
val currentGrouping = context.config.getFolderGrouping(path)
if (currentGrouping and GROUP_BY_NONE != 0) {
media.forEach {
val thumbnailMedium = ThumbnailMedium(it.name, it.path, it.parentPath, it.modified, it.taken, it.size, it.type, it.isFavorite)
thumbnailItems.add(thumbnailMedium)
}
return thumbnailItems
}
media.forEach {
val key = it.getGroupingKey(currentGrouping)
if (!mediumGroups.containsKey(key)) {
mediumGroups[key] = ArrayList()
}
mediumGroups[key]!!.add(it)
}
val sortDescending = currentGrouping and GROUP_DESCENDING != 0
val sorted = mediumGroups.toSortedMap(if (sortDescending) compareByDescending { it } else compareBy { it })
mediumGroups.clear()
sorted.forEach { key, value ->
mediumGroups[key] = value
}
for ((key, value) in mediumGroups) {
thumbnailItems.add(ThumbnailSection(getFormattedKey(key, currentGrouping)))
value.forEach {
val thumbnailMedium = ThumbnailMedium(it.name, it.path, it.parentPath, it.modified, it.taken, it.size, it.type, it.isFavorite)
thumbnailItems.add(thumbnailMedium)
}
}
return thumbnailItems
}
private fun getFormattedKey(key: String, grouping: Int): String {
return when {
grouping and GROUP_BY_LAST_MODIFIED != 0 || grouping and GROUP_BY_DATE_TAKEN != 0 -> formatDate(key)
grouping and GROUP_BY_FILE_TYPE != 0 -> getFileTypeString(key)
grouping and GROUP_BY_EXTENSION != 0 -> key.toUpperCase()
grouping and GROUP_BY_FOLDER != 0 -> context.humanizePath(key)
else -> key
}
}
private fun formatDate(timestamp: String): String {
return if (timestamp.areDigitsOnly()) {
val cal = Calendar.getInstance(Locale.ENGLISH)
cal.timeInMillis = timestamp.toLong()
DateFormat.format("dd MMM yyyy", cal).toString()
} else {
""
}
}
private fun getFileTypeString(key: String): String {
val stringId = when (key.toInt()) {
TYPE_IMAGES -> R.string.images
TYPE_VIDEOS -> R.string.videos
TYPE_GIFS -> R.string.gifs
else -> R.string.raw_images
}
return context.getString(stringId)
}
}