diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt index 805362dd7..35597a447 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt @@ -218,7 +218,9 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n Row(modifier = Modifier.fillMaxWidth()) { UploadFromGallery( - isUploading = postViewModel.isUploadingImage + isUploading = postViewModel.isUploadingImage, + tint = MaterialTheme.colors.primary, + modifier = Modifier.padding(bottom = 10.dp) ) { postViewModel.upload(it, context) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt index 1d15d88a4..d8797f355 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt @@ -4,23 +4,38 @@ import android.net.Uri import android.os.Build import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.animateFloat +import androidx.compose.animation.core.infiniteRepeatable +import androidx.compose.animation.core.rememberInfiniteTransition +import androidx.compose.animation.core.tween +import androidx.compose.foundation.border import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.AddPhotoAlternate import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.rememberPermissionState import com.vitorpamplona.amethyst.R +import java.util.concurrent.atomic.AtomicBoolean @OptIn(ExperimentalPermissionsApi::class) @Composable fun UploadFromGallery( isUploading: Boolean, + tint: Color, + modifier: Modifier, onImageChosen: (Uri) -> Unit ) { val cameraPermissionState = @@ -43,13 +58,13 @@ fun UploadFromGallery( } } ) - } else { - UploadBoxButton(isUploading) { - showGallerySelect = true - } + } + + UploadBoxButton(isUploading, tint, modifier) { + showGallerySelect = true } } else { - UploadBoxButton(isUploading) { + UploadBoxButton(isUploading, tint, modifier) { cameraPermissionState.launchPermissionRequest() } } @@ -58,50 +73,96 @@ fun UploadFromGallery( @Composable private fun UploadBoxButton( isUploading: Boolean, + tint: Color, + modifier: Modifier, onClick: () -> Unit ) { Box() { - TextButton( - modifier = Modifier - .align(Alignment.TopCenter), + IconButton( + modifier = modifier.align(Alignment.Center), enabled = !isUploading, onClick = { onClick() } ) { - Icon( - painter = painterResource(id = R.drawable.ic_add_photo), - contentDescription = stringResource(id = R.string.upload_image), - modifier = Modifier - .height(20.dp) - .padding(end = 8.dp), - tint = MaterialTheme.colors.primary - ) - if (!isUploading) { - Text(stringResource(R.string.upload_image)) + Icon( + imageVector = Icons.Default.AddPhotoAlternate, + contentDescription = stringResource(id = R.string.upload_image), + modifier = Modifier.height(25.dp), + tint = tint + ) } else { - Text(stringResource(R.string.uploading)) + LoadingAnimation() } } } } +@Composable +fun LoadingAnimation( + indicatorSize: Dp = 20.dp, + circleColors: List = listOf( + Color(0xFF5851D8), + Color(0xFF833AB4), + Color(0xFFC13584), + Color(0xFFE1306C), + Color(0xFFFD1D1D), + Color(0xFFF56040), + Color(0xFFF77737), + Color(0xFFFCAF45), + Color(0xFFFFDC80), + Color(0xFF5851D8) + ), + animationDuration: Int = 1000 +) { + val infiniteTransition = rememberInfiniteTransition() + + val rotateAnimation by infiniteTransition.animateFloat( + initialValue = 0f, + targetValue = 360f, + animationSpec = infiniteRepeatable( + animation = tween( + durationMillis = animationDuration, + easing = LinearEasing + ) + ) + ) + + CircularProgressIndicator( + modifier = Modifier + .size(size = indicatorSize) + .rotate(degrees = rotateAnimation) + .border( + width = 4.dp, + brush = Brush.sweepGradient(circleColors), + shape = CircleShape + ), + progress = 1f, + strokeWidth = 1.dp, + color = MaterialTheme.colors.background // Set background color + ) +} + @Composable fun GallerySelect( onImageUri: (Uri?) -> Unit = { } ) { + var hasLaunched by remember { mutableStateOf(AtomicBoolean(false)) } val launcher = rememberLauncherForActivityResult( contract = ActivityResultContracts.GetContent(), onResult = { uri: Uri? -> onImageUri(uri) + hasLaunched.set(false) } ) @Composable fun LaunchGallery() { SideEffect { - launcher.launch("image/*") + if (!hasLaunched.getAndSet(true)) { + launcher.launch("image/*") + } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt index 6aaab262c..20fa53f64 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt @@ -178,13 +178,6 @@ fun ChannelScreen( } } - Row(modifier = Modifier.fillMaxWidth()) { - UploadFromGallery( - isUploading = channelScreenModel.isUploadingImage - ) { - channelScreenModel.upload(it, context) - } - } // LAST ROW Row( modifier = Modifier.padding(start = 10.dp, end = 10.dp, bottom = 10.dp, top = 5.dp).fillMaxWidth(), @@ -220,6 +213,15 @@ fun ChannelScreen( modifier = Modifier.padding(end = 10.dp) ) }, + leadingIcon = { + UploadFromGallery( + isUploading = channelScreenModel.isUploadingImage, + tint = MaterialTheme.colors.onSurface.copy(alpha = 0.32f), + modifier = Modifier.padding(start = 5.dp) + ) { + channelScreenModel.upload(it, context) + } + }, colors = TextFieldDefaults.textFieldColors( focusedIndicatorColor = Color.Transparent, unfocusedIndicatorColor = Color.Transparent diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt index 37a0d0477..2eb2588b7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt @@ -156,13 +156,6 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr } } - Row(modifier = Modifier.fillMaxWidth()) { - UploadFromGallery( - isUploading = chatRoomScreenModel.isUploadingImage - ) { - chatRoomScreenModel.upload(it, context) - } - } // LAST ROW Row( modifier = Modifier.padding(start = 10.dp, end = 10.dp, bottom = 10.dp, top = 5.dp) @@ -193,10 +186,19 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr replyTo.value = null feedViewModel.refresh() // Don't wait a full second before updating }, - isActive = chatRoomScreenModel.message.text.isNotBlank() && !chatRoomScreenModel.isUploadingImage, - modifier = Modifier.padding(end = 10.dp), + isActive = chatRoomScreenModel.message.text.isNotBlank() && !chatRoomScreenModel.isUploadingImage, + modifier = Modifier.padding(end = 10.dp) ) }, + leadingIcon = { + UploadFromGallery( + isUploading = chatRoomScreenModel.isUploadingImage, + tint = MaterialTheme.colors.onSurface.copy(alpha = 0.32f), + modifier = Modifier.padding(start = 5.dp) + ) { + chatRoomScreenModel.upload(it, context) + } + }, colors = TextFieldDefaults.textFieldColors( focusedIndicatorColor = Color.Transparent, unfocusedIndicatorColor = Color.Transparent