From dc994a7baef632e7958944a97c3b6423cde0fb0c Mon Sep 17 00:00:00 2001 From: T8RIN Date: Fri, 24 Jan 2025 03:04:47 +0300 Subject: [PATCH] Code refactor --- .../ui/widget/image/ImageNotPickedWidget.kt | 38 ++- .../core/ui/widget/text/Marquee.kt | 6 +- .../cipher/presentation/CipherContent.kt | 32 +-- .../pdf_tools/presentation/PdfToolsContent.kt | 5 +- .../feature/zip/presentation/ZipContent.kt | 251 +---------------- .../presentation/components/ZipControls.kt | 253 ++++++++++++++++++ .../presentation/screenLogic/ZipComponent.kt | 5 +- 7 files changed, 309 insertions(+), 281 deletions(-) create mode 100644 feature/zip/src/main/java/ru/tech/imageresizershrinker/feature/zip/presentation/components/ZipControls.kt diff --git a/core/ui/src/main/kotlin/ru/tech/imageresizershrinker/core/ui/widget/image/ImageNotPickedWidget.kt b/core/ui/src/main/kotlin/ru/tech/imageresizershrinker/core/ui/widget/image/ImageNotPickedWidget.kt index db45988fd2..c1dde8af9f 100644 --- a/core/ui/src/main/kotlin/ru/tech/imageresizershrinker/core/ui/widget/image/ImageNotPickedWidget.kt +++ b/core/ui/src/main/kotlin/ru/tech/imageresizershrinker/core/ui/widget/image/ImageNotPickedWidget.kt @@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.twotone.FileOpen import androidx.compose.material.icons.twotone.Image import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme @@ -41,8 +42,8 @@ import ru.tech.imageresizershrinker.core.ui.widget.modifier.container @Composable fun ImageNotPickedWidget( - modifier: Modifier = Modifier, onPickImage: () -> Unit, + modifier: Modifier = Modifier, text: String = stringResource(R.string.pick_image), ) { Column( @@ -72,4 +73,39 @@ fun ImageNotPickedWidget( color = MaterialTheme.colorScheme.onSurfaceVariant ) } +} + +@Composable +fun FileNotPickedWidget( + onPickFile: () -> Unit, + modifier: Modifier = Modifier, + text: String = stringResource(R.string.pick_file_to_start) +) { + Column( + modifier = modifier.container(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(Modifier.height(16.dp)) + Icon( + imageVector = Icons.TwoTone.FileOpen, + contentDescription = null, + modifier = Modifier + .size(100.dp) + .container( + shape = CloverShape, + resultPadding = 0.dp, + color = MaterialTheme.colorScheme.secondaryContainer + ) + .hapticsClickable(onClick = onPickFile) + .padding(12.dp), + tint = MaterialTheme.colorScheme.onSecondaryContainer + ) + Text( + text = text, + modifier = Modifier.padding(16.dp), + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } } \ No newline at end of file diff --git a/core/ui/src/main/kotlin/ru/tech/imageresizershrinker/core/ui/widget/text/Marquee.kt b/core/ui/src/main/kotlin/ru/tech/imageresizershrinker/core/ui/widget/text/Marquee.kt index 965e3f766a..2fb09b09c6 100644 --- a/core/ui/src/main/kotlin/ru/tech/imageresizershrinker/core/ui/widget/text/Marquee.kt +++ b/core/ui/src/main/kotlin/ru/tech/imageresizershrinker/core/ui/widget/text/Marquee.kt @@ -36,7 +36,7 @@ import com.gigamole.composefadingedges.marqueeHorizontalFadingEdges fun Modifier.marquee( - edgeColor: Color = Color.Unspecified, + edgesColor: Color = Color.Unspecified, ) = this.composed { var showMarquee by remember { mutableStateOf(false) } @@ -45,9 +45,9 @@ fun Modifier.marquee( .then( if (showMarquee) { Modifier.marqueeHorizontalFadingEdges( - fillType = if (edgeColor.isSpecified) { + fillType = if (edgesColor.isSpecified) { FadingEdgesFillType.FadeColor( - color = edgeColor + color = edgesColor ) } else FadingEdgesFillType.FadeClip(), length = 10.dp, diff --git a/feature/cipher/src/main/java/ru/tech/imageresizershrinker/feature/cipher/presentation/CipherContent.kt b/feature/cipher/src/main/java/ru/tech/imageresizershrinker/feature/cipher/presentation/CipherContent.kt index a97cdb2f89..cfc1792e76 100644 --- a/feature/cipher/src/main/java/ru/tech/imageresizershrinker/feature/cipher/presentation/CipherContent.kt +++ b/feature/cipher/src/main/java/ru/tech/imageresizershrinker/feature/cipher/presentation/CipherContent.kt @@ -48,7 +48,6 @@ import androidx.compose.material.icons.rounded.FileOpen import androidx.compose.material.icons.rounded.Key import androidx.compose.material.icons.rounded.Share import androidx.compose.material.icons.rounded.Shuffle -import androidx.compose.material.icons.twotone.FileOpen import androidx.compose.material3.Badge import androidx.compose.material3.Icon import androidx.compose.material3.LocalContentColor @@ -78,7 +77,6 @@ import ru.tech.imageresizershrinker.core.resources.R import ru.tech.imageresizershrinker.core.resources.icons.ShieldKey import ru.tech.imageresizershrinker.core.resources.icons.ShieldOpen import ru.tech.imageresizershrinker.core.settings.presentation.provider.LocalSettingsState -import ru.tech.imageresizershrinker.core.ui.shapes.CloverShape import ru.tech.imageresizershrinker.core.ui.theme.Green import ru.tech.imageresizershrinker.core.ui.theme.outlineVariant import ru.tech.imageresizershrinker.core.ui.utils.content_pickers.rememberFilePicker @@ -94,8 +92,8 @@ import ru.tech.imageresizershrinker.core.ui.widget.dialogs.ExitWithoutSavingDial import ru.tech.imageresizershrinker.core.ui.widget.dialogs.LoadingDialog import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedButton import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedIconButton -import ru.tech.imageresizershrinker.core.ui.widget.enhanced.hapticsClickable import ru.tech.imageresizershrinker.core.ui.widget.image.AutoFilePicker +import ru.tech.imageresizershrinker.core.ui.widget.image.FileNotPickedWidget import ru.tech.imageresizershrinker.core.ui.widget.modifier.container import ru.tech.imageresizershrinker.core.ui.widget.modifier.scaleOnTap import ru.tech.imageresizershrinker.core.ui.widget.other.TopAppBarEmoji @@ -251,33 +249,7 @@ fun CipherContent( }, canShowScreenData = component.uri != null, noDataControls = { - Column( - modifier = Modifier.container(), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - ) { - Spacer(Modifier.height(16.dp)) - Icon( - imageVector = Icons.TwoTone.FileOpen, - contentDescription = null, - modifier = Modifier - .size(100.dp) - .container( - shape = CloverShape, - resultPadding = 0.dp, - color = MaterialTheme.colorScheme.secondaryContainer - ) - .hapticsClickable(onClick = filePicker::pickFile) - .padding(12.dp), - tint = MaterialTheme.colorScheme.onSecondaryContainer - ) - Text( - text = stringResource(R.string.pick_file_to_start), - modifier = Modifier.padding(16.dp), - textAlign = TextAlign.Center, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) - } + FileNotPickedWidget(onPickFile = filePicker::pickFile) }, controls = { Column(horizontalAlignment = Alignment.CenterHorizontally) { diff --git a/feature/pdf-tools/src/main/java/ru/tech/imageresizershrinker/feature/pdf_tools/presentation/PdfToolsContent.kt b/feature/pdf-tools/src/main/java/ru/tech/imageresizershrinker/feature/pdf_tools/presentation/PdfToolsContent.kt index dc0dc0c9c7..a94add68d6 100644 --- a/feature/pdf-tools/src/main/java/ru/tech/imageresizershrinker/feature/pdf_tools/presentation/PdfToolsContent.kt +++ b/feature/pdf-tools/src/main/java/ru/tech/imageresizershrinker/feature/pdf_tools/presentation/PdfToolsContent.kt @@ -197,7 +197,10 @@ fun PdfToolsContent( } }, title = { - TitleItem(text = stringResource(id = R.string.pick_file), icon = Icons.Rounded.FileOpen) + TitleItem( + text = stringResource(id = R.string.pick_file), + icon = Icons.Rounded.FileOpen + ) } ) diff --git a/feature/zip/src/main/java/ru/tech/imageresizershrinker/feature/zip/presentation/ZipContent.kt b/feature/zip/src/main/java/ru/tech/imageresizershrinker/feature/zip/presentation/ZipContent.kt index 3d1f963506..bd2afe7f72 100644 --- a/feature/zip/src/main/java/ru/tech/imageresizershrinker/feature/zip/presentation/ZipContent.kt +++ b/feature/zip/src/main/java/ru/tech/imageresizershrinker/feature/zip/presentation/ZipContent.kt @@ -17,51 +17,20 @@ package ru.tech.imageresizershrinker.feature.zip.presentation -import androidx.activity.compose.rememberLauncherForActivityResult -import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.rounded.CheckCircle -import androidx.compose.material.icons.rounded.FileDownload import androidx.compose.material.icons.rounded.FileOpen -import androidx.compose.material.icons.rounded.Share -import androidx.compose.material.icons.twotone.FileOpen -import androidx.compose.material3.Icon -import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import ru.tech.imageresizershrinker.core.resources.R -import ru.tech.imageresizershrinker.core.settings.presentation.provider.LocalSettingsState -import ru.tech.imageresizershrinker.core.ui.shapes.CloverShape -import ru.tech.imageresizershrinker.core.ui.theme.Green -import ru.tech.imageresizershrinker.core.ui.theme.outlineVariant import ru.tech.imageresizershrinker.core.ui.utils.content_pickers.rememberFilePicker import ru.tech.imageresizershrinker.core.ui.utils.helper.isPortraitOrientationAsState import ru.tech.imageresizershrinker.core.ui.utils.provider.rememberLocalEssentials @@ -69,31 +38,19 @@ import ru.tech.imageresizershrinker.core.ui.widget.AdaptiveLayoutScreen import ru.tech.imageresizershrinker.core.ui.widget.buttons.BottomButtonsBlock import ru.tech.imageresizershrinker.core.ui.widget.dialogs.ExitWithoutSavingDialog import ru.tech.imageresizershrinker.core.ui.widget.dialogs.LoadingDialog -import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedButton import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedChip -import ru.tech.imageresizershrinker.core.ui.widget.enhanced.hapticsClickable import ru.tech.imageresizershrinker.core.ui.widget.image.AutoFilePicker -import ru.tech.imageresizershrinker.core.ui.widget.image.UrisPreview -import ru.tech.imageresizershrinker.core.ui.widget.modifier.container +import ru.tech.imageresizershrinker.core.ui.widget.image.FileNotPickedWidget import ru.tech.imageresizershrinker.core.ui.widget.other.TopAppBarEmoji -import ru.tech.imageresizershrinker.core.ui.widget.text.AutoSizeText -import ru.tech.imageresizershrinker.core.ui.widget.text.RoundedTextField import ru.tech.imageresizershrinker.core.ui.widget.text.marquee +import ru.tech.imageresizershrinker.feature.zip.presentation.components.ZipControls import ru.tech.imageresizershrinker.feature.zip.presentation.screenLogic.ZipComponent -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale @Composable fun ZipContent( component: ZipComponent ) { - val settingsState = LocalSettingsState.current - - val essentials = rememberLocalEssentials() - val showConfetti: () -> Unit = essentials::showConfetti - var showExitDialog by rememberSaveable { mutableStateOf(false) } val onBack = { @@ -102,17 +59,7 @@ fun ZipContent( } else component.onGoBack() } - val saveLauncher = rememberLauncherForActivityResult( - contract = ActivityResultContracts.CreateDocument("application/zip"), - onResult = { - it?.let { uri -> - component.saveResultTo( - uri = uri, - onResult = essentials::parseFileSaveResult - ) - } - } - ) + val essentials = rememberLocalEssentials() val filePicker = rememberFilePicker(onSuccess = component::setUris) @@ -121,8 +68,6 @@ fun ZipContent( isPickedAlready = !component.initialUris.isNullOrEmpty() ) - val additionalFilePicker = rememberFilePicker(onSuccess = component::addUris) - val isPortrait by isPortraitOrientationAsState() AdaptiveLayoutScreen( @@ -142,186 +87,12 @@ fun ZipContent( showImagePreviewAsStickyHeader = false, placeImagePreview = false, noDataControls = { - Column( - modifier = Modifier.container(), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - ) { - Spacer(Modifier.height(16.dp)) - Icon( - imageVector = Icons.TwoTone.FileOpen, - contentDescription = null, - modifier = Modifier - .size(100.dp) - .container( - shape = CloverShape, - resultPadding = 0.dp, - color = MaterialTheme.colorScheme.secondaryContainer - ) - .hapticsClickable(onClick = filePicker::pickFile) - .padding(12.dp), - tint = MaterialTheme.colorScheme.onSecondaryContainer - ) - Text( - text = stringResource(R.string.pick_file_to_start), - modifier = Modifier.padding(16.dp), - textAlign = TextAlign.Center, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) - } + FileNotPickedWidget(onPickFile = filePicker::pickFile) }, controls = { - AnimatedVisibility(visible = component.byteArray != null) { - LaunchedEffect(it) { - it.animateScrollToItem(0) - } - Column( - modifier = Modifier - .fillMaxWidth() - .padding(top = 24.dp) - .container( - shape = MaterialTheme.shapes.extraLarge, - color = MaterialTheme - .colorScheme - .surfaceContainerHighest, - resultPadding = 0.dp - ) - .padding(16.dp) - ) { - Row(verticalAlignment = Alignment.CenterVertically) { - Icon( - imageVector = Icons.Rounded.CheckCircle, - contentDescription = null, - tint = Green, - modifier = Modifier - .size(36.dp) - .background( - color = MaterialTheme.colorScheme.surface, - shape = CircleShape - ) - .border( - width = settingsState.borderWidth, - color = MaterialTheme.colorScheme.outlineVariant(), - shape = CircleShape - ) - .padding(4.dp) - ) - Spacer(modifier = Modifier.width(16.dp)) - Text( - stringResource(R.string.file_proceed), - fontSize = 17.sp, - fontWeight = FontWeight.Medium - ) - } - Text( - text = stringResource(R.string.store_file_desc), - fontSize = 13.sp, - color = LocalContentColor.current.copy(alpha = 0.7f), - lineHeight = 14.sp, - modifier = Modifier.padding(vertical = 16.dp) - ) - var name by rememberSaveable(component.byteArray, component.uris) { - val count = component.uris.size.let { - if (it > 1) "($it)" - else "" - } - val timeStamp = SimpleDateFormat( - "yyyy-MM-dd_HH-mm-ss", - Locale.getDefault() - ).format(Date()) - - mutableStateOf("ZIP${count}_$timeStamp.zip") - } - RoundedTextField( - modifier = Modifier - .padding(top = 8.dp) - .container( - shape = MaterialTheme.shapes.large, - resultPadding = 8.dp - ), - value = name, - keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), - singleLine = false, - onValueChange = { name = it }, - label = { - Text(stringResource(R.string.filename)) - } - ) - - Row( - modifier = Modifier - .padding(top = 24.dp) - .fillMaxWidth() - ) { - EnhancedButton( - onClick = { - runCatching { - saveLauncher.launch(name) - }.onFailure { - essentials.showActivateFilesToast() - } - }, - modifier = Modifier - .padding(end = 8.dp) - .fillMaxWidth(0.5f) - .height(50.dp), - containerColor = MaterialTheme.colorScheme.secondaryContainer - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { - Icon( - imageVector = Icons.Rounded.FileDownload, - contentDescription = null - ) - Spacer(modifier = Modifier.width(8.dp)) - AutoSizeText( - text = stringResource(id = R.string.save), - maxLines = 1 - ) - } - } - EnhancedButton( - onClick = { - component.byteArray?.let { - component.shareFile( - it = it, - filename = name, - onComplete = showConfetti - ) - } - }, - modifier = Modifier - .padding(start = 8.dp) - .fillMaxWidth() - .height(50.dp), - containerColor = MaterialTheme.colorScheme.secondaryContainer - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { - Icon( - imageVector = Icons.Rounded.Share, - contentDescription = stringResource(R.string.share) - ) - Spacer(modifier = Modifier.width(8.dp)) - AutoSizeText( - text = stringResource(id = R.string.share), - maxLines = 1 - ) - } - } - } - } - } - Spacer(modifier = Modifier.height(24.dp)) - UrisPreview( - uris = component.uris, - isPortrait = isPortrait, - onRemoveUri = component::removeUri, - onAddUris = additionalFilePicker::pickFile + ZipControls( + component = component, + lazyListState = it ) }, buttons = { @@ -332,13 +103,7 @@ fun ZipContent( secondaryButtonText = stringResource(R.string.pick_file), isPrimaryButtonVisible = component.uris.isNotEmpty(), onPrimaryButtonClick = { - component.startCompression { - if (it != null) { - essentials.showFailureToast( - throwable = it - ) - } - } + component.startCompression(essentials::showFailureToast) }, actions = { EnhancedChip( diff --git a/feature/zip/src/main/java/ru/tech/imageresizershrinker/feature/zip/presentation/components/ZipControls.kt b/feature/zip/src/main/java/ru/tech/imageresizershrinker/feature/zip/presentation/components/ZipControls.kt new file mode 100644 index 0000000000..f3e7f06e52 --- /dev/null +++ b/feature/zip/src/main/java/ru/tech/imageresizershrinker/feature/zip/presentation/components/ZipControls.kt @@ -0,0 +1,253 @@ +/* + * ImageToolbox is an image editor for android + * Copyright (c) 2025 T8RIN (Malik Mukhametzyanov) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * You should have received a copy of the Apache License + * along with this program. If not, see . + */ + +package ru.tech.imageresizershrinker.feature.zip.presentation.components + +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.CheckCircle +import androidx.compose.material.icons.rounded.FileDownload +import androidx.compose.material.icons.rounded.Share +import androidx.compose.material3.Icon +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import ru.tech.imageresizershrinker.core.resources.R +import ru.tech.imageresizershrinker.core.settings.presentation.provider.LocalSettingsState +import ru.tech.imageresizershrinker.core.ui.theme.Green +import ru.tech.imageresizershrinker.core.ui.theme.outlineVariant +import ru.tech.imageresizershrinker.core.ui.utils.content_pickers.rememberFilePicker +import ru.tech.imageresizershrinker.core.ui.utils.helper.isPortraitOrientationAsState +import ru.tech.imageresizershrinker.core.ui.utils.provider.rememberLocalEssentials +import ru.tech.imageresizershrinker.core.ui.widget.enhanced.EnhancedButton +import ru.tech.imageresizershrinker.core.ui.widget.image.UrisPreview +import ru.tech.imageresizershrinker.core.ui.widget.modifier.container +import ru.tech.imageresizershrinker.core.ui.widget.text.AutoSizeText +import ru.tech.imageresizershrinker.core.ui.widget.text.RoundedTextField +import ru.tech.imageresizershrinker.feature.zip.presentation.screenLogic.ZipComponent +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale + +@Composable +internal fun ColumnScope.ZipControls( + component: ZipComponent, + lazyListState: LazyListState +) { + val isPortrait by isPortraitOrientationAsState() + val settingsState = LocalSettingsState.current + + val essentials = rememberLocalEssentials() + val showConfetti: () -> Unit = essentials::showConfetti + + val saveLauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.CreateDocument("application/zip"), + onResult = { + it?.let { uri -> + component.saveResultTo( + uri = uri, + onResult = essentials::parseFileSaveResult + ) + } + } + ) + + val additionalFilePicker = rememberFilePicker(onSuccess = component::addUris) + + AnimatedVisibility(visible = component.byteArray != null) { + LaunchedEffect(lazyListState) { + lazyListState.animateScrollToItem(0) + } + Column( + modifier = Modifier + .fillMaxWidth() + .padding(top = 24.dp) + .container( + shape = MaterialTheme.shapes.extraLarge, + color = MaterialTheme + .colorScheme + .surfaceContainerHighest, + resultPadding = 0.dp + ) + .padding(16.dp) + ) { + Row(verticalAlignment = Alignment.CenterVertically) { + Icon( + imageVector = Icons.Rounded.CheckCircle, + contentDescription = null, + tint = Green, + modifier = Modifier + .size(36.dp) + .background( + color = MaterialTheme.colorScheme.surface, + shape = CircleShape + ) + .border( + width = settingsState.borderWidth, + color = MaterialTheme.colorScheme.outlineVariant(), + shape = CircleShape + ) + .padding(4.dp) + ) + Spacer(modifier = Modifier.width(16.dp)) + Text( + stringResource(R.string.file_proceed), + fontSize = 17.sp, + fontWeight = FontWeight.Medium + ) + } + Text( + text = stringResource(R.string.store_file_desc), + fontSize = 13.sp, + color = LocalContentColor.current.copy(alpha = 0.7f), + lineHeight = 14.sp, + modifier = Modifier.padding(vertical = 16.dp) + ) + var name by rememberSaveable(component.byteArray, component.uris) { + val count = component.uris.size.let { + if (it > 1) "($it)" + else "" + } + val timeStamp = SimpleDateFormat( + "yyyy-MM-dd_HH-mm-ss", + Locale.getDefault() + ).format(Date()) + + mutableStateOf("ZIP${count}_$timeStamp.zip") + } + RoundedTextField( + modifier = Modifier + .padding(top = 8.dp) + .container( + shape = MaterialTheme.shapes.large, + resultPadding = 8.dp + ), + value = name, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), + singleLine = false, + onValueChange = { name = it }, + label = { + Text(stringResource(R.string.filename)) + } + ) + + Row( + modifier = Modifier + .padding(top = 24.dp) + .fillMaxWidth() + ) { + EnhancedButton( + onClick = { + runCatching { + saveLauncher.launch(name) + }.onFailure { + essentials.showActivateFilesToast() + } + }, + modifier = Modifier + .padding(end = 8.dp) + .fillMaxWidth(0.5f) + .height(50.dp), + containerColor = MaterialTheme.colorScheme.secondaryContainer + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Icon( + imageVector = Icons.Rounded.FileDownload, + contentDescription = null + ) + Spacer(modifier = Modifier.width(8.dp)) + AutoSizeText( + text = stringResource(id = R.string.save), + maxLines = 1 + ) + } + } + EnhancedButton( + onClick = { + component.byteArray?.let { + component.shareFile( + it = it, + filename = name, + onComplete = showConfetti + ) + } + }, + modifier = Modifier + .padding(start = 8.dp) + .fillMaxWidth() + .height(50.dp), + containerColor = MaterialTheme.colorScheme.secondaryContainer + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Icon( + imageVector = Icons.Rounded.Share, + contentDescription = stringResource(R.string.share) + ) + Spacer(modifier = Modifier.width(8.dp)) + AutoSizeText( + text = stringResource(id = R.string.share), + maxLines = 1 + ) + } + } + } + } + } + Spacer(modifier = Modifier.height(24.dp)) + UrisPreview( + uris = component.uris, + isPortrait = isPortrait, + onRemoveUri = component::removeUri, + onAddUris = additionalFilePicker::pickFile + ) +} \ No newline at end of file diff --git a/feature/zip/src/main/java/ru/tech/imageresizershrinker/feature/zip/presentation/screenLogic/ZipComponent.kt b/feature/zip/src/main/java/ru/tech/imageresizershrinker/feature/zip/presentation/screenLogic/ZipComponent.kt index d29b3272b3..4d0333afaa 100644 --- a/feature/zip/src/main/java/ru/tech/imageresizershrinker/feature/zip/presentation/screenLogic/ZipComponent.kt +++ b/feature/zip/src/main/java/ru/tech/imageresizershrinker/feature/zip/presentation/screenLogic/ZipComponent.kt @@ -78,12 +78,11 @@ class ZipComponent @AssistedInject internal constructor( } fun startCompression( - onComplete: (Throwable?) -> Unit + onFailure: (Throwable) -> Unit ) { savingJob = componentScope.launch(defaultDispatcher) { _isSaving.value = true if (uris.isEmpty()) { - onComplete(null) return@launch } runCatching { @@ -95,7 +94,7 @@ class ZipComponent @AssistedInject internal constructor( _done.update { it + 1 } } ) - }.onFailure(onComplete) + }.onFailure(onFailure) _isSaving.value = false } }