diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 502600a2..77d1bcec 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -118,6 +118,11 @@
android:configChanges="orientation|screenSize"
android:theme="@style/Theme.Revolt" />
+
+
= 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 da014bcb..045180ee 100644
--- a/app/src/main/java/chat/revolt/api/settings/FeatureFlags.kt
+++ b/app/src/main/java/chat/revolt/api/settings/FeatureFlags.kt
@@ -30,6 +30,19 @@ 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(
@@ -55,4 +68,17 @@ 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 e65acc43..3be5412e 100644
--- a/app/src/main/java/chat/revolt/components/chat/Message.kt
+++ b/app/src/main/java/chat/revolt/components/chat/Message.kt
@@ -54,6 +54,7 @@ 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
@@ -66,6 +67,7 @@ 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
@@ -387,7 +389,10 @@ fun Message(
attachmentView.launch(
Intent(
context,
- VideoViewActivity::class.java
+ when (FeatureFlags.videoViewActivity2Granted) {
+ true -> VideoViewActivity2::class.java
+ else -> VideoViewActivity::class.java
+ }
).apply {
putExtra("autumnResource", attachment)
}
diff --git a/app/src/main/res/drawable/ic_arrow_left_24dp.xml b/app/src/main/res/drawable/ic_arrow_left_24dp.xml
new file mode 100644
index 00000000..3a96b6d5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_arrow_left_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/font/inter_display.xml b/app/src/main/res/font/inter_display.xml
new file mode 100644
index 00000000..cf677387
--- /dev/null
+++ b/app/src/main/res/font/inter_display.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_videoplayer.xml b/app/src/main/res/layout/activity_videoplayer.xml
new file mode 100644
index 00000000..fc3252fe
--- /dev/null
+++ b/app/src/main/res/layout/activity_videoplayer.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_videoplayer.xml b/app/src/main/res/menu/menu_videoplayer.xml
new file mode 100644
index 00000000..02482fe7
--- /dev/null
+++ b/app/src/main/res/menu/menu_videoplayer.xml
@@ -0,0 +1,29 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index bb584711..986de0b3 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -1,9 +1,10 @@
-
+
+
+
+
+
\ No newline at end of file