1
+ /*
2
+ * Copyright 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
+ * https://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.example.platform.storage.storageaccessframework
18
+
19
+ import androidx.activity.compose.rememberLauncherForActivityResult
20
+ import androidx.activity.result.contract.ActivityResultContracts
21
+ import androidx.compose.foundation.layout.Box
22
+ import androidx.compose.foundation.layout.fillMaxSize
23
+ import androidx.compose.foundation.layout.padding
24
+ import androidx.compose.foundation.layout.size
25
+ import androidx.compose.foundation.layout.wrapContentSize
26
+ import androidx.compose.foundation.lazy.LazyColumn
27
+ import androidx.compose.foundation.lazy.items
28
+ import androidx.compose.foundation.rememberScrollState
29
+ import androidx.compose.material.icons.Icons
30
+ import androidx.compose.material.icons.filled.Check
31
+ import androidx.compose.material.icons.outlined.Check
32
+ import androidx.compose.material3.DropdownMenu
33
+ import androidx.compose.material3.DropdownMenuItem
34
+ import androidx.compose.material3.ExtendedFloatingActionButton
35
+ import androidx.compose.material3.HorizontalDivider
36
+ import androidx.compose.material3.Icon
37
+ import androidx.compose.material3.IconButton
38
+ import androidx.compose.material3.ListItem
39
+ import androidx.compose.material3.Scaffold
40
+ import androidx.compose.material3.Switch
41
+ import androidx.compose.material3.SwitchDefaults
42
+ import androidx.compose.material3.Text
43
+ import androidx.compose.runtime.Composable
44
+ import androidx.compose.runtime.LaunchedEffect
45
+ import androidx.compose.runtime.getValue
46
+ import androidx.compose.runtime.mutableStateOf
47
+ import androidx.compose.runtime.remember
48
+ import androidx.compose.runtime.rememberCoroutineScope
49
+ import androidx.compose.runtime.setValue
50
+ import androidx.compose.ui.Alignment
51
+ import androidx.compose.ui.Modifier
52
+ import androidx.compose.ui.platform.LocalContext
53
+ import androidx.compose.ui.res.painterResource
54
+ import androidx.compose.ui.semantics.contentDescription
55
+ import androidx.compose.ui.semantics.semantics
56
+ import com.example.platform.storage.R
57
+ import com.example.platform.storage.storageaccessframework.shared.AudioFileCard
58
+ import com.example.platform.storage.storageaccessframework.shared.BinaryFileCard
59
+ import com.example.platform.storage.storageaccessframework.shared.FileRecord
60
+ import com.example.platform.storage.storageaccessframework.shared.FileType
61
+ import com.example.platform.storage.storageaccessframework.shared.ImageFileCard
62
+ import com.example.platform.storage.storageaccessframework.shared.PdfFileCard
63
+ import com.example.platform.storage.storageaccessframework.shared.TextFileCard
64
+ import com.example.platform.storage.storageaccessframework.shared.VideoFileCard
65
+ import kotlinx.coroutines.launch
66
+
67
+ @Composable
68
+ fun GetContentSample () {
69
+ val coroutineScope = rememberCoroutineScope()
70
+ val context = LocalContext .current
71
+ var selectedFilter by remember { mutableStateOf(FileType .Any ) }
72
+ var selectMultiple by remember { mutableStateOf(false ) }
73
+ var expanded by remember { mutableStateOf(false ) }
74
+ var selectedFiles by remember { mutableStateOf(emptyList<FileRecord >()) }
75
+
76
+ val getSingleDocument =
77
+ rememberLauncherForActivityResult(ActivityResultContracts .GetContent ()) { uri ->
78
+ coroutineScope.launch {
79
+ selectedFiles = uri?.let { uri ->
80
+ FileRecord .fromUri(uri, context)?.let { listOf (it) }
81
+ } ? : emptyList()
82
+ }
83
+ }
84
+
85
+ val getMultipleDocuments =
86
+ rememberLauncherForActivityResult(ActivityResultContracts .GetMultipleContents ()) { uris ->
87
+ coroutineScope.launch {
88
+ selectedFiles = uris.mapNotNull { uri ->
89
+ FileRecord .fromUri(uri, context)
90
+ }
91
+ }
92
+ }
93
+
94
+ Scaffold (
95
+ modifier = Modifier .fillMaxSize(),
96
+ floatingActionButton = {
97
+ ExtendedFloatingActionButton (
98
+ onClick = {
99
+ if (selectMultiple) {
100
+ getMultipleDocuments.launch(selectedFilter.mimeType)
101
+ } else {
102
+ getSingleDocument.launch(selectedFilter.mimeType)
103
+ }
104
+ },
105
+ ) {
106
+ Text (if (selectMultiple) " Select Files" else " Select File" )
107
+ }
108
+ },
109
+ ) { paddingValues ->
110
+ LazyColumn (Modifier .padding(paddingValues)) {
111
+ item {
112
+ ListItem (
113
+ headlineContent = { Text (" File type filter" ) },
114
+ supportingContent = {
115
+ Text (selectedFilter.name)
116
+ },
117
+ trailingContent = {
118
+ val scrollState = rememberScrollState()
119
+ Box (
120
+ modifier = Modifier
121
+ .wrapContentSize(Alignment .TopStart ),
122
+ ) {
123
+ IconButton (onClick = { expanded = true }) {
124
+ Icon (
125
+ painter = painterResource(R .drawable.ic_filter_alt_24),
126
+ contentDescription = " Localized description" ,
127
+ )
128
+ }
129
+ DropdownMenu (
130
+ expanded = expanded,
131
+ onDismissRequest = { expanded = false },
132
+ scrollState = scrollState,
133
+ ) {
134
+ FileType .entries.forEach { fileType ->
135
+ DropdownMenuItem (
136
+ text = { Text (fileType.name) },
137
+ onClick = { selectedFilter = fileType },
138
+ leadingIcon = {
139
+ if (selectedFilter == fileType) {
140
+ Icon (
141
+ Icons .Outlined .Check ,
142
+ contentDescription = " Selected" ,
143
+ )
144
+ }
145
+ },
146
+ )
147
+ }
148
+ }
149
+ LaunchedEffect (expanded) {
150
+ if (expanded) {
151
+ // Scroll to show the bottom menu items.
152
+ scrollState.scrollTo(scrollState.maxValue)
153
+ }
154
+ }
155
+ }
156
+ },
157
+ )
158
+ HorizontalDivider ()
159
+ }
160
+ item {
161
+ ListItem (
162
+ headlineContent = { Text (" Select multiple files?" ) },
163
+ trailingContent = {
164
+ Switch (
165
+ modifier = Modifier .semantics {
166
+ contentDescription = " Select multiple files"
167
+ },
168
+ checked = selectMultiple,
169
+ onCheckedChange = { selectMultiple = it },
170
+ thumbContent = {
171
+ if (selectMultiple) {
172
+ Icon (
173
+ imageVector = Icons .Filled .Check ,
174
+ contentDescription = null ,
175
+ modifier = Modifier .size(SwitchDefaults .IconSize ),
176
+ )
177
+ }
178
+ },
179
+ )
180
+ },
181
+ )
182
+ HorizontalDivider ()
183
+ }
184
+ items(selectedFiles) { file ->
185
+ when (file.fileType) {
186
+ FileType .Image -> ImageFileCard (file)
187
+ FileType .Video -> VideoFileCard (file)
188
+ FileType .Audio -> AudioFileCard (file)
189
+ FileType .Text -> TextFileCard (file)
190
+ FileType .Pdf -> PdfFileCard (file)
191
+ FileType .Any -> BinaryFileCard (file)
192
+ }
193
+ }
194
+ }
195
+ }
196
+ }
0 commit comments