1 /* 2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.photopicker.features.preview 18 19 import androidx.compose.runtime.Composable 20 import androidx.compose.ui.Modifier 21 import androidx.compose.ui.window.DialogProperties 22 import androidx.navigation.NamedNavArgument 23 import androidx.navigation.NavBackStackEntry 24 import androidx.navigation.NavDeepLink 25 import com.android.photopicker.core.configuration.PhotopickerConfiguration 26 import com.android.photopicker.core.configuration.PhotopickerRuntimeEnv 27 import com.android.photopicker.core.events.Event 28 import com.android.photopicker.core.events.RegisteredEventClass 29 import com.android.photopicker.core.features.FeatureManager 30 import com.android.photopicker.core.features.FeatureRegistration 31 import com.android.photopicker.core.features.FeatureToken 32 import com.android.photopicker.core.features.Location 33 import com.android.photopicker.core.features.LocationParams 34 import com.android.photopicker.core.features.PhotopickerUiFeature 35 import com.android.photopicker.core.features.PrefetchResultKey 36 import com.android.photopicker.core.features.Priority 37 import com.android.photopicker.core.navigation.PhotopickerDestinations 38 import com.android.photopicker.core.navigation.Route 39 import com.android.photopicker.data.model.Media 40 import kotlinx.coroutines.Deferred 41 42 /** 43 * Feature class for the Photopicker's media preview. 44 * 45 * This feature adds the [PREVIEW_MEDIA] and [PREVIEW_SELECTION] routes to the application. 46 */ 47 class PreviewFeature : PhotopickerUiFeature { 48 49 companion object Registration : FeatureRegistration { 50 override val TAG: String = "PhotopickerPreviewFeature" 51 isEnablednull52 override fun isEnabled( 53 config: PhotopickerConfiguration, 54 deferredPrefetchResultsMap: Map<PrefetchResultKey, Deferred<Any?>>, 55 ) = config.runtimeEnv != PhotopickerRuntimeEnv.EMBEDDED 56 57 override fun build(featureManager: FeatureManager) = PreviewFeature() 58 59 val PREVIEW_MEDIA_KEY = "preview_media" 60 } 61 62 override val token = FeatureToken.PREVIEW.token 63 64 /** Events consumed by the Preview page */ 65 override val eventsConsumed = emptySet<RegisteredEventClass>() 66 67 /** Events produced by the Preview page */ 68 override val eventsProduced = 69 setOf<RegisteredEventClass>( 70 Event.LogPhotopickerUIEvent::class.java, 71 Event.LogPhotopickerPreviewInfo::class.java, 72 ) 73 74 override fun registerLocations(): List<Pair<Location, Int>> { 75 return listOf(Pair(Location.SELECTION_BAR_SECONDARY_ACTION, Priority.HIGH.priority)) 76 } 77 registerNavigationRoutesnull78 override fun registerNavigationRoutes(): Set<Route> { 79 return setOf( 80 object : Route { 81 override val route = PhotopickerDestinations.PREVIEW_SELECTION.route 82 override val initialRoutePriority = Priority.LAST.priority 83 override val arguments = emptyList<NamedNavArgument>() 84 override val deepLinks = emptyList<NavDeepLink>() 85 override val isDialog = true 86 override val dialogProperties = 87 DialogProperties( 88 dismissOnBackPress = true, 89 dismissOnClickOutside = true, 90 usePlatformDefaultWidth = false, 91 decorFitsSystemWindows = true, 92 ) 93 94 override val enterTransition = null 95 override val exitTransition = null 96 override val popEnterTransition = null 97 override val popExitTransition = null 98 99 @Composable 100 override fun composable(navBackStackEntry: NavBackStackEntry?) { 101 PreviewSelection() 102 } 103 }, 104 object : Route { 105 override val route = PhotopickerDestinations.PREVIEW_MEDIA.route 106 override val initialRoutePriority = Priority.LAST.priority 107 override val arguments = emptyList<NamedNavArgument>() 108 override val deepLinks = emptyList<NavDeepLink>() 109 override val isDialog = true 110 override val dialogProperties = 111 DialogProperties( 112 dismissOnBackPress = true, 113 dismissOnClickOutside = true, 114 usePlatformDefaultWidth = false, 115 decorFitsSystemWindows = true, 116 ) 117 118 override val enterTransition = null 119 override val exitTransition = null 120 override val popEnterTransition = null 121 override val popExitTransition = null 122 123 @Composable 124 override fun composable(navBackStackEntry: NavBackStackEntry?) { 125 val flow = 126 checkNotNull( 127 navBackStackEntry 128 ?.savedStateHandle 129 ?.getStateFlow<Media?>(PREVIEW_MEDIA_KEY, null) 130 ) { 131 "Unable to get a savedStateHandle for preview media" 132 } 133 PreviewSelection(previewItemFlow = flow) 134 } 135 }, 136 ) 137 } 138 139 @Composable composenull140 override fun compose(location: Location, modifier: Modifier, params: LocationParams) { 141 when (location) { 142 Location.SELECTION_BAR_SECONDARY_ACTION -> PreviewSelectionButton(modifier) 143 else -> {} 144 } 145 } 146 } 147