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.photogrid 18 19 import androidx.compose.animation.AnimatedContentTransitionScope 20 import androidx.compose.animation.EnterTransition 21 import androidx.compose.animation.ExitTransition 22 import androidx.compose.animation.slideInHorizontally 23 import androidx.compose.animation.slideOutHorizontally 24 import androidx.compose.runtime.Composable 25 import androidx.compose.ui.Modifier 26 import androidx.navigation.NamedNavArgument 27 import androidx.navigation.NavBackStackEntry 28 import androidx.navigation.NavDeepLink 29 import com.android.photopicker.core.animations.springDefaultEffectOffset 30 import com.android.photopicker.core.configuration.PhotopickerConfiguration 31 import com.android.photopicker.core.events.Event 32 import com.android.photopicker.core.events.RegisteredEventClass 33 import com.android.photopicker.core.features.FeatureManager 34 import com.android.photopicker.core.features.FeatureRegistration 35 import com.android.photopicker.core.features.FeatureToken 36 import com.android.photopicker.core.features.Location 37 import com.android.photopicker.core.features.LocationParams 38 import com.android.photopicker.core.features.PhotopickerUiFeature 39 import com.android.photopicker.core.features.PrefetchResultKey 40 import com.android.photopicker.core.features.Priority 41 import com.android.photopicker.core.navigation.PhotopickerDestinations 42 import com.android.photopicker.core.navigation.Route 43 import kotlinx.coroutines.Deferred 44 45 /** 46 * Feature class for the Photopicker's primary photo grid. 47 * 48 * This feature adds the [PHOTO_GRID] route to the application as a high priority initial route. 49 */ 50 class PhotoGridFeature : PhotopickerUiFeature { 51 companion object Registration : FeatureRegistration { 52 override val TAG: String = "PhotopickerPhotoGridFeature" 53 isEnablednull54 override fun isEnabled( 55 config: PhotopickerConfiguration, 56 deferredPrefetchResultsMap: Map<PrefetchResultKey, Deferred<Any?>>, 57 ) = true 58 59 override fun build(featureManager: FeatureManager) = PhotoGridFeature() 60 } 61 62 override val token = FeatureToken.PHOTO_GRID.token 63 64 /** Events consumed by the Photo grid */ 65 override val eventsConsumed = emptySet<RegisteredEventClass>() 66 67 /** Events produced by the Photo grid */ 68 override val eventsProduced = 69 setOf(Event.ShowSnackbarMessage::class.java, Event.LogPhotopickerUIEvent::class.java) 70 71 override fun registerLocations(): List<Pair<Location, Int>> { 72 return listOf(Pair(Location.NAVIGATION_BAR_NAV_BUTTON, Priority.HIGHEST.priority)) 73 } 74 registerNavigationRoutesnull75 override fun registerNavigationRoutes(): Set<Route> { 76 return setOf( 77 // The main grid of the user's photos. 78 object : Route { 79 override val route = PhotopickerDestinations.PHOTO_GRID.route 80 override val initialRoutePriority = Priority.HIGH.priority 81 override val arguments = emptyList<NamedNavArgument>() 82 override val deepLinks = emptyList<NavDeepLink>() 83 override val isDialog = false 84 override val dialogProperties = null 85 86 /* 87 Animations for PHOTO_GRID 88 - When navigating directly, content will slide IN from the left edge. 89 - When navigating away, content will slide OUT towards the left edge. 90 - When returning from the backstack, content will slide IN from the right edge. 91 - When popping to another route on the backstack, content will slide OUT towards 92 the left edge. 93 */ 94 override val enterTransition: 95 (AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition)? = 96 { 97 // Positive value to slide left-to-right 98 slideInHorizontally(animationSpec = springDefaultEffectOffset) { it } 99 } 100 override val exitTransition: 101 (AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition)? = 102 { 103 // Negative value to slide right-to-left 104 slideOutHorizontally(animationSpec = springDefaultEffectOffset) { -it } 105 } 106 override val popEnterTransition: 107 (AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition)? = 108 { 109 // When returning from the backstack slide right-to-left 110 slideInHorizontally(animationSpec = springDefaultEffectOffset) { -it } 111 } 112 override val popExitTransition: 113 (AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition)? = 114 { 115 // When navigating to the backstack slide left-to-right 116 slideOutHorizontally(animationSpec = springDefaultEffectOffset) { -it } 117 } 118 119 @Composable 120 override fun composable(navBackStackEntry: NavBackStackEntry?) { 121 PhotoGrid() 122 } 123 } 124 ) 125 } 126 127 @Composable composenull128 override fun compose(location: Location, modifier: Modifier, params: LocationParams) { 129 when (location) { 130 Location.NAVIGATION_BAR_NAV_BUTTON -> PhotoGridNavButton(modifier) 131 else -> {} 132 } 133 } 134 } 135