Add selected photos access.

This commit is contained in:
Michelle Tang
2024-07-30 11:35:48 -04:00
committed by mtang-signal
parent 4f001a0c95
commit 57adab858c
19 changed files with 505 additions and 65 deletions

View File

@@ -308,9 +308,9 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
})
.onSomePermanentlyDenied(deniedPermissions -> {
if (deniedPermissions.containsAll(List.of(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO))) {
showPermissionFragment(R.string.CameraXFragment_allow_access_camera_microphone, R.string.CameraXFragment_to_capture_photos_videos).show(getParentFragmentManager(), BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG);
showPermissionFragment(R.string.CameraXFragment_allow_access_camera_microphone, R.string.CameraXFragment_to_capture_photos_videos, false).show(getParentFragmentManager(), BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG);
} else if (deniedPermissions.contains(Manifest.permission.CAMERA)) {
showPermissionFragment(R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_capture_photos_videos).show(getParentFragmentManager(), BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG);
showPermissionFragment(R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_capture_photos_videos, false).show(getParentFragmentManager(), BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG);
}
})
.onSomeDenied(deniedPermissions -> {

View File

@@ -55,7 +55,7 @@ public class MediaRepository {
* Retrieves a list of folders that contain media.
*/
public void getFolders(@NonNull Context context, @NonNull Callback<List<MediaFolder>> callback) {
if (!StorageUtil.canReadFromMediaStore()) {
if (!StorageUtil.canReadAnyFromMediaStore()) {
Log.w(TAG, "No storage permissions!", new Throwable());
callback.onComplete(Collections.emptyList());
return;
@@ -69,7 +69,7 @@ public class MediaRepository {
*/
public Single<List<Media>> getRecentMedia() {
return Single.<List<Media>>fromCallable(() -> {
if (!StorageUtil.canReadFromMediaStore()) {
if (!StorageUtil.canReadAnyFromMediaStore()) {
Log.w(TAG, "No storage permissions!", new Throwable());
return Collections.emptyList();
}
@@ -87,7 +87,7 @@ public class MediaRepository {
* Retrieves a list of media items (images and videos) that are present int he specified bucket.
*/
public void getMediaInBucket(@NonNull Context context, @NonNull String bucketId, @NonNull Callback<List<Media>> callback) {
if (!StorageUtil.canReadFromMediaStore()) {
if (!StorageUtil.canReadAnyFromMediaStore()) {
Log.w(TAG, "No storage permissions!", new Throwable());
callback.onComplete(Collections.emptyList());
return;
@@ -106,7 +106,7 @@ public class MediaRepository {
return;
}
if (!StorageUtil.canReadFromMediaStore()) {
if (!StorageUtil.canReadAnyFromMediaStore()) {
Log.w(TAG, "No storage permissions!", new Throwable());
callback.onComplete(media);
return;
@@ -117,7 +117,7 @@ public class MediaRepository {
}
void getMostRecentItem(@NonNull Context context, @NonNull Callback<Optional<Media>> callback) {
if (!StorageUtil.canReadFromMediaStore()) {
if (!StorageUtil.canReadAnyFromMediaStore()) {
Log.w(TAG, "No storage permissions!", new Throwable());
callback.onComplete(Optional.empty());
return;

View File

@@ -29,7 +29,7 @@ class MediaCaptureRepository(context: Context) {
private val context: Context = context.applicationContext
fun getMostRecentItem(callback: (Media?) -> Unit) {
if (!StorageUtil.canReadFromMediaStore()) {
if (!StorageUtil.canReadAnyFromMediaStore()) {
Log.w(TAG, "Cannot read from storage.")
callback(null)
return

View File

@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.mediasend.v2.gallery
import android.Manifest
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.constraintlayout.widget.ConstraintLayout
@@ -17,6 +18,7 @@ import androidx.recyclerview.widget.ItemTouchHelper
import org.signal.core.util.Stopwatch
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.recyclerview.GridDividerDecoration
import org.thoughtcrime.securesms.conversation.ManageContextMenu
import org.thoughtcrime.securesms.databinding.V2MediaGalleryFragmentBinding
import org.thoughtcrime.securesms.mediasend.Media
import org.thoughtcrime.securesms.mediasend.MediaRepository
@@ -24,6 +26,7 @@ import org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil
import org.thoughtcrime.securesms.permissions.PermissionCompat
import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.util.Material3OnScrollHelper
import org.thoughtcrime.securesms.util.StorageUtil
import org.thoughtcrime.securesms.util.SystemWindowInsetsSetter
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
@@ -164,8 +167,6 @@ class MediaGalleryFragment : Fragment(R.layout.v2_media_gallery_fragment) {
binding.mediaGalleryToolbar.title = state.bucketTitle ?: requireContext().getString(R.string.AttachmentKeyboard_gallery)
}
binding.mediaGalleryAllowAccess.setOnClickListener { requestRequiredPermissions() }
val galleryItemsWithSelection = LiveDataUtil.combineLatest(
viewModel.state.map { it.items },
viewStateLiveData.map { it.selectedMedia }
@@ -180,20 +181,44 @@ class MediaGalleryFragment : Fragment(R.layout.v2_media_gallery_fragment) {
}
galleryItemsWithSelection.observe(viewLifecycleOwner) {
if (!Permissions.hasAll(requireContext(), *PermissionCompat.forImagesAndVideos())) {
binding.mediaGalleryMissingPermissions.visibility = View.VISIBLE
shouldEnableScrolling = false
galleryAdapter.submitList((1..100).map { MediaGallerySelectableItem.PlaceholderModel() })
} else {
binding.mediaGalleryMissingPermissions.visibility = View.GONE
if (StorageUtil.canReadAllFromMediaStore()) {
binding.mediaGalleryMissingPermissions.visible = false
binding.mediaGalleryManageContainer.visible = false
shouldEnableScrolling = true
galleryAdapter.submitList(it)
} else if (StorageUtil.canOnlyReadSelectedMediaStore() && it.isEmpty()) {
binding.mediaGalleryMissingPermissions.visible = true
binding.mediaGalleryManageContainer.visible = false
binding.mediaGalleryPermissionText.text = getString(R.string.MediaGalleryFragment__no_photos_found)
binding.mediaGalleryAllowAccess.text = getString(R.string.AttachmentKeyboard_manage)
binding.mediaGalleryAllowAccess.setOnClickListener { v -> showManageContextMenu(v, v.parent as ViewGroup, false, true) }
shouldEnableScrolling = false
galleryAdapter.submitList((1..100).map { MediaGallerySelectableItem.PlaceholderModel() })
} else if (StorageUtil.canOnlyReadSelectedMediaStore()) {
binding.mediaGalleryMissingPermissions.visible = false
binding.mediaGalleryManageContainer.visible = true
binding.mediaGalleryManageButton.setOnClickListener { v -> showManageContextMenu(v, v.rootView as ViewGroup, false, false) }
shouldEnableScrolling = true
galleryAdapter.submitList(it)
} else {
binding.mediaGalleryMissingPermissions.visible = true
binding.mediaGalleryManageContainer.visible = false
binding.mediaGalleryPermissionText.text = getString(R.string.AttachmentKeyboard_Signal_needs_permission_to_show_your_photos_and_videos)
binding.mediaGalleryAllowAccess.text = getString(R.string.AttachmentKeyboard_allow_access)
binding.mediaGalleryAllowAccess.setOnClickListener { requestRequiredPermissions() }
shouldEnableScrolling = false
galleryAdapter.submitList((1..100).map { MediaGallerySelectableItem.PlaceholderModel() })
}
}
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, onBackPressedCallback)
}
override fun onResume() {
super.onResume()
refreshMediaGallery()
}
private fun refreshMediaGallery() {
viewModel.refreshMediaGallery()
}
@@ -203,13 +228,37 @@ class MediaGalleryFragment : Fragment(R.layout.v2_media_gallery_fragment) {
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults)
}
private fun showManageContextMenu(view: View, rootView: ViewGroup, showAbove: Boolean, showAtStart: Boolean) {
ManageContextMenu.show(
context = requireContext(),
anchorView = view,
rootView = rootView,
showAbove = showAbove,
showAtStart = showAtStart,
onSelectMore = { selectMorePhotos() },
onSettings = { requireContext().startActivity(Permissions.getApplicationSettingsIntent(requireContext())) }
)
}
private fun selectMorePhotos() {
Permissions.with(requireParentFragment())
.request(*PermissionCompat.forImagesAndVideos())
.onAnyResult { refreshMediaGallery() }
.execute()
}
private fun requestRequiredPermissions() {
Permissions.with(this)
.request(*PermissionCompat.forImagesAndVideos())
.ifNecessary()
.onAllGranted { refreshMediaGallery() }
.withPermanentDenialDialog(getString(R.string.AttachmentManager_signal_requires_the_external_storage_permission_in_order_to_attach_photos_videos_or_audio), null, R.string.AttachmentManager_signal_allow_storage, R.string.AttachmentManager_signal_to_show_photos, parentFragmentManager)
.onAnyDenied { Toast.makeText(requireContext(), R.string.AttachmentManager_signal_needs_storage_access, Toast.LENGTH_LONG).show() }
.onAnyResult { refreshMediaGallery() }
.withPermanentDenialDialog(getString(R.string.AttachmentManager_signal_requires_the_external_storage_permission_in_order_to_attach_photos_videos_or_audio), null, R.string.AttachmentManager_signal_allow_storage, R.string.AttachmentManager_signal_to_show_photos, true, parentFragmentManager)
.onSomeDenied {
val deniedPermission = PermissionCompat.getRequiredPermissionsForDenial()
if (it.containsAll(deniedPermission.toList())) {
Toast.makeText(requireContext(), R.string.AttachmentManager_signal_needs_storage_access, Toast.LENGTH_LONG).show()
}
}
.execute()
}