From 0bae4916985e336db37a3b1bb95199d6134f35b9 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Thu, 9 Nov 2023 23:07:18 +0100 Subject: [PATCH 01/29] Update necessary dependencies --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index f67667b098e..eee1024e8f1 100644 --- a/build.gradle +++ b/build.gradle @@ -101,18 +101,18 @@ ext { constraintLayoutVersion = '1.2.0' libaddressinputVersion = '0.0.2' eventBusVersion = '3.3.1' - googlePlayCoreVersion = '1.10.3' + googlePlayVersion = '2.0.1' coroutinesVersion = '1.6.4' lifecycleVersion = '2.6.2' aztecVersion = 'v1.3.45' flipperVersion = '0.176.1' stateMachineVersion = '0.2.0' - coreKtxVersion = '1.8.0' + coreKtxVersion = '1.12.0' appCompatVersion = '1.4.2' materialVersion = '1.6.1' hiltJetpackVersion = '1.0.0' wordPressUtilsVersion = '2.6.0' - mediapickerVersion = '0.2' + mediapickerVersion = '74-4545425a0e5f50e401fe98f7cce6237a5f0fcb33' wordPressLoginVersion = '1.7.0' aboutAutomatticVersion = '0.0.6' automatticTracksVersion = '3.2.0' From a4317092ea9744311b0d5a9a6cb83501a121fa49 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Thu, 9 Nov 2023 23:07:58 +0100 Subject: [PATCH 02/29] Replace media picker device source with camera source module --- WooCommerce/build.gradle | 11 +++-------- settings.gradle | 2 +- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 0fb8a763f22..5554fb0ce3f 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -359,14 +359,9 @@ dependencies { implementation "com.tinder.statemachine:statemachine:$stateMachineVersion" - implementation("${gradle.ext.mediaPickerBinaryPath}:$mediapickerVersion") { - exclude group: "org.wordpress", module: "utils" - } - implementation("${gradle.ext.mediaPickerSourceDeviceBinaryPath}:$mediapickerVersion") - implementation("${gradle.ext.mediaPickerSourceWordPressBinaryPath}:$mediapickerVersion") { - exclude group: "org.wordpress", module: "utils" - exclude group: "org.wordpress", module: "fluxc" - } + implementation("${gradle.ext.mediaPickerBinaryPath}:$mediapickerVersion") + implementation("${gradle.ext.mediaPickerSourceCameraBinaryPath}:$mediapickerVersion") + implementation("${gradle.ext.mediaPickerSourceWordPressBinaryPath}:$mediapickerVersion") // Jetpack Compose implementation platform("androidx.compose:compose-bom:$composeBOMVersion") diff --git a/settings.gradle b/settings.gradle index f3e03470a5a..06f5c39bc50 100644 --- a/settings.gradle +++ b/settings.gradle @@ -57,7 +57,7 @@ gradle.ext.fluxCWooCommercePluginBinaryPath = "org.wordpress.fluxc.plugins:wooco gradle.ext.loginFlowBinaryPath = "org.wordpress:login" gradle.ext.mediaPickerBinaryPath = "org.wordpress:mediapicker" gradle.ext.mediaPickerDomainBinaryPath = "org.wordpress.mediapicker:domain" -gradle.ext.mediaPickerSourceDeviceBinaryPath = "org.wordpress.mediapicker:source-device" +gradle.ext.mediaPickerSourceCameraBinaryPath = "org.wordpress.mediapicker:source-camera" gradle.ext.mediaPickerSourceGifBinaryPath = "org.wordpress.mediapicker:source-gif" gradle.ext.mediaPickerSourceWordPressBinaryPath = "org.wordpress.mediapicker:source-wordpress" From edd9f450a7dbbe7bd30956563578f805dd80e691 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Thu, 9 Nov 2023 23:08:25 +0100 Subject: [PATCH 03/29] Replace the deprecated play core library with new granular dependencies --- WooCommerce/build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 5554fb0ce3f..1723251cd74 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -280,7 +280,9 @@ dependencies { implementation "com.github.bumptech.glide:glide:$glideVersion" kapt "com.github.bumptech.glide:compiler:$glideVersion" implementation "com.github.bumptech.glide:volley-integration:$glideVersion@aar" - implementation "com.google.android.play:core:$googlePlayCoreVersion" + + implementation "com.google.android.play:app-update-ktx:$googlePlayVersion" + implementation "com.google.android.play:review-ktx:$googlePlayVersion" implementation 'com.google.android.gms:play-services-code-scanner:16.0.0-beta3' From e803abbccb81fb3e011dbd03cb587ee6b0242450 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Thu, 9 Nov 2023 23:09:06 +0100 Subject: [PATCH 04/29] Add the photo picker backport configuration to the manifest --- WooCommerce/src/main/AndroidManifest.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/WooCommerce/src/main/AndroidManifest.xml b/WooCommerce/src/main/AndroidManifest.xml index e94638d98d8..f8ab0c129a8 100644 --- a/WooCommerce/src/main/AndroidManifest.xml +++ b/WooCommerce/src/main/AndroidManifest.xml @@ -228,6 +228,18 @@ android:value="barcode_ui,ocr" /> + + + + + + + + + From 8b20a01b42f48e33d8765494321d2b5bf4324897 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Thu, 9 Nov 2023 23:09:48 +0100 Subject: [PATCH 05/29] Add the missing LiveData extension function --- .../com/woocommerce/android/extensions/LiveDataExt.kt | 10 ++++++++++ .../android/ui/orders/list/OrderListViewModel.kt | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/LiveDataExt.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/LiveDataExt.kt index 516ffa894de..7f821e5e82a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/LiveDataExt.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/extensions/LiveDataExt.kt @@ -60,3 +60,13 @@ fun LiveData.filterNotNull(): LiveData { } return mediator } + +fun LiveData.filter(predicate: (T) -> Boolean): LiveData { + val mediator = MediatorLiveData() + mediator.addSource(this) { + if (it != null && predicate(it)) { + mediator.value = it + } + } + return mediator +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt index 38376ebdf47..2de0c4c4701 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListViewModel.kt @@ -29,6 +29,7 @@ import com.woocommerce.android.analytics.AnalyticsTracker.Companion.KEY_IPP_BANN import com.woocommerce.android.analytics.AnalyticsTracker.Companion.VALUE_IPP_BANNER_SOURCE_ORDER_LIST import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.extensions.NotificationReceivedEvent +import com.woocommerce.android.extensions.filter import com.woocommerce.android.extensions.filterNotNull import com.woocommerce.android.model.FeatureFeedbackSettings import com.woocommerce.android.model.RequestResult.SUCCESS @@ -78,7 +79,6 @@ import org.wordpress.android.fluxc.store.ListStore import org.wordpress.android.fluxc.store.WCOrderStore import org.wordpress.android.fluxc.store.WCOrderStore.OnOrderChanged import org.wordpress.android.fluxc.store.WCOrderStore.OnOrderSummariesFetched -import org.wordpress.android.mediapicker.util.filter import javax.inject.Inject private const val EMPTY_VIEW_THROTTLE = 250L From 9c93cde5532547ee83be734286cd26a6d448342a Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Thu, 9 Nov 2023 23:10:19 +0100 Subject: [PATCH 06/29] Fix glide setup after library update --- .../kotlin/com/woocommerce/android/di/WooCommerceGlideModule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/WooCommerceGlideModule.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/WooCommerceGlideModule.kt index c890b021eae..ebed908cc9c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/di/WooCommerceGlideModule.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/di/WooCommerceGlideModule.kt @@ -53,7 +53,7 @@ class WooCommerceGlideModule : AppGlideModule() { WooCommerceGlideEntryPoint::class.java ).requestQueue() - glide.registry.replace(GlideUrl::class.java, InputStream::class.java, VolleyUrlLoader.Factory(requestQueue)) + registry.replace(GlideUrl::class.java, InputStream::class.java, VolleyUrlLoader.Factory(requestQueue)) } /** From aebb58a10c9cb621bf53480b1f9a986f4e815103 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Thu, 9 Nov 2023 23:11:51 +0100 Subject: [PATCH 07/29] Replace the media picker device source with photo picker --- .../android/mediapicker/MediaPickerHelper.kt | 40 ++++++++++++------- .../mediapicker/MediaPickerLoaderFactory.kt | 9 +---- .../mediapicker/MediaPickerSetupFactory.kt | 22 +--------- .../android/mediapicker/MediaPickerUtil.kt | 23 +++++++++++ .../ui/products/ProductImagesFragment.kt | 39 +++++++++++++----- 5 files changed, 79 insertions(+), 54 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt index 1d051ca271b..f840e692a37 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt @@ -1,6 +1,11 @@ package com.woocommerce.android.mediapicker +import android.net.Uri import androidx.activity.result.ActivityResult +import androidx.activity.result.PickVisualMediaRequest +import androidx.activity.result.contract.ActivityResultContracts.PickMultipleVisualMedia +import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia +import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia.VisualMediaType import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult import androidx.fragment.app.Fragment import com.woocommerce.android.mediapicker.MediaPickerUtil.processDeviceMediaResult @@ -8,7 +13,11 @@ import com.woocommerce.android.mediapicker.MediaPickerUtil.processMediaLibraryRe import dagger.hilt.android.scopes.FragmentScoped import org.wordpress.android.mediapicker.api.MediaPickerSetup import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource +import org.wordpress.android.mediapicker.model.MediaType +import org.wordpress.android.mediapicker.model.MediaType.IMAGE +import org.wordpress.android.mediapicker.model.MediaType.VIDEO import org.wordpress.android.mediapicker.model.MediaTypes +import org.wordpress.android.mediapicker.model.MediaUri import org.wordpress.android.mediapicker.ui.MediaPickerActivity import javax.inject.Inject @@ -17,8 +26,9 @@ class MediaPickerHelper @Inject constructor( private val fragment: Fragment, private val mediaPickerSetupFactory: MediaPickerSetup.Factory ) { - private val deviceLibraryLauncher = fragment.registerForActivityResult(StartActivityForResult()) { - handleDeviceMediaResult(it) + + private val photoPicker = fragment.registerForActivityResult(PickVisualMedia()) { uri -> + handlePhotoPickerResult(uri) } private val mediaLibraryLauncher = fragment.registerForActivityResult(StartActivityForResult()) { @@ -26,25 +36,25 @@ class MediaPickerHelper @Inject constructor( } fun showMediaPicker(source: DataSource) { - val mediaPickerIntent = MediaPickerActivity.buildIntent( - context = fragment.requireContext(), - mediaPickerSetupFactory.build( - source = source, - mediaTypes = MediaTypes.IMAGES - ) - ) if (source == DataSource.WP_MEDIA_LIBRARY) { + val mediaPickerIntent = MediaPickerActivity.buildIntent( + context = fragment.requireContext(), + mediaPickerSetupFactory.build( + source = source, + mediaTypes = MediaTypes.IMAGES + ) + ) mediaLibraryLauncher.launch(mediaPickerIntent) } else { - deviceLibraryLauncher.launch(mediaPickerIntent) + photoPicker.launch( + PickVisualMediaRequest(MediaTypes.IMAGES.allowedTypes.toPhotoPickerTypes()) + ) } } - private fun handleDeviceMediaResult(result: ActivityResult) { - result.processDeviceMediaResult()?.let { mediaUris -> - if (mediaUris.isNotEmpty()) { - (fragment as MediaPickerResultHandler).onMediaSelected(mediaUris.first().toString()) - } + private fun handlePhotoPickerResult(uri: Uri?) { + uri?.let { + (fragment as MediaPickerResultHandler).onMediaSelected(it.toString()) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerLoaderFactory.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerLoaderFactory.kt index 38f08c5f089..801fe562396 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerLoaderFactory.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerLoaderFactory.kt @@ -3,21 +3,14 @@ package com.woocommerce.android.mediapicker import org.wordpress.android.mediapicker.api.MediaPickerSetup import org.wordpress.android.mediapicker.loader.MediaLoader import org.wordpress.android.mediapicker.loader.MediaLoaderFactory -import org.wordpress.android.mediapicker.source.device.DeviceMediaSource import org.wordpress.android.mediapicker.source.wordpress.MediaLibrarySource import javax.inject.Inject // A factory class responsible for building an image-loader class, which is specific to a source. class MediaPickerLoaderFactory @Inject constructor( - private val deviceMediaSourceFactory: DeviceMediaSource.Factory, private val mediaLibrarySourceFactory: MediaLibrarySource.Factory ) : MediaLoaderFactory { override fun build(mediaPickerSetup: MediaPickerSetup): MediaLoader { - return when (mediaPickerSetup.primaryDataSource) { - MediaPickerSetup.DataSource.WP_MEDIA_LIBRARY -> { - mediaLibrarySourceFactory.build(mediaPickerSetup.allowedTypes) - } - else -> deviceMediaSourceFactory.build(mediaPickerSetup.allowedTypes) - }.toMediaLoader() + return mediaLibrarySourceFactory.build(mediaPickerSetup.allowedTypes).toMediaLoader() } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerSetupFactory.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerSetupFactory.kt index 8cabe090407..57da82e207a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerSetupFactory.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerSetupFactory.kt @@ -4,12 +4,9 @@ import com.woocommerce.android.R import org.wordpress.android.mediapicker.api.MediaPickerSetup import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.CAMERA -import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.DEVICE -import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.SYSTEM_PICKER import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.WP_MEDIA_LIBRARY -import org.wordpress.android.mediapicker.api.MediaPickerSetup.SearchMode.VISIBLE_UNTOGGLED import org.wordpress.android.mediapicker.model.MediaTypes -import org.wordpress.android.mediapicker.source.device.DeviceMediaPickerSetup +import org.wordpress.android.mediapicker.source.camera.CameraMediaPickerSetup import org.wordpress.android.mediapicker.source.wordpress.MediaLibraryPickerSetup import java.security.InvalidParameterException import javax.inject.Inject @@ -21,27 +18,12 @@ class MediaPickerSetupFactory @Inject constructor() : MediaPickerSetup.Factory { isMultiSelectAllowed: Boolean ): MediaPickerSetup { return when (source) { - CAMERA -> DeviceMediaPickerSetup.buildCameraPicker() + CAMERA -> CameraMediaPickerSetup.build() WP_MEDIA_LIBRARY -> MediaLibraryPickerSetup.build( mediaTypes = mediaTypes, canMultiSelect = isMultiSelectAllowed ) - DEVICE -> MediaPickerSetup( - primaryDataSource = DEVICE, - isMultiSelectEnabled = isMultiSelectAllowed, - areResultsQueued = false, - searchMode = VISIBLE_UNTOGGLED, - availableDataSources = setOf(SYSTEM_PICKER), - allowedTypes = mediaTypes.allowedTypes, - title = R.string.photo_picker_title - ) - - SYSTEM_PICKER -> DeviceMediaPickerSetup.buildSystemPicker( - mediaTypes = mediaTypes, - canMultiSelect = false - ) - else -> throw InvalidParameterException("${source.name} source is not supported") } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerUtil.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerUtil.kt index 4100f457e73..105104befc5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerUtil.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerUtil.kt @@ -3,6 +3,8 @@ package com.woocommerce.android.mediapicker import android.net.Uri import android.os.Bundle import androidx.activity.result.ActivityResult +import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia +import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia.VisualMediaType import androidx.appcompat.app.AppCompatActivity import com.woocommerce.android.extensions.parcelableArrayList import com.woocommerce.android.model.Product @@ -10,6 +12,9 @@ import com.woocommerce.android.util.WooLog import org.wordpress.android.mediapicker.MediaPickerConstants import org.wordpress.android.mediapicker.api.MediaPickerSetup import org.wordpress.android.mediapicker.model.MediaItem +import org.wordpress.android.mediapicker.model.MediaType +import org.wordpress.android.mediapicker.model.MediaType.IMAGE +import org.wordpress.android.mediapicker.model.MediaType.VIDEO import org.wordpress.android.util.DateTimeUtils import java.security.InvalidParameterException @@ -62,3 +67,21 @@ object MediaPickerUtil { ?: emptyList() } } + +fun Set.toPhotoPickerTypes(): VisualMediaType { + return when { + contains(IMAGE) && contains(VIDEO) -> { + PickVisualMedia.ImageAndVideo + } + contains(IMAGE) -> { + PickVisualMedia.ImageOnly + } + contains(VIDEO) -> { + PickVisualMedia.VideoOnly + } else -> { + throw IllegalArgumentException( + "Missing or unsupported photo picker media types: $this" + ) + } + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImagesFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImagesFragment.kt index 8ba4b6ee96c..7e14ff2841e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImagesFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImagesFragment.kt @@ -9,7 +9,10 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import androidx.activity.result.ActivityResult +import androidx.activity.result.PickVisualMediaRequest import androidx.activity.result.contract.ActivityResultContracts +import androidx.activity.result.contract.ActivityResultContracts.PickMultipleVisualMedia +import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia import androidx.appcompat.app.AlertDialog import androidx.core.text.HtmlCompat import androidx.core.view.MenuProvider @@ -28,6 +31,7 @@ import com.woocommerce.android.extensions.navigateSafely import com.woocommerce.android.extensions.takeIfNotEqualTo import com.woocommerce.android.mediapicker.MediaPickerUtil.processDeviceMediaResult import com.woocommerce.android.mediapicker.MediaPickerUtil.processMediaLibraryResult +import com.woocommerce.android.mediapicker.toPhotoPickerTypes import com.woocommerce.android.model.Product.Image import com.woocommerce.android.ui.products.ProductImagesViewModel.ProductImagesState import com.woocommerce.android.ui.products.ProductImagesViewModel.ShowCamera @@ -50,9 +54,9 @@ import dagger.hilt.android.AndroidEntryPoint import org.wordpress.android.mediapicker.MediaPickerUtils import org.wordpress.android.mediapicker.api.MediaPickerSetup import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.CAMERA -import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.DEVICE import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.WP_MEDIA_LIBRARY import org.wordpress.android.mediapicker.model.MediaTypes +import org.wordpress.android.mediapicker.model.MediaTypes.IMAGES import org.wordpress.android.mediapicker.ui.MediaPickerActivity import javax.inject.Inject @@ -299,16 +303,11 @@ class ProductImagesFragment : } private fun showLocalDeviceMediaPicker() { - val intent = MediaPickerActivity.buildIntent( - requireContext(), - mediaPickerSetupFactory.build( - source = DEVICE, - mediaTypes = MediaTypes.IMAGES, - isMultiSelectAllowed = viewModel.isMultiSelectionAllowed - ) - ) - - mediaDeviceMediaPickerLauncher.launch(intent) + if (viewModel.isMultiSelectionAllowed) { + multiPhotoPicker.launch(PickVisualMediaRequest(IMAGES.allowedTypes.toPhotoPickerTypes())) + } else { + photoPicker.launch(PickVisualMediaRequest(IMAGES.allowedTypes.toPhotoPickerTypes())) + } } private fun captureProductImage() { @@ -326,6 +325,14 @@ class ProductImagesFragment : handleDeviceMediaResult(it, AnalyticsTracker.IMAGE_SOURCE_DEVICE) } + private val photoPicker = registerForActivityResult(PickVisualMedia()) { uri -> + handlePhotoPickerResult(uri?.let { listOf(it) } ?: emptyList(), AnalyticsTracker.IMAGE_SOURCE_DEVICE) + } + + private val multiPhotoPicker = registerForActivityResult(PickMultipleVisualMedia()) { uris -> + handlePhotoPickerResult(uris, AnalyticsTracker.IMAGE_SOURCE_DEVICE) + } + private val cameraLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { handleDeviceMediaResult(it, AnalyticsTracker.IMAGE_SOURCE_CAMERA) } @@ -356,6 +363,16 @@ class ProductImagesFragment : } } + private fun handlePhotoPickerResult(uris: List, source: String) { + if (uris.isNotEmpty()) { + AnalyticsTracker.track( + AnalyticsEvent.PRODUCT_IMAGE_ADDED, + mapOf(AnalyticsTracker.KEY_IMAGE_SOURCE to source) + ) + viewModel.uploadProductImages(navArgs.remoteId, uris) + } + } + override fun onExit() { viewModel.onNavigateBackButtonClicked() } From e00f619a3ff5e431a8d7d090cc779746d44572b3 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Thu, 9 Nov 2023 23:12:48 +0100 Subject: [PATCH 08/29] Update the product model properties' nullability --- .../src/main/kotlin/com/woocommerce/android/model/Product.kt | 4 ++-- .../kotlin/com/woocommerce/android/model/ProductVariation.kt | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/Product.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/Product.kt index 698344e8d36..a542f92cb40 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/Product.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/Product.kt @@ -94,9 +94,9 @@ data class Product( @Parcelize data class Image( val id: Long, - val name: String, + val name: String?, val source: String, - val dateCreated: Date + val dateCreated: Date? ) : Parcelable fun isSameProduct(product: Product): Boolean { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductVariation.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductVariation.kt index 4ebb5eba3f0..317c8f6bfe1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductVariation.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/ProductVariation.kt @@ -114,7 +114,10 @@ open class ProductVariation( json.addProperty("id", variantImage.id) json.addProperty("name", variantImage.name) json.addProperty("src", variantImage.source) - json.addProperty("date_created_gmt", variantImage.dateCreated.formatToYYYYmmDDhhmmss()) + json.addProperty( + /* property = */ "date_created_gmt", + /* value = */ variantImage.dateCreated?.formatToYYYYmmDDhhmmss() ?: "" + ) }.toString() } ?: "" } From cc24608540a4daa0f9d39199c43fa808a1d7638f Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Thu, 9 Nov 2023 23:13:20 +0100 Subject: [PATCH 09/29] Update the Compose animation functions after library update --- .../ui/blaze/BlazeCampaignCreationScreen.kt | 3 ++- .../jetpack/main/JetpackActivationMainScreen.kt | 16 +++++++++++++++- .../android/ui/products/ProductDetailFragment.kt | 4 +++- .../ui/shipping/InstallWCShippingScreen.kt | 6 +++--- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeCampaignCreationScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeCampaignCreationScreen.kt index f2e4f646fa9..dba81a8c654 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeCampaignCreationScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeCampaignCreationScreen.kt @@ -7,6 +7,7 @@ import androidx.compose.animation.AnimatedContent import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut +import androidx.compose.animation.togetherWith import androidx.compose.animation.with import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -84,7 +85,7 @@ fun BlazeCampaignCreationScreen( ) { paddingValues -> AnimatedContent( targetState = viewState, - transitionSpec = { fadeIn() with fadeOut() } + transitionSpec = { fadeIn() togetherWith fadeOut() }, label = "" ) { targetState -> when (targetState) { is BlazeCreationViewState.Intro -> BlazeCreationIntroScreen( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/jetpack/main/JetpackActivationMainScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/jetpack/main/JetpackActivationMainScreen.kt index daa3415069c..0e6d4b5c232 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/jetpack/main/JetpackActivationMainScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/jetpack/main/JetpackActivationMainScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically +import androidx.compose.animation.togetherWith import androidx.compose.animation.with import androidx.compose.foundation.Canvas import androidx.compose.foundation.Image @@ -109,7 +110,12 @@ fun JetpackActivationMainScreen( transition.AnimatedContent( contentKey = { it is JetpackActivationMainViewModel.ViewState.ErrorViewState }, transitionSpec = { - fadeIn(animationSpec = tween(DefaultDurationMillis, delayMillis = DefaultDurationMillis)) with + fadeIn( + animationSpec = tween( + DefaultDurationMillis, + delayMillis = DefaultDurationMillis + ) + ) togetherWith fadeOut(animationSpec = tween(DefaultDurationMillis)) }, modifier = Modifier.weight(1f) @@ -119,6 +125,7 @@ fun JetpackActivationMainScreen( viewState = targetState, onContinueClick = onContinueClick ) + is JetpackActivationMainViewModel.ViewState.ErrorViewState -> ErrorState( viewState = targetState, onGetHelpClick = onGetHelpClick, @@ -294,10 +301,13 @@ private fun AnimatedVisibilityScope.ErrorState( val retryButton = when (viewState.stepType) { JetpackActivationMainViewModel.StepType.Installation -> R.string.login_jetpack_installation_retry_installing + JetpackActivationMainViewModel.StepType.Activation -> R.string.login_jetpack_installation_retry_activating + JetpackActivationMainViewModel.StepType.Connection -> R.string.login_jetpack_installation_retry_authorizing + else -> null } retryButton?.let { @@ -328,9 +338,11 @@ private fun JetpackActivationStep( JetpackActivationMainViewModel.StepState.Idle -> { IdleCircle(indicatorModifier) } + JetpackActivationMainViewModel.StepState.Ongoing -> { CircularProgressIndicator(indicatorModifier) } + JetpackActivationMainViewModel.StepState.Success -> { Image( painter = painterResource(id = R.drawable.ic_progress_circle_complete), @@ -338,6 +350,7 @@ private fun JetpackActivationStep( modifier = indicatorModifier ) } + is JetpackActivationMainViewModel.StepState.Error -> { Icon( painter = painterResource(id = R.drawable.ic_gridicons_notice), @@ -385,6 +398,7 @@ private fun ConnectionStepHint(connectionStep: JetpackActivationMainViewModel.Co R.string.login_jetpack_steps_authorizing_validation, R.color.color_on_surface_medium ) + else -> Pair( R.string.login_jetpack_steps_authorizing_done, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt index e4a159a6199..13c003e4faa 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt @@ -114,7 +114,9 @@ class ProductDetailFragment : override val activityAppBarStatus: AppBarStatus get() { - val navigationIcon = if (findNavController().backQueue.any { it.destination.id == R.id.products }) { + val navigationIcon = if (findNavController().currentBackStack.value + .any { it.destination.id == R.id.products } + ) { R.drawable.ic_back_24dp } else { R.drawable.ic_gridicons_cross_24dp diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt index 472c1008cc2..5a74ea52c59 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt @@ -11,7 +11,7 @@ import androidx.compose.animation.core.tween import androidx.compose.animation.core.updateTransition import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.animation.with +import androidx.compose.animation.togetherWith import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.material.MaterialTheme @@ -49,10 +49,10 @@ fun InstallWCShippingScreen(viewState: ViewState) { // Apply a fade-in/fade-out globally, // then each child will animate the individual components separately fadeIn(tween(500, delayMillis = 500)) - .with(fadeOut(tween(500, easing = LinearOutSlowInEasing))) + .togetherWith(fadeOut(tween(500, easing = LinearOutSlowInEasing))) } else { // No-op animation, each screen will define animations for specific components separately - EnterTransition.None.with(ExitTransition.None) + EnterTransition.None.togetherWith(ExitTransition.None) } } ) { targetState -> From 755df2d0c2332c5747014a8d9c29bf21b4c94eaa Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Thu, 9 Nov 2023 23:13:39 +0100 Subject: [PATCH 10/29] Update the glide callbacks after library update --- .../android/ui/products/ImageViewerFragment.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ImageViewerFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ImageViewerFragment.kt index b88812cf34c..fe6ea202f54 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ImageViewerFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ImageViewerFragment.kt @@ -8,6 +8,7 @@ import androidx.fragment.app.Fragment import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.engine.GlideException import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target import com.woocommerce.android.R import com.woocommerce.android.analytics.AnalyticsTracker import com.woocommerce.android.databinding.FragmentImageViewerBinding @@ -95,7 +96,7 @@ class ImageViewerFragment : Fragment(R.layout.fragment_image_viewer), RequestLis override fun onLoadFailed( e: GlideException?, model: Any?, - target: com.bumptech.glide.request.target.Target?, + target: Target, isFirstResource: Boolean ): Boolean { showProgress(false) @@ -107,10 +108,10 @@ class ImageViewerFragment : Fragment(R.layout.fragment_image_viewer), RequestLis * Glide has loaded the image, hide the progress bar */ override fun onResourceReady( - resource: Drawable?, - model: Any?, - target: com.bumptech.glide.request.target.Target?, - dataSource: DataSource?, + resource: Drawable, + model: Any, + target: Target?, + dataSource: DataSource, isFirstResource: Boolean ): Boolean { showProgress(false) From 7fb0f93a211547a3a09f8b4a2b0affb8ff35bdf5 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Thu, 9 Nov 2023 23:15:17 +0100 Subject: [PATCH 11/29] Fix ktlint issues --- .../woocommerce/android/mediapicker/MediaPickerHelper.kt | 7 ------- .../android/mediapicker/MediaPickerSetupFactory.kt | 1 - .../android/ui/blaze/BlazeCampaignCreationScreen.kt | 1 - .../android/ui/products/ProductDetailFragment.kt | 2 +- .../android/ui/products/ProductImagesFragment.kt | 6 ------ 5 files changed, 1 insertion(+), 16 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt index f840e692a37..3b1781e370e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt @@ -3,21 +3,14 @@ package com.woocommerce.android.mediapicker import android.net.Uri import androidx.activity.result.ActivityResult import androidx.activity.result.PickVisualMediaRequest -import androidx.activity.result.contract.ActivityResultContracts.PickMultipleVisualMedia import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia -import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia.VisualMediaType import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult import androidx.fragment.app.Fragment -import com.woocommerce.android.mediapicker.MediaPickerUtil.processDeviceMediaResult import com.woocommerce.android.mediapicker.MediaPickerUtil.processMediaLibraryResult import dagger.hilt.android.scopes.FragmentScoped import org.wordpress.android.mediapicker.api.MediaPickerSetup import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource -import org.wordpress.android.mediapicker.model.MediaType -import org.wordpress.android.mediapicker.model.MediaType.IMAGE -import org.wordpress.android.mediapicker.model.MediaType.VIDEO import org.wordpress.android.mediapicker.model.MediaTypes -import org.wordpress.android.mediapicker.model.MediaUri import org.wordpress.android.mediapicker.ui.MediaPickerActivity import javax.inject.Inject diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerSetupFactory.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerSetupFactory.kt index 57da82e207a..b3839bb98e1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerSetupFactory.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerSetupFactory.kt @@ -1,6 +1,5 @@ package com.woocommerce.android.mediapicker -import com.woocommerce.android.R import org.wordpress.android.mediapicker.api.MediaPickerSetup import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.CAMERA diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeCampaignCreationScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeCampaignCreationScreen.kt index dba81a8c654..c3427153c41 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeCampaignCreationScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeCampaignCreationScreen.kt @@ -8,7 +8,6 @@ import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.togetherWith -import androidx.compose.animation.with import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt index 13c003e4faa..58f274026cc 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt @@ -115,7 +115,7 @@ class ProductDetailFragment : override val activityAppBarStatus: AppBarStatus get() { val navigationIcon = if (findNavController().currentBackStack.value - .any { it.destination.id == R.id.products } + .any { it.destination.id == R.id.products } ) { R.drawable.ic_back_24dp } else { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImagesFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImagesFragment.kt index 7e14ff2841e..ed4c0128d5b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImagesFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImagesFragment.kt @@ -319,12 +319,6 @@ class ProductImagesFragment : cameraLauncher.launch(intent) } - private val mediaDeviceMediaPickerLauncher = registerForActivityResult( - ActivityResultContracts.StartActivityForResult() - ) { - handleDeviceMediaResult(it, AnalyticsTracker.IMAGE_SOURCE_DEVICE) - } - private val photoPicker = registerForActivityResult(PickVisualMedia()) { uri -> handlePhotoPickerResult(uri?.let { listOf(it) } ?: emptyList(), AnalyticsTracker.IMAGE_SOURCE_DEVICE) } From a405cb47995a74cc8580e55272d159b809647e4e Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Fri, 10 Nov 2023 11:04:41 +0100 Subject: [PATCH 12/29] Refactor the media picker helper to be more reusable --- .../android/mediapicker/MediaPickerHelper.kt | 84 +++++++++++++++---- 1 file changed, 67 insertions(+), 17 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt index 3b1781e370e..8defba753df 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt @@ -3,14 +3,21 @@ package com.woocommerce.android.mediapicker import android.net.Uri import androidx.activity.result.ActivityResult import androidx.activity.result.PickVisualMediaRequest +import androidx.activity.result.contract.ActivityResultContracts.PickMultipleVisualMedia import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult import androidx.fragment.app.Fragment +import com.woocommerce.android.analytics.AnalyticsTracker +import com.woocommerce.android.mediapicker.MediaPickerUtil.processDeviceMediaResult import com.woocommerce.android.mediapicker.MediaPickerUtil.processMediaLibraryResult +import com.woocommerce.android.model.Product import dagger.hilt.android.scopes.FragmentScoped import org.wordpress.android.mediapicker.api.MediaPickerSetup import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource -import org.wordpress.android.mediapicker.model.MediaTypes +import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.CAMERA +import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.DEVICE +import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.WP_MEDIA_LIBRARY +import org.wordpress.android.mediapicker.model.MediaTypes.IMAGES import org.wordpress.android.mediapicker.ui.MediaPickerActivity import javax.inject.Inject @@ -21,43 +28,86 @@ class MediaPickerHelper @Inject constructor( ) { private val photoPicker = fragment.registerForActivityResult(PickVisualMedia()) { uri -> - handlePhotoPickerResult(uri) + handlePhotoPickerResult(uri?.let { listOf(it) } ?: emptyList()) + } + + private val multiPhotoPicker = fragment.registerForActivityResult(PickMultipleVisualMedia()) { uris -> + handlePhotoPickerResult(uris) } private val mediaLibraryLauncher = fragment.registerForActivityResult(StartActivityForResult()) { handleMediaLibraryPickerResult(it) } - fun showMediaPicker(source: DataSource) { - if (source == DataSource.WP_MEDIA_LIBRARY) { - val mediaPickerIntent = MediaPickerActivity.buildIntent( - context = fragment.requireContext(), - mediaPickerSetupFactory.build( - source = source, - mediaTypes = MediaTypes.IMAGES - ) + private val cameraLauncher = fragment.registerForActivityResult(StartActivityForResult()) { + handleCameraCaptureResult(it) + } + + fun showMediaPicker(source: DataSource, allowMultiSelect: Boolean = false) { + when (source) { + WP_MEDIA_LIBRARY -> launchWPMediaLibrary(source, allowMultiSelect) + CAMERA -> launchCamera() + DEVICE -> launchPhotoPicker(allowMultiSelect) + else -> throw IllegalArgumentException("Unsupported data source: $source") + } + } + + private fun launchPhotoPicker(allowMultiSelect: Boolean) { + if (allowMultiSelect) { + multiPhotoPicker.launch( + PickVisualMediaRequest(IMAGES.allowedTypes.toPhotoPickerTypes()) ) - mediaLibraryLauncher.launch(mediaPickerIntent) } else { photoPicker.launch( - PickVisualMediaRequest(MediaTypes.IMAGES.allowedTypes.toPhotoPickerTypes()) + PickVisualMediaRequest(IMAGES.allowedTypes.toPhotoPickerTypes()) + ) + } + } + + private fun launchCamera() { + val intent = MediaPickerActivity.buildIntent( + fragment.requireContext(), + mediaPickerSetupFactory.build(CAMERA) + ) + + cameraLauncher.launch(intent) + } + + private fun launchWPMediaLibrary( + source: DataSource, + allowMultiSelect: Boolean + ) { + val mediaPickerIntent = MediaPickerActivity.buildIntent( + context = fragment.requireContext(), + mediaPickerSetupFactory.build( + source = source, + mediaTypes = IMAGES, + isMultiSelectAllowed = allowMultiSelect ) + ) + mediaLibraryLauncher.launch(mediaPickerIntent) + } + + private fun handleCameraCaptureResult(result: ActivityResult) { + result.processDeviceMediaResult()?.let { uris -> + (fragment as MediaPickerResultHandler).onDeviceMediaSelected(uris, AnalyticsTracker.IMAGE_SOURCE_CAMERA) } } - private fun handlePhotoPickerResult(uri: Uri?) { - uri?.let { - (fragment as MediaPickerResultHandler).onMediaSelected(it.toString()) + private fun handlePhotoPickerResult(uris: List) { + if (uris.isNotEmpty()) { + (fragment as MediaPickerResultHandler).onDeviceMediaSelected(uris, AnalyticsTracker.IMAGE_SOURCE_DEVICE) } } private fun handleMediaLibraryPickerResult(result: ActivityResult) { result.processMediaLibraryResult()?.let { mediaItems -> - (fragment as MediaPickerResultHandler).onMediaSelected(mediaItems.map { it.source }.first()) + (fragment as MediaPickerResultHandler).onWPMediaSelected(mediaItems) } } interface MediaPickerResultHandler { - fun onMediaSelected(mediaUri: String) + fun onDeviceMediaSelected(imageUris: List, source: String) + fun onWPMediaSelected(images: List) } } From 56227fb3a22807e05e6114663a99d99182f02fbc Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Fri, 10 Nov 2023 11:05:18 +0100 Subject: [PATCH 13/29] Reuse the media picker helper in all places where media picker is used --- .../ui/products/ProductImagesFragment.kt | 110 ++++-------------- .../products/ai/AddProductWithAIFragment.kt | 28 +++-- .../ai/PackagePhotoBottomSheetFragment.kt | 21 +++- 3 files changed, 60 insertions(+), 99 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImagesFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImagesFragment.kt index ed4c0128d5b..8f6f8b7a9ca 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImagesFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductImagesFragment.kt @@ -8,11 +8,6 @@ import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import android.view.View -import androidx.activity.result.ActivityResult -import androidx.activity.result.PickVisualMediaRequest -import androidx.activity.result.contract.ActivityResultContracts -import androidx.activity.result.contract.ActivityResultContracts.PickMultipleVisualMedia -import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia import androidx.appcompat.app.AlertDialog import androidx.core.text.HtmlCompat import androidx.core.view.MenuProvider @@ -29,9 +24,8 @@ import com.woocommerce.android.databinding.FragmentProductImagesBinding import com.woocommerce.android.extensions.navigateBackWithResult import com.woocommerce.android.extensions.navigateSafely import com.woocommerce.android.extensions.takeIfNotEqualTo -import com.woocommerce.android.mediapicker.MediaPickerUtil.processDeviceMediaResult -import com.woocommerce.android.mediapicker.MediaPickerUtil.processMediaLibraryResult -import com.woocommerce.android.mediapicker.toPhotoPickerTypes +import com.woocommerce.android.mediapicker.MediaPickerHelper +import com.woocommerce.android.mediapicker.MediaPickerHelper.MediaPickerResultHandler import com.woocommerce.android.model.Product.Image import com.woocommerce.android.ui.products.ProductImagesViewModel.ProductImagesState import com.woocommerce.android.ui.products.ProductImagesViewModel.ShowCamera @@ -52,17 +46,17 @@ import com.woocommerce.android.viewmodel.fixedHiltNavGraphViewModels import com.woocommerce.android.widgets.WCProductImageGalleryView.OnGalleryImageInteractionListener import dagger.hilt.android.AndroidEntryPoint import org.wordpress.android.mediapicker.MediaPickerUtils -import org.wordpress.android.mediapicker.api.MediaPickerSetup import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.CAMERA +import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.DEVICE import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.WP_MEDIA_LIBRARY -import org.wordpress.android.mediapicker.model.MediaTypes -import org.wordpress.android.mediapicker.model.MediaTypes.IMAGES -import org.wordpress.android.mediapicker.ui.MediaPickerActivity import javax.inject.Inject @AndroidEntryPoint class ProductImagesFragment : - BaseProductEditorFragment(R.layout.fragment_product_images), OnGalleryImageInteractionListener, MenuProvider { + BaseProductEditorFragment(R.layout.fragment_product_images), + OnGalleryImageInteractionListener, + MenuProvider, + MediaPickerResultHandler { private val navArgs: ProductImagesFragmentArgs by navArgs() private val viewModel: ProductImagesViewModel by fixedHiltNavGraphViewModels(R.id.nav_graph_image_gallery) @@ -73,7 +67,7 @@ class ProductImagesFragment : lateinit var mediaPickerUtils: MediaPickerUtils @Inject - lateinit var mediaPickerSetupFactory: MediaPickerSetup.Factory + lateinit var mediaPickerHelper: MediaPickerHelper private var _binding: FragmentProductImagesBinding? = null private val binding get() = _binding!! @@ -201,9 +195,9 @@ class ProductImagesFragment : is ShowDialog -> event.showDialog() ShowImageSourceDialog -> showImageSourceDialog() is ShowImageDetail -> showImageDetail(event.image, event.isOpenedDirectly) - ShowStorageChooser -> showLocalDeviceMediaPicker() - ShowCamera -> captureProductImage() - ShowWPMediaPicker -> showMediaLibraryPicker() + ShowStorageChooser -> mediaPickerHelper.showMediaPicker(DEVICE, allowMultiSelect = true) + ShowCamera -> mediaPickerHelper.showMediaPicker(CAMERA) + ShowWPMediaPicker -> mediaPickerHelper.showMediaPicker(WP_MEDIA_LIBRARY, allowMultiSelect = true) is ShowDeleteImageConfirmation -> showConfirmationDialog(event.image) else -> event.isHandled = false } @@ -289,85 +283,25 @@ class ProductImagesFragment : .show() } - private fun showMediaLibraryPicker() { - val intent = MediaPickerActivity.buildIntent( - requireContext(), - mediaPickerSetupFactory.build( - source = WP_MEDIA_LIBRARY, - mediaTypes = MediaTypes.IMAGES, - isMultiSelectAllowed = viewModel.isMultiSelectionAllowed - ) - ) - - mediaLibraryLauncher.launch(intent) - } - - private fun showLocalDeviceMediaPicker() { - if (viewModel.isMultiSelectionAllowed) { - multiPhotoPicker.launch(PickVisualMediaRequest(IMAGES.allowedTypes.toPhotoPickerTypes())) - } else { - photoPicker.launch(PickVisualMediaRequest(IMAGES.allowedTypes.toPhotoPickerTypes())) - } - } - - private fun captureProductImage() { - val intent = MediaPickerActivity.buildIntent( - requireContext(), - mediaPickerSetupFactory.build(CAMERA) - ) - - cameraLauncher.launch(intent) - } - - private val photoPicker = registerForActivityResult(PickVisualMedia()) { uri -> - handlePhotoPickerResult(uri?.let { listOf(it) } ?: emptyList(), AnalyticsTracker.IMAGE_SOURCE_DEVICE) - } - - private val multiPhotoPicker = registerForActivityResult(PickMultipleVisualMedia()) { uris -> - handlePhotoPickerResult(uris, AnalyticsTracker.IMAGE_SOURCE_DEVICE) - } - - private val cameraLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - handleDeviceMediaResult(it, AnalyticsTracker.IMAGE_SOURCE_CAMERA) - } - - private val mediaLibraryLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - handleMediaLibraryPickerResult(it) - } - - private fun handleDeviceMediaResult(result: ActivityResult, source: String) { - result.processDeviceMediaResult()?.let { mediaUris -> - if (mediaUris.isNotEmpty()) { - AnalyticsTracker.track( - AnalyticsEvent.PRODUCT_IMAGE_ADDED, - mapOf(AnalyticsTracker.KEY_IMAGE_SOURCE to source) - ) - viewModel.uploadProductImages(navArgs.remoteId, mediaUris) - } - } - } - - private fun handleMediaLibraryPickerResult(result: ActivityResult) { - result.processMediaLibraryResult()?.let { - AnalyticsTracker.track( - AnalyticsEvent.PRODUCT_IMAGE_ADDED, - mapOf(AnalyticsTracker.KEY_IMAGE_SOURCE to AnalyticsTracker.IMAGE_SOURCE_WPMEDIA) - ) - viewModel.onMediaLibraryImagesAdded(it) - } + override fun onExit() { + viewModel.onNavigateBackButtonClicked() } - private fun handlePhotoPickerResult(uris: List, source: String) { - if (uris.isNotEmpty()) { + override fun onDeviceMediaSelected(imageUris: List, source: String) { + if (imageUris.isNotEmpty()) { AnalyticsTracker.track( AnalyticsEvent.PRODUCT_IMAGE_ADDED, mapOf(AnalyticsTracker.KEY_IMAGE_SOURCE to source) ) - viewModel.uploadProductImages(navArgs.remoteId, uris) + viewModel.uploadProductImages(navArgs.remoteId, imageUris) } } - override fun onExit() { - viewModel.onNavigateBackButtonClicked() + override fun onWPMediaSelected(images: List) { + AnalyticsTracker.track( + AnalyticsEvent.PRODUCT_IMAGE_ADDED, + mapOf(AnalyticsTracker.KEY_IMAGE_SOURCE to AnalyticsTracker.IMAGE_SOURCE_WPMEDIA) + ) + viewModel.onMediaLibraryImagesAdded(images) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/AddProductWithAIFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/AddProductWithAIFragment.kt index f91cad59892..e081f0a0a1f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/AddProductWithAIFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/AddProductWithAIFragment.kt @@ -1,5 +1,6 @@ package com.woocommerce.android.ui.products.ai +import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -15,6 +16,7 @@ import com.woocommerce.android.extensions.handleDialogResult import com.woocommerce.android.extensions.navigateSafely import com.woocommerce.android.mediapicker.MediaPickerHelper import com.woocommerce.android.mediapicker.MediaPickerHelper.MediaPickerResultHandler +import com.woocommerce.android.model.Product.Image import com.woocommerce.android.ui.base.BaseFragment import com.woocommerce.android.ui.base.UIMessageResolver import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground @@ -80,13 +82,6 @@ class AddProductWithAIFragment : BaseFragment(), MediaPickerResultHandler { } } - override fun onMediaSelected(mediaUri: String) { - findNavController().navigateSafely( - directions = AddProductWithAIFragmentDirections - .actionAddProductWithAIFragmentToPackagePhotoBottomSheetFragment(mediaUri) - ) - } - private fun handleResults() { handleDialogResult( key = AIProductNameBottomSheetFragment.KEY_AI_GENERATED_PRODUCT_NAME_RESULT, @@ -109,4 +104,23 @@ class AddProductWithAIFragment : BaseFragment(), MediaPickerResultHandler { .actionAddProductWithAIFragmentToAIProductNameBottomSheetFragment(initialName) findNavController().navigateSafely(action) } + + override fun onDeviceMediaSelected(imageUris: List, source: String) { + if (imageUris.isNotEmpty()) { + onImageSelected(imageUris.first().toString()) + } + } + + override fun onWPMediaSelected(images: List) { + if (images.isNotEmpty()) { + onImageSelected(images.first().source) + } + } + + private fun onImageSelected(mediaUri: String) { + findNavController().navigateSafely( + directions = AddProductWithAIFragmentDirections + .actionAddProductWithAIFragmentToPackagePhotoBottomSheetFragment(mediaUri) + ) + } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/PackagePhotoBottomSheetFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/PackagePhotoBottomSheetFragment.kt index fd812bc15e5..887313961b4 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/PackagePhotoBottomSheetFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ai/PackagePhotoBottomSheetFragment.kt @@ -1,5 +1,6 @@ package com.woocommerce.android.ui.products.ai +import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -10,6 +11,7 @@ import androidx.fragment.app.viewModels import com.woocommerce.android.extensions.navigateBackWithResult import com.woocommerce.android.mediapicker.MediaPickerHelper import com.woocommerce.android.mediapicker.MediaPickerHelper.MediaPickerResultHandler +import com.woocommerce.android.model.Product.Image import com.woocommerce.android.ui.compose.theme.WooTheme import com.woocommerce.android.ui.products.ai.PackagePhotoViewModel.ShowMediaLibrary import com.woocommerce.android.ui.products.ai.PackagePhotoViewModel.ShowMediaLibraryDialog @@ -40,10 +42,6 @@ class PackagePhotoBottomSheetFragment : WCBottomSheetDialogFragment(), MediaPick } } - override fun onMediaSelected(mediaUri: String) { - viewModel.onImageChanged(mediaUri) - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -64,4 +62,19 @@ class PackagePhotoBottomSheetFragment : WCBottomSheetDialogFragment(), MediaPick } } } + override fun onDeviceMediaSelected(imageUris: List, source: String) { + if (imageUris.isNotEmpty()) { + onImageSelected(imageUris.first().toString()) + } + } + + override fun onWPMediaSelected(images: List) { + if (images.isNotEmpty()) { + onImageSelected(images.first().source) + } + } + + private fun onImageSelected(mediaUri: String) { + viewModel.onImageChanged(mediaUri) + } } From 278be69022d62475fe43f6eab96db03d546e55b4 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Fri, 10 Nov 2023 11:44:52 +0100 Subject: [PATCH 14/29] Remove restricted API usage --- .../android/ui/products/ProductDetailFragment.kt | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt index 58f274026cc..322eef7eace 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt @@ -112,20 +112,6 @@ class ProductDetailFragment : private var _binding: FragmentProductDetailBinding? = null private val binding get() = _binding!! - override val activityAppBarStatus: AppBarStatus - get() { - val navigationIcon = if (findNavController().currentBackStack.value - .any { it.destination.id == R.id.products } - ) { - R.drawable.ic_back_24dp - } else { - R.drawable.ic_gridicons_cross_24dp - } - return AppBarStatus.Visible( - navigationIcon = navigationIcon - ) - } - @Inject lateinit var crashLogging: CrashLogging override fun onCreate(savedInstanceState: Bundle?) { From 4a9d472ae7525d09863a74ca02affac090a0ae49 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Fri, 10 Nov 2023 11:46:13 +0100 Subject: [PATCH 15/29] Optimize imports --- .../com/woocommerce/android/ui/products/ProductDetailFragment.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt index 322eef7eace..39545fdd99d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt @@ -45,7 +45,6 @@ import com.woocommerce.android.ui.aztec.AztecEditorFragment.Companion.ARG_AZTEC_ import com.woocommerce.android.ui.aztec.AztecEditorFragment.Companion.ARG_AZTEC_TITLE_FROM_AI_DESCRIPTION import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground import com.woocommerce.android.ui.dialog.WooDialog -import com.woocommerce.android.ui.main.AppBarStatus import com.woocommerce.android.ui.main.MainNavigationRouter import com.woocommerce.android.ui.products.AIProductDescriptionBottomSheetFragment.Companion.KEY_AI_GENERATED_DESCRIPTION_RESULT import com.woocommerce.android.ui.products.ProductDetailViewModel.HideImageUploadErrorSnackbar From 42e54ac1cabdeafe95f8b5851e6f04567ccf6f9f Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Fri, 10 Nov 2023 11:59:12 +0100 Subject: [PATCH 16/29] Fix lint issues --- .../android/ui/shipping/InstallWCShippingFlow.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt index 357a8e1eac6..6392e6caf9a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt @@ -338,14 +338,14 @@ private fun InstallationLoadingIndicator(showLoadingIndicator: Boolean, modifier val progressColor = colorResource(id = R.color.woo_purple_50) val startAngle by if (showLoadingIndicator) { - val transition = rememberInfiniteTransition() + val transition = rememberInfiniteTransition(label = "") transition.animateFloat( -90f, 270f, infiniteRepeatable( animation = tween(1332, easing = LinearEasing) - ) + ), label = "" ) } else { remember { mutableStateOf(-90f) } @@ -375,9 +375,10 @@ private fun InstallationLoadingIndicator(showLoadingIndicator: Boolean, modifier @Preview @Composable +@Suppress("UnusedContentLambdaTargetStateParameter") private fun PreInstallationPreview() { WooThemeWithBackground { - AnimatedContent(targetState = Unit) { + AnimatedContent(targetState = Unit, label = "") { InstallWCShippingFlow( viewState = PreInstallation( extensionsName = R.string.install_wc_shipping_extension_name, @@ -394,9 +395,10 @@ private fun PreInstallationPreview() { @Preview @Composable +@Suppress("UnusedContentLambdaTargetStateParameter") private fun InstallationOngoingPreview() { WooThemeWithBackground { - AnimatedContent(targetState = Unit) { + AnimatedContent(targetState = Unit, label = "") { InstallationContent( viewState = InstallationOngoing( extensionsName = R.string.install_wc_shipping_extension_name, From 6f6f26af1da405e20dd7fe1418ea5a7685f4520e Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Fri, 10 Nov 2023 12:08:13 +0100 Subject: [PATCH 17/29] Fix ktlint issues --- .../android/ui/shipping/InstallWCShippingFlow.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt index 6392e6caf9a..bcb745dba6e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt @@ -43,7 +43,7 @@ import androidx.compose.material.icons.outlined.Info import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -341,14 +341,15 @@ private fun InstallationLoadingIndicator(showLoadingIndicator: Boolean, modifier val transition = rememberInfiniteTransition(label = "") transition.animateFloat( - -90f, - 270f, - infiniteRepeatable( + initialValue = -90f, + targetValue = 270f, + animationSpec = infiniteRepeatable( animation = tween(1332, easing = LinearEasing) - ), label = "" + ), + label = "" ) } else { - remember { mutableStateOf(-90f) } + remember { mutableFloatStateOf(-90f) } } Canvas(modifier) { From aab09a44787929fcafb0b6db1611143f05f241d4 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Fri, 10 Nov 2023 15:03:31 +0100 Subject: [PATCH 18/29] Update the MediaPicker hash --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index eee1024e8f1..408b8e3c8a5 100644 --- a/build.gradle +++ b/build.gradle @@ -112,7 +112,7 @@ ext { materialVersion = '1.6.1' hiltJetpackVersion = '1.0.0' wordPressUtilsVersion = '2.6.0' - mediapickerVersion = '74-4545425a0e5f50e401fe98f7cce6237a5f0fcb33' + mediapickerVersion = '74-1604bfc033e68f2f590cc5db470dea5ae5a5cb3d' wordPressLoginVersion = '1.7.0' aboutAutomatticVersion = '0.0.6' automatticTracksVersion = '3.2.0' From bca9469900520a5e997ce5d1e9e3ee8dcf384a67 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Mon, 13 Nov 2023 19:02:08 +0100 Subject: [PATCH 19/29] Revert the changes related to the animation deprecations --- .../ui/blaze/BlazeCampaignCreationScreen.kt | 4 ++-- .../jetpack/main/JetpackActivationMainScreen.kt | 16 +--------------- .../android/ui/products/ProductDetailFragment.kt | 13 +++++++++++++ .../android/ui/shipping/InstallWCShippingFlow.kt | 4 ++-- .../ui/shipping/InstallWCShippingScreen.kt | 6 +++--- 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeCampaignCreationScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeCampaignCreationScreen.kt index c3427153c41..f2e4f646fa9 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeCampaignCreationScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/blaze/BlazeCampaignCreationScreen.kt @@ -7,7 +7,7 @@ import androidx.compose.animation.AnimatedContent import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.animation.togetherWith +import androidx.compose.animation.with import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column @@ -84,7 +84,7 @@ fun BlazeCampaignCreationScreen( ) { paddingValues -> AnimatedContent( targetState = viewState, - transitionSpec = { fadeIn() togetherWith fadeOut() }, label = "" + transitionSpec = { fadeIn() with fadeOut() } ) { targetState -> when (targetState) { is BlazeCreationViewState.Intro -> BlazeCreationIntroScreen( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/jetpack/main/JetpackActivationMainScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/jetpack/main/JetpackActivationMainScreen.kt index 0e6d4b5c232..daa3415069c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/jetpack/main/JetpackActivationMainScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/jetpack/main/JetpackActivationMainScreen.kt @@ -11,7 +11,6 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically -import androidx.compose.animation.togetherWith import androidx.compose.animation.with import androidx.compose.foundation.Canvas import androidx.compose.foundation.Image @@ -110,12 +109,7 @@ fun JetpackActivationMainScreen( transition.AnimatedContent( contentKey = { it is JetpackActivationMainViewModel.ViewState.ErrorViewState }, transitionSpec = { - fadeIn( - animationSpec = tween( - DefaultDurationMillis, - delayMillis = DefaultDurationMillis - ) - ) togetherWith + fadeIn(animationSpec = tween(DefaultDurationMillis, delayMillis = DefaultDurationMillis)) with fadeOut(animationSpec = tween(DefaultDurationMillis)) }, modifier = Modifier.weight(1f) @@ -125,7 +119,6 @@ fun JetpackActivationMainScreen( viewState = targetState, onContinueClick = onContinueClick ) - is JetpackActivationMainViewModel.ViewState.ErrorViewState -> ErrorState( viewState = targetState, onGetHelpClick = onGetHelpClick, @@ -301,13 +294,10 @@ private fun AnimatedVisibilityScope.ErrorState( val retryButton = when (viewState.stepType) { JetpackActivationMainViewModel.StepType.Installation -> R.string.login_jetpack_installation_retry_installing - JetpackActivationMainViewModel.StepType.Activation -> R.string.login_jetpack_installation_retry_activating - JetpackActivationMainViewModel.StepType.Connection -> R.string.login_jetpack_installation_retry_authorizing - else -> null } retryButton?.let { @@ -338,11 +328,9 @@ private fun JetpackActivationStep( JetpackActivationMainViewModel.StepState.Idle -> { IdleCircle(indicatorModifier) } - JetpackActivationMainViewModel.StepState.Ongoing -> { CircularProgressIndicator(indicatorModifier) } - JetpackActivationMainViewModel.StepState.Success -> { Image( painter = painterResource(id = R.drawable.ic_progress_circle_complete), @@ -350,7 +338,6 @@ private fun JetpackActivationStep( modifier = indicatorModifier ) } - is JetpackActivationMainViewModel.StepState.Error -> { Icon( painter = painterResource(id = R.drawable.ic_gridicons_notice), @@ -398,7 +385,6 @@ private fun ConnectionStepHint(connectionStep: JetpackActivationMainViewModel.Co R.string.login_jetpack_steps_authorizing_validation, R.color.color_on_surface_medium ) - else -> Pair( R.string.login_jetpack_steps_authorizing_done, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt index 39545fdd99d..e4a159a6199 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/ProductDetailFragment.kt @@ -45,6 +45,7 @@ import com.woocommerce.android.ui.aztec.AztecEditorFragment.Companion.ARG_AZTEC_ import com.woocommerce.android.ui.aztec.AztecEditorFragment.Companion.ARG_AZTEC_TITLE_FROM_AI_DESCRIPTION import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground import com.woocommerce.android.ui.dialog.WooDialog +import com.woocommerce.android.ui.main.AppBarStatus import com.woocommerce.android.ui.main.MainNavigationRouter import com.woocommerce.android.ui.products.AIProductDescriptionBottomSheetFragment.Companion.KEY_AI_GENERATED_DESCRIPTION_RESULT import com.woocommerce.android.ui.products.ProductDetailViewModel.HideImageUploadErrorSnackbar @@ -111,6 +112,18 @@ class ProductDetailFragment : private var _binding: FragmentProductDetailBinding? = null private val binding get() = _binding!! + override val activityAppBarStatus: AppBarStatus + get() { + val navigationIcon = if (findNavController().backQueue.any { it.destination.id == R.id.products }) { + R.drawable.ic_back_24dp + } else { + R.drawable.ic_gridicons_cross_24dp + } + return AppBarStatus.Visible( + navigationIcon = navigationIcon + ) + } + @Inject lateinit var crashLogging: CrashLogging override fun onCreate(savedInstanceState: Bundle?) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt index bcb745dba6e..53d0bd09d42 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingFlow.kt @@ -43,7 +43,7 @@ import androidx.compose.material.icons.outlined.Info import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -349,7 +349,7 @@ private fun InstallationLoadingIndicator(showLoadingIndicator: Boolean, modifier label = "" ) } else { - remember { mutableFloatStateOf(-90f) } + remember { mutableStateOf(-90f) } } Canvas(modifier) { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt index 5a74ea52c59..472c1008cc2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/shipping/InstallWCShippingScreen.kt @@ -11,7 +11,7 @@ import androidx.compose.animation.core.tween import androidx.compose.animation.core.updateTransition import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.animation.togetherWith +import androidx.compose.animation.with import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.material.MaterialTheme @@ -49,10 +49,10 @@ fun InstallWCShippingScreen(viewState: ViewState) { // Apply a fade-in/fade-out globally, // then each child will animate the individual components separately fadeIn(tween(500, delayMillis = 500)) - .togetherWith(fadeOut(tween(500, easing = LinearOutSlowInEasing))) + .with(fadeOut(tween(500, easing = LinearOutSlowInEasing))) } else { // No-op animation, each screen will define animations for specific components separately - EnterTransition.None.togetherWith(ExitTransition.None) + EnterTransition.None.with(ExitTransition.None) } } ) { targetState -> From 6647482e13280aacb64b799e25fc752373fba5c2 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Mon, 13 Nov 2023 19:02:27 +0100 Subject: [PATCH 20/29] Update the MediaPicker reference --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 408b8e3c8a5..24f948be204 100644 --- a/build.gradle +++ b/build.gradle @@ -112,7 +112,7 @@ ext { materialVersion = '1.6.1' hiltJetpackVersion = '1.0.0' wordPressUtilsVersion = '2.6.0' - mediapickerVersion = '74-1604bfc033e68f2f590cc5db470dea5ae5a5cb3d' + mediapickerVersion = '74-04a58e289b238fb3a8d458f7e08c43f9079e1e73' wordPressLoginVersion = '1.7.0' aboutAutomatticVersion = '0.0.6' automatticTracksVersion = '3.2.0' From eaedcb145b591e2c76e110bb387a0efd681600d5 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Mon, 13 Nov 2023 19:02:50 +0100 Subject: [PATCH 21/29] Revert "Replace the deprecated play core library with new granular dependencies" This reverts commit edd9f450a7dbbe7bd30956563578f805dd80e691. --- WooCommerce/build.gradle | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/WooCommerce/build.gradle b/WooCommerce/build.gradle index 1723251cd74..5554fb0ce3f 100644 --- a/WooCommerce/build.gradle +++ b/WooCommerce/build.gradle @@ -280,9 +280,7 @@ dependencies { implementation "com.github.bumptech.glide:glide:$glideVersion" kapt "com.github.bumptech.glide:compiler:$glideVersion" implementation "com.github.bumptech.glide:volley-integration:$glideVersion@aar" - - implementation "com.google.android.play:app-update-ktx:$googlePlayVersion" - implementation "com.google.android.play:review-ktx:$googlePlayVersion" + implementation "com.google.android.play:core:$googlePlayCoreVersion" implementation 'com.google.android.gms:play-services-code-scanner:16.0.0-beta3' From 8273e477251dc87c1a3ffbe17e741897215bb3b5 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Mon, 13 Nov 2023 19:08:32 +0100 Subject: [PATCH 22/29] Update the PlayCore library version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 24f948be204..9f846ca125f 100644 --- a/build.gradle +++ b/build.gradle @@ -101,7 +101,7 @@ ext { constraintLayoutVersion = '1.2.0' libaddressinputVersion = '0.0.2' eventBusVersion = '3.3.1' - googlePlayVersion = '2.0.1' + googlePlayCoreVersion = '1.10.3' coroutinesVersion = '1.6.4' lifecycleVersion = '2.6.2' aztecVersion = 'v1.3.45' From d5703fd463f3ae27aaa88101b616872c7f0f3e52 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Mon, 13 Nov 2023 19:49:08 +0100 Subject: [PATCH 23/29] Update the release notes --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 534720cd4f4..d2132d3e3dc 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -7,6 +7,7 @@ ----- - [*] [Internal] Improve handling of Jetpack Connection for Jetpack CP sites when using Application Passwords [https://github.com/woocommerce/woocommerce-android/pull/10083] - [***] Custom Amounts M2: Redesign Payments and Customers section [https://github.com/woocommerce/woocommerce-android/pull/10122] +- [**] Replaced the custom device image picker with Android photo picker, which doesn't require special image & video permissions [https://github.com/woocommerce/woocommerce-android/pull/10141] 16.1 ----- From 40236e0cf2dfd45605fadd911b9b8c71e622404b Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Mon, 13 Nov 2023 21:37:10 +0100 Subject: [PATCH 24/29] Bump minor Kotlin version --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 06f5c39bc50..34aaa6a973f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,7 +3,7 @@ pluginManagement { gradle.ext.googleServicesVersion = '4.4.0' gradle.ext.daggerVersion = '2.45' gradle.ext.detektVersion = '1.19.0' - gradle.ext.kotlinVersion = '1.8.21' + gradle.ext.kotlinVersion = '1.8.22' gradle.ext.navigationVersion = '2.5.3' gradle.ext.sentryVersion = '3.5.0' gradle.ext.violationCommentsVersion = '1.69.0' From 108681a4f90dbe5e5fa1ab539886cd03413304d3 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Tue, 14 Nov 2023 09:58:33 +0100 Subject: [PATCH 25/29] Update dependencies --- build.gradle | 4 ++-- settings.gradle | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 23b01fdec9b..bb1a926df40 100644 --- a/build.gradle +++ b/build.gradle @@ -107,12 +107,12 @@ ext { aztecVersion = 'v1.3.45' flipperVersion = '0.176.1' stateMachineVersion = '0.2.0' - coreKtxVersion = '1.12.0' + coreKtxVersion = '1.8.0' appCompatVersion = '1.4.2' materialVersion = '1.6.1' hiltJetpackVersion = '1.0.0' wordPressUtilsVersion = '3.5.0' - mediapickerVersion = '74-04a58e289b238fb3a8d458f7e08c43f9079e1e73' + mediapickerVersion = 'trunk-10f3b7d3aeb31bb0bacacde3d9fc2456c09105a9' wordPressLoginVersion = '1.8.0' aboutAutomatticVersion = '0.0.6' automatticTracksVersion = '3.2.0' diff --git a/settings.gradle b/settings.gradle index 34aaa6a973f..06f5c39bc50 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,7 +3,7 @@ pluginManagement { gradle.ext.googleServicesVersion = '4.4.0' gradle.ext.daggerVersion = '2.45' gradle.ext.detektVersion = '1.19.0' - gradle.ext.kotlinVersion = '1.8.22' + gradle.ext.kotlinVersion = '1.8.21' gradle.ext.navigationVersion = '2.5.3' gradle.ext.sentryVersion = '3.5.0' gradle.ext.violationCommentsVersion = '1.69.0' From cd89efa8db5b3fe0ef9759f5aff45cf2e11ab20a Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Tue, 14 Nov 2023 11:36:20 +0100 Subject: [PATCH 26/29] Remove imported READ_EXTERNAL_STORAGE permission from the merged manifest --- WooCommerce/src/main/AndroidManifest.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/WooCommerce/src/main/AndroidManifest.xml b/WooCommerce/src/main/AndroidManifest.xml index f8ab0c129a8..e507660bf62 100644 --- a/WooCommerce/src/main/AndroidManifest.xml +++ b/WooCommerce/src/main/AndroidManifest.xml @@ -17,6 +17,10 @@ + Date: Tue, 14 Nov 2023 12:17:22 +0100 Subject: [PATCH 27/29] Add system media picker helper functions --- .../android/mediapicker/MediaPickerHelper.kt | 51 +++++++++++++------ .../mediapicker/MediaPickerSetupFactory.kt | 3 ++ 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt index 8defba753df..fd90b8c07b4 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt @@ -16,8 +16,11 @@ import org.wordpress.android.mediapicker.api.MediaPickerSetup import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.CAMERA import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.DEVICE +import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.SYSTEM_PICKER import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.WP_MEDIA_LIBRARY +import org.wordpress.android.mediapicker.model.MediaTypes import org.wordpress.android.mediapicker.model.MediaTypes.IMAGES +import org.wordpress.android.mediapicker.model.MediaTypes.MEDIA import org.wordpress.android.mediapicker.ui.MediaPickerActivity import javax.inject.Inject @@ -40,26 +43,43 @@ class MediaPickerHelper @Inject constructor( } private val cameraLauncher = fragment.registerForActivityResult(StartActivityForResult()) { - handleCameraCaptureResult(it) + handleMediaPickerResult(it, AnalyticsTracker.IMAGE_SOURCE_CAMERA) } - fun showMediaPicker(source: DataSource, allowMultiSelect: Boolean = false) { + private val systemMediaPickerLauncher = fragment.registerForActivityResult(StartActivityForResult()) { + handleMediaPickerResult(it, AnalyticsTracker.IMAGE_SOURCE_DEVICE) + } + + fun showMediaPicker(source: DataSource, allowMultiSelect: Boolean = false, mediaTypes: MediaTypes = IMAGES) { when (source) { - WP_MEDIA_LIBRARY -> launchWPMediaLibrary(source, allowMultiSelect) + WP_MEDIA_LIBRARY -> launchWPMediaLibrary(source, allowMultiSelect, mediaTypes) CAMERA -> launchCamera() - DEVICE -> launchPhotoPicker(allowMultiSelect) + DEVICE -> launchPhotoPicker(allowMultiSelect, mediaTypes) + SYSTEM_PICKER -> launchSystemMediaPicker(mediaTypes) else -> throw IllegalArgumentException("Unsupported data source: $source") } } - private fun launchPhotoPicker(allowMultiSelect: Boolean) { + private fun launchSystemMediaPicker(mediaTypes: MediaTypes) { + val intent = MediaPickerActivity.buildIntent( + fragment.requireContext(), + mediaPickerSetupFactory.build( + source = SYSTEM_PICKER, + mediaTypes = mediaTypes + ) + ) + + systemMediaPickerLauncher.launch(intent) + } + + private fun launchPhotoPicker(allowMultiSelect: Boolean, mediaTypes: MediaTypes) { if (allowMultiSelect) { multiPhotoPicker.launch( - PickVisualMediaRequest(IMAGES.allowedTypes.toPhotoPickerTypes()) + PickVisualMediaRequest(mediaTypes.allowedTypes.toPhotoPickerTypes()) ) } else { photoPicker.launch( - PickVisualMediaRequest(IMAGES.allowedTypes.toPhotoPickerTypes()) + PickVisualMediaRequest(mediaTypes.allowedTypes.toPhotoPickerTypes()) ) } } @@ -75,25 +95,20 @@ class MediaPickerHelper @Inject constructor( private fun launchWPMediaLibrary( source: DataSource, - allowMultiSelect: Boolean + allowMultiSelect: Boolean, + mediaTypes: MediaTypes ) { val mediaPickerIntent = MediaPickerActivity.buildIntent( context = fragment.requireContext(), mediaPickerSetupFactory.build( source = source, - mediaTypes = IMAGES, + mediaTypes = mediaTypes, isMultiSelectAllowed = allowMultiSelect ) ) mediaLibraryLauncher.launch(mediaPickerIntent) } - private fun handleCameraCaptureResult(result: ActivityResult) { - result.processDeviceMediaResult()?.let { uris -> - (fragment as MediaPickerResultHandler).onDeviceMediaSelected(uris, AnalyticsTracker.IMAGE_SOURCE_CAMERA) - } - } - private fun handlePhotoPickerResult(uris: List) { if (uris.isNotEmpty()) { (fragment as MediaPickerResultHandler).onDeviceMediaSelected(uris, AnalyticsTracker.IMAGE_SOURCE_DEVICE) @@ -106,6 +121,12 @@ class MediaPickerHelper @Inject constructor( } } + private fun handleMediaPickerResult(result: ActivityResult, source: String) { + result.processDeviceMediaResult()?.let { uris -> + (fragment as MediaPickerResultHandler).onDeviceMediaSelected(uris, source) + } + } + interface MediaPickerResultHandler { fun onDeviceMediaSelected(imageUris: List, source: String) fun onWPMediaSelected(images: List) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerSetupFactory.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerSetupFactory.kt index b3839bb98e1..7874a4fe290 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerSetupFactory.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerSetupFactory.kt @@ -3,8 +3,10 @@ package com.woocommerce.android.mediapicker import org.wordpress.android.mediapicker.api.MediaPickerSetup import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.CAMERA +import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.SYSTEM_PICKER import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.WP_MEDIA_LIBRARY import org.wordpress.android.mediapicker.model.MediaTypes +import org.wordpress.android.mediapicker.setup.SystemMediaPickerSetup import org.wordpress.android.mediapicker.source.camera.CameraMediaPickerSetup import org.wordpress.android.mediapicker.source.wordpress.MediaLibraryPickerSetup import java.security.InvalidParameterException @@ -22,6 +24,7 @@ class MediaPickerSetupFactory @Inject constructor() : MediaPickerSetup.Factory { mediaTypes = mediaTypes, canMultiSelect = isMultiSelectAllowed ) + SYSTEM_PICKER -> SystemMediaPickerSetup.build(mediaTypes = mediaTypes, canMultiSelect = false) else -> throw InvalidParameterException("${source.name} source is not supported") } From e080b19e1c01c55f32ea9a83e8ba612faf1a833a Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Tue, 14 Nov 2023 12:18:16 +0100 Subject: [PATCH 28/29] Fix the product downloads media picker --- .../AddProductDownloadBottomSheetFragment.kt | 96 ++++++------------- 1 file changed, 28 insertions(+), 68 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/AddProductDownloadBottomSheetFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/AddProductDownloadBottomSheetFragment.kt index 0d500a372d2..41ae9f91e5b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/AddProductDownloadBottomSheetFragment.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/products/downloads/AddProductDownloadBottomSheetFragment.kt @@ -5,14 +5,13 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.activity.result.ActivityResult -import androidx.activity.result.contract.ActivityResultContracts import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import com.woocommerce.android.R import com.woocommerce.android.databinding.DialogProductAddDownloadableFileBinding -import com.woocommerce.android.mediapicker.MediaPickerUtil.processDeviceMediaResult -import com.woocommerce.android.mediapicker.MediaPickerUtil.processMediaLibraryResult +import com.woocommerce.android.mediapicker.MediaPickerHelper +import com.woocommerce.android.mediapicker.MediaPickerHelper.MediaPickerResultHandler +import com.woocommerce.android.model.Product.Image import com.woocommerce.android.ui.base.UIMessageResolver import com.woocommerce.android.ui.products.ProductDetailViewModel import com.woocommerce.android.ui.products.ProductNavigationTarget.ViewProductDownloadDetails @@ -24,19 +23,21 @@ import com.woocommerce.android.ui.products.downloads.AddProductDownloadViewModel import com.woocommerce.android.viewmodel.fixedHiltNavGraphViewModels import com.woocommerce.android.widgets.WCBottomSheetDialogFragment import dagger.hilt.android.AndroidEntryPoint -import org.wordpress.android.mediapicker.api.MediaPickerSetup -import org.wordpress.android.mediapicker.model.MediaTypes -import org.wordpress.android.mediapicker.ui.MediaPickerActivity +import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.SYSTEM_PICKER +import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.WP_MEDIA_LIBRARY +import org.wordpress.android.mediapicker.model.MediaTypes.DOCUMENTS +import org.wordpress.android.mediapicker.model.MediaTypes.EVERYTHING +import org.wordpress.android.mediapicker.model.MediaTypes.MEDIA import javax.inject.Inject @AndroidEntryPoint -class AddProductDownloadBottomSheetFragment : WCBottomSheetDialogFragment() { +class AddProductDownloadBottomSheetFragment : WCBottomSheetDialogFragment(), MediaPickerResultHandler { @Inject lateinit var navigator: ProductNavigator @Inject lateinit var uiMessageResolver: UIMessageResolver @Inject - lateinit var mediaPickerSetupFactory: MediaPickerSetup.Factory + lateinit var mediaPickerHelper: MediaPickerHelper private val viewModel: AddProductDownloadViewModel by viewModels() private val parentViewModel: ProductDetailViewModel by fixedHiltNavGraphViewModels(R.id.nav_graph_products) @@ -66,9 +67,18 @@ class AddProductDownloadBottomSheetFragment : WCBottomSheetDialogFragment() { private fun setupObservers(viewModel: AddProductDownloadViewModel) { viewModel.event.observe(viewLifecycleOwner) { event -> when (event) { - is PickFileFromMedialLibrary -> showMediaLibraryPicker() - is PickMediaFileFromDevice -> showLocalDeviceMediaPicker() - is PickDocumentFromDevice -> showLocalDeviceDocumentPicker() + is PickFileFromMedialLibrary -> mediaPickerHelper.showMediaPicker( + source = WP_MEDIA_LIBRARY, + mediaTypes = EVERYTHING + ) + is PickMediaFileFromDevice -> mediaPickerHelper.showMediaPicker( + source = SYSTEM_PICKER, + mediaTypes = MEDIA + ) + is PickDocumentFromDevice -> mediaPickerHelper.showMediaPicker( + source = SYSTEM_PICKER, + mediaTypes = DOCUMENTS + ) is AddFile -> { findNavController().navigateUp() parentViewModel.handleSelectedDownloadableFile(event.uri.toString()) @@ -80,65 +90,15 @@ class AddProductDownloadBottomSheetFragment : WCBottomSheetDialogFragment() { } } - private val mediaLibraryLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - handleMediaLibraryPickerResult(it) - } - - private val mediaDeviceMediaPickerLauncher = registerForActivityResult( - ActivityResultContracts.StartActivityForResult() - ) { - handleDeviceMediaResult(it) - } - - private fun handleMediaLibraryPickerResult(result: ActivityResult) { - result.processMediaLibraryResult()?.let { images -> - images.forEach { - viewModel.launchFileUpload(Uri.parse(it.source)) - } + override fun onDeviceMediaSelected(imageUris: List, source: String) { + if (imageUris.isNotEmpty()) { + viewModel.launchFileUpload(imageUris.first()) } } - private fun showMediaLibraryPicker() { - val intent = MediaPickerActivity.buildIntent( - requireContext(), - mediaPickerSetupFactory.build( - source = MediaPickerSetup.DataSource.WP_MEDIA_LIBRARY, - mediaTypes = MediaTypes.EVERYTHING - ) - ) - - mediaLibraryLauncher.launch(intent) - } - - private fun handleDeviceMediaResult(result: ActivityResult) { - result.processDeviceMediaResult()?.let { mediaUris -> - if (mediaUris.isNotEmpty()) { - viewModel.launchFileUpload(mediaUris.first()) - } + override fun onWPMediaSelected(images: List) { + images.forEach { + viewModel.launchFileUpload(Uri.parse(it.source)) } } - - private fun showLocalDeviceMediaPicker() { - val intent = MediaPickerActivity.buildIntent( - requireContext(), - mediaPickerSetupFactory.build( - source = MediaPickerSetup.DataSource.DEVICE, - mediaTypes = MediaTypes.MEDIA - ) - ) - - mediaDeviceMediaPickerLauncher.launch(intent) - } - - private fun showLocalDeviceDocumentPicker() { - val intent = MediaPickerActivity.buildIntent( - requireContext(), - mediaPickerSetupFactory.build( - source = MediaPickerSetup.DataSource.SYSTEM_PICKER, - mediaTypes = MediaTypes.DOCUMENTS - ) - ) - - mediaDeviceMediaPickerLauncher.launch(intent) - } } From 878bb05e7a4830ed2f3729756c3af2a9b216d634 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Tue, 14 Nov 2023 12:18:28 +0100 Subject: [PATCH 29/29] Optimize imports --- .../com/woocommerce/android/mediapicker/MediaPickerHelper.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt index fd90b8c07b4..bb8f72a71aa 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/mediapicker/MediaPickerHelper.kt @@ -20,7 +20,6 @@ import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.SYSTEM_ import org.wordpress.android.mediapicker.api.MediaPickerSetup.DataSource.WP_MEDIA_LIBRARY import org.wordpress.android.mediapicker.model.MediaTypes import org.wordpress.android.mediapicker.model.MediaTypes.IMAGES -import org.wordpress.android.mediapicker.model.MediaTypes.MEDIA import org.wordpress.android.mediapicker.ui.MediaPickerActivity import javax.inject.Inject