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.preview.PreviewFeature
29
30 /**
31 * Utility function for navigating to the [PhotopickerDestinations.PHOTO_GRID] route.
32 *
33 * This attempts to reclaim an existing BackStack entry, preserving any previous state that existed.
34 *
35 * If the route is not currently on the BackStack, then this will navigate directly.
36 */
NavControllernull37 fun NavController.navigateToPhotoGrid(navOptions: NavOptions? = null) {
38 // First, check to see if the destination is already the current route.
39 if (this.currentDestination?.route == PHOTO_GRID.route) {
40 // Nothing to do. Return early to prevent navigation animations from triggering.
41 return
42 } else if (
43 // Try to return to the entry that is already on the backstack, so the user's
44 // previous state and scroll position is restored.
45 !this.popBackStack(
46 PHOTO_GRID.route,
47 /* inclusive= */ false,
48 /* saveState = */ false,
49 )
50 ) {
51 // Last resort; PHOTO_GRID isn't on the backstack, then navigate directly.
52 this.navigate(PHOTO_GRID.route, navOptions)
53 }
54 }
55
56 /** Utility function for navigating to the [PhotopickerDestinations.PREVIEW_SELECTION] route. */
NavControllernull57 fun NavController.navigateToPreviewSelection(navOptions: NavOptions? = null) {
58 this.navigate(PREVIEW_SELECTION.route, navOptions)
59 }
60
61 /**
62 * Utility function for navigating to the [PhotopickerDestinations.PREVIEW_MEDIA] route.
63 *
64 * Additionally, this adds the relevant media data to the BackStackEntry for the route to use to
65 * avoid refetching it from the provider.
66 *
67 * @param media The media item that should be previewed in full resolution.
68 */
NavControllernull69 fun NavController.navigateToPreviewMedia(
70 media: Media,
71 navOptions: NavOptions? = null,
72 ) {
73 this.navigate(PREVIEW_MEDIA.route, navOptions)
74 // Media object must be parcellized and passed to the new route so it can be loaded.
75 // This back stack entry is guaranteed to exist since it was just navigated to.
76 this.getBackStackEntry(PREVIEW_MEDIA.route)
77 .savedStateHandle
78 .set(PreviewFeature.PREVIEW_MEDIA_KEY, media)
79 }
80
81 /**
82 * Utility function for navigating to the [PhotopickerDestinations.ALBUM_GRID] route.
83 *
84 * This attempts to reclaim an existing BackStack entry, preserving any previous state that existed.
85 *
86 * If the route is not currently on the BackStack, then this will navigate directly.
87 */
NavControllernull88 fun NavController.navigateToAlbumGrid(navOptions: NavOptions? = null) {
89 // First, check to see if the destination is already the current route.
90 if (this.currentDestination?.route == PhotopickerDestinations.ALBUM_GRID.route) {
91 // Nothing to do. Return early to prevent navigation animations from triggering.
92 return
93 } else if (
94 // Try to return to the entry that is already on the backstack, so the user's
95 // previous state and scroll position is restored.
96 !this.popBackStack(
97 PhotopickerDestinations.ALBUM_GRID.route,
98 /* inclusive= */ false,
99 /* saveState = */ true,
100 )
101 ) {
102 // Last resort; ALBUM_GRID isn't on the backstack, then navigate directly.
103 this.navigate(PhotopickerDestinations.ALBUM_GRID.route, navOptions)
104 }
105 }
106
107 /**
108 * Utility function for navigating to the [PhotopickerDestinations.ALBUM_MEDIA_GRID] route.
109 *
110 * @param album The album for which the media needs to be displayed.
111 */
navigateToAlbumMediaGridnull112 fun NavController.navigateToAlbumMediaGrid(
113 navOptions: NavOptions? = null,
114 album: Group.Album,
115 ) {
116 this.navigate(PhotopickerDestinations.ALBUM_MEDIA_GRID.route, navOptions)
117
118 // Album object must be parcellized and passed to the new route so it can be loaded.
119 // This back stack entry is guaranteed to exist since it was just navigated to.
120 this.getBackStackEntry(PhotopickerDestinations.ALBUM_MEDIA_GRID.route)
121 .savedStateHandle
122 .set(AlbumGridFeature.ALBUM_KEY, album)
123 }
124