mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-3072 Tech | Photo picker, integration, part 2 (#2070)
This commit is contained in:
parent
f99d9f713f
commit
ef06ea85f2
9 changed files with 98 additions and 62 deletions
|
@ -11,6 +11,9 @@
|
|||
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<!-- <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />-->
|
||||
<!-- <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />-->
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="29" />
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
package com.anytypeio.anytype.device
|
||||
|
||||
import android.content.Context
|
||||
import com.anytypeio.anytype.core_utils.ext.getJsonDataFromAsset
|
||||
import com.anytypeio.anytype.domain.cover.CoverCollectionProvider
|
||||
import com.anytypeio.anytype.domain.cover.CoverImage
|
||||
import com.google.gson.Gson
|
||||
|
||||
class DeviceCoverCollectionProvider(
|
||||
private val context: Context,
|
||||
private val gson: Gson
|
||||
) : CoverCollectionProvider {
|
||||
|
||||
override fun provide(): List<CoverImage> {
|
||||
val json = context.getJsonDataFromAsset(COVER_FILE)
|
||||
return if (json != null) {
|
||||
gson.fromJson(json, Array<CoverImage>::class.java).toList()
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val COVER_FILE = "covers.json"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.anytypeio.anytype.device
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.PickVisualMediaRequest
|
||||
import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia
|
||||
import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia.VisualMediaType
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.anytypeio.anytype.core_utils.ext.Mimetype
|
||||
import com.anytypeio.anytype.other.MediaPermissionHelper
|
||||
import com.anytypeio.anytype.ui.editor.PickerDelegate
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Launches a media picker (for images or videos) in a [Fragment].
|
||||
*
|
||||
* This function checks if the device supports the photo picker. If available,
|
||||
* it launches the [pickMedia] launcher with a request for the specified [mediaType].
|
||||
* If the picker is not available, it falls back to opening a file picker using [pickerDelegate]
|
||||
* with the provided [fallbackMimeType].
|
||||
*
|
||||
* @param pickMedia The [ActivityResultLauncher] used to launch the media picker.
|
||||
* @param pickerDelegate A delegate to open a fallback file picker when the media picker is unavailable.
|
||||
* @param mediaType The type of media to pick (e.g. [PickVisualMedia.ImageOnly] or [PickVisualMedia.VideoOnly]).
|
||||
* @param fallbackMimeType The MIME type to use with the fallback file picker (e.g. [Mimetype.MIME_IMAGE_ALL] or [Mimetype.MIME_VIDEO_ALL]).
|
||||
*/
|
||||
fun Fragment.launchMediaPicker(
|
||||
pickMedia: ActivityResultLauncher<PickVisualMediaRequest>,
|
||||
pickerDelegate: PickerDelegate,
|
||||
mediaType: VisualMediaType,
|
||||
fallbackMimeType: Mimetype
|
||||
) {
|
||||
context?.let { ctx ->
|
||||
if (PickVisualMedia.isPhotoPickerAvailable(ctx)) {
|
||||
pickMedia.launch(PickVisualMediaRequest(mediaType))
|
||||
} else {
|
||||
Timber.w("$mediaType picker is not available, using pickerDelegate")
|
||||
pickerDelegate.openFilePicker(fallbackMimeType, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Fragment.launchMediaPicker(
|
||||
pickMedia: ActivityResultLauncher<PickVisualMediaRequest>,
|
||||
permissionHelper: MediaPermissionHelper,
|
||||
mediaType: VisualMediaType,
|
||||
fallbackMimeType: Mimetype
|
||||
) {
|
||||
context?.let { ctx ->
|
||||
if (PickVisualMedia.isPhotoPickerAvailable(ctx)) {
|
||||
pickMedia.launch(PickVisualMediaRequest(mediaType))
|
||||
} else {
|
||||
Timber.w("$mediaType picker is not available, using pickerDelegate")
|
||||
permissionHelper.openFilePicker(fallbackMimeType, null)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,6 +44,7 @@ class MediaPermissionHelper(
|
|||
}
|
||||
|
||||
fun openFilePicker(mimeType: Mimetype, requestCode: Int?) {
|
||||
Timber.d("openFilePicker, mimeType:$mimeType, requestCode:$requestCode")
|
||||
if (isRequestInProgress) {
|
||||
Timber.w("Permission request already in progress")
|
||||
return
|
||||
|
@ -62,10 +63,12 @@ class MediaPermissionHelper(
|
|||
|
||||
val hasPermission = mimeType.hasPermission(context)
|
||||
if (hasPermission) {
|
||||
Timber.d("Permission already granted")
|
||||
onPermissionSuccess(mimeType, requestCode)
|
||||
isRequestInProgress = false
|
||||
} else {
|
||||
val permissions = mimeType.getPermissionToRequestByMime()
|
||||
Timber.d("Requesting permissions: $permissions")
|
||||
if (permissions.isNotEmpty()) {
|
||||
permissionReadStorage.launch(permissions)
|
||||
} else {
|
||||
|
|
|
@ -121,6 +121,7 @@ import com.anytypeio.anytype.core_utils.ext.toast
|
|||
import com.anytypeio.anytype.core_utils.ext.visible
|
||||
import com.anytypeio.anytype.core_utils.ui.showActionableSnackBar
|
||||
import com.anytypeio.anytype.databinding.FragmentEditorBinding
|
||||
import com.anytypeio.anytype.device.launchMediaPicker
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
import com.anytypeio.anytype.di.feature.DefaultComponentParam
|
||||
import com.anytypeio.anytype.ext.extractMarks
|
||||
|
@ -956,22 +957,20 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
).showChildFragment()
|
||||
}
|
||||
is Command.OpenPhotoPicker -> {
|
||||
try {
|
||||
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))
|
||||
} catch (e: Exception) {
|
||||
Timber.w(e, "Error while opening photo picker")
|
||||
toast("Error while opening photo picker")
|
||||
pickerDelegate.openFilePicker(Mimetype.MIME_IMAGE_ALL, null)
|
||||
}
|
||||
launchMediaPicker(
|
||||
pickMedia = pickMedia,
|
||||
pickerDelegate = pickerDelegate,
|
||||
mediaType = PickVisualMedia.ImageOnly,
|
||||
fallbackMimeType = Mimetype.MIME_IMAGE_ALL
|
||||
)
|
||||
}
|
||||
is Command.OpenVideoPicker -> {
|
||||
try {
|
||||
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.VideoOnly))
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error while opening video picker")
|
||||
toast("Error while opening video picker")
|
||||
pickerDelegate.openFilePicker(Mimetype.MIME_VIDEO_ALL, null)
|
||||
}
|
||||
launchMediaPicker(
|
||||
pickMedia = pickMedia,
|
||||
pickerDelegate = pickerDelegate,
|
||||
mediaType = PickVisualMedia.VideoOnly,
|
||||
fallbackMimeType = Mimetype.MIME_VIDEO_ALL
|
||||
)
|
||||
}
|
||||
is Command.OpenFilePicker -> {
|
||||
pickerDelegate.openFilePicker(Mimetype.MIME_FILE_ALL, null)
|
||||
|
|
|
@ -28,6 +28,7 @@ import com.anytypeio.anytype.core_utils.ext.subscribe
|
|||
import com.anytypeio.anytype.core_utils.ext.toast
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetFragment
|
||||
import com.anytypeio.anytype.databinding.FragmentDocCoverGalleryBinding
|
||||
import com.anytypeio.anytype.device.launchMediaPicker
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
import com.anytypeio.anytype.di.feature.DefaultComponentParam
|
||||
import com.anytypeio.anytype.other.MediaPermissionHelper
|
||||
|
@ -104,13 +105,12 @@ abstract class SelectCoverGalleryFragment :
|
|||
|
||||
binding.btnUpload.clicks()
|
||||
.onEach {
|
||||
try {
|
||||
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))
|
||||
} catch (e: Exception) {
|
||||
Timber.w(e, "Error while opening photo picker")
|
||||
toast("Error while opening photo picker")
|
||||
permissionHelper.openFilePicker(Mimetype.MIME_IMAGE_ALL, null)
|
||||
}
|
||||
launchMediaPicker(
|
||||
pickMedia = pickMedia,
|
||||
permissionHelper = permissionHelper,
|
||||
mediaType = PickVisualMedia.ImageOnly,
|
||||
fallbackMimeType = Mimetype.MIME_IMAGE_ALL
|
||||
)
|
||||
}
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.anytypeio.anytype.core_utils.ext.toast
|
|||
import com.anytypeio.anytype.core_utils.ext.visible
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetTextInputFragment
|
||||
import com.anytypeio.anytype.databinding.FragmentPageIconPickerBinding
|
||||
import com.anytypeio.anytype.device.launchMediaPicker
|
||||
import com.anytypeio.anytype.library_page_icon_picker_widget.ui.DocumentEmojiIconPickerAdapter
|
||||
import com.anytypeio.anytype.other.MediaPermissionHelper
|
||||
import com.anytypeio.anytype.presentation.editor.picker.EmojiPickerView.Companion.HOLDER_EMOJI_CATEGORY_HEADER
|
||||
|
@ -85,13 +86,12 @@ abstract class IconPickerFragmentBase<T> :
|
|||
btnRemoveIcon.setOnClickListener { vm.onRemoveClicked(target) }
|
||||
tvTabRandom.setOnClickListener { vm.onRandomEmoji(target) }
|
||||
tvTabUpload.setOnClickListener {
|
||||
try {
|
||||
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))
|
||||
} catch (e: Exception) {
|
||||
Timber.w(e, "Error while opening photo picker")
|
||||
toast("Error while opening photo picker")
|
||||
permissionHelper.openFilePicker(Mimetype.MIME_IMAGE_ALL, 0)
|
||||
}
|
||||
launchMediaPicker(
|
||||
pickMedia = pickMedia,
|
||||
permissionHelper = permissionHelper,
|
||||
mediaType = PickVisualMedia.ImageOnly,
|
||||
fallbackMimeType = Mimetype.MIME_IMAGE_ALL
|
||||
)
|
||||
}
|
||||
}
|
||||
skipCollapsed()
|
||||
|
|
|
@ -28,6 +28,7 @@ import com.anytypeio.anytype.core_utils.ext.subscribe
|
|||
import com.anytypeio.anytype.core_utils.ext.toast
|
||||
import com.anytypeio.anytype.core_utils.tools.FeatureToggles
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
|
||||
import com.anytypeio.anytype.device.launchMediaPicker
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
import com.anytypeio.anytype.other.MediaPermissionHelper
|
||||
import com.anytypeio.anytype.ui.profile.KeychainPhraseDialog
|
||||
|
@ -140,13 +141,12 @@ class ProfileSettingsFragment : BaseBottomSheetComposeFragment() {
|
|||
}
|
||||
|
||||
private fun proceedWithIconClick() {
|
||||
try {
|
||||
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))
|
||||
} catch (e: Exception) {
|
||||
Timber.w(e, "Error while opening photo picker")
|
||||
toast("Error while opening photo picker")
|
||||
permissionHelper.openFilePicker(Mimetype.MIME_IMAGE_ALL, null)
|
||||
}
|
||||
launchMediaPicker(
|
||||
pickMedia = pickMedia,
|
||||
permissionHelper = permissionHelper,
|
||||
mediaType = PickVisualMedia.ImageOnly,
|
||||
fallbackMimeType = Mimetype.MIME_IMAGE_ALL
|
||||
)
|
||||
}
|
||||
|
||||
private fun openGallery() {
|
||||
|
|
|
@ -10,6 +10,7 @@ import timber.log.Timber
|
|||
object FilePickerUtils {
|
||||
|
||||
fun Mimetype.hasPermission(context: Context): Boolean {
|
||||
Timber.d("hasPermission check, mimetype:$this")
|
||||
return when (this) {
|
||||
Mimetype.MIME_VIDEO_ALL -> context.isPermissionGranted(getPermissionToRequestForVideos())
|
||||
Mimetype.MIME_IMAGE_ALL -> context.isPermissionGranted(getPermissionToRequestForImages())
|
||||
|
@ -26,7 +27,7 @@ object FilePickerUtils {
|
|||
|
||||
private fun Context.isPermissionGranted(permission: Array<String>): Boolean {
|
||||
val hasPermission = permission.isNotEmpty() && ContextCompat.checkSelfPermission(this, permission[0]) == PackageManager.PERMISSION_GRANTED
|
||||
Timber.d("hasExternalStoragePermission, hasPermission:$hasPermission for permission:$permission")
|
||||
Timber.d("hasExternalStoragePermission, hasPermission:$hasPermission for permission:${permission.getOrNull(0)}")
|
||||
return hasPermission
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue