diff --git a/feature/settings/import/src/main/kotlin/app/k9mail/feature/settings/import/ui/SettingsImportFragment.kt b/feature/settings/import/src/main/kotlin/app/k9mail/feature/settings/import/ui/SettingsImportFragment.kt index 2b0a68c5976..5e05dca35f8 100644 --- a/feature/settings/import/src/main/kotlin/app/k9mail/feature/settings/import/ui/SettingsImportFragment.kt +++ b/feature/settings/import/src/main/kotlin/app/k9mail/feature/settings/import/ui/SettingsImportFragment.kt @@ -44,11 +44,11 @@ class SettingsImportFragment : Fragment() { } } - private val pickDocumentResultLauncher = registerForActivityResult( + private val pickDocumentLauncher = registerForActivityResult( ActivityResultContracts.GetContent(), pickDocumentCallback, ) - private val qrCodeScannerResultContract = registerForActivityResult( + private val qrCodeScannerLauncher = registerForActivityResult( migrationManager.getQrCodeActivityResultContract(), pickDocumentCallback, ) @@ -226,11 +226,11 @@ class SettingsImportFragment : Fragment() { } private fun pickDocument() { - pickDocumentResultLauncher.launch("*/*") + pickDocumentLauncher.launch("*/*") } private fun scanQrCode() { - qrCodeScannerResultContract.launch(Unit) + qrCodeScannerLauncher.launch(Unit) } private fun pickApp() { diff --git a/feature/widget/unread/src/main/kotlin/app/k9mail/feature/widget/unread/UnreadWidgetConfigurationFragment.kt b/feature/widget/unread/src/main/kotlin/app/k9mail/feature/widget/unread/UnreadWidgetConfigurationFragment.kt index 6f76956fc4d..d81a25d9afe 100644 --- a/feature/widget/unread/src/main/kotlin/app/k9mail/feature/widget/unread/UnreadWidgetConfigurationFragment.kt +++ b/feature/widget/unread/src/main/kotlin/app/k9mail/feature/widget/unread/UnreadWidgetConfigurationFragment.kt @@ -25,11 +25,11 @@ class UnreadWidgetConfigurationFragment : PreferenceFragmentCompat() { private val repository: UnreadWidgetRepository by inject() private val unreadWidgetUpdater: UnreadWidgetUpdater by inject() - private val chooseAccountResultLauncher: ActivityResultLauncher = + private val chooseAccountLauncher: ActivityResultLauncher = registerForActivityResult(UnreadWidgetChooseAccountResultContract()) { accountUuid -> handleChooseAccount(accountUuid) } - private val chooseFolderResultLauncher: ActivityResultLauncher = + private val chooseFolderLauncher: ActivityResultLauncher = registerForActivityResult(ChooseFolderResultContract(action = ChooseFolderActivity.Action.CHOOSE)) { result -> if (result != null) { handleChooseFolder( @@ -56,7 +56,7 @@ class UnreadWidgetConfigurationFragment : PreferenceFragmentCompat() { unreadAccount = findPreference(PREFERENCE_UNREAD_ACCOUNT)!! unreadAccount.onPreferenceClickListener = Preference.OnPreferenceClickListener { - chooseAccountResultLauncher.launch(Unit) + chooseAccountLauncher.launch(Unit) false } @@ -70,7 +70,7 @@ class UnreadWidgetConfigurationFragment : PreferenceFragmentCompat() { unreadFolder = findPreference(PREFERENCE_UNREAD_FOLDER)!! unreadFolder.onPreferenceClickListener = Preference.OnPreferenceClickListener { - chooseFolderResultLauncher.launch( + chooseFolderLauncher.launch( input = ChooseFolderResultContract.Input( accountUuid = selectedAccountUuid!!, ), diff --git a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListFragment.kt b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListFragment.kt index 5f70f03b902..94d54d21a25 100644 --- a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListFragment.kt +++ b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListFragment.kt @@ -1,6 +1,5 @@ package com.fsck.k9.ui.messagelist -import android.app.Activity import android.app.SearchManager import android.content.Context import android.content.Intent @@ -12,6 +11,7 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.Toast +import androidx.activity.result.ActivityResultLauncher import androidx.annotation.StringRes import androidx.appcompat.view.ActionMode import androidx.core.os.BundleCompat @@ -51,6 +51,7 @@ import com.fsck.k9.ui.R import com.fsck.k9.ui.changelog.RecentChangesActivity import com.fsck.k9.ui.changelog.RecentChangesViewModel import com.fsck.k9.ui.choosefolder.ChooseFolderActivity +import com.fsck.k9.ui.choosefolder.ChooseFolderResultContract import com.fsck.k9.ui.helper.RelativeDateTimeFormatter import com.fsck.k9.ui.messagelist.MessageListFragment.MessageListFragmentListener.Companion.MAX_PROGRESS import com.google.android.material.floatingactionbutton.FloatingActionButton @@ -87,6 +88,19 @@ class MessageListFragment : private val activityListener = MessageListActivityListener() private val actionModeCallback = ActionModeCallback() + private val chooseFolderForMoveLauncher: ActivityResultLauncher = + registerForActivityResult(ChooseFolderResultContract(ChooseFolderActivity.Action.MOVE)) { result -> + handleChooseFolderResult(result) { folderId, messages -> + move(messages, folderId) + } + } + private val chooseFolderForCopyLauncher: ActivityResultLauncher = + registerForActivityResult(ChooseFolderResultContract(ChooseFolderActivity.Action.COPY)) { result -> + handleChooseFolderResult(result) { folderId, messages -> + copy(messages, folderId) + } + } + private lateinit var fragmentListener: MessageListFragmentListener private lateinit var recentChangesSnackbar: Snackbar @@ -705,33 +719,6 @@ class MessageListFragment : } } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - if (resultCode != Activity.RESULT_OK) return - - when (requestCode) { - ACTIVITY_CHOOSE_FOLDER_MOVE, - ACTIVITY_CHOOSE_FOLDER_COPY, - -> { - if (data == null) return - - val destinationFolderId = data.getLongExtra(ChooseFolderActivity.RESULT_SELECTED_FOLDER_ID, -1L) - val messages = activeMessages!! - if (destinationFolderId != -1L) { - activeMessages = null - - if (messages.isNotEmpty()) { - MlfUtils.setLastSelectedFolder(accountManager, messages, destinationFolderId) - } - - when (requestCode) { - ACTIVITY_CHOOSE_FOLDER_MOVE -> move(messages, destinationFolderId) - ACTIVITY_CHOOSE_FOLDER_COPY -> copy(messages, destinationFolderId) - } - } - } - } - } - private fun onExpunge() { currentFolder?.let { folderInfoHolder -> messagingController.expunge(account, folderInfoHolder.databaseId) @@ -1050,7 +1037,6 @@ class MessageListFragment : displayFolderChoice( operation = FolderOperation.MOVE, - requestCode = ACTIVITY_CHOOSE_FOLDER_MOVE, sourceFolderId = folderId, accountUuid = messages.first().accountUuid, lastSelectedFolderId = null, @@ -1073,7 +1059,6 @@ class MessageListFragment : displayFolderChoice( operation = FolderOperation.COPY, - requestCode = ACTIVITY_CHOOSE_FOLDER_COPY, sourceFolderId = folderId, accountUuid = messages.first().accountUuid, lastSelectedFolderId = null, @@ -1083,29 +1068,43 @@ class MessageListFragment : private fun displayFolderChoice( operation: FolderOperation, - requestCode: Int, sourceFolderId: Long?, accountUuid: String, lastSelectedFolderId: Long?, messages: List, ) { - val action = when (operation) { - FolderOperation.COPY -> ChooseFolderActivity.Action.COPY - FolderOperation.MOVE -> ChooseFolderActivity.Action.MOVE - } - val intent = ChooseFolderActivity.buildLaunchIntent( - context = requireContext(), - action = action, + // Remember the selected messages so they are available in the registerForActivityResult() callbacks + activeMessages = messages + + val input = ChooseFolderResultContract.Input( accountUuid = accountUuid, currentFolderId = sourceFolderId, scrollToFolderId = lastSelectedFolderId, - messageReference = null, ) + when (operation) { + FolderOperation.COPY -> chooseFolderForCopyLauncher.launch(input) + FolderOperation.MOVE -> chooseFolderForMoveLauncher.launch(input) + } + } - // remember the selected messages for #onActivityResult - activeMessages = messages + private fun handleChooseFolderResult( + result: ChooseFolderResultContract.Result?, + action: (Long, List) -> Unit, + ) { + if (result == null) return + + val destinationFolderId = result.folderId + val messages = activeMessages!! + + if (destinationFolderId != -1L) { + activeMessages = null - startActivityForResult(intent, requestCode) + if (messages.isNotEmpty()) { + MlfUtils.setLastSelectedFolder(accountManager, messages, destinationFolderId) + } + + action(destinationFolderId, messages) + } } private fun onArchive(message: MessageReference) { @@ -2073,8 +2072,6 @@ class MessageListFragment : } companion object { - private const val ACTIVITY_CHOOSE_FOLDER_MOVE = 1 - private const val ACTIVITY_CHOOSE_FOLDER_COPY = 2 private const val ARG_SEARCH = "searchObject" private const val ARG_THREADED_LIST = "showingThreadedList" diff --git a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.kt b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.kt index 9328c2d3efe..d44868361c7 100644 --- a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.kt +++ b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.kt @@ -1,12 +1,12 @@ package com.fsck.k9.ui.messageview -import android.app.Activity import android.content.ActivityNotFoundException import android.content.ContentResolver import android.content.Context import android.content.Intent import android.content.IntentSender import android.content.IntentSender.SendIntentException +import android.net.Uri import android.os.Bundle import android.os.Parcelable import android.os.SystemClock @@ -18,11 +18,13 @@ import android.view.View import android.view.ViewGroup import android.view.inputmethod.InputMethodManager import android.widget.Toast +import androidx.activity.result.ActivityResultLauncher import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment import androidx.fragment.app.setFragmentResultListener +import app.k9mail.core.android.common.activity.CreateDocumentResultContract import app.k9mail.core.ui.legacy.designsystem.atom.icon.Icons import app.k9mail.core.ui.theme.api.Theme import app.k9mail.legacy.account.Account @@ -49,6 +51,7 @@ import com.fsck.k9.mailstore.MessageViewInfo import com.fsck.k9.ui.R import com.fsck.k9.ui.base.extensions.withArguments import com.fsck.k9.ui.choosefolder.ChooseFolderActivity +import com.fsck.k9.ui.choosefolder.ChooseFolderResultContract import com.fsck.k9.ui.messagedetails.MessageDetailsFragment import com.fsck.k9.ui.messagesource.MessageSourceActivity import com.fsck.k9.ui.messageview.MessageCryptoPresenter.MessageCryptoMvpView @@ -71,6 +74,19 @@ class MessageViewFragment : private val shareIntentBuilder: ShareIntentBuilder by inject() private val generalSettingsManager: GeneralSettingsManager by inject() + private val createDocumentLauncher: ActivityResultLauncher = + registerForActivityResult(CreateDocumentResultContract()) { documentUri -> + onCreateDocumentResult(documentUri) + } + private val chooseFolderForCopyLauncher: ActivityResultLauncher = + registerForActivityResult(ChooseFolderResultContract(ChooseFolderActivity.Action.COPY)) { result -> + onChooseFolderCopyResult(result) + } + private val chooseFolderForMoveLauncher: ActivityResultLauncher = + registerForActivityResult(ChooseFolderResultContract(ChooseFolderActivity.Action.MOVE)) { result -> + onChooseFolderMoveResult(result) + } + private lateinit var messageTopView: MessageTopView private var message: LocalMessage? = null @@ -512,7 +528,14 @@ class MessageViewFragment : return } - startRefileActivity(FolderOperation.MOVE, ACTIVITY_CHOOSE_FOLDER_MOVE) + chooseFolderForMoveLauncher.launch( + input = ChooseFolderResultContract.Input( + accountUuid = account.uuid, + currentFolderId = messageReference.folderId, + scrollToFolderId = account.lastSelectedFolderId, + messageReference = messageReference, + ), + ) } fun onCopy() { @@ -524,7 +547,14 @@ class MessageViewFragment : return } - startRefileActivity(FolderOperation.COPY, ACTIVITY_CHOOSE_FOLDER_COPY) + chooseFolderForCopyLauncher.launch( + input = ChooseFolderResultContract.Input( + accountUuid = account.uuid, + currentFolderId = messageReference.folderId, + scrollToFolderId = account.lastSelectedFolderId, + messageReference = messageReference, + ), + ) } private fun onMoveToDrafts() { @@ -552,25 +582,6 @@ class MessageViewFragment : onRefile(account.spamFolderId) } - private fun startRefileActivity(operation: FolderOperation, requestCode: Int) { - val action = if (operation == FolderOperation.MOVE) { - ChooseFolderActivity.Action.MOVE - } else { - ChooseFolderActivity.Action.COPY - } - - val intent = ChooseFolderActivity.buildLaunchIntent( - context = requireActivity(), - action = action, - accountUuid = account.uuid, - currentFolderId = messageReference.folderId, - scrollToFolderId = account.lastSelectedFolderId, - messageReference = messageReference, - ) - - startActivityForResult(intent, requestCode) - } - @Deprecated("Switch to Activity Result API") override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (requestCode and REQUEST_MASK_LOADER_HELPER == REQUEST_MASK_LOADER_HELPER) { @@ -580,14 +591,6 @@ class MessageViewFragment : val maskedRequestCode = requestCode xor REQUEST_MASK_CRYPTO_PRESENTER messageCryptoPresenter.onActivityResult(maskedRequestCode, resultCode, data) } - - if (resultCode != Activity.RESULT_OK) return - - when (requestCode) { - REQUEST_CODE_CREATE_DOCUMENT -> onCreateDocumentResult(data) - ACTIVITY_CHOOSE_FOLDER_MOVE -> onChooseFolderMoveResult(data) - ACTIVITY_CHOOSE_FOLDER_COPY -> onChooseFolderCopyResult(data) - } } private fun onMessageDetailsResult(requestKey: String, result: Bundle) { @@ -606,18 +609,18 @@ class MessageViewFragment : } } - private fun onCreateDocumentResult(data: Intent?) { - val documentUri = data?.data ?: return - require(documentUri.scheme == ContentResolver.SCHEME_CONTENT) { "content: URI required" } + private fun onCreateDocumentResult(uri: Uri?) { + if (uri == null) return + require(uri.scheme == ContentResolver.SCHEME_CONTENT) { "content: URI required" } - createAttachmentController(currentAttachmentViewInfo).saveAttachmentTo(documentUri) + createAttachmentController(currentAttachmentViewInfo).saveAttachmentTo(uri) } - private fun onChooseFolderMoveResult(data: Intent?) { - if (data == null) return + private fun onChooseFolderMoveResult(result: ChooseFolderResultContract.Result?) { + if (result == null) return - val destinationFolderId = data.getLongExtra(ChooseFolderActivity.RESULT_SELECTED_FOLDER_ID, -1L) - val messageReferenceString = data.getStringExtra(ChooseFolderActivity.RESULT_MESSAGE_REFERENCE) + val destinationFolderId = result.folderId + val messageReferenceString = result.messageReference val messageReference = MessageReference.parse(messageReferenceString) if (this.messageReference != messageReference) return @@ -628,11 +631,11 @@ class MessageViewFragment : moveMessage(messageReference, destinationFolderId) } - private fun onChooseFolderCopyResult(data: Intent?) { - if (data == null) return + private fun onChooseFolderCopyResult(result: ChooseFolderResultContract.Result?) { + if (result == null) return - val destinationFolderId = data.getLongExtra(ChooseFolderActivity.RESULT_SELECTED_FOLDER_ID, -1L) - val messageReferenceString = data.getStringExtra(ChooseFolderActivity.RESULT_MESSAGE_REFERENCE) + val destinationFolderId = result.folderId + val messageReferenceString = result.messageReference val messageReference = MessageReference.parse(messageReferenceString) if (this.messageReference != messageReference) return @@ -859,17 +862,6 @@ class MessageViewFragment : } } - interface MessageViewFragmentListener { - fun onForward(messageReference: MessageReference, decryptionResultForReply: Parcelable?) - fun onForwardAsAttachment(messageReference: MessageReference, decryptionResultForReply: Parcelable?) - fun onEditAsNewMessage(messageReference: MessageReference) - fun onReplyAll(messageReference: MessageReference, decryptionResultForReply: Parcelable?) - fun onReply(messageReference: MessageReference, decryptionResultForReply: Parcelable?) - fun setProgress(enable: Boolean) - fun performNavigationAfterMessageRemoval() - fun performNavigationAfterMarkAsUnread() - } - private val messageLoaderCallbacks: MessageLoaderCallbacks = object : MessageLoaderCallbacks { override fun onMessageDataLoadFinished(message: LocalMessage) { this@MessageViewFragment.message = message @@ -950,14 +942,13 @@ class MessageViewFragment : override fun onSaveAttachment(attachment: AttachmentViewInfo) { currentAttachmentViewInfo = attachment - val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { - type = attachment.mimeType - putExtra(Intent.EXTRA_TITLE, attachment.displayName) - addCategory(Intent.CATEGORY_OPENABLE) - } - try { - startActivityForResult(intent, REQUEST_CODE_CREATE_DOCUMENT) + createDocumentLauncher.launch( + input = CreateDocumentResultContract.Input( + title = attachment.displayName, + mimeType = attachment.mimeType, + ), + ) } catch (e: ActivityNotFoundException) { Toast.makeText(requireContext(), R.string.error_activity_not_found, Toast.LENGTH_LONG).show() } @@ -971,11 +962,6 @@ class MessageViewFragment : activity?.invalidateMenu() } - private enum class FolderOperation { - COPY, - MOVE, - } - companion object { const val REQUEST_MASK_LOADER_HELPER = 1 shl 8 const val REQUEST_MASK_CRYPTO_PRESENTER = 1 shl 9 @@ -987,10 +973,6 @@ class MessageViewFragment : private const val STATE_WAS_MESSAGE_MARKED_AS_OPENED = "wasMessageMarkedAsOpened" private const val STATE_IS_ACTIVE = "isActive" - private const val ACTIVITY_CHOOSE_FOLDER_MOVE = 1 - private const val ACTIVITY_CHOOSE_FOLDER_COPY = 2 - private const val REQUEST_CODE_CREATE_DOCUMENT = 3 - fun newInstance(reference: MessageReference, showAccountChip: Boolean): MessageViewFragment { return MessageViewFragment().withArguments( ARG_REFERENCE to reference.toIdentityString(), diff --git a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragmentListener.kt b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragmentListener.kt new file mode 100644 index 00000000000..f0e3683828c --- /dev/null +++ b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragmentListener.kt @@ -0,0 +1,15 @@ +package com.fsck.k9.ui.messageview + +import android.os.Parcelable +import app.k9mail.legacy.message.controller.MessageReference + +interface MessageViewFragmentListener { + fun onForward(messageReference: MessageReference, decryptionResultForReply: Parcelable?) + fun onForwardAsAttachment(messageReference: MessageReference, decryptionResultForReply: Parcelable?) + fun onEditAsNewMessage(messageReference: MessageReference) + fun onReplyAll(messageReference: MessageReference, decryptionResultForReply: Parcelable?) + fun onReply(messageReference: MessageReference, decryptionResultForReply: Parcelable?) + fun setProgress(enable: Boolean) + fun performNavigationAfterMessageRemoval() + fun performNavigationAfterMarkAsUnread() +} diff --git a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/settings/export/SettingsExportFragment.kt b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/settings/export/SettingsExportFragment.kt index 96a4029355f..153346af554 100644 --- a/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/settings/export/SettingsExportFragment.kt +++ b/legacy/ui/legacy/src/main/java/com/fsck/k9/ui/settings/export/SettingsExportFragment.kt @@ -24,7 +24,7 @@ class SettingsExportFragment : Fragment() { private lateinit var settingsExportAdapter: FastAdapter> private lateinit var itemAdapter: ItemAdapter> - private val createDocumentResultLauncher: ActivityResultLauncher = + private val createDocumentLauncher: ActivityResultLauncher = registerForActivityResult( CreateDocumentResultContract(), ) { contentUri -> @@ -139,7 +139,7 @@ class SettingsExportFragment : Fragment() { } private fun pickDocument(fileNameSuggestion: String, mimeType: String) { - createDocumentResultLauncher.launch( + createDocumentLauncher.launch( input = CreateDocumentResultContract.Input( title = fileNameSuggestion, mimeType = mimeType,