diff --git a/app/src/androidTest/java/com/owncloud/android/ui/activity/ConflictsResolveActivityIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/activity/ConflictsResolveActivityIT.kt index a115f79b1308..a7e549a74fc4 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/activity/ConflictsResolveActivityIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/activity/ConflictsResolveActivityIT.kt @@ -25,10 +25,10 @@ import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.db.OCUpload -import com.owncloud.android.ui.dialog.ConflictsResolveDialog -import com.owncloud.android.ui.dialog.ConflictsResolveDialog.Companion.newInstance -import com.owncloud.android.ui.dialog.ConflictsResolveDialog.Decision -import com.owncloud.android.ui.dialog.ConflictsResolveDialog.OnConflictDecisionMadeListener +import com.owncloud.android.ui.dialog.conflict.ConflictsResolveDialog +import com.owncloud.android.ui.dialog.conflict.ConflictsResolveDialog.Decision +import com.owncloud.android.ui.dialog.conflict.ConflictsResolveDialog.OnConflictDecisionMadeListener +import com.owncloud.android.ui.dialog.conflict.ConflictResolveDialogFactory import com.owncloud.android.utils.EspressoIdlingResource import com.owncloud.android.utils.FileStorageUtils import com.owncloud.android.utils.ScreenshotTest @@ -69,7 +69,7 @@ class ConflictsResolveActivityIT : AbstractIT() { launchActivity(intent).use { scenario -> var dialog: ConflictsResolveDialog? = null scenario.onActivity { sut -> - dialog = newInstance( + dialog = ConflictResolveDialogFactory.forNormal( storageManager.getDecryptedPath(existingFile), targetContext, newFile, diff --git a/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java b/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java index f1a2ac752b30..6710289ad52e 100644 --- a/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java +++ b/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java @@ -79,7 +79,7 @@ import com.owncloud.android.ui.dialog.ChooseRichDocumentsTemplateDialogFragment; import com.owncloud.android.ui.dialog.ChooseTemplateDialogFragment; import com.owncloud.android.ui.dialog.ConfirmationDialogFragment; -import com.owncloud.android.ui.dialog.ConflictsResolveDialog; +import com.owncloud.android.ui.dialog.conflict.ConflictsResolveDialog; import com.owncloud.android.ui.dialog.CreateAlbumDialogFragment; import com.owncloud.android.ui.dialog.CreateFolderDialogFragment; import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt index 9df9ce325ab4..5f9d0caed0db 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt @@ -37,9 +37,9 @@ import com.owncloud.android.files.services.NameCollisionPolicy import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation import com.owncloud.android.lib.resources.files.model.RemoteFile -import com.owncloud.android.ui.dialog.ConflictsResolveDialog -import com.owncloud.android.ui.dialog.ConflictsResolveDialog.Decision -import com.owncloud.android.ui.dialog.ConflictsResolveDialog.OnConflictDecisionMadeListener +import com.owncloud.android.ui.dialog.conflict.ConflictsResolveDialog.Decision +import com.owncloud.android.ui.dialog.conflict.ConflictsResolveDialog.OnConflictDecisionMadeListener +import com.owncloud.android.ui.dialog.conflict.ConflictResolveDialogFactory import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.FileStorageUtils import kotlinx.coroutines.Dispatchers @@ -273,7 +273,7 @@ class ConflictsResolveActivity : } val (ft, _) = prepareDialogTransaction() - ConflictsResolveDialog.newInstance( + ConflictResolveDialogFactory.forOffline( context = this, leftFile = offlineOperation, rightFile = newFile!! @@ -307,7 +307,7 @@ class ConflictsResolveActivity : private fun showFileConflictDialog(remotePath: String) { val (ft, user) = prepareDialogTransaction() if (existingFile != null && storageManager.fileExists(remotePath) && newFile != null) { - ConflictsResolveDialog.newInstance( + ConflictResolveDialogFactory.forNormal( title = storageManager.getDecryptedPath(existingFile!!), context = this, leftFile = newFile!!, diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/conflict/ConflictResolveDialogFactory.kt b/app/src/main/java/com/owncloud/android/ui/dialog/conflict/ConflictResolveDialogFactory.kt new file mode 100644 index 000000000000..9a6fd6a32a98 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/dialog/conflict/ConflictResolveDialogFactory.kt @@ -0,0 +1,88 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.ui.dialog.conflict + +import android.content.Context +import android.os.Bundle +import androidx.annotation.StringRes +import com.nextcloud.client.account.User +import com.nextcloud.client.database.entity.OfflineOperationEntity +import com.owncloud.android.R +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.ui.dialog.conflict.model.ConflictDialogData +import com.owncloud.android.ui.dialog.conflict.model.ConflictDialogType +import com.owncloud.android.ui.dialog.conflict.model.ConflictFileData +import com.owncloud.android.utils.DisplayUtils +import java.io.File + +object ConflictResolveDialogFactory { + + private const val SECONDS_TO_MILLIS = 1000L + private const val UNKNOWN_FOLDER_SIZE = 0L + + fun forOffline(context: Context, leftFile: OfflineOperationEntity, rightFile: OCFile): ConflictsResolveDialog { + val data = ConflictDialogData( + headline = context.getString(R.string.conflict_folder_headline), + description = context.getString(R.string.conflict_message_description_for_folder), + localFile = context.conflictFileData( + titleId = R.string.prefs_synced_folders_local_path_title, + timestamp = (leftFile.createdAt ?: 0L) * SECONDS_TO_MILLIS, + fileLength = UNKNOWN_FOLDER_SIZE + ), + serverFile = context.conflictFileData(R.string.prefs_synced_folders_remote_path_title, rightFile) + ) + + return createDialog(ConflictDialogType.Offline(data)) { + putParcelable(ConflictsResolveDialog.ARG_RIGHT_FILE, rightFile) + } + } + + fun forNormal( + title: String, + context: Context, + leftFile: OCFile, + rightFile: OCFile, + user: User? + ): ConflictsResolveDialog { + val localFile = File(leftFile.storagePath) + val data = ConflictDialogData( + headline = context.getString(R.string.choose_which_file), + description = context.getString(R.string.conflict_message_description), + localFile = context.conflictFileData( + titleId = R.string.conflict_local_file, + timestamp = localFile.lastModified(), + fileLength = localFile.length() + ), + serverFile = context.conflictFileData(R.string.conflict_server_file, rightFile) + ) + + return createDialog(ConflictDialogType.Normal(title, data)) { + putSerializable(ConflictsResolveDialog.ARG_LEFT_FILE, localFile) + putParcelable(ConflictsResolveDialog.ARG_RIGHT_FILE, rightFile) + putParcelable(ConflictsResolveDialog.ARG_USER, user) + } + } + + private fun Context.conflictFileData(@StringRes titleId: Int, file: OCFile): ConflictFileData = + conflictFileData(titleId, file.modificationTimestamp, file.fileLength) + + private fun Context.conflictFileData(@StringRes titleId: Int, timestamp: Long, fileLength: Long): ConflictFileData = + ConflictFileData( + title = getString(titleId), + timestamp = DisplayUtils.getRelativeTimestamp(this, timestamp).toString(), + fileSize = DisplayUtils.bytesToHumanReadable(fileLength) + ) + + private fun createDialog(type: ConflictDialogType, putFiles: Bundle.() -> Unit): ConflictsResolveDialog = + ConflictsResolveDialog().apply { + arguments = Bundle().apply { + putParcelable(ConflictsResolveDialog.ARG_CONFLICT_DATA, type) + putFiles() + } + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/conflict/ConflictsResolveDialog.kt similarity index 50% rename from app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt rename to app/src/main/java/com/owncloud/android/ui/dialog/conflict/ConflictsResolveDialog.kt index b8c65143760a..84f5c4d1b848 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/conflict/ConflictsResolveDialog.kt @@ -4,7 +4,7 @@ * SPDX-FileCopyrightText: 2024 Alper Ozturk * SPDX-License-Identifier: AGPL-3.0-or-later */ -package com.owncloud.android.ui.dialog +package com.owncloud.android.ui.dialog.conflict import android.app.Dialog import android.content.Context @@ -17,7 +17,6 @@ import androidx.fragment.app.DialogFragment import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.nextcloud.client.account.User -import com.nextcloud.client.database.entity.OfflineOperationEntity import com.nextcloud.client.di.Injectable import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.getSerializableArgument @@ -28,8 +27,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.SyncedFolderProvider import com.owncloud.android.ui.adapter.localFileList.LocalFileThumbnailBinder -import com.owncloud.android.ui.dialog.parcel.ConflictDialogData -import com.owncloud.android.ui.dialog.parcel.ConflictFileData +import com.owncloud.android.ui.dialog.conflict.model.ConflictDialogType import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.MimeTypeUtil import com.owncloud.android.utils.theme.ViewThemeUtils @@ -47,7 +45,7 @@ class ConflictsResolveDialog : var listener: OnConflictDecisionMadeListener? = null private var positiveButton: MaterialButton? = null - private var data: ConflictDialogData? = null + private lateinit var dialogType: ConflictDialogType private var user: User? = null private var leftDataFile: File? = null private var rightDataFile: OCFile? = null @@ -110,25 +108,13 @@ class ConflictsResolveDialog : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - val bundle = savedInstanceState ?: arguments - - if (bundle != null) { - data = bundle.getParcelableArgument(ARG_CONFLICT_DATA, ConflictDialogData::class.java) - leftDataFile = bundle.getSerializableArgument(ARG_LEFT_FILE, File::class.java) - rightDataFile = bundle.getParcelableArgument(ARG_RIGHT_FILE, OCFile::class.java) - user = bundle.getParcelableArgument(ARG_USER, User::class.java) - } else { - activity?.let { - DisplayUtils.showSnackMessage(it, R.string.failed_to_create_conflict_dialog) - } - } - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - outState.run { - putParcelable(ARG_CONFLICT_DATA, data) + val bundle = requireArguments() + dialogType = requireNotNull(bundle.getParcelableArgument(ARG_CONFLICT_DATA, ConflictDialogType::class.java)) { + "$ARG_CONFLICT_DATA is required, create this dialog through ConflictResolveDialogFactory" } + leftDataFile = bundle.getSerializableArgument(ARG_LEFT_FILE, File::class.java) + rightDataFile = bundle.getParcelableArgument(ARG_RIGHT_FILE, OCFile::class.java) + user = bundle.getParcelableArgument(ARG_USER, User::class.java) } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { @@ -156,20 +142,20 @@ class ConflictsResolveDialog : .setNegativeButton(R.string.common_cancel) { _: DialogInterface?, _: Int -> listener?.conflictDecisionMade(Decision.CANCEL) } - .setTitle(data?.dialogTitle) + .setTitle(dialogType.dialogTitle) private fun okButtonClick() { binding.run { - val isDialogTitleNotExists = (data?.dialogTitle == null) + val isDialogTypeOffline = (dialogType is ConflictDialogType.Offline) val decision = when { leftCheckbox.isChecked && rightCheckbox.isChecked -> - if (isDialogTitleNotExists) Decision.KEEP_BOTH_FOLDER else Decision.KEEP_BOTH + if (isDialogTypeOffline) Decision.KEEP_BOTH_FOLDER else Decision.KEEP_BOTH leftCheckbox.isChecked -> - if (isDialogTitleNotExists) Decision.KEEP_OFFLINE_FOLDER else Decision.KEEP_LOCAL + if (isDialogTypeOffline) Decision.KEEP_OFFLINE_FOLDER else Decision.KEEP_LOCAL rightCheckbox.isChecked -> - if (isDialogTitleNotExists) Decision.KEEP_SERVER_FOLDER else Decision.KEEP_SERVER + if (isDialogTypeOffline) Decision.KEEP_SERVER_FOLDER else Decision.KEEP_SERVER else -> null } @@ -179,34 +165,26 @@ class ConflictsResolveDialog : } private fun setupUI() { + val data = dialogType.data + binding.run { - data?.let { - val (leftData, rightData) = it.checkboxData - - headline.visibility = if (it.headline == null) { - View.GONE - } else { - View.VISIBLE - } - headline.text = it.headline - - description.text = it.description - - leftCheckbox.text = leftData.title - leftTimestamp.text = leftData.timestamp - leftFileSize.text = leftData.fileSize - - rightCheckbox.text = rightData.title - rightTimestamp.text = rightData.timestamp - rightFileSize.text = rightData.fileSize - - if (leftDataFile != null && rightDataFile != null && user != null) { - setThumbnailsForFileConflicts() - } else { - val folderIcon = MimeTypeUtil.getDefaultFolderIcon(requireContext(), viewThemeUtils) - leftThumbnail.setImageDrawable(folderIcon) - rightThumbnail.setImageDrawable(folderIcon) - } + headline.text = data.headline + description.text = data.description + + leftCheckbox.text = data.localFile.title + leftTimestamp.text = data.localFile.timestamp + leftFileSize.text = data.localFile.fileSize + + rightCheckbox.text = data.serverFile.title + rightTimestamp.text = data.serverFile.timestamp + rightFileSize.text = data.serverFile.fileSize + + if (leftDataFile != null && rightDataFile != null && user != null) { + setThumbnailsForFileConflicts() + } else { + val folderIcon = MimeTypeUtil.getDefaultFolderIcon(requireContext(), viewThemeUtils) + leftThumbnail.setImageDrawable(folderIcon) + rightThumbnail.setImageDrawable(folderIcon) } } } @@ -269,88 +247,9 @@ class ConflictsResolveDialog : } companion object { - private const val ARG_CONFLICT_DATA = "CONFLICT_DATA" - private const val ARG_LEFT_FILE = "LEFT_FILE" - private const val ARG_RIGHT_FILE = "RIGHT_FILE" - private const val ARG_USER = "USER" - - @JvmStatic - fun newInstance( - title: String, - context: Context, - leftFile: OCFile, - rightFile: OCFile, - user: User? - ): ConflictsResolveDialog { - val file = File(leftFile.storagePath) - val conflictData = getFileConflictData(title, file, rightFile, context) - - val bundle = Bundle().apply { - putParcelable(ARG_CONFLICT_DATA, conflictData) - putSerializable(ARG_LEFT_FILE, file) - putParcelable(ARG_RIGHT_FILE, rightFile) - putParcelable(ARG_USER, user) - } - - return ConflictsResolveDialog().apply { - arguments = bundle - } - } - - fun newInstance(context: Context, leftFile: OfflineOperationEntity, rightFile: OCFile): ConflictsResolveDialog { - val conflictData = getFolderConflictData(leftFile, rightFile, context) - - val bundle = Bundle().apply { - putParcelable(ARG_CONFLICT_DATA, conflictData) - putParcelable(ARG_RIGHT_FILE, rightFile) - } - - return ConflictsResolveDialog().apply { - arguments = bundle - } - } - - @Suppress("MagicNumber") - private fun getFolderConflictData( - offlineOperation: OfflineOperationEntity, - rightFile: OCFile, - context: Context - ): ConflictDialogData { - val leftTitle = context.getString(R.string.prefs_synced_folders_local_path_title) - val leftTimestamp = - DisplayUtils.getRelativeTimestamp(context, offlineOperation.createdAt?.times(1000L) ?: 0) - val leftFileSize = DisplayUtils.bytesToHumanReadable(0) - val leftCheckBoxData = ConflictFileData(leftTitle, leftTimestamp.toString(), leftFileSize) - - val rightTitle = context.getString(R.string.prefs_synced_folders_remote_path_title) - val rightTimestamp = DisplayUtils.getRelativeTimestamp(context, rightFile.modificationTimestamp) - val rightFileSize = DisplayUtils.bytesToHumanReadable(rightFile.fileLength) - val rightCheckBoxData = ConflictFileData(rightTitle, rightTimestamp.toString(), rightFileSize) - - val title = context.getString(R.string.conflict_folder_headline) - val description = context.getString(R.string.conflict_message_description_for_folder) - return ConflictDialogData(null, title, description, Pair(leftCheckBoxData, rightCheckBoxData)) - } - - private fun getFileConflictData( - title: String, - leftFile: File, - rightFile: OCFile, - context: Context - ): ConflictDialogData { - val leftTitle = context.getString(R.string.conflict_local_file) - val leftTimestamp = DisplayUtils.getRelativeTimestamp(context, leftFile.lastModified()) - val leftFileSize = DisplayUtils.bytesToHumanReadable(leftFile.length()) - val leftCheckBoxData = ConflictFileData(leftTitle, leftTimestamp.toString(), leftFileSize) - - val rightTitle = context.getString(R.string.conflict_server_file) - val rightTimestamp = DisplayUtils.getRelativeTimestamp(context, rightFile.modificationTimestamp) - val rightFileSize = DisplayUtils.bytesToHumanReadable(rightFile.fileLength) - val rightCheckBoxData = ConflictFileData(rightTitle, rightTimestamp.toString(), rightFileSize) - - val headline = context.getString(R.string.choose_which_file) - val description = context.getString(R.string.conflict_message_description) - return ConflictDialogData(title, headline, description, Pair(leftCheckBoxData, rightCheckBoxData)) - } + internal const val ARG_CONFLICT_DATA = "CONFLICT_DATA" + internal const val ARG_LEFT_FILE = "LEFT_FILE" + internal const val ARG_RIGHT_FILE = "RIGHT_FILE" + internal const val ARG_USER = "USER" } } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/conflict/model/ConflictDialogData.kt b/app/src/main/java/com/owncloud/android/ui/dialog/conflict/model/ConflictDialogData.kt new file mode 100644 index 000000000000..686ab9d1312c --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/dialog/conflict/model/ConflictDialogData.kt @@ -0,0 +1,19 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.ui.dialog.conflict.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class ConflictDialogData( + val headline: String, + val description: String, + val localFile: ConflictFileData, + val serverFile: ConflictFileData +) : Parcelable diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/conflict/model/ConflictDialogType.kt b/app/src/main/java/com/owncloud/android/ui/dialog/conflict/model/ConflictDialogType.kt new file mode 100644 index 000000000000..05b42c89f181 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/dialog/conflict/model/ConflictDialogType.kt @@ -0,0 +1,25 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.ui.dialog.conflict.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +sealed interface ConflictDialogType : Parcelable { + val data: ConflictDialogData + val dialogTitle: String? + + @Parcelize + data class Offline(override val data: ConflictDialogData) : ConflictDialogType { + override val dialogTitle: String? + get() = null + } + + @Parcelize + data class Normal(override val dialogTitle: String, override val data: ConflictDialogData) : ConflictDialogType +} diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/conflict/model/ConflictFileData.kt b/app/src/main/java/com/owncloud/android/ui/dialog/conflict/model/ConflictFileData.kt new file mode 100644 index 000000000000..57b2c118158c --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/dialog/conflict/model/ConflictFileData.kt @@ -0,0 +1,14 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.ui.dialog.conflict.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class ConflictFileData(val title: String, val timestamp: String, val fileSize: String) : Parcelable diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/parcel/ConflictDialogData.kt b/app/src/main/java/com/owncloud/android/ui/dialog/parcel/ConflictDialogData.kt deleted file mode 100644 index cca5ae12ec55..000000000000 --- a/app/src/main/java/com/owncloud/android/ui/dialog/parcel/ConflictDialogData.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2024 Alper Ozturk - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -package com.owncloud.android.ui.dialog.parcel - -import android.os.Parcel -import android.os.Parcelable -import com.nextcloud.utils.extensions.readParcelableCompat - -data class ConflictDialogData( - val dialogTitle: String?, - val headline: String?, - val description: String, - val checkboxData: Pair -) : Parcelable { - constructor(parcel: Parcel) : this( - parcel.readString() ?: "", - parcel.readString() ?: "", - parcel.readString() ?: "", - checkboxData = Pair( - parcel.readParcelableCompat(ConflictFileData::class.java.classLoader) ?: ConflictFileData("", "", ""), - parcel.readParcelableCompat(ConflictFileData::class.java.classLoader) ?: ConflictFileData("", "", "") - ) - ) - - override fun writeToParcel(parcel: Parcel, flags: Int) { - parcel.writeString(dialogTitle) - parcel.writeString(headline) - parcel.writeString(description) - parcel.writeParcelable(checkboxData.first, flags) - parcel.writeParcelable(checkboxData.second, flags) - } - - override fun describeContents(): Int = 0 - - companion object CREATOR : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel): ConflictDialogData = ConflictDialogData(parcel) - override fun newArray(size: Int): Array = arrayOfNulls(size) - } -} - -data class ConflictFileData(val title: String, val timestamp: String, val fileSize: String) : Parcelable { - constructor(parcel: Parcel) : this( - parcel.readString() ?: "", - parcel.readString() ?: "", - parcel.readString() ?: "" - ) - - override fun writeToParcel(parcel: Parcel, flags: Int) { - parcel.writeString(title) - parcel.writeString(timestamp) - parcel.writeString(fileSize) - } - - override fun describeContents(): Int = 0 - - companion object CREATOR : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel): ConflictFileData = ConflictFileData(parcel) - override fun newArray(size: Int): Array = arrayOfNulls(size) - } -}