Simplify ConflictResolveDialog

Signed-off-by: alperozturk <alper_ozturk@proton.me>
This commit is contained in:
alperozturk 2024-08-21 14:07:44 +02:00
parent ae5064d9a5
commit 9dcdb7d05b
No known key found for this signature in database
GPG key ID: 4E577DC593B59BDF
4 changed files with 109 additions and 89 deletions

View file

@ -0,0 +1,20 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package com.nextcloud.utils.extensions
import android.os.Parcel
import android.os.Parcelable
inline fun <reified T : Parcelable> Parcel.readParcelableCompat(classLoader: ClassLoader?): T? {
return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
readParcelable(classLoader, T::class.java)
} else {
@Suppress("DEPRECATION")
readParcelable(classLoader)
}
}

View file

@ -9,6 +9,7 @@
*/ */
package com.owncloud.android.ui.activity package com.owncloud.android.ui.activity
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
@ -114,33 +115,29 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener
} }
private fun handleFolderConflict(decision: Decision) { private fun handleFolderConflict(decision: Decision) {
offlineOperationPath?.let { path -> val path = offlineOperationPath ?: return
newFile?.let { serverFile -> val serverFile = newFile ?: return
val offlineOperation = fileDataStorageManager.offlineOperationDao.getByPath(path) val offlineOperation = fileDataStorageManager.offlineOperationDao.getByPath(path) ?: return
offlineOperation?.let { entity -> when(decision) {
when(decision) { Decision.KEEP_OFFLINE_FOLDER -> {
Decision.KEEP_OFFLINE_FOLDER -> { fileOperationsHelper?.removeFiles(listOf(serverFile), false, false)
fileOperationsHelper?.removeFiles(listOf(serverFile), false, false) backgroundJobManager.startOfflineOperations()
backgroundJobManager.startOfflineOperations()
}
Decision.KEEP_SERVER_FOLDER -> {
fileDataStorageManager.offlineOperationDao.deleteByPath(path)
}
Decision.KEEP_BOTH_FOLDER -> {
fileDataStorageManager.keepOfflineOperationAndServerFile(entity)
backgroundJobManager.startOfflineOperations()
}
else -> Unit
}
offlineOperationNotificationManager.dismissNotification(offlineOperation.id)
}
} }
Decision.KEEP_SERVER_FOLDER -> {
fileDataStorageManager.offlineOperationDao.deleteByPath(path)
}
Decision.KEEP_BOTH_FOLDER -> {
fileDataStorageManager.keepOfflineOperationAndServerFile(offlineOperation)
backgroundJobManager.startOfflineOperations()
}
else -> Unit
} }
offlineOperationNotificationManager.dismissNotification(offlineOperation.id)
} }
private fun keepLocal(file: OCFile?, upload: OCUpload?, user: User) { private fun keepLocal(file: OCFile?, upload: OCUpload?, user: User) {
@ -230,7 +227,7 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener
return return
} }
val (ft, user) = prepareDialog() val (ft, _) = prepareDialog()
val dialog = ConflictsResolveDialog.newInstance( val dialog = ConflictsResolveDialog.newInstance(
this, this,
offlineOperation, offlineOperation,
@ -268,6 +265,7 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener
} }
} }
@SuppressLint("CommitTransaction")
private fun prepareDialog(): Pair<FragmentTransaction, User> { private fun prepareDialog(): Pair<FragmentTransaction, User> {
val userOptional = user val userOptional = user
if (!userOptional.isPresent) { if (!userOptional.isPresent) {
@ -292,7 +290,7 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener
val dialog = ConflictsResolveDialog.newInstance( val dialog = ConflictsResolveDialog.newInstance(
this, this,
newFile!!, newFile!!,
existingFile, existingFile!!,
user user
) )
dialog.show(ft, "conflictDialog") dialog.show(ft, "conflictDialog")

View file

@ -106,16 +106,13 @@ class ConflictsResolveDialog : DialogFragment(), Injectable {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (savedInstanceState != null) { val bundle = savedInstanceState ?: arguments
data = savedInstanceState.getParcelableArgument(CONFLICT_DATA, ConflictDialogData::class.java)
leftDataFile = savedInstanceState.getSerializableArgument(LEFT_FILE, File::class.java) if (bundle != null) {
rightDataFile = savedInstanceState.getParcelableArgument(RIGHT_FILE, OCFile::class.java) data = bundle.getParcelableArgument(ARG_CONFLICT_DATA, ConflictDialogData::class.java)
user = savedInstanceState.getParcelableArgument(USER, User::class.java) leftDataFile = bundle.getSerializableArgument(ARG_LEFT_FILE, File::class.java)
} else if (arguments != null) { rightDataFile = bundle.getParcelableArgument(ARG_RIGHT_FILE, OCFile::class.java)
data = arguments.getParcelableArgument(CONFLICT_DATA, ConflictDialogData::class.java) user = bundle.getParcelableArgument(ARG_USER, User::class.java)
leftDataFile = arguments.getSerializableArgument(LEFT_FILE, File::class.java)
rightDataFile = arguments.getParcelableArgument(RIGHT_FILE, OCFile::class.java)
user = arguments.getParcelableArgument(USER, User::class.java)
} else { } else {
Toast.makeText(context, "Failed to create conflict dialog", Toast.LENGTH_LONG).show() Toast.makeText(context, "Failed to create conflict dialog", Toast.LENGTH_LONG).show()
} }
@ -124,45 +121,57 @@ class ConflictsResolveDialog : DialogFragment(), Injectable {
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
outState.run { outState.run {
putParcelable(CONFLICT_DATA, data) putParcelable(ARG_CONFLICT_DATA, data)
} }
} }
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
binding = ConflictResolveDialogBinding.inflate(requireActivity().layoutInflater) binding = ConflictResolveDialogBinding.inflate(requireActivity().layoutInflater)
viewThemeUtils.platform.themeCheckbox(binding.leftCheckbox) val builder = createDialogBuilder()
viewThemeUtils.platform.themeCheckbox(binding.rightCheckbox)
val builder = MaterialAlertDialogBuilder(requireContext()) setupUI()
setOnClickListeners()
viewThemeUtils.run {
platform.themeCheckbox(binding.leftCheckbox)
platform.themeCheckbox(binding.rightCheckbox)
dialog.colorMaterialAlertDialogBackground(requireContext(), builder)
}
return builder.create()
}
private fun createDialogBuilder(): MaterialAlertDialogBuilder {
return MaterialAlertDialogBuilder(requireContext())
.setView(binding.root) .setView(binding.root)
.setPositiveButton(R.string.common_ok) { _: DialogInterface?, _: Int -> .setPositiveButton(R.string.common_ok) { _: DialogInterface?, _: Int ->
val decision = when { okButtonClick()
binding.leftCheckbox.isChecked && binding.rightCheckbox.isChecked ->
if (data?.folderName == null) Decision.KEEP_BOTH_FOLDER else Decision.KEEP_BOTH
binding.leftCheckbox.isChecked ->
if (data?.folderName == null) Decision.KEEP_OFFLINE_FOLDER else Decision.KEEP_LOCAL
binding.rightCheckbox.isChecked ->
if (data?.folderName == null) Decision.KEEP_SERVER_FOLDER else Decision.KEEP_SERVER
else -> null
}
decision?.let { listener?.conflictDecisionMade(it) }
} }
.setNegativeButton(R.string.common_cancel) { _: DialogInterface?, _: Int -> .setNegativeButton(R.string.common_cancel) { _: DialogInterface?, _: Int ->
listener?.conflictDecisionMade(Decision.CANCEL) listener?.conflictDecisionMade(Decision.CANCEL)
} }
.setTitle(data?.folderName) .setTitle(data?.folderName)
}
setupUI() private fun okButtonClick() {
setOnClickListeners() binding.run {
val isFolderNameNotExists = (data?.folderName == null)
val decision = when {
leftCheckbox.isChecked && rightCheckbox.isChecked ->
if (isFolderNameNotExists) Decision.KEEP_BOTH_FOLDER else Decision.KEEP_BOTH
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.rightFileContainer.context, builder) leftCheckbox.isChecked ->
if (isFolderNameNotExists) Decision.KEEP_OFFLINE_FOLDER else Decision.KEEP_LOCAL
return builder.create() rightCheckbox.isChecked ->
if (isFolderNameNotExists) Decision.KEEP_SERVER_FOLDER else Decision.KEEP_SERVER
else -> null
}
decision?.let { listener?.conflictDecisionMade(it) }
}
} }
private fun setupUI() { private fun setupUI() {
@ -284,25 +293,26 @@ class ConflictsResolveDialog : DialogFragment(), Injectable {
} }
companion object { companion object {
private const val CONFLICT_DATA = "CONFLICT_DATA" private const val ARG_CONFLICT_DATA = "CONFLICT_DATA"
private const val LEFT_FILE = "KEY_LEFT_FILE" private const val ARG_LEFT_FILE = "LEFT_FILE"
private const val RIGHT_FILE = "KEY_RIGHT_FILE" private const val ARG_RIGHT_FILE = "RIGHT_FILE"
private const val USER = "user" private const val ARG_USER = "USER"
@JvmStatic @JvmStatic
fun newInstance( fun newInstance(
context: Context, context: Context,
leftFile: OCFile, leftFile: OCFile,
rightFile: OCFile?, rightFile: OCFile,
user: User? user: User?
): ConflictsResolveDialog { ): ConflictsResolveDialog {
val file = File(leftFile.storagePath) val file = File(leftFile.storagePath)
val conflictData = getFileConflictData(file, rightFile, context)
val bundle = Bundle().apply { val bundle = Bundle().apply {
putParcelable(CONFLICT_DATA, getConflictDataForFileConflict(file, rightFile, context)) putParcelable(ARG_CONFLICT_DATA, conflictData)
putSerializable(LEFT_FILE, file) putSerializable(ARG_LEFT_FILE, file)
putParcelable(RIGHT_FILE, rightFile) putParcelable(ARG_RIGHT_FILE, rightFile)
putParcelable(USER, user) putParcelable(ARG_USER, user)
} }
return ConflictsResolveDialog().apply { return ConflictsResolveDialog().apply {
@ -314,13 +324,13 @@ class ConflictsResolveDialog : DialogFragment(), Injectable {
fun newInstance( fun newInstance(
context: Context, context: Context,
offlineOperation: OfflineOperationEntity, offlineOperation: OfflineOperationEntity,
rightFile: OCFile?, rightFile: OCFile,
): ConflictsResolveDialog { ): ConflictsResolveDialog {
val conflictData = getConflictDataForFolderConflict(offlineOperation, rightFile, context) val conflictData = getFolderConflictData(offlineOperation, rightFile, context)
val bundle = Bundle().apply { val bundle = Bundle().apply {
putParcelable(CONFLICT_DATA, conflictData) putParcelable(ARG_CONFLICT_DATA, conflictData)
putParcelable(RIGHT_FILE, rightFile) putParcelable(ARG_RIGHT_FILE, rightFile)
} }
return ConflictsResolveDialog().apply { return ConflictsResolveDialog().apply {
@ -329,9 +339,9 @@ class ConflictsResolveDialog : DialogFragment(), Injectable {
} }
@JvmStatic @JvmStatic
fun getConflictDataForFolderConflict( private fun getFolderConflictData(
offlineOperation: OfflineOperationEntity, offlineOperation: OfflineOperationEntity,
rightFile: OCFile?, rightFile: OCFile,
context: Context context: Context
): ConflictDialogData { ): ConflictDialogData {
val folderName = null val folderName = null
@ -343,8 +353,8 @@ class ConflictsResolveDialog : DialogFragment(), Injectable {
val leftCheckBoxData = ConflictFileData(leftTitle, leftTimestamp.toString(), leftFileSize) val leftCheckBoxData = ConflictFileData(leftTitle, leftTimestamp.toString(), leftFileSize)
val rightTitle = context.getString(R.string.prefs_synced_folders_remote_path_title) val rightTitle = context.getString(R.string.prefs_synced_folders_remote_path_title)
val rightTimestamp = DisplayUtils.getRelativeTimestamp(context, rightFile?.modificationTimestamp ?: 0) val rightTimestamp = DisplayUtils.getRelativeTimestamp(context, rightFile.modificationTimestamp)
val rightFileSize = DisplayUtils.bytesToHumanReadable(rightFile?.fileLength ?: 0) val rightFileSize = DisplayUtils.bytesToHumanReadable(rightFile.fileLength)
val rightCheckBoxData = ConflictFileData(rightTitle, rightTimestamp.toString(), rightFileSize) val rightCheckBoxData = ConflictFileData(rightTitle, rightTimestamp.toString(), rightFileSize)
val title = context.getString(R.string.conflict_folder_headline) val title = context.getString(R.string.conflict_folder_headline)
@ -353,12 +363,12 @@ class ConflictsResolveDialog : DialogFragment(), Injectable {
} }
@JvmStatic @JvmStatic
fun getConflictDataForFileConflict( private fun getFileConflictData(
file: File, file: File,
rightFile: OCFile?, rightFile: OCFile,
context: Context context: Context
): ConflictDialogData { ): ConflictDialogData {
val parentFile = rightFile?.remotePath?.let { File(it).parentFile } val parentFile = File(rightFile.remotePath).parentFile
val folderName = if (parentFile != null) { val folderName = if (parentFile != null) {
String.format(context.getString(R.string.in_folder), parentFile.absolutePath) String.format(context.getString(R.string.in_folder), parentFile.absolutePath)
} else { } else {
@ -371,8 +381,8 @@ class ConflictsResolveDialog : DialogFragment(), Injectable {
val leftCheckBoxData = ConflictFileData(leftTitle, leftTimestamp.toString(), leftFileSize) val leftCheckBoxData = ConflictFileData(leftTitle, leftTimestamp.toString(), leftFileSize)
val rightTitle = context.getString(R.string.conflict_server_file) val rightTitle = context.getString(R.string.conflict_server_file)
val rightTimestamp = DisplayUtils.getRelativeTimestamp(context, rightFile?.modificationTimestamp ?: 0) val rightTimestamp = DisplayUtils.getRelativeTimestamp(context, rightFile.modificationTimestamp)
val rightFileSize = DisplayUtils.bytesToHumanReadable(rightFile?.fileLength ?: 0) val rightFileSize = DisplayUtils.bytesToHumanReadable(rightFile.fileLength)
val rightCheckBoxData = ConflictFileData(rightTitle, rightTimestamp.toString(), rightFileSize) val rightCheckBoxData = ConflictFileData(rightTitle, rightTimestamp.toString(), rightFileSize)
val title = context.getString(R.string.choose_which_file) val title = context.getString(R.string.choose_which_file)

View file

@ -9,6 +9,7 @@ package com.owncloud.android.ui.dialog.parcel
import android.os.Parcel import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import com.nextcloud.utils.extensions.readParcelableCompat
data class ConflictDialogData( data class ConflictDialogData(
val folderName: String?, val folderName: String?,
@ -66,12 +67,3 @@ data class ConflictFileData(
override fun newArray(size: Int): Array<ConflictFileData?> = arrayOfNulls(size) override fun newArray(size: Int): Array<ConflictFileData?> = arrayOfNulls(size)
} }
} }
inline fun <reified T : Parcelable> Parcel.readParcelableCompat(classLoader: ClassLoader?): T? {
return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
readParcelable(classLoader, T::class.java)
} else {
@Suppress("DEPRECATION")
readParcelable(classLoader)
}
}