From bb6673db59ee1e1a3418651e8b91a405630cf90c Mon Sep 17 00:00:00 2001 From: Christophe Beyls Date: Tue, 23 Apr 2024 15:24:36 +0200 Subject: [PATCH] update permission request code in SearchStatusesFragment and SFragment, store the argument in a field saved as part of instance state. --- .../fragments/SearchStatusesFragment.kt | 79 ++++++++++++------- .../keylesspalace/tusky/fragment/SFragment.kt | 62 ++++++++++----- 2 files changed, 95 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt index abbfea9d0..0a87c8589 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt @@ -21,16 +21,18 @@ import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.content.Intent -import android.content.pm.PackageManager import android.net.Uri import android.os.Build +import android.os.Bundle import android.os.Environment import android.util.Log import android.view.View import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.PopupMenu import androidx.core.app.ActivityOptionsCompat +import androidx.core.content.getSystemService import androidx.core.view.ViewCompat import androidx.lifecycle.lifecycleScope import androidx.paging.PagingData @@ -41,7 +43,6 @@ import androidx.recyclerview.widget.LinearLayoutManager import at.connyduck.calladapter.networkresult.fold import at.connyduck.calladapter.networkresult.onFailure import com.google.android.material.snackbar.Snackbar -import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.R import com.keylesspalace.tusky.ViewMediaActivity import com.keylesspalace.tusky.components.compose.ComposeActivity @@ -79,6 +80,34 @@ class SearchStatusesFragment : SearchFragment(), Status private val searchAdapter get() = super.adapter as SearchStatusesAdapter + private var pendingMediaDownloads: List? = null + + private val downloadAllMediaPermissionLauncher = + registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> + if (isGranted) { + pendingMediaDownloads?.let { downloadAllMedia(it) } + } else { + Toast.makeText( + context, + R.string.error_media_download_permission, + Toast.LENGTH_SHORT + ).show() + } + pendingMediaDownloads = null + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + pendingMediaDownloads = savedInstanceState?.getStringArrayList(PENDING_MEDIA_DOWNLOADS_STATE_KEY) + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + pendingMediaDownloads?.let { + outState.putStringArrayList(PENDING_MEDIA_DOWNLOADS_STATE_KEY, ArrayList(it)) + } + } + override fun createAdapter(): PagingDataAdapter { val preferences = PreferenceManager.getDefaultSharedPreferences( binding.searchRecyclerView.context @@ -236,10 +265,6 @@ class SearchStatusesFragment : SearchFragment(), Status } } - companion object { - fun newInstance() = SearchStatusesFragment() - } - private fun reply(status: StatusViewData.Concrete) { val actionableStatus = status.actionable val mentionedUsernames = actionableStatus.mentions.map { it.username } @@ -499,37 +524,31 @@ class SearchStatusesFragment : SearchFragment(), Status ) } - private fun downloadAllMedia(status: Status) { + private fun downloadAllMedia(mediaUrls: List) { Toast.makeText(context, R.string.downloading_media, Toast.LENGTH_SHORT).show() - for ((_, url) in status.attachments) { - val uri = Uri.parse(url) - val filename = uri.lastPathSegment + val downloadManager: DownloadManager = requireContext().getSystemService()!! - val downloadManager = requireActivity().getSystemService( - Context.DOWNLOAD_SERVICE - ) as DownloadManager + for (url in mediaUrls) { + val uri = Uri.parse(url) val request = DownloadManager.Request(uri) - request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename) + request.setDestinationInExternalPublicDir( + Environment.DIRECTORY_DOWNLOADS, + uri.lastPathSegment + ) downloadManager.enqueue(request) } } private fun requestDownloadAllMedia(status: Status) { + if (status.attachments.isEmpty()) { + return + } + val mediaUrls = status.attachments.map { it.url } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - val permissions = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) - (activity as BaseActivity).requestPermissions(permissions) { _, grantResults -> - if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - downloadAllMedia(status) - } else { - Toast.makeText( - context, - R.string.error_media_download_permission, - Toast.LENGTH_SHORT - ).show() - } - } + pendingMediaDownloads = mediaUrls + downloadAllMediaPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) } else { - downloadAllMedia(status) + downloadAllMedia(mediaUrls) } } @@ -628,4 +647,10 @@ class SearchStatusesFragment : SearchFragment(), Status ) } } + + companion object { + private const val PENDING_MEDIA_DOWNLOADS_STATE_KEY = "pending_media_downloads" + + fun newInstance() = SearchStatusesFragment() + } } diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt index 110a99e95..9b67aeab1 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt @@ -21,17 +21,19 @@ import android.content.ClipboardManager import android.content.Context import android.content.DialogInterface import android.content.Intent -import android.content.pm.PackageManager import android.net.Uri import android.os.Build +import android.os.Bundle import android.os.Environment import android.util.Log import android.view.MenuItem import android.view.View import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.PopupMenu import androidx.core.app.ActivityOptionsCompat +import androidx.core.content.getSystemService import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import at.connyduck.calladapter.networkresult.fold @@ -93,6 +95,22 @@ abstract class SFragment : Fragment(), Injectable { @Inject lateinit var instanceInfoRepository: InstanceInfoRepository + private var pendingMediaDownloads: List? = null + + private val downloadAllMediaPermissionLauncher = + registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> + if (isGranted) { + pendingMediaDownloads?.let { downloadAllMedia(it) } + } else { + Toast.makeText( + context, + R.string.error_media_download_permission, + Toast.LENGTH_SHORT + ).show() + } + pendingMediaDownloads = null + } + override fun startActivity(intent: Intent) { requireActivity().startActivityWithSlideInAnimation(intent) } @@ -106,6 +124,18 @@ abstract class SFragment : Fragment(), Injectable { } } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + pendingMediaDownloads = savedInstanceState?.getStringArrayList(PENDING_MEDIA_DOWNLOADS_STATE_KEY) + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + pendingMediaDownloads?.let { + outState.putStringArrayList(PENDING_MEDIA_DOWNLOADS_STATE_KEY, ArrayList(it)) + } + } + override fun onResume() { super.onResume() @@ -522,13 +552,11 @@ abstract class SFragment : Fragment(), Injectable { } } - private fun downloadAllMedia(status: Status) { + private fun downloadAllMedia(mediaUrls: List) { Toast.makeText(context, R.string.downloading_media, Toast.LENGTH_SHORT).show() - val downloadManager = requireActivity().getSystemService( - Context.DOWNLOAD_SERVICE - ) as DownloadManager + val downloadManager: DownloadManager = requireContext().getSystemService()!! - for ((_, url) in status.attachments) { + for (url in mediaUrls) { val uri = Uri.parse(url) downloadManager.enqueue( DownloadManager.Request(uri).apply { @@ -542,26 +570,22 @@ abstract class SFragment : Fragment(), Injectable { } private fun requestDownloadAllMedia(status: Status) { + if (status.attachments.isEmpty()) { + return + } + val mediaUrls = status.attachments.map { it.url } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - val permissions = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) - (activity as BaseActivity).requestPermissions(permissions) { _, grantResults -> - if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - downloadAllMedia(status) - } else { - Toast.makeText( - context, - R.string.error_media_download_permission, - Toast.LENGTH_SHORT - ).show() - } - } + pendingMediaDownloads = mediaUrls + downloadAllMediaPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) } else { - downloadAllMedia(status) + downloadAllMedia(mediaUrls) } } companion object { private const val TAG = "SFragment" + private const val PENDING_MEDIA_DOWNLOADS_STATE_KEY = "pending_media_downloads" + private fun accountIsInMentions( account: AccountEntity?, mentions: List