• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.extensions
18 
19 import androidx.navigation.NavController
20 import androidx.navigation.NavOptions
21 import com.android.photopicker.core.navigation.PhotopickerDestinations
22 import com.android.photopicker.core.navigation.PhotopickerDestinations.PHOTO_GRID
23 import com.android.photopicker.core.navigation.PhotopickerDestinations.PREVIEW_MEDIA
24 import com.android.photopicker.core.navigation.PhotopickerDestinations.PREVIEW_SELECTION
25 import com.android.photopicker.data.model.Group
26 import com.android.photopicker.data.model.Media
27 import com.android.photopicker.features.albumgrid.AlbumGridFeature
28 import com.android.photopicker.features.categorygrid.CategoryGridFeature
29 import com.android.photopicker.features.preview.PreviewFeature
30 
31 /**
32  * Utility function for navigating to the [PhotopickerDestinations.PHOTO_GRID] route.
33  *
34  * This attempts to reclaim an existing BackStack entry, preserving any previous state that existed.
35  *
36  * If the route is not currently on the BackStack, then this will navigate directly.
37  */
NavControllernull38 fun NavController.navigateToPhotoGrid(navOptions: NavOptions? = null) {
39     // First, check to see if the destination is already the current route.
40     if (this.currentDestination?.route == PHOTO_GRID.route) {
41         // Nothing to do. Return early to prevent navigation animations from triggering.
42         return
43     } else if (
44         // Try to return to the entry that is already on the backstack, so the user's
45         // previous state and scroll position is restored.
46         !this.popBackStack(PHOTO_GRID.route, /* inclusive= */ false, /* saveState= */ false)
47     ) {
48         // Last resort; PHOTO_GRID isn't on the backstack, then navigate directly.
49         this.navigate(PHOTO_GRID.route, navOptions)
50     }
51 }
52 
53 /** Utility function for navigating to the [PhotopickerDestinations.PREVIEW_SELECTION] route. */
NavControllernull54 fun NavController.navigateToPreviewSelection(navOptions: NavOptions? = null) {
55     this.navigate(PREVIEW_SELECTION.route, navOptions)
56 }
57 
58 /**
59  * Utility function for navigating to the [PhotopickerDestinations.PREVIEW_MEDIA] route.
60  *
61  * Additionally, this adds the relevant media data to the BackStackEntry for the route to use to
62  * avoid refetching it from the provider.
63  *
64  * @param media The media item that should be previewed in full resolution.
65  */
NavControllernull66 fun NavController.navigateToPreviewMedia(media: Media, navOptions: NavOptions? = null) {
67     this.navigate(PREVIEW_MEDIA.route, navOptions)
68     // Media object must be parcellized and passed to the new route so it can be loaded.
69     // This back stack entry is guaranteed to exist since it was just navigated to.
70     this.getBackStackEntry(PREVIEW_MEDIA.route)
71         .savedStateHandle
72         .set(PreviewFeature.PREVIEW_MEDIA_KEY, media)
73 }
74 
75 /**
76  * Utility function for navigating to the [PhotopickerDestinations.ALBUM_GRID] route.
77  *
78  * This attempts to reclaim an existing BackStack entry, preserving any previous state that existed.
79  *
80  * If the route is not currently on the BackStack, then this will navigate directly.
81  */
NavControllernull82 fun NavController.navigateToAlbumGrid(navOptions: NavOptions? = null) {
83     // First, check to see if the destination is already the current route.
84     if (this.currentDestination?.route == PhotopickerDestinations.ALBUM_GRID.route) {
85         // Nothing to do. Return early to prevent navigation animations from triggering.
86         return
87     } else if (
88         // Try to return to the entry that is already on the backstack, so the user's
89         // previous state and scroll position is restored.
90         !this.popBackStack(
91             PhotopickerDestinations.ALBUM_GRID.route,
92             /* inclusive= */ false,
93             /* saveState = */ true,
94         )
95     ) {
96         // Last resort; ALBUM_GRID isn't on the backstack, then navigate directly.
97         this.navigate(PhotopickerDestinations.ALBUM_GRID.route, navOptions)
98     }
99 }
100 
101 /**
102  * Utility function for navigating to the [PhotopickerDestinations.ALBUM_MEDIA_GRID] route.
103  *
104  * @param album The album for which the media needs to be displayed.
105  */
navigateToAlbumMediaGridnull106 fun NavController.navigateToAlbumMediaGrid(navOptions: NavOptions? = null, album: Group.Album) {
107     this.navigate(PhotopickerDestinations.ALBUM_MEDIA_GRID.route, navOptions)
108 
109     // Album object must be parcellized and passed to the new route so it can be loaded.
110     // This back stack entry is guaranteed to exist since it was just navigated to.
111     this.getBackStackEntry(PhotopickerDestinations.ALBUM_MEDIA_GRID.route)
112         .savedStateHandle
113         .set(AlbumGridFeature.ALBUM_KEY, album)
114 }
115 
116 /**
117  * Utility function for navigating to the [PhotopickerDestinations.ALBUM_GRID] route.
118  *
119  * This attempts to reclaim an existing BackStack entry, preserving any previous state that existed.
120  *
121  * If the route is not currently on the BackStack, then this will navigate directly.
122  */
navigateToCategoryGridnull123 fun NavController.navigateToCategoryGrid(navOptions: NavOptions? = null) {
124     // First, check to see if the destination is already the current route.
125     if (this.currentDestination?.route == PhotopickerDestinations.ALBUM_GRID.route) {
126         // Nothing to do. Return early to prevent navigation animations from triggering.
127         return
128     } else if (
129         // Try to return to the entry that is already on the backstack, so the user's
130         // previous state and scroll position is restored.
131         !this.popBackStack(
132             PhotopickerDestinations.ALBUM_GRID.route,
133             /* inclusive= */ false,
134             /* saveState = */ true,
135         )
136     ) {
137         // Last resort; ALBUM_GRID for Category isn't on the backstack, then navigate directly.
138         this.navigate(PhotopickerDestinations.ALBUM_GRID.route, navOptions)
139     }
140 }
141 
142 /**
143  * Utility function for navigating to the [PhotopickerDestinations.ALBUM_MEDIA_GRID] route for
144  * categories.
145  *
146  * @param album The album for which the media needs to be displayed.
147  */
NavControllernull148 fun NavController.navigateToAlbumMediaGridForCategories(
149     navOptions: NavOptions? = null,
150     album: Group.Album,
151 ) {
152     this.navigate(PhotopickerDestinations.ALBUM_MEDIA_GRID.route, navOptions)
153 
154     // Album object must be parcellized and passed to the new route so it can be loaded.
155     // This back stack entry is guaranteed to exist since it was just navigated to.
156     this.getBackStackEntry(PhotopickerDestinations.ALBUM_MEDIA_GRID.route)
157         .savedStateHandle
158         .set(CategoryGridFeature.GROUP_KEY, album)
159 }
160 
161 /**
162  * Utility function for navigating to the [PhotopickerDestinations.MEDIA_SET_CONTENT_GRID] route for
163  * categories.
164  *
165  * @param mediaSet The media set for which the media needs to be displayed.
166  */
navigateToMediaSetContentGridnull167 fun NavController.navigateToMediaSetContentGrid(
168     navOptions: NavOptions? = null,
169     mediaSet: Group.MediaSet,
170 ) {
171     this.navigate(PhotopickerDestinations.MEDIA_SET_CONTENT_GRID.route, navOptions)
172 
173     // Album object must be parcellized and passed to the new route so it can be loaded.
174     // This back stack entry is guaranteed to exist since it was just navigated to.
175     this.getBackStackEntry(PhotopickerDestinations.MEDIA_SET_CONTENT_GRID.route)
176         .savedStateHandle
177         .set(CategoryGridFeature.GROUP_KEY, mediaSet)
178 }
179 
180 /**
181  * Utility function for navigating to the [PhotopickerDestinations.MEDIA_SET_GRID] route for
182  * categories.
183  *
184  * @param category The category for which the media set needs to be displayed.
185  */
navigateToMediaSetGridnull186 fun NavController.navigateToMediaSetGrid(
187     navOptions: NavOptions? = null,
188     category: Group.Category? = null,
189 ) {
190     if (this.currentDestination?.route == PhotopickerDestinations.MEDIA_SET_GRID.route) {
191         // Nothing to do. Return early to prevent navigation animations from triggering.
192         return
193     } else if (
194         // Try to return to the entry that is already on the backstack, so the user's
195         // previous state and scroll position is restored.
196         !this.popBackStack(
197             PhotopickerDestinations.MEDIA_SET_GRID.route,
198             /* inclusive= */ false,
199             /* saveState = */ true,
200         )
201     ) {
202         // Last resort; MEDIA_SET_GRID isn't on the backstack, then navigate directly.
203         this.navigate(PhotopickerDestinations.MEDIA_SET_GRID.route, navOptions)
204         // Category object must be parcellized and passed to the new route so it can be loaded.
205         // This back stack entry is guaranteed to exist since it was just navigated to.
206         this.getBackStackEntry(PhotopickerDestinations.MEDIA_SET_GRID.route)
207             .savedStateHandle
208             .set(CategoryGridFeature.GROUP_KEY, category)
209     }
210 }
211