306 lines
11 KiB
Kotlin
306 lines
11 KiB
Kotlin
package com.simplemobiletools.voicerecorder.adapters
|
|
|
|
import android.view.*
|
|
import android.widget.PopupMenu
|
|
import android.widget.TextView
|
|
import com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
|
|
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
|
|
import com.simplemobiletools.commons.extensions.*
|
|
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
|
|
import com.simplemobiletools.commons.helpers.isQPlus
|
|
import com.simplemobiletools.commons.views.MyRecyclerView
|
|
import com.simplemobiletools.voicerecorder.BuildConfig
|
|
import com.simplemobiletools.voicerecorder.R
|
|
import com.simplemobiletools.voicerecorder.activities.SimpleActivity
|
|
import com.simplemobiletools.voicerecorder.databinding.ItemRecordingBinding
|
|
import com.simplemobiletools.voicerecorder.dialogs.DeleteConfirmationDialog
|
|
import com.simplemobiletools.voicerecorder.dialogs.RenameRecordingDialog
|
|
import com.simplemobiletools.voicerecorder.extensions.config
|
|
import com.simplemobiletools.voicerecorder.extensions.deleteRecordings
|
|
import com.simplemobiletools.voicerecorder.extensions.moveRecordingsToRecycleBin
|
|
import com.simplemobiletools.voicerecorder.helpers.getAudioFileContentUri
|
|
import com.simplemobiletools.voicerecorder.interfaces.RefreshRecordingsListener
|
|
import com.simplemobiletools.voicerecorder.models.Events
|
|
import com.simplemobiletools.voicerecorder.models.Recording
|
|
import org.greenrobot.eventbus.EventBus
|
|
import com.simplemobiletools.commons.R as CommonsR
|
|
|
|
class RecordingsAdapter(
|
|
activity: SimpleActivity,
|
|
var recordings: ArrayList<Recording>,
|
|
val refreshListener: RefreshRecordingsListener,
|
|
recyclerView: MyRecyclerView,
|
|
itemClick: (Any) -> Unit
|
|
) :
|
|
MyRecyclerViewAdapter(activity, recyclerView, itemClick), RecyclerViewFastScroller.OnPopupTextUpdate {
|
|
|
|
var currRecordingId = 0
|
|
|
|
init {
|
|
setupDragListener(true)
|
|
}
|
|
|
|
override fun getActionMenuId() = R.menu.cab_recordings
|
|
|
|
override fun prepareActionMode(menu: Menu) {
|
|
menu.apply {
|
|
findItem(R.id.cab_rename).isVisible = isOneItemSelected()
|
|
findItem(R.id.cab_open_with).isVisible = isOneItemSelected()
|
|
}
|
|
}
|
|
|
|
override fun actionItemPressed(id: Int) {
|
|
if (selectedKeys.isEmpty()) {
|
|
return
|
|
}
|
|
|
|
when (id) {
|
|
R.id.cab_rename -> renameRecording()
|
|
R.id.cab_share -> shareRecordings()
|
|
R.id.cab_delete -> askConfirmDelete()
|
|
R.id.cab_select_all -> selectAll()
|
|
R.id.cab_open_with -> openRecordingWith()
|
|
}
|
|
}
|
|
|
|
override fun getSelectableItemCount() = recordings.size
|
|
|
|
override fun getIsItemSelectable(position: Int) = true
|
|
|
|
override fun getItemSelectionKey(position: Int) = recordings.getOrNull(position)?.id
|
|
|
|
override fun getItemKeyPosition(key: Int) = recordings.indexOfFirst { it.id == key }
|
|
|
|
override fun onActionModeCreated() {}
|
|
|
|
override fun onActionModeDestroyed() {}
|
|
|
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
|
return createViewHolder(ItemRecordingBinding.inflate(layoutInflater, parent, false).root)
|
|
}
|
|
|
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
|
val recording = recordings[position]
|
|
holder.bindView(recording, true, true) { itemView, layoutPosition ->
|
|
setupView(itemView, recording)
|
|
}
|
|
bindViewHolder(holder)
|
|
}
|
|
|
|
override fun getItemCount() = recordings.size
|
|
|
|
private fun getItemWithKey(key: Int): Recording? = recordings.firstOrNull { it.id == key }
|
|
|
|
fun updateItems(newItems: ArrayList<Recording>) {
|
|
if (newItems.hashCode() != recordings.hashCode()) {
|
|
recordings = newItems
|
|
notifyDataSetChanged()
|
|
finishActMode()
|
|
}
|
|
}
|
|
|
|
private fun renameRecording() {
|
|
val recording = getItemWithKey(selectedKeys.first()) ?: return
|
|
RenameRecordingDialog(activity, recording) {
|
|
finishActMode()
|
|
refreshListener.refreshRecordings()
|
|
}
|
|
}
|
|
|
|
private fun openRecordingWith() {
|
|
val recording = getItemWithKey(selectedKeys.first()) ?: return
|
|
val path = if (isQPlus()) {
|
|
getAudioFileContentUri(recording.id.toLong()).toString()
|
|
} else {
|
|
recording.path
|
|
}
|
|
|
|
activity.openPathIntent(path, false, BuildConfig.APPLICATION_ID, "audio/*")
|
|
}
|
|
|
|
private fun shareRecordings() {
|
|
val selectedItems = getSelectedItems()
|
|
val paths = selectedItems.map {
|
|
it.path.ifEmpty {
|
|
getAudioFileContentUri(it.id.toLong()).toString()
|
|
}
|
|
}
|
|
|
|
activity.sharePathsIntent(paths, BuildConfig.APPLICATION_ID)
|
|
}
|
|
|
|
private fun askConfirmDelete() {
|
|
val itemsCnt = selectedKeys.size
|
|
val firstItem = getSelectedItems().firstOrNull() ?: return
|
|
val items = if (itemsCnt == 1) {
|
|
"\"${firstItem.title}\""
|
|
} else {
|
|
resources.getQuantityString(R.plurals.delete_recordings, itemsCnt, itemsCnt)
|
|
}
|
|
|
|
val baseString = if (activity.config.useRecycleBin) {
|
|
CommonsR.string.move_to_recycle_bin_confirmation
|
|
} else {
|
|
R.string.delete_recordings_confirmation
|
|
}
|
|
val question = String.format(resources.getString(baseString), items)
|
|
|
|
DeleteConfirmationDialog(activity, question, activity.config.useRecycleBin) { skipRecycleBin ->
|
|
ensureBackgroundThread {
|
|
val toRecycleBin = !skipRecycleBin && activity.config.useRecycleBin
|
|
if (toRecycleBin) {
|
|
moveMediaStoreRecordingsToRecycleBin()
|
|
} else {
|
|
deleteMediaStoreRecordings()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun deleteMediaStoreRecordings() {
|
|
if (selectedKeys.isEmpty()) {
|
|
return
|
|
}
|
|
|
|
val oldRecordingIndex = recordings.indexOfFirst { it.id == currRecordingId }
|
|
val recordingsToRemove = recordings.filter { selectedKeys.contains(it.id) } as ArrayList<Recording>
|
|
val positions = getSelectedItemPositions()
|
|
|
|
activity.deleteRecordings(recordingsToRemove) { success ->
|
|
if (success) {
|
|
doDeleteAnimation(oldRecordingIndex, recordingsToRemove, positions)
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun moveMediaStoreRecordingsToRecycleBin() {
|
|
if (selectedKeys.isEmpty()) {
|
|
return
|
|
}
|
|
|
|
val oldRecordingIndex = recordings.indexOfFirst { it.id == currRecordingId }
|
|
val recordingsToRemove = recordings.filter { selectedKeys.contains(it.id) } as ArrayList<Recording>
|
|
val positions = getSelectedItemPositions()
|
|
|
|
activity.moveRecordingsToRecycleBin(recordingsToRemove) { success ->
|
|
if (success) {
|
|
doDeleteAnimation(oldRecordingIndex, recordingsToRemove, positions)
|
|
EventBus.getDefault().post(Events.RecordingTrashUpdated())
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun doDeleteAnimation(oldRecordingIndex: Int, recordingsToRemove: ArrayList<Recording>, positions: ArrayList<Int>) {
|
|
recordings.removeAll(recordingsToRemove.toSet())
|
|
activity.runOnUiThread {
|
|
if (recordings.isEmpty()) {
|
|
refreshListener.refreshRecordings()
|
|
finishActMode()
|
|
} else {
|
|
positions.sortDescending()
|
|
removeSelectedItems(positions)
|
|
if (recordingsToRemove.map { it.id }.contains(currRecordingId)) {
|
|
val newRecordingIndex = Math.min(oldRecordingIndex, recordings.size - 1)
|
|
val newRecording = recordings[newRecordingIndex]
|
|
refreshListener.playRecording(newRecording, false)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun updateCurrentRecording(newId: Int) {
|
|
val oldId = currRecordingId
|
|
currRecordingId = newId
|
|
notifyItemChanged(recordings.indexOfFirst { it.id == oldId })
|
|
notifyItemChanged(recordings.indexOfFirst { it.id == newId })
|
|
}
|
|
|
|
private fun getSelectedItems() = recordings.filter { selectedKeys.contains(it.id) } as ArrayList<Recording>
|
|
|
|
private fun setupView(view: View, recording: Recording) {
|
|
ItemRecordingBinding.bind(view).apply {
|
|
root.setupViewBackground(activity)
|
|
recordingFrame.isSelected = selectedKeys.contains(recording.id)
|
|
|
|
arrayListOf<TextView>(recordingTitle, recordingDate, recordingDuration, recordingSize).forEach {
|
|
it.setTextColor(textColor)
|
|
}
|
|
|
|
if (recording.id == currRecordingId) {
|
|
recordingTitle.setTextColor(root.context.getProperPrimaryColor())
|
|
}
|
|
|
|
recordingTitle.text = recording.title
|
|
recordingDate.text = recording.timestamp.formatDate(root.context)
|
|
recordingDuration.text = recording.duration.getFormattedDuration()
|
|
recordingSize.text = recording.size.formatSize()
|
|
|
|
overflowMenuIcon.drawable.apply {
|
|
mutate()
|
|
setTint(activity.getProperTextColor())
|
|
}
|
|
|
|
overflowMenuIcon.setOnClickListener {
|
|
showPopupMenu(overflowMenuAnchor, recording)
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun onChange(position: Int) = recordings.getOrNull(position)?.title ?: ""
|
|
|
|
private fun showPopupMenu(view: View, recording: Recording) {
|
|
if (selectedKeys.isNotEmpty()) {
|
|
selectedKeys.clear()
|
|
notifyDataSetChanged()
|
|
}
|
|
|
|
finishActMode()
|
|
val theme = activity.getPopupMenuTheme()
|
|
val contextTheme = ContextThemeWrapper(activity, theme)
|
|
|
|
PopupMenu(contextTheme, view, Gravity.END).apply {
|
|
inflate(getActionMenuId())
|
|
menu.findItem(R.id.cab_select_all).isVisible = false
|
|
setOnMenuItemClickListener { item ->
|
|
val recordingId = recording.id
|
|
when (item.itemId) {
|
|
R.id.cab_rename -> {
|
|
executeItemMenuOperation(recordingId) {
|
|
renameRecording()
|
|
}
|
|
}
|
|
|
|
R.id.cab_share -> {
|
|
executeItemMenuOperation(recordingId) {
|
|
shareRecordings()
|
|
}
|
|
}
|
|
|
|
R.id.cab_open_with -> {
|
|
executeItemMenuOperation(recordingId) {
|
|
openRecordingWith()
|
|
}
|
|
}
|
|
|
|
R.id.cab_delete -> {
|
|
executeItemMenuOperation(recordingId, removeAfterCallback = false) {
|
|
askConfirmDelete()
|
|
}
|
|
}
|
|
}
|
|
|
|
true
|
|
}
|
|
show()
|
|
}
|
|
}
|
|
|
|
private fun executeItemMenuOperation(callId: Int, removeAfterCallback: Boolean = true, callback: () -> Unit) {
|
|
selectedKeys.add(callId)
|
|
callback()
|
|
if (removeAfterCallback) {
|
|
selectedKeys.remove(callId)
|
|
}
|
|
}
|
|
}
|