11/*
2- * Copyright (C) 2022 - 2024 Mateus Rodrigues Costa
2+ * Copyright (C) 2022 - 2025 Mateus Rodrigues Costa
33 *
44 * This program is free software: you can redistribute it and/or modify
55 * it under the terms of the GNU Affero General Public License as
1717
1818package com.mateusrodcosta.apps.share2storage.screens
1919
20- import android.text.format.Formatter
21- import androidx.compose.foundation.clickable
2220import androidx.compose.foundation.layout.Arrangement
2321import androidx.compose.foundation.layout.Box
2422import androidx.compose.foundation.layout.Column
@@ -28,22 +26,15 @@ import androidx.compose.foundation.layout.WindowInsetsSides
2826import androidx.compose.foundation.layout.fillMaxSize
2927import androidx.compose.foundation.layout.only
3028import androidx.compose.foundation.layout.padding
31- import androidx.compose.foundation.layout.size
3229import androidx.compose.foundation.layout.systemBars
3330import androidx.compose.foundation.layout.windowInsetsPadding
3431import androidx.compose.foundation.rememberScrollState
3532import androidx.compose.foundation.verticalScroll
3633import androidx.compose.material.icons.Icons
37- import androidx.compose.material.icons.outlined.AudioFile
38- import androidx.compose.material.icons.outlined.Description
39- import androidx.compose.material.icons.outlined.Image
40- import androidx.compose.material.icons.outlined.VideoFile
4134import androidx.compose.material.icons.rounded.Download
42- import androidx.compose.material3.CircularProgressIndicator
4335import androidx.compose.material3.ExperimentalMaterial3Api
4436import androidx.compose.material3.FloatingActionButton
4537import androidx.compose.material3.Icon
46- import androidx.compose.material3.ListItem
4738import androidx.compose.material3.MaterialTheme
4839import androidx.compose.material3.Scaffold
4940import androidx.compose.material3.Text
@@ -52,22 +43,16 @@ import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass
5243import androidx.compose.material3.windowsizeclass.WindowSizeClass
5344import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
5445import androidx.compose.runtime.Composable
55- import androidx.compose.runtime.collectAsState
56- import androidx.compose.runtime.getValue
5746import androidx.compose.ui.Alignment
5847import androidx.compose.ui.Modifier
59- import androidx.compose.ui.layout.ContentScale
60- import androidx.compose.ui.platform.LocalContext
6148import androidx.compose.ui.res.stringResource
6249import androidx.compose.ui.tooling.preview.Preview
6350import androidx.compose.ui.tooling.preview.PreviewParameter
64- import androidx.compose.ui.unit.dp
65- import coil3.compose.AsyncImagePainter
66- import coil3.compose.SubcomposeAsyncImage
67- import coil3.compose.SubcomposeAsyncImageContent
6851import com.mateusrodcosta.apps.share2storage.R
6952import com.mateusrodcosta.apps.share2storage.model.SampleUriDataProvider
7053import com.mateusrodcosta.apps.share2storage.model.UriData
54+ import com.mateusrodcosta.apps.share2storage.screens.shared.FileInfo
55+ import com.mateusrodcosta.apps.share2storage.screens.shared.FilePreview
7156import com.mateusrodcosta.apps.share2storage.screens.shared.shouldShowLandscape
7257import com.mateusrodcosta.apps.share2storage.ui.theme.AppTheme
7358
@@ -164,16 +149,8 @@ fun FileDetailsPortrait(uriData: UriData) {
164149 horizontalAlignment = Alignment .CenterHorizontally ,
165150 verticalArrangement = Arrangement .SpaceEvenly
166151 ) {
167- Box (
168- modifier = Modifier
169- .fillMaxSize()
170- .weight(1.0f )
171- ) {
172- FilePreview (uriData)
173- }
174- Box {
175- FileInfo (uriData)
176- }
152+ FilePreview (uriData, modifier = Modifier .weight(1.0f ))
153+ FileInfo (uriData, modifier = Modifier .verticalScroll(rememberScrollState()))
177154 }
178155}
179156
@@ -184,98 +161,13 @@ fun FileDetailsLandscape(uriData: UriData) {
184161 horizontalArrangement = Arrangement .SpaceEvenly ,
185162 verticalAlignment = Alignment .CenterVertically ,
186163 ) {
187- Box (modifier = Modifier .weight(1.0f )) {
188- FilePreview (uriData)
189- }
190- Box (modifier = Modifier .weight(1.0f )) {
191- FileInfo (uriData)
192- }
193- }
194- }
195-
196- @Composable
197- fun FileInfo (uriData : UriData ) {
198- Column (
199- modifier = Modifier .verticalScroll(rememberScrollState()),
200- verticalArrangement = Arrangement .Center
201- ) {
202- FileInfoLine (
203- label = stringResource(R .string.file_name),
204- content = uriData.displayName
205- )
206- FileInfoLine (
207- label = stringResource(R .string.file_type),
208- content = uriData.mimeType ? : " */*"
209- )
210- FileInfoLine (
211- label = stringResource(R .string.file_size),
212- content = Formatter .formatFileSize(LocalContext .current, uriData.size)
164+ FilePreview (
165+ uriData, modifier = Modifier .weight(1.0f )
213166 )
167+ FileInfo (uriData, modifier = Modifier .weight(1.0f ))
214168 }
215169}
216170
217- @Composable
218- fun FileInfoLine (label : String , content : String ) {
219- ListItem (modifier = Modifier .clickable { }, headlineContent = {
220- Text (label)
221- }, supportingContent = {
222- Text (content, softWrap = true )
223- })
224- }
225-
226- @Composable
227- fun FilePreview (uriData : UriData ) {
228- val mimeType = uriData.mimeType
229- val primaryType = mimeType?.substringBefore(' /' )
230-
231- val fallbackFileIcon = when (primaryType) {
232- " image" -> Icons .Outlined .Image
233- " audio" -> Icons .Outlined .AudioFile
234- " video" -> Icons .Outlined .VideoFile
235- else -> Icons .Outlined .Description
236- }
237- val fallbackFileLabel = when (primaryType) {
238- " image" -> " Image"
239- " audio" -> " Audio"
240- " video" -> " Video"
241- else -> " File"
242- }
243-
244- Box (
245- modifier = Modifier
246- .fillMaxSize()
247- .padding(16 .dp)
248- ) {
249- SubcomposeAsyncImage (
250- modifier = Modifier .align(Alignment .Center ),
251- model = uriData.uri,
252- contentDescription = stringResource(R .string.app_name),
253- contentScale = ContentScale .Fit ,
254- ) {
255- val state by painter.state.collectAsState()
256-
257- when (state) {
258- is AsyncImagePainter .State .Loading -> {
259- CircularProgressIndicator ()
260- }
261- // Display fallback icon if can't create thumbnail
262- is AsyncImagePainter .State .Error -> {
263- Icon (
264- modifier = Modifier
265- .size(128 .dp)
266- .align(Alignment .Center ),
267- imageVector = fallbackFileIcon,
268- contentDescription = fallbackFileLabel,
269- tint = MaterialTheme .colorScheme.tertiary
270- )
271- }
272- else -> {
273- SubcomposeAsyncImageContent ()
274- }
275- }
276- }
277- }
278- }
279171
280172@Preview(apiLevel = 34 , showSystemUi = true , showBackground = true )
281173@Composable
0 commit comments