1 /*
<lambda>null2  * Copyright (C) 2023 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 package com.android.wallpaper.picker.preview.ui.fragment
17 
18 import android.content.Context
19 import android.os.Bundle
20 import android.view.LayoutInflater
21 import android.view.SurfaceView
22 import android.view.View
23 import android.view.ViewGroup
24 import androidx.cardview.widget.CardView
25 import androidx.core.content.ContextCompat
26 import androidx.core.view.ViewCompat
27 import androidx.core.view.isVisible
28 import androidx.fragment.app.activityViewModels
29 import androidx.navigation.NavController
30 import androidx.navigation.fragment.findNavController
31 import androidx.transition.Transition
32 import com.android.wallpaper.R
33 import com.android.wallpaper.picker.AppbarFragment
34 import com.android.wallpaper.picker.di.modules.MainDispatcher
35 import com.android.wallpaper.picker.preview.ui.binder.CropWallpaperButtonBinder
36 import com.android.wallpaper.picker.preview.ui.binder.FullWallpaperPreviewBinder
37 import com.android.wallpaper.picker.preview.ui.binder.PreviewTooltipBinder
38 import com.android.wallpaper.picker.preview.ui.binder.WorkspacePreviewBinder
39 import com.android.wallpaper.picker.preview.ui.transition.ChangeScaleAndPosition
40 import com.android.wallpaper.picker.preview.ui.util.AnimationUtil
41 import com.android.wallpaper.picker.preview.ui.viewmodel.WallpaperPreviewViewModel
42 import com.android.wallpaper.util.DisplayUtils
43 import com.android.wallpaper.util.wallpaperconnection.WallpaperConnectionUtils
44 import dagger.hilt.android.AndroidEntryPoint
45 import dagger.hilt.android.qualifiers.ApplicationContext
46 import javax.inject.Inject
47 import kotlinx.coroutines.CompletableDeferred
48 import kotlinx.coroutines.CoroutineScope
49 
50 /** Shows full preview of user selected wallpaper for cropping, zooming and positioning. */
51 @AndroidEntryPoint(AppbarFragment::class)
52 class FullPreviewFragment : Hilt_FullPreviewFragment() {
53 
54     @Inject @ApplicationContext lateinit var appContext: Context
55     @Inject @MainDispatcher lateinit var mainScope: CoroutineScope
56     @Inject lateinit var displayUtils: DisplayUtils
57     @Inject lateinit var wallpaperConnectionUtils: WallpaperConnectionUtils
58 
59     private lateinit var currentView: View
60 
61     private val wallpaperPreviewViewModel by activityViewModels<WallpaperPreviewViewModel>()
62     private val isFirstBindingDeferred = CompletableDeferred<Boolean>()
63 
64     private var useLightToolbarOverride = false
65     private var navigateUpListener: NavController.OnDestinationChangedListener? = null
66 
67     override fun onCreate(savedInstanceState: Bundle?) {
68         super.onCreate(savedInstanceState)
69         enterTransition = AnimationUtil.getFastFadeInTransition()
70         returnTransition = AnimationUtil.getFastFadeOutTransition()
71         sharedElementEnterTransition = ChangeScaleAndPosition()
72     }
73 
74     override fun onCreateView(
75         inflater: LayoutInflater,
76         container: ViewGroup?,
77         savedInstanceState: Bundle?,
78     ): View {
79         currentView = inflater.inflate(R.layout.fragment_full_preview, container, false)
80 
81         navigateUpListener =
82             NavController.OnDestinationChangedListener { _, destination, _ ->
83                 if (destination.id == R.id.smallPreviewFragment) {
84                     wallpaperPreviewViewModel.handleBackPressed()
85                     currentView.findViewById<View>(R.id.crop_wallpaper_button)?.isVisible = false
86                     currentView.findViewById<View>(R.id.full_preview_tooltip_stub)?.isVisible =
87                         false
88                     // When navigate up back to small preview, move previews up app window for
89                     // smooth shared element transition. It's the earliest timing to do this, it'll
90                     // be to late in transition started callback.
91                     currentView
92                         .requireViewById<SurfaceView>(R.id.wallpaper_surface)
93                         .setZOrderOnTop(true)
94                     currentView
95                         .requireViewById<SurfaceView>(R.id.workspace_surface)
96                         .setZOrderOnTop(true)
97                 }
98             }
99         navigateUpListener?.let { findNavController().addOnDestinationChangedListener(it) }
100 
101         setUpToolbar(currentView, true, true)
102 
103         val previewCard: CardView = currentView.requireViewById(R.id.preview_card)
104         ViewCompat.setTransitionName(
105             previewCard,
106             SmallPreviewFragment.FULL_PREVIEW_SHARED_ELEMENT_ID,
107         )
108 
109         FullWallpaperPreviewBinder.bind(
110             applicationContext = appContext,
111             view = currentView,
112             viewModel = wallpaperPreviewViewModel,
113             transition = sharedElementEnterTransition as? Transition,
114             displayUtils = displayUtils,
115             mainScope = mainScope,
116             lifecycleOwner = viewLifecycleOwner,
117             savedInstanceState = savedInstanceState,
118             wallpaperConnectionUtils = wallpaperConnectionUtils,
119             isFirstBindingDeferred = isFirstBindingDeferred,
120         ) { isFullScreen ->
121             useLightToolbarOverride = isFullScreen
122             setUpToolbar(view)
123         }
124 
125         CropWallpaperButtonBinder.bind(
126             button = currentView.requireViewById(R.id.crop_wallpaper_button),
127             viewModel = wallpaperPreviewViewModel,
128             lifecycleOwner = viewLifecycleOwner,
129         ) {
130             wallpaperPreviewViewModel.handleBackPressed()
131             findNavController().popBackStack()
132         }
133 
134         WorkspacePreviewBinder.bindFullWorkspacePreview(
135             surface = currentView.requireViewById(R.id.workspace_surface),
136             viewModel = wallpaperPreviewViewModel,
137             lifecycleOwner = viewLifecycleOwner,
138         )
139 
140         PreviewTooltipBinder.bindFullPreviewTooltip(
141             tooltipStub = currentView.requireViewById(R.id.full_preview_tooltip_stub),
142             viewModel = wallpaperPreviewViewModel.fullTooltipViewModel,
143             lifecycleOwner = viewLifecycleOwner,
144         )
145 
146         return currentView
147     }
148 
149     override fun onViewStateRestored(savedInstanceState: Bundle?) {
150         super.onViewStateRestored(savedInstanceState)
151         isFirstBindingDeferred.complete(savedInstanceState == null)
152     }
153 
154     override fun onDestroyView() {
155         super.onDestroyView()
156         navigateUpListener?.let { findNavController().removeOnDestinationChangedListener(it) }
157     }
158 
159     // TODO(b/291761856): Use real string
160     override fun getDefaultTitle(): CharSequence {
161         return ""
162     }
163 
164     override fun getToolbarTextColor(): Int {
165         return if (useLightToolbarOverride) {
166             ContextCompat.getColor(requireContext(), android.R.color.system_on_primary_light)
167         } else {
168             ContextCompat.getColor(requireContext(), R.color.system_on_surface)
169         }
170     }
171 
172     override fun isStatusBarLightText(): Boolean {
173         return requireContext().resources.getBoolean(R.bool.isFragmentStatusBarLightText) or
174             useLightToolbarOverride
175     }
176 }
177