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.google.jetpackcamera.settings
17
18 import android.Manifest
19 import android.content.res.Configuration
20 import androidx.compose.foundation.background
21 import androidx.compose.foundation.layout.Column
22 import androidx.compose.foundation.layout.padding
23 import androidx.compose.foundation.rememberScrollState
24 import androidx.compose.foundation.verticalScroll
25 import androidx.compose.material3.ExperimentalMaterial3Api
26 import androidx.compose.material3.MaterialTheme
27 import androidx.compose.material3.Scaffold
28 import androidx.compose.material3.TopAppBarDefaults
29 import androidx.compose.material3.rememberTopAppBarState
30 import androidx.compose.runtime.Composable
31 import androidx.compose.runtime.collectAsState
32 import androidx.compose.runtime.getValue
33 import androidx.compose.ui.Modifier
34 import androidx.compose.ui.input.nestedscroll.nestedScroll
35 import androidx.compose.ui.res.stringResource
36 import androidx.compose.ui.tooling.preview.Preview
37 import androidx.hilt.navigation.compose.hiltViewModel
38 import com.google.accompanist.permissions.ExperimentalPermissionsApi
39 import com.google.accompanist.permissions.rememberMultiplePermissionsState
40 import com.google.jetpackcamera.settings.model.AspectRatio
41 import com.google.jetpackcamera.settings.model.DarkMode
42 import com.google.jetpackcamera.settings.model.FlashMode
43 import com.google.jetpackcamera.settings.model.LensFacing
44 import com.google.jetpackcamera.settings.model.StabilizationMode
45 import com.google.jetpackcamera.settings.model.StreamConfig
46 import com.google.jetpackcamera.settings.model.VideoQuality
47 import com.google.jetpackcamera.settings.ui.AspectRatioSetting
48 import com.google.jetpackcamera.settings.ui.DarkModeSetting
49 import com.google.jetpackcamera.settings.ui.DefaultCameraFacing
50 import com.google.jetpackcamera.settings.ui.FlashModeSetting
51 import com.google.jetpackcamera.settings.ui.MaxVideoDurationSetting
52 import com.google.jetpackcamera.settings.ui.RecordingAudioSetting
53 import com.google.jetpackcamera.settings.ui.SectionHeader
54 import com.google.jetpackcamera.settings.ui.SettingsPageHeader
55 import com.google.jetpackcamera.settings.ui.StabilizationSetting
56 import com.google.jetpackcamera.settings.ui.StreamConfigSetting
57 import com.google.jetpackcamera.settings.ui.TargetFpsSetting
58 import com.google.jetpackcamera.settings.ui.VersionInfo
59 import com.google.jetpackcamera.settings.ui.VideoQualitySetting
60 import com.google.jetpackcamera.settings.ui.theme.SettingsPreviewTheme
61
62 /**
63 * Screen used for the Settings feature.
64 */
65
66 @OptIn(ExperimentalPermissionsApi::class)
67 @Composable
68 fun SettingsScreen(
69 versionInfo: VersionInfoHolder,
70 viewModel: SettingsViewModel = hiltViewModel(),
71 onNavigateBack: () -> Unit
72 ) {
73 val settingsUiState by viewModel.settingsUiState.collectAsState()
74
75 SettingsScreen(
76 uiState = settingsUiState,
77 versionInfo = versionInfo,
78 onNavigateBack = onNavigateBack,
79 setDefaultLensFacing = viewModel::setDefaultLensFacing,
80 setFlashMode = viewModel::setFlashMode,
81 setTargetFrameRate = viewModel::setTargetFrameRate,
82 setAspectRatio = viewModel::setAspectRatio,
83 setCaptureMode = viewModel::setStreamConfig,
84 setAudio = viewModel::setVideoAudio,
85 setStabilizationMode = viewModel::setStabilizationMode,
86 setMaxVideoDuration = viewModel::setMaxVideoDuration,
87 setDarkMode = viewModel::setDarkMode,
88 setVideoQuality = viewModel::setVideoQuality
89 )
90 val permissionStates = rememberMultiplePermissionsState(
91 permissions =
92 listOf(
93 Manifest.permission.CAMERA,
94 Manifest.permission.RECORD_AUDIO
95 )
96 )
97
98 viewModel.setGrantedPermissions(permissionStates)
99 }
100
101 @OptIn(ExperimentalMaterial3Api::class)
102 @Composable
SettingsScreennull103 private fun SettingsScreen(
104 uiState: SettingsUiState,
105 versionInfo: VersionInfoHolder,
106 onNavigateBack: () -> Unit = {},
<lambda>null107 setDefaultLensFacing: (LensFacing) -> Unit = {},
<lambda>null108 setFlashMode: (FlashMode) -> Unit = {},
<lambda>null109 setTargetFrameRate: (Int) -> Unit = {},
<lambda>null110 setAspectRatio: (AspectRatio) -> Unit = {},
<lambda>null111 setCaptureMode: (StreamConfig) -> Unit = {},
<lambda>null112 setStabilizationMode: (StabilizationMode) -> Unit = {},
<lambda>null113 setAudio: (Boolean) -> Unit = {},
<lambda>null114 setMaxVideoDuration: (Long) -> Unit = {},
<lambda>null115 setDarkMode: (DarkMode) -> Unit = {},
<lambda>null116 setVideoQuality: (VideoQuality) -> Unit = {}
117 ) {
118 val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(
119 rememberTopAppBarState()
120 )
121
122 Scaffold(
123 modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
<lambda>null124 topBar = {
125 SettingsPageHeader(
126 title = stringResource(id = R.string.settings_title),
127 navBack = onNavigateBack,
128 scrollBehavior = scrollBehavior
129 )
130 }
innerPaddingnull131 ) { innerPadding ->
132 Column(
133 modifier = Modifier
134 .padding(innerPadding)
135 .verticalScroll(rememberScrollState())
136 .background(color = MaterialTheme.colorScheme.background)
137 ) {
138 if (uiState is SettingsUiState.Enabled) {
139 SettingsList(
140 uiState = uiState,
141 versionInfo = versionInfo,
142 setDefaultLensFacing = setDefaultLensFacing,
143 setFlashMode = setFlashMode,
144 setTargetFrameRate = setTargetFrameRate,
145 setAspectRatio = setAspectRatio,
146 setCaptureMode = setCaptureMode,
147 setStabilizationMode = setStabilizationMode,
148 setAudio = setAudio,
149 setMaxVideoDuration = setMaxVideoDuration,
150 setDarkMode = setDarkMode,
151 setVideoQuality = setVideoQuality
152 )
153 }
154 }
155 }
156 }
157
158 @Composable
SettingsListnull159 fun SettingsList(
160 uiState: SettingsUiState.Enabled,
161 versionInfo: VersionInfoHolder,
162 setDefaultLensFacing: (LensFacing) -> Unit = {},
<lambda>null163 setFlashMode: (FlashMode) -> Unit = {},
<lambda>null164 setTargetFrameRate: (Int) -> Unit = {},
<lambda>null165 setAspectRatio: (AspectRatio) -> Unit = {},
<lambda>null166 setCaptureMode: (StreamConfig) -> Unit = {},
<lambda>null167 setAudio: (Boolean) -> Unit = {},
<lambda>null168 setStabilizationMode: (StabilizationMode) -> Unit = {},
<lambda>null169 setVideoQuality: (VideoQuality) -> Unit = {},
<lambda>null170 setMaxVideoDuration: (Long) -> Unit = {},
<lambda>null171 setDarkMode: (DarkMode) -> Unit = {}
172 ) {
173 SectionHeader(title = stringResource(id = R.string.section_title_camera_settings))
174
175 DefaultCameraFacing(
176 lensUiState = uiState.lensFlipUiState,
177 setDefaultLensFacing = setDefaultLensFacing
178 )
179
180 FlashModeSetting(
181 flashUiState = uiState.flashUiState,
182 setFlashMode = setFlashMode
183 )
184
185 TargetFpsSetting(
186 fpsUiState = uiState.fpsUiState,
187 setTargetFps = setTargetFrameRate
188 )
189
190 AspectRatioSetting(
191 aspectRatioUiState = uiState.aspectRatioUiState,
192 setAspectRatio = setAspectRatio
193 )
194
195 StreamConfigSetting(
196 streamConfigUiState = uiState.streamConfigUiState,
197 setStreamConfig = setCaptureMode
198 )
199
200 SectionHeader(title = stringResource(R.string.section_title_recording_settings))
201
202 RecordingAudioSetting(
203 audioUiState = uiState.audioUiState,
204 setDefaultAudio = setAudio
205 )
206
207 MaxVideoDurationSetting(
208 maxVideoDurationUiState = uiState.maxVideoDurationUiState,
209 setMaxDuration = setMaxVideoDuration
210 )
211
212 StabilizationSetting(
213 stabilizationUiState = uiState.stabilizationUiState,
214 setStabilizationMode = setStabilizationMode
215 )
216
217 VideoQualitySetting(
218 videQualityUiState = uiState.videoQualityUiState,
219 setVideoQuality = setVideoQuality
220 )
221
222 SectionHeader(title = stringResource(id = R.string.section_title_app_settings))
223
224 DarkModeSetting(
225 darkModeUiState = uiState.darkModeUiState,
226 setDarkMode = setDarkMode
227 )
228
229 SectionHeader(title = stringResource(id = R.string.section_title_software_info))
230
231 VersionInfo(
232 versionName = versionInfo.versionName,
233 buildType = versionInfo.buildType
234 )
235 }
236
237 // will allow you to open stabilization popup or give disabled rationale
238
239 data class VersionInfoHolder(val versionName: String, val buildType: String)
240
241 @Preview(name = "Light Mode")
242 @Preview(name = "Dark Mode", uiMode = Configuration.UI_MODE_NIGHT_YES)
243 @Composable
Preview_SettingsScreennull244 private fun Preview_SettingsScreen() {
245 SettingsPreviewTheme {
246 SettingsScreen(
247 uiState = TYPICAL_SETTINGS_UISTATE,
248 versionInfo = VersionInfoHolder(
249 versionName = "1.0.0",
250 buildType = "release"
251 )
252 )
253 }
254 }
255