Skip to content

Commit

Permalink
Merge community code multi selection (#161)
Browse files Browse the repository at this point in the history
* added header and count for multip

* added feature to move multiple files together

* fixed space issue while creating the folder

* remove extra option from library actions

* added move action on top header

* added delete , restore and forever delete actions (#276)

* MOBILEAPPS-1986 (#277)

* added multi offline action

* fixed snackbar delayed issue after action and added multiple offline actions

* added strings

* fixed move issue

* MOBILEAPPS-2033 (#278)

* added multi action for favorite

* added action for start process and also added required options on sheet in multi-action (#279)

* fixed deletion issue and removed unused code (#280)

* MOBILEAPPS-2038 (#281)

* accessibility action sheet issue fixed

* fixed internet issue

* merge community code and fixed build issue
  • Loading branch information
aman-alfresco authored Jul 28, 2023
1 parent 1392ba2 commit 784a22b
Show file tree
Hide file tree
Showing 49 changed files with 543 additions and 233 deletions.
44 changes: 44 additions & 0 deletions actions/src/main/kotlin/com/alfresco/content/actions/Action.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import com.alfresco.events.on
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.net.SocketTimeoutException

Expand All @@ -28,7 +29,13 @@ interface Action {
val eventName: EventName

suspend fun execute(context: Context): ParentEntry
suspend fun executeMulti(context: Context): Pair<ParentEntry, List<Entry>> {
return Pair(entry, entries)
}
fun copy(_entry: ParentEntry): Action
fun copy(_entries: List<Entry>): Action {
return this
}

fun execute(
context: Context,
Expand Down Expand Up @@ -67,6 +74,43 @@ interface Action {
}
}

fun executeMulti(
context: Context,
scope: CoroutineScope,
) = scope.launch(Dispatchers.IO) {
val bus = EventBus.default
try {
val newEntry = executeMulti(context)
val newAction = copy(newEntry.second)
sendAnalytics(true)
bus.send(newAction)
} catch (ex: CancellationException) {
// no-op
if (entry is Entry && (entry as Entry).uploadServer == UploadServerType.UPLOAD_TO_TASK &&
ex.message == ERROR_FILE_SIZE_EXCEED
) {
bus.send(Error(context.getString(R.string.error_file_size_exceed)))
}
} catch (ex: Exception) {
sendAnalytics(false)
bus.send(Error(ex.message ?: ""))
} catch (ex: SocketTimeoutException) {
sendAnalytics(false)
bus.send(Error(context.getString(R.string.action_timeout_error)))
} catch (ex: kotlin.Exception) {
sendAnalytics(false)
Logger.e(ex)
when (title) {
R.string.action_create_folder -> {
if (ex.message?.contains("409") == true) {
bus.send(Error(context.getString(R.string.error_duplicate_folder)))
}
}
else -> bus.send(Error(context.getString(R.string.action_generic_error)))
}
}
}

private fun sendAnalytics(status: Boolean) {
if (title == R.string.action_create_folder) {
AnalyticsManager().apiTracker(APIEvent.NewFolder, status)
Expand Down
129 changes: 104 additions & 25 deletions actions/src/main/kotlin/com/alfresco/content/actions/ActionDelete.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,28 @@ import com.alfresco.kotlin.ellipsize
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.withContext
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

data class ActionDelete(
override var entry: Entry,
override val entries: List<Entry> = emptyList(),
override val icon: Int = R.drawable.ic_delete,
override val title: Int = R.string.action_delete_title,
override val eventName: EventName = EventName.MoveTrash,
) : Action {

override suspend fun execute(context: Context): Entry {
try {
delete(entry)
withContext(Dispatchers.IO) {
delete(entry)
}
} catch (ex: KotlinNullPointerException) {
// no-op. expected for 204
ex.printStackTrace()
}

// Cleanup associated upload if any
Expand All @@ -39,6 +45,29 @@ data class ActionDelete(
return entry
}

override suspend fun executeMulti(context: Context): Pair<ParentEntry, List<Entry>> = coroutineScope {
val entriesObj = entries.toMutableList()
try {
entriesObj.map {
async(Dispatchers.IO) {
delete(it)
}
}
} catch (ex: KotlinNullPointerException) {
// no-op. expected for 204
ex.printStackTrace()
}

// Cleanup associated upload if any
entriesObj.forEach {
if (it.type == Entry.Type.FILE) {
OfflineRepository().removeUpload(it.id)
}
}

return@coroutineScope Pair(entry, entriesObj)
}

private suspend inline fun delete(entry: Entry) {
when (entry.type) {
Entry.Type.FILE, Entry.Type.FOLDER -> BrowseRepository().deleteEntry(entry)
Expand All @@ -49,49 +78,71 @@ data class ActionDelete(

override fun copy(_entry: ParentEntry): Action = copy(entry = _entry as Entry)

override fun showToast(view: View, anchorView: View?) =
Action.showToast(
view,
anchorView,
R.string.action_delete_toast,
entry.name.ellipsize(maxFileNameInToast(view)),
)
override fun copy(_entries: List<Entry>): Action = copy(entries = _entries)

override fun showToast(view: View, anchorView: View?) {
if (entries.size > 1) {
Action.showToast(view, anchorView, R.string.action_delete_multiple_toast, entries.size.toString())
} else {
Action.showToast(view, anchorView, R.string.action_delete_toast, entry.name.ellipsize(maxFileNameInToast(view)))
}
}
}

data class ActionRestore(
override var entry: Entry,
override val entries: List<Entry> = emptyList(),
override val icon: Int = R.drawable.ic_restore,
override val title: Int = R.string.action_restore_title,
override val eventName: EventName = EventName.Restore,
) : Action {
override suspend fun execute(context: Context): Entry {
TrashCanRepository().restoreEntry(entry)
withContext(Dispatchers.IO) {
TrashCanRepository().restoreEntry(entry)
}
return entry
}

override suspend fun executeMulti(context: Context): Pair<ParentEntry, List<Entry>> = coroutineScope {
val entriesObj = entries.toMutableList()
entriesObj.map {
async(Dispatchers.IO) {
TrashCanRepository().restoreEntry(it)
}
}
return@coroutineScope Pair(entry, entriesObj)
}

override fun copy(_entry: ParentEntry): Action = copy(entry = _entry as Entry)

override fun showToast(view: View, anchorView: View?) =
Action.showToast(
view,
anchorView,
R.string.action_restored_toast,
entry.name.ellipsize(maxFileNameInToast(view)),
)
override fun copy(_entries: List<Entry>): Action = copy(entries = _entries)

override fun showToast(view: View, anchorView: View?) {
if (entries.size > 1) {
Action.showToast(view, anchorView, R.string.action_restored_multiple_toast, entries.size.toString())
} else {
Action.showToast(view, anchorView, R.string.action_restored_toast, entry.name.ellipsize(maxFileNameInToast(view)))
}
}
}

data class ActionDeleteForever(
override var entry: Entry,
override val entries: List<Entry> = emptyList(),
override val icon: Int = R.drawable.ic_delete_forever,
override val title: Int = R.string.action_delete_forever_title,
override val eventName: EventName = EventName.PermanentlyDelete,
) : Action {

override suspend fun execute(context: Context): Entry {
if (showConfirmation(context)) {
try {
delete(entry)
withContext(Dispatchers.IO) {
delete(entry)
}
} catch (ex: KotlinNullPointerException) {
// no-op. expected for 204
ex.printStackTrace()
}
} else {
throw CancellationException()
Expand All @@ -100,11 +151,37 @@ data class ActionDeleteForever(
return entry
}

override suspend fun executeMulti(context: Context): Pair<ParentEntry, List<Entry>> = coroutineScope {
val entriesObj = entries.toMutableList()
if (showConfirmation(context)) {
try {
entriesObj.map {
async(Dispatchers.IO) {
delete(it)
}
}
} catch (ex: KotlinNullPointerException) {
// no-op. expected for 204
ex.printStackTrace()
}
} else {
throw CancellationException()
}
return@coroutineScope Pair(entry, entriesObj)
}

private suspend fun showConfirmation(context: Context) = withContext(Dispatchers.Main) {
suspendCoroutine<Boolean> {
MaterialAlertDialogBuilder(context)
.setTitle(context.getString(R.string.action_delete_confirmation_title))
.setMessage(context.getString(R.string.action_delete_confirmation_message, entry.name))
.setMessage(
if (entries.size > 1) {
context.getString(
R.string.action_delete_multiple_confirmation_message,
entries.size.toString(),
)
} else context.getString(R.string.action_delete_confirmation_message, entry.name),
)
.setNegativeButton(context.getString(R.string.action_delete_confirmation_negative)) { _, _ ->
it.resume(false)
}
Expand All @@ -119,11 +196,13 @@ data class ActionDeleteForever(

override fun copy(_entry: ParentEntry): Action = copy(entry = _entry as Entry)

override fun showToast(view: View, anchorView: View?) =
Action.showToast(
view,
anchorView,
R.string.action_delete_forever_toast,
entry.name.ellipsize(maxFileNameInToast(view)),
)
override fun copy(_entries: List<Entry>): Action = copy(entries = _entries)

override fun showToast(view: View, anchorView: View?) {
if (entries.size > 1) {
Action.showToast(view, anchorView, R.string.action_delete_forever_multiple_toast, entries.size.toString())
} else {
Action.showToast(view, anchorView, R.string.action_delete_forever_toast, entry.name.ellipsize(maxFileNameInToast(view)))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ import com.alfresco.content.data.Entry
import com.alfresco.content.data.EventName
import com.alfresco.content.data.FavoritesRepository
import com.alfresco.content.data.ParentEntry
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope

data class ActionAddFavorite(
override val entry: Entry,
override val entries: List<Entry> = emptyList(),
override val icon: Int = R.drawable.ic_favorite,
override val title: Int = R.string.action_add_favorite_title,
override val eventName: EventName = EventName.AddFavorite,
Expand All @@ -20,14 +24,30 @@ data class ActionAddFavorite(
return entry.copy(isFavorite = true)
}

override fun copy(_entry: ParentEntry): Action = copy(entry = _entry as Entry)
override suspend fun executeMulti(context: Context): Pair<ParentEntry, List<Entry>> = coroutineScope {
val entriesObj = entries.toMutableList()
entriesObj.map {
async(Dispatchers.IO) {
repository.addFavorite(it)
}
}
return@coroutineScope Pair(entry, entriesObj.map { it.copy(isFavorite = true, isSelectedForMultiSelection = false) })
}

override fun showToast(view: View, anchorView: View?) =
Action.showToast(view, anchorView, R.string.action_add_favorite_toast)
override fun copy(_entry: ParentEntry): Action = copy(entry = _entry as Entry)
override fun copy(_entries: List<Entry>): Action = copy(entries = _entries)
override fun showToast(view: View, anchorView: View?) {
if (entries.size > 1) {
Action.showToast(view, anchorView, R.string.action_add_favorite_multiple_toast, entries.size.toString())
} else {
Action.showToast(view, anchorView, R.string.action_add_favorite_toast)
}
}
}

data class ActionRemoveFavorite(
override var entry: Entry,
override val entries: List<Entry> = emptyList(),
override val icon: Int = R.drawable.ic_favorite_filled,
override val title: Int = R.string.action_remove_favorite_title,
override val eventName: EventName = EventName.RemoveFavorite,
Expand All @@ -43,8 +63,28 @@ data class ActionRemoveFavorite(
return entry.copy(isFavorite = false)
}

override fun copy(_entry: ParentEntry): Action = copy(entry = _entry as Entry)
override suspend fun executeMulti(context: Context): Pair<ParentEntry, List<Entry>> = coroutineScope {
val entriesObj = entries.toMutableList()
try {
entriesObj.map {
async(Dispatchers.IO) {
repository.removeFavorite(it)
}
}
} catch (ex: KotlinNullPointerException) {
// no-op. expected for 204
ex.printStackTrace()
}
return@coroutineScope Pair(entry, entriesObj.map { it.copy(isFavorite = false, isSelectedForMultiSelection = false) })
}

override fun showToast(view: View, anchorView: View?) =
Action.showToast(view, anchorView, R.string.action_remove_favorite_toast)
override fun copy(_entry: ParentEntry): Action = copy(entry = _entry as Entry)
override fun copy(_entries: List<Entry>): Action = copy(entries = _entries)
override fun showToast(view: View, anchorView: View?) {
if (entries.size > 1) {
Action.showToast(view, anchorView, R.string.action_remove_favorite_multiple_toast, entries.size.toString())
} else {
Action.showToast(view, anchorView, R.string.action_remove_favorite_toast)
}
}
}
Loading

0 comments on commit 784a22b

Please sign in to comment.