From 70927bd1a4941fb28745197348bf6f380d7f560f Mon Sep 17 00:00:00 2001 From: Infi Date: Sun, 30 Jun 2024 19:32:53 +0200 Subject: [PATCH] feat: graduate VVA2 to GA Signed-off-by: Infi --- app/src/main/AndroidManifest.xml | 5 - .../activities/media/VideoViewActivity.kt | 322 +++++++----------- .../activities/media/VideoViewActivity2.kt | 220 ------------ .../chat/revolt/api/settings/FeatureFlags.kt | 26 -- .../chat/revolt/components/chat/Message.kt | 7 +- 5 files changed, 117 insertions(+), 463 deletions(-) delete mode 100644 app/src/main/java/chat/revolt/activities/media/VideoViewActivity2.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 77d1bcec..502600a2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -118,11 +118,6 @@ android:configChanges="orientation|screenSize" android:theme="@style/Theme.Revolt" /> - - { + downloadFile(autumnResource, resourceUrl) + true + } + + R.id.mi_share_file -> { + shareFile(autumnResource, resourceUrl) + true + } + + R.id.mi_share_link -> { + shareUrl(resourceUrl) + true + } + + else -> false + } } + + player = ExoPlayer.Builder(this).build().apply { + setMediaItem(MediaItem.fromUri(resourceUrl)) + prepare() + play() + } + + binding.xpPlayer.player = player + binding.xpPlayer.setFullscreenButtonClickListener { + when (binding.alTop.visibility) { + android.view.View.VISIBLE -> { + binding.alTop.visibility = android.view.View.GONE + WindowInsetsControllerCompat(window, binding.root).let { controller -> + controller.hide(WindowInsetsCompat.Type.systemBars()) + controller.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + } + binding.xpPlayer.background = ColorDrawable(Color.BLACK) + } + + else -> { + binding.alTop.visibility = android.view.View.VISIBLE + WindowInsetsControllerCompat(window, binding.root).let { controller -> + controller.show(WindowInsetsCompat.Type.systemBars()) + controller.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_DEFAULT + } + binding.xpPlayer.background = null + } + } + } + + + setContentView(binding.root) } -} -@OptIn(ExperimentalMaterial3Api::class) -@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) -@Composable -fun VideoViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) { - val resourceUrl = "$REVOLT_FILES/attachments/${resource.id}/${resource.filename}" + override fun onDestroy() { + super.onDestroy() + player?.release() + } - val context = LocalContext.current - val coroutineScope = rememberCoroutineScope() - val activityLauncher = rememberLauncherForActivityResult( - ActivityResultContracts.StartActivityForResult() - ) {} - - val shareSubmenuIsOpen = remember { mutableStateOf(false) } - val snackbarHostState = remember { SnackbarHostState() } - - fun shareUrl() { - shareSubmenuIsOpen.value = false + override fun onPause() { + super.onPause() + player?.pause() + } + private fun shareUrl(resourceUrl: String) { val intent = Intent(Intent.ACTION_SEND) intent.type = "text/plain" @@ -111,15 +133,13 @@ fun VideoViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) { ) val shareIntent = Intent.createChooser(intent, null) - activityLauncher.launch(shareIntent) + startActivity(shareIntent) } - fun shareVideo() { - shareSubmenuIsOpen.value = false - - coroutineScope.launch { + private fun shareFile(resource: AutumnResource, resourceUrl: String) { + lifecycleScope.launch { val contentUri = getAttachmentContentUri( - context, + this@VideoViewActivity, resourceUrl, resource.id!!, resource.filename ?: "video" @@ -128,19 +148,27 @@ fun VideoViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) { val intent = Intent(Intent.ACTION_SEND) intent.type = resource.contentType ?: "video/*" + intent.putExtra( + Intent.EXTRA_TITLE, + resource.filename + ) + intent.putExtra( + Intent.EXTRA_SUBJECT, + resource.filename + ) intent.putExtra( Intent.EXTRA_STREAM, contentUri ) val shareIntent = Intent.createChooser(intent, null) - activityLauncher.launch(shareIntent) + startActivity(shareIntent) } } - fun saveToGallery() { - coroutineScope.launch { - context.applicationContext.let { + private fun downloadFile(resource: AutumnResource, resourceUrl: String) { + lifecycleScope.launch { + this@VideoViewActivity.applicationContext.let { it.contentResolver.insert( MediaStore.Video.Media.EXTERNAL_CONTENT_URI, ContentValues().apply { @@ -151,11 +179,11 @@ fun VideoViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) { } ) }?.let { uri -> - context.contentResolver.openOutputStream(uri).use { stream -> + this@VideoViewActivity.contentResolver.openOutputStream(uri).use { stream -> val video = RevoltHttp.get(resourceUrl).readBytes() stream?.write(video) - context.applicationContext.let { + this@VideoViewActivity.applicationContext.let { it.contentResolver.update( uri, ContentValues().apply { @@ -166,145 +194,27 @@ fun VideoViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) { ) } - val snackbar = snackbarHostState.showSnackbar( - message = context.getString(R.string.media_viewer_saved), - actionLabel = context.getString(R.string.media_viewer_open), - duration = SnackbarDuration.Short - ) - - if (snackbar == SnackbarResult.ActionPerformed) { + Snackbar.make( + binding.xpPlayer, + R.string.media_viewer_saved, + Snackbar.LENGTH_SHORT + ).setAction( + R.string.media_viewer_open + ) { val intent = Intent(Intent.ACTION_VIEW) intent.setDataAndType(uri, resource.contentType) intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION - activityLauncher.launch(intent) + startActivity(intent) } - } - } - } - } - - val player = remember { - ExoPlayer.Builder(context).build().apply { - setMediaItem(MediaItem.fromUri(resourceUrl)) - prepare() - play() - } - } - - DisposableEffect(player) { - onDispose { - player.release() - } - } - - RevoltTheme( - requestedTheme = GlobalState.theme, - colourOverrides = SyncedSettings.android.colourOverrides - ) { - Scaffold( - topBar = { - TopAppBar( - title = { - Text( - text = stringResource( - id = R.string.media_viewer_title_video, - resource.filename ?: resource.id!! - ), - maxLines = 1, - overflow = TextOverflow.Ellipsis, + .setActionTextColor( + MaterialColors.getColor( + binding.xpPlayer, + com.google.android.material.R.attr.colorPrimary + ) ) - }, - navigationIcon = { - IconButton(onClick = { - onClose() - }) { - Icon( - imageVector = Icons.AutoMirrored.Default.ArrowBack, - contentDescription = stringResource(id = R.string.back) - ) - } - }, - actions = { - IconButton(onClick = { - shareSubmenuIsOpen.value = true - }) { - Icon( - painter = painterResource(id = R.drawable.ic_share_24dp), - contentDescription = stringResource(id = R.string.share) - ) - } - - DropdownMenu( - expanded = shareSubmenuIsOpen.value, - onDismissRequest = { - shareSubmenuIsOpen.value = false - } - ) { - DropdownMenuItem( - onClick = { - shareUrl() - }, - text = { - Text( - stringResource(id = R.string.media_viewer_share_url) - ) - } - ) - DropdownMenuItem( - onClick = { - shareVideo() - }, - text = { - Text( - stringResource( - id = R.string.media_viewer_share_video - ) - ) - } - ) - } - - IconButton(onClick = { - saveToGallery() - }) { - Icon( - painter = painterResource(id = R.drawable.ic_download_24dp), - contentDescription = stringResource( - id = R.string.media_viewer_save - ) - ) - } - } - ) - }, - snackbarHost = { SnackbarHost(hostState = snackbarHostState) } - ) { pv -> - Surface( - modifier = Modifier - .padding(pv) - .background(MaterialTheme.colorScheme.background) - .fillMaxSize() - ) { - Box( - modifier = Modifier - .clip(RectangleShape) - .fillMaxSize() - ) { - AndroidView( - factory = { context -> - PlayerView(context).apply { - setShowBuffering(PlayerView.SHOW_BUFFERING_ALWAYS) - } - }, - update = { - it.player = player - }, - modifier = Modifier - .fillMaxSize() - .background(MaterialTheme.colorScheme.background) - ) + .show() } } } } -} +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/activities/media/VideoViewActivity2.kt b/app/src/main/java/chat/revolt/activities/media/VideoViewActivity2.kt deleted file mode 100644 index d5dcbe2b..00000000 --- a/app/src/main/java/chat/revolt/activities/media/VideoViewActivity2.kt +++ /dev/null @@ -1,220 +0,0 @@ -package chat.revolt.activities.media - -import android.content.ContentValues -import android.content.Intent -import android.graphics.Color -import android.graphics.drawable.ColorDrawable -import android.os.Build -import android.os.Bundle -import android.provider.MediaStore -import android.util.Log -import androidx.core.view.WindowCompat -import androidx.core.view.WindowInsetsCompat -import androidx.core.view.WindowInsetsControllerCompat -import androidx.fragment.app.FragmentActivity -import androidx.lifecycle.lifecycleScope -import androidx.media3.common.MediaItem -import androidx.media3.exoplayer.ExoPlayer -import chat.revolt.R -import chat.revolt.api.REVOLT_FILES -import chat.revolt.api.RevoltHttp -import chat.revolt.api.schemas.AutumnResource -import chat.revolt.databinding.ActivityVideoplayerBinding -import chat.revolt.provider.getAttachmentContentUri -import com.google.android.material.color.MaterialColors -import com.google.android.material.snackbar.Snackbar -import io.ktor.client.request.get -import io.ktor.client.statement.readBytes -import kotlinx.coroutines.launch - -class VideoViewActivity2 : FragmentActivity() { - private lateinit var binding: ActivityVideoplayerBinding - - private var player: ExoPlayer? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - val autumnResource = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - intent.getParcelableExtra("autumnResource", AutumnResource::class.java) - } else { - @Suppress("DEPRECATION") - intent.getParcelableExtra("autumnResource") - } - - if (autumnResource?.id == null) { - Log.e("VideoViewActivity", "No AutumnResource provided") - finish() - return - } - - val resourceUrl = - "$REVOLT_FILES/attachments/${autumnResource.id}/${autumnResource.filename}" - - WindowCompat.setDecorFitsSystemWindows(window, false) - - binding = ActivityVideoplayerBinding.inflate(layoutInflater) - - binding.tbTop.title = autumnResource.filename - binding.tbTop.setNavigationOnClickListener { finish() } - binding.tbTop.setOnMenuItemClickListener { - when (it.itemId) { - R.id.mi_save -> { - downloadFile(autumnResource, resourceUrl) - true - } - - R.id.mi_share_file -> { - shareFile(autumnResource, resourceUrl) - true - } - - R.id.mi_share_link -> { - shareUrl(resourceUrl) - true - } - - else -> false - } - } - - player = ExoPlayer.Builder(this).build().apply { - setMediaItem(MediaItem.fromUri(resourceUrl)) - prepare() - play() - } - - binding.xpPlayer.player = player - binding.xpPlayer.setFullscreenButtonClickListener { - when (binding.alTop.visibility) { - android.view.View.VISIBLE -> { - binding.alTop.visibility = android.view.View.GONE - WindowInsetsControllerCompat(window, binding.root).let { controller -> - controller.hide(WindowInsetsCompat.Type.systemBars()) - controller.systemBarsBehavior = - WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE - } - binding.xpPlayer.background = ColorDrawable(Color.BLACK) - } - - else -> { - binding.alTop.visibility = android.view.View.VISIBLE - WindowInsetsControllerCompat(window, binding.root).let { controller -> - controller.show(WindowInsetsCompat.Type.systemBars()) - controller.systemBarsBehavior = - WindowInsetsControllerCompat.BEHAVIOR_DEFAULT - } - binding.xpPlayer.background = null - } - } - } - - - setContentView(binding.root) - } - - override fun onDestroy() { - super.onDestroy() - player?.release() - } - - override fun onPause() { - super.onPause() - player?.pause() - } - - private fun shareUrl(resourceUrl: String) { - val intent = - Intent(Intent.ACTION_SEND) - intent.type = "text/plain" - intent.putExtra( - Intent.EXTRA_TEXT, - resourceUrl - ) - - val shareIntent = Intent.createChooser(intent, null) - startActivity(shareIntent) - } - - private fun shareFile(resource: AutumnResource, resourceUrl: String) { - lifecycleScope.launch { - val contentUri = getAttachmentContentUri( - this@VideoViewActivity2, - resourceUrl, - resource.id!!, - resource.filename ?: "video" - ) - - val intent = - Intent(Intent.ACTION_SEND) - intent.type = resource.contentType ?: "video/*" - intent.putExtra( - Intent.EXTRA_TITLE, - resource.filename - ) - intent.putExtra( - Intent.EXTRA_SUBJECT, - resource.filename - ) - intent.putExtra( - Intent.EXTRA_STREAM, - contentUri - ) - - val shareIntent = Intent.createChooser(intent, null) - startActivity(shareIntent) - } - } - - private fun downloadFile(resource: AutumnResource, resourceUrl: String) { - lifecycleScope.launch { - this@VideoViewActivity2.applicationContext.let { - it.contentResolver.insert( - MediaStore.Video.Media.EXTERNAL_CONTENT_URI, - ContentValues().apply { - put(MediaStore.Video.Media.DISPLAY_NAME, resource.filename) - put(MediaStore.Video.Media.MIME_TYPE, resource.contentType) - put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/Revolt") - put(MediaStore.Video.Media.IS_PENDING, 1) - } - ) - }?.let { uri -> - this@VideoViewActivity2.contentResolver.openOutputStream(uri).use { stream -> - val video = RevoltHttp.get(resourceUrl).readBytes() - stream?.write(video) - - this@VideoViewActivity2.applicationContext.let { - it.contentResolver.update( - uri, - ContentValues().apply { - put(MediaStore.Video.Media.IS_PENDING, 0) - }, - null, - null - ) - } - - Snackbar.make( - binding.xpPlayer, - R.string.media_viewer_saved, - Snackbar.LENGTH_SHORT - ).setAction( - R.string.media_viewer_open - ) { - val intent = Intent(Intent.ACTION_VIEW) - intent.setDataAndType(uri, resource.contentType) - intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION - startActivity(intent) - } - .setActionTextColor( - MaterialColors.getColor( - binding.xpPlayer, - com.google.android.material.R.attr.colorPrimary - ) - ) - .show() - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/api/settings/FeatureFlags.kt b/app/src/main/java/chat/revolt/api/settings/FeatureFlags.kt index 045180ee..da014bcb 100644 --- a/app/src/main/java/chat/revolt/api/settings/FeatureFlags.kt +++ b/app/src/main/java/chat/revolt/api/settings/FeatureFlags.kt @@ -30,19 +30,6 @@ sealed class MediaConversationsVariates { data class Restricted(val predicate: () -> Boolean) : MediaConversationsVariates() } -@FeatureFlag("VideoViewActivity2") -sealed class ViewViewActivity2Variates { - @Treatment( - "Enable the new XML-based video player activity for all users" - ) - object Enabled : ViewViewActivity2Variates() - - @Treatment( - "Enable the new XML-based video player activity for users that meet certain or all criteria (implementation-specific)" - ) - data class Restricted(val predicate: () -> Boolean) : ViewViewActivity2Variates() -} - object FeatureFlags { @FeatureFlag("LabsAccessControl") var labsAccessControl by mutableStateOf( @@ -68,17 +55,4 @@ object FeatureFlags { is MediaConversationsVariates.Enabled -> true is MediaConversationsVariates.Restricted -> (mediaConversations as MediaConversationsVariates.Restricted).predicate() } - - @FeatureFlag("VideoViewActivity2") - var videoViewActivity2 by mutableStateOf( - ViewViewActivity2Variates.Restricted { - RevoltAPI.selfId == SpecialUsers.JENNIFER - } - ) - - val videoViewActivity2Granted: Boolean - get() = when (videoViewActivity2) { - is ViewViewActivity2Variates.Enabled -> true - is ViewViewActivity2Variates.Restricted -> (videoViewActivity2 as ViewViewActivity2Variates.Restricted).predicate() - } } diff --git a/app/src/main/java/chat/revolt/components/chat/Message.kt b/app/src/main/java/chat/revolt/components/chat/Message.kt index 3be5412e..e65acc43 100644 --- a/app/src/main/java/chat/revolt/components/chat/Message.kt +++ b/app/src/main/java/chat/revolt/components/chat/Message.kt @@ -54,7 +54,6 @@ import androidx.compose.ui.unit.sp import chat.revolt.R import chat.revolt.activities.media.ImageViewActivity import chat.revolt.activities.media.VideoViewActivity -import chat.revolt.activities.media.VideoViewActivity2 import chat.revolt.api.REVOLT_FILES import chat.revolt.api.RevoltAPI import chat.revolt.api.internals.BrushCompat @@ -67,7 +66,6 @@ import chat.revolt.api.routes.channel.unreact import chat.revolt.api.routes.microservices.january.asJanuaryProxyUrl import chat.revolt.api.schemas.AutumnResource import chat.revolt.api.schemas.User -import chat.revolt.api.settings.FeatureFlags import chat.revolt.api.settings.GlobalState import chat.revolt.api.settings.MessageReplyStyle import chat.revolt.callbacks.Action @@ -389,10 +387,7 @@ fun Message( attachmentView.launch( Intent( context, - when (FeatureFlags.videoViewActivity2Granted) { - true -> VideoViewActivity2::class.java - else -> VideoViewActivity::class.java - } + VideoViewActivity::class.java ).apply { putExtra("autumnResource", attachment) }