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