Add camera button in the stories screen

This commit is contained in:
greenart7c3 2024-09-09 15:37:30 -03:00
parent 2e110422c8
commit 1e3104d489
No known key found for this signature in database
GPG Key ID: 885822EED3A26A6D
3 changed files with 140 additions and 39 deletions

View File

@ -21,11 +21,9 @@
package com.vitorpamplona.amethyst.ui.actions
import android.Manifest
import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.util.Log
import android.util.Size
import android.widget.Toast
@ -123,7 +121,6 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.core.content.FileProvider
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
@ -189,11 +186,7 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import java.io.File
import java.lang.Math.round
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
@OptIn(ExperimentalMaterial3Api::class, FlowPreview::class)
@Composable
@ -645,23 +638,6 @@ private fun BottomRowActions(postViewModel: NewPostViewModel) {
}
}
fun getPhotoUri(context: Context): Uri {
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())
val storageDir: File? = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
return File
.createTempFile(
"JPEG_${timeStamp}_",
".jpg",
storageDir,
).let {
FileProvider.getUriForFile(
context,
"${context.packageName}.provider",
it,
)
}
}
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun TakePictureButton(onPictureTaken: (Uri) -> Unit) {

View File

@ -20,8 +20,10 @@
*/
package com.vitorpamplona.amethyst.ui.actions
import android.content.Context
import android.net.Uri
import android.os.Build
import android.os.Environment
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.animateFloat
@ -52,6 +54,7 @@ import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.core.content.FileProvider
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
@ -60,6 +63,10 @@ import com.vitorpamplona.amethyst.ui.GetMediaActivityResultContract
import com.vitorpamplona.amethyst.ui.stringRes
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.concurrent.atomic.AtomicBoolean
@OptIn(ExperimentalPermissionsApi::class)
@ -125,6 +132,23 @@ private fun UploadBoxButton(
}
}
fun getPhotoUri(context: Context): Uri {
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())
val storageDir: File? = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
return File
.createTempFile(
"JPEG_${timeStamp}_",
".jpg",
storageDir,
).let {
FileProvider.getUriForFile(
context,
"${context.packageName}.provider",
it,
)
}
}
val DefaultAnimationColors =
listOf(
Color(0xFF5851D8),

View File

@ -23,11 +23,19 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.video
import android.Manifest
import android.net.Uri
import android.os.Build
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AddPhotoAlternate
import androidx.compose.material.icons.filled.CameraAlt
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
@ -45,6 +53,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
@ -57,6 +66,7 @@ import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.actions.GallerySelect
import com.vitorpamplona.amethyst.ui.actions.NewMediaModel
import com.vitorpamplona.amethyst.ui.actions.NewMediaView
import com.vitorpamplona.amethyst.ui.actions.getPhotoUri
import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.stringRes
@ -73,7 +83,15 @@ fun NewImageButton(
nav: INav,
navScrollToTop: () -> Unit,
) {
var wantsToPost by remember { mutableStateOf(false) }
val context = LocalContext.current
var isOpen by remember { mutableStateOf(false) }
var wantsToPostFromGallery by remember { mutableStateOf(false) }
var wantsToPostFromCamera by remember { mutableStateOf(false) }
var cameraUri by remember { mutableStateOf<Uri?>(null) }
var pickedURI by remember { mutableStateOf<Uri?>(null) }
@ -87,7 +105,46 @@ fun NewImageButton(
}
}
if (wantsToPost) {
if (wantsToPostFromCamera) {
val launcher =
rememberLauncherForActivityResult(
contract = ActivityResultContracts.TakePicture(),
) { success ->
if (success) {
cameraUri?.let {
pickedURI = it
}
}
cameraUri = null
wantsToPostFromCamera = false
}
val cameraPermissionState =
rememberPermissionState(
Manifest.permission.CAMERA,
onPermissionResult = {
if (it) {
scope.launch(Dispatchers.IO) {
cameraUri = getPhotoUri(context)
cameraUri?.let { launcher.launch(it) }
}
}
},
)
if (cameraPermissionState.status.isGranted) {
LaunchedEffect(key1 = accountViewModel) {
launch(Dispatchers.IO) {
cameraUri = getPhotoUri(context)
cameraUri?.let { launcher.launch(it) }
}
}
} else {
LaunchedEffect(key1 = accountViewModel) { cameraPermissionState.launchPermissionRequest() }
}
}
if (wantsToPostFromGallery) {
val cameraPermissionState =
rememberPermissionState(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
@ -102,7 +159,7 @@ fun NewImageButton(
if (showGallerySelect) {
GallerySelect(
onImageUri = { uri ->
wantsToPost = false
wantsToPostFromGallery = false
showGallerySelect = false
pickedURI = uri
},
@ -128,18 +185,62 @@ fun NewImageButton(
if (postViewModel.isUploadingImage) {
ShowProgress(postViewModel)
} else {
FloatingActionButton(
onClick = { wantsToPost = true },
modifier = Size55Modifier,
shape = CircleShape,
containerColor = MaterialTheme.colorScheme.primary,
) {
Icon(
painter = painterResource(R.drawable.ic_compose),
contentDescription = stringRes(id = R.string.new_short),
modifier = Modifier.size(26.dp),
tint = Color.White,
)
Column {
if (isOpen) {
FloatingActionButton(
onClick = {
wantsToPostFromCamera = true
isOpen = false
},
modifier = Size55Modifier,
shape = CircleShape,
containerColor = MaterialTheme.colorScheme.primary,
) {
Icon(
imageVector = Icons.Default.CameraAlt,
contentDescription = stringRes(id = R.string.upload_image),
modifier = Modifier.size(26.dp),
tint = Color.White,
)
}
Spacer(modifier = Modifier.height(20.dp))
FloatingActionButton(
onClick = {
wantsToPostFromGallery = true
isOpen = false
},
modifier = Size55Modifier,
shape = CircleShape,
containerColor = MaterialTheme.colorScheme.primary,
) {
Icon(
imageVector = Icons.Default.AddPhotoAlternate,
contentDescription = stringRes(id = R.string.upload_image),
modifier = Modifier.size(26.dp),
tint = Color.White,
)
}
Spacer(modifier = Modifier.height(20.dp))
}
FloatingActionButton(
onClick = {
isOpen = !isOpen
},
modifier = Size55Modifier,
shape = CircleShape,
containerColor = MaterialTheme.colorScheme.primary,
) {
Icon(
painter = painterResource(R.drawable.ic_compose),
contentDescription = stringRes(id = R.string.new_short),
modifier = Modifier.size(26.dp),
tint = Color.White,
)
}
}
}
}