diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/TakePicture.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/TakePicture.kt index b5675ee8a..05bfb1442 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/TakePicture.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/TakePicture.kt @@ -29,6 +29,7 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.height import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.CameraAlt +import androidx.compose.material.icons.filled.Videocam import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -152,3 +153,99 @@ fun getPhotoUri(context: Context): Uri { ) } } + +@Composable +fun TakeVideoButton(onVideoTaken: (ImmutableList) -> Unit) { + var showCamera by remember { mutableStateOf(false) } + if (showCamera) { + TakeVideo( + onVideoTaken = { uri -> + showCamera = false + if (uri.isNotEmpty()) { + onVideoTaken(uri) + } + }, + ) + } + + VideoButton { showCamera = true } +} + +@OptIn(ExperimentalPermissionsApi::class) +@Composable +fun TakeVideo(onVideoTaken: (ImmutableList) -> Unit) { + val context = LocalContext.current + var videoUri by remember { mutableStateOf(null) } + val scope = rememberCoroutineScope() + + val launcher = + rememberLauncherForActivityResult( + contract = ActivityResultContracts.CaptureVideo(), + ) { success -> + if (success) { + videoUri?.let { + onVideoTaken(persistentListOf(SelectedMedia(it, "video/mp4"))) + } + } else { + onVideoTaken(persistentListOf()) + } + videoUri = null + } + + val cameraPermissionState = + rememberPermissionState( + Manifest.permission.CAMERA, + onPermissionResult = { + if (it) { + scope.launch(Dispatchers.IO) { + videoUri = getVideoUri(context) + videoUri?.let { launcher.launch(it) } + } + } + }, + ) + + if (cameraPermissionState.status.isGranted) { + LaunchedEffect(key1 = Unit) { + launch(Dispatchers.IO) { + videoUri = getVideoUri(context) + videoUri?.let { launcher.launch(it) } + } + } + } else { + LaunchedEffect(key1 = Unit) { + cameraPermissionState.launchPermissionRequest() + } + } +} + +@Composable +fun VideoButton(onClick: () -> Unit) { + IconButton( + onClick = onClick, + ) { + Icon( + imageVector = Icons.Default.Videocam, + contentDescription = stringRes(id = R.string.record_a_video), + modifier = Modifier.height(22.dp), + tint = MaterialTheme.colorScheme.onBackground, + ) + } +} + +fun getVideoUri(context: Context): Uri { + val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date()) + val storageDir: File? = context.getExternalFilesDir(Environment.DIRECTORY_MOVIES) + return File + .createTempFile( + "MP4_${timeStamp}_", + ".mp4", + storageDir, + ).let { + FileProvider.getUriForFile( + context, + "${context.packageName}.provider", + it, + ) + } +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostScreen.kt index 2d95deecc..1929fc017 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostScreen.kt @@ -60,6 +60,7 @@ import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerType import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.TakePictureButton +import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideoButton import com.vitorpamplona.amethyst.ui.components.getActivity import com.vitorpamplona.amethyst.ui.navigation.navs.Nav import com.vitorpamplona.amethyst.ui.navigation.topbars.PostingTopBar @@ -431,6 +432,12 @@ private fun BottomRowActions(postViewModel: ShortNotePostViewModel) { }, ) + TakeVideoButton( + onVideoTaken = { + postViewModel.selectImage(it) + }, + ) + if (postViewModel.canUsePoll) { // These should be hashtag recommendations the user selects in the future. // val hashtag = stringRes(R.string.poll_hashtag) diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index 6b7c23159..175d30684 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -160,6 +160,7 @@ Failed to save the video Upload Image Take a picture + Record a video Record a message Record a message Click and hold to record a message