feat: graduate VVA2 to GA
Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
parent
f0d27b9a80
commit
70927bd1a4
|
|
@ -118,11 +118,6 @@
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:theme="@style/Theme.Revolt" />
|
android:theme="@style/Theme.Revolt" />
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name=".activities.media.VideoViewActivity2"
|
|
||||||
android:configChanges="orientation|screenSize"
|
|
||||||
android:theme="@style/Theme.Revolt" />
|
|
||||||
|
|
||||||
<!-- Backport photo picker via Google Play Services -->
|
<!-- Backport photo picker via Google Play Services -->
|
||||||
<service
|
<service
|
||||||
android:name="com.google.android.gms.metadata.ModuleDependencies"
|
android:name="com.google.android.gms.metadata.ModuleDependencies"
|
||||||
|
|
|
||||||
|
|
@ -2,64 +2,36 @@ package chat.revolt.activities.media
|
||||||
|
|
||||||
import android.content.ContentValues
|
import android.content.ContentValues
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.activity.ComponentActivity
|
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
|
||||||
import androidx.activity.compose.setContent
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
|
||||||
import androidx.compose.material3.DropdownMenu
|
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.SnackbarDuration
|
|
||||||
import androidx.compose.material3.SnackbarHost
|
|
||||||
import androidx.compose.material3.SnackbarHostState
|
|
||||||
import androidx.compose.material3.SnackbarResult
|
|
||||||
import androidx.compose.material3.Surface
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.DisposableEffect
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.graphics.RectangleShape
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.res.painterResource
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
|
||||||
import androidx.core.view.WindowCompat
|
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.common.MediaItem
|
||||||
import androidx.media3.exoplayer.ExoPlayer
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import androidx.media3.ui.PlayerView
|
|
||||||
import chat.revolt.R
|
import chat.revolt.R
|
||||||
import chat.revolt.api.REVOLT_FILES
|
import chat.revolt.api.REVOLT_FILES
|
||||||
import chat.revolt.api.RevoltHttp
|
import chat.revolt.api.RevoltHttp
|
||||||
import chat.revolt.api.schemas.AutumnResource
|
import chat.revolt.api.schemas.AutumnResource
|
||||||
import chat.revolt.api.settings.GlobalState
|
import chat.revolt.databinding.ActivityVideoplayerBinding
|
||||||
import chat.revolt.api.settings.SyncedSettings
|
|
||||||
import chat.revolt.provider.getAttachmentContentUri
|
import chat.revolt.provider.getAttachmentContentUri
|
||||||
import chat.revolt.ui.theme.RevoltTheme
|
import com.google.android.material.color.MaterialColors
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import io.ktor.client.request.get
|
import io.ktor.client.request.get
|
||||||
import io.ktor.client.statement.readBytes
|
import io.ktor.client.statement.readBytes
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class VideoViewActivity : ComponentActivity() {
|
class VideoViewActivity : FragmentActivity() {
|
||||||
|
private lateinit var binding: ActivityVideoplayerBinding
|
||||||
|
|
||||||
|
private var player: ExoPlayer? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
|
@ -76,32 +48,82 @@ class VideoViewActivity : ComponentActivity() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val resourceUrl =
|
||||||
|
"$REVOLT_FILES/attachments/${autumnResource.id}/${autumnResource.filename}"
|
||||||
|
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
|
|
||||||
setContent {
|
binding = ActivityVideoplayerBinding.inflate(layoutInflater)
|
||||||
VideoViewScreen(resource = autumnResource, onClose = { finish() })
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
override fun onDestroy() {
|
||||||
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
super.onDestroy()
|
||||||
@Composable
|
player?.release()
|
||||||
fun VideoViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) {
|
}
|
||||||
val resourceUrl = "$REVOLT_FILES/attachments/${resource.id}/${resource.filename}"
|
|
||||||
|
|
||||||
val context = LocalContext.current
|
override fun onPause() {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
super.onPause()
|
||||||
val activityLauncher = rememberLauncherForActivityResult(
|
player?.pause()
|
||||||
ActivityResultContracts.StartActivityForResult()
|
}
|
||||||
) {}
|
|
||||||
|
|
||||||
val shareSubmenuIsOpen = remember { mutableStateOf(false) }
|
|
||||||
val snackbarHostState = remember { SnackbarHostState() }
|
|
||||||
|
|
||||||
fun shareUrl() {
|
|
||||||
shareSubmenuIsOpen.value = false
|
|
||||||
|
|
||||||
|
private fun shareUrl(resourceUrl: String) {
|
||||||
val intent =
|
val intent =
|
||||||
Intent(Intent.ACTION_SEND)
|
Intent(Intent.ACTION_SEND)
|
||||||
intent.type = "text/plain"
|
intent.type = "text/plain"
|
||||||
|
|
@ -111,15 +133,13 @@ fun VideoViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) {
|
||||||
)
|
)
|
||||||
|
|
||||||
val shareIntent = Intent.createChooser(intent, null)
|
val shareIntent = Intent.createChooser(intent, null)
|
||||||
activityLauncher.launch(shareIntent)
|
startActivity(shareIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shareVideo() {
|
private fun shareFile(resource: AutumnResource, resourceUrl: String) {
|
||||||
shareSubmenuIsOpen.value = false
|
lifecycleScope.launch {
|
||||||
|
|
||||||
coroutineScope.launch {
|
|
||||||
val contentUri = getAttachmentContentUri(
|
val contentUri = getAttachmentContentUri(
|
||||||
context,
|
this@VideoViewActivity,
|
||||||
resourceUrl,
|
resourceUrl,
|
||||||
resource.id!!,
|
resource.id!!,
|
||||||
resource.filename ?: "video"
|
resource.filename ?: "video"
|
||||||
|
|
@ -128,19 +148,27 @@ fun VideoViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) {
|
||||||
val intent =
|
val intent =
|
||||||
Intent(Intent.ACTION_SEND)
|
Intent(Intent.ACTION_SEND)
|
||||||
intent.type = resource.contentType ?: "video/*"
|
intent.type = resource.contentType ?: "video/*"
|
||||||
|
intent.putExtra(
|
||||||
|
Intent.EXTRA_TITLE,
|
||||||
|
resource.filename
|
||||||
|
)
|
||||||
|
intent.putExtra(
|
||||||
|
Intent.EXTRA_SUBJECT,
|
||||||
|
resource.filename
|
||||||
|
)
|
||||||
intent.putExtra(
|
intent.putExtra(
|
||||||
Intent.EXTRA_STREAM,
|
Intent.EXTRA_STREAM,
|
||||||
contentUri
|
contentUri
|
||||||
)
|
)
|
||||||
|
|
||||||
val shareIntent = Intent.createChooser(intent, null)
|
val shareIntent = Intent.createChooser(intent, null)
|
||||||
activityLauncher.launch(shareIntent)
|
startActivity(shareIntent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveToGallery() {
|
private fun downloadFile(resource: AutumnResource, resourceUrl: String) {
|
||||||
coroutineScope.launch {
|
lifecycleScope.launch {
|
||||||
context.applicationContext.let {
|
this@VideoViewActivity.applicationContext.let {
|
||||||
it.contentResolver.insert(
|
it.contentResolver.insert(
|
||||||
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
|
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
|
||||||
ContentValues().apply {
|
ContentValues().apply {
|
||||||
|
|
@ -151,11 +179,11 @@ fun VideoViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}?.let { uri ->
|
}?.let { uri ->
|
||||||
context.contentResolver.openOutputStream(uri).use { stream ->
|
this@VideoViewActivity.contentResolver.openOutputStream(uri).use { stream ->
|
||||||
val video = RevoltHttp.get(resourceUrl).readBytes()
|
val video = RevoltHttp.get(resourceUrl).readBytes()
|
||||||
stream?.write(video)
|
stream?.write(video)
|
||||||
|
|
||||||
context.applicationContext.let {
|
this@VideoViewActivity.applicationContext.let {
|
||||||
it.contentResolver.update(
|
it.contentResolver.update(
|
||||||
uri,
|
uri,
|
||||||
ContentValues().apply {
|
ContentValues().apply {
|
||||||
|
|
@ -166,145 +194,27 @@ fun VideoViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val snackbar = snackbarHostState.showSnackbar(
|
Snackbar.make(
|
||||||
message = context.getString(R.string.media_viewer_saved),
|
binding.xpPlayer,
|
||||||
actionLabel = context.getString(R.string.media_viewer_open),
|
R.string.media_viewer_saved,
|
||||||
duration = SnackbarDuration.Short
|
Snackbar.LENGTH_SHORT
|
||||||
)
|
).setAction(
|
||||||
|
R.string.media_viewer_open
|
||||||
if (snackbar == SnackbarResult.ActionPerformed) {
|
) {
|
||||||
val intent = Intent(Intent.ACTION_VIEW)
|
val intent = Intent(Intent.ACTION_VIEW)
|
||||||
intent.setDataAndType(uri, resource.contentType)
|
intent.setDataAndType(uri, resource.contentType)
|
||||||
intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
activityLauncher.launch(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
}
|
.setActionTextColor(
|
||||||
}
|
MaterialColors.getColor(
|
||||||
}
|
binding.xpPlayer,
|
||||||
}
|
com.google.android.material.R.attr.colorPrimary
|
||||||
|
)
|
||||||
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,
|
|
||||||
)
|
)
|
||||||
},
|
.show()
|
||||||
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)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -30,19 +30,6 @@ sealed class MediaConversationsVariates {
|
||||||
data class Restricted(val predicate: () -> Boolean) : 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 {
|
object FeatureFlags {
|
||||||
@FeatureFlag("LabsAccessControl")
|
@FeatureFlag("LabsAccessControl")
|
||||||
var labsAccessControl by mutableStateOf<LabsAccessControlVariates>(
|
var labsAccessControl by mutableStateOf<LabsAccessControlVariates>(
|
||||||
|
|
@ -68,17 +55,4 @@ object FeatureFlags {
|
||||||
is MediaConversationsVariates.Enabled -> true
|
is MediaConversationsVariates.Enabled -> true
|
||||||
is MediaConversationsVariates.Restricted -> (mediaConversations as MediaConversationsVariates.Restricted).predicate()
|
is MediaConversationsVariates.Restricted -> (mediaConversations as MediaConversationsVariates.Restricted).predicate()
|
||||||
}
|
}
|
||||||
|
|
||||||
@FeatureFlag("VideoViewActivity2")
|
|
||||||
var videoViewActivity2 by mutableStateOf<ViewViewActivity2Variates>(
|
|
||||||
ViewViewActivity2Variates.Restricted {
|
|
||||||
RevoltAPI.selfId == SpecialUsers.JENNIFER
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
val videoViewActivity2Granted: Boolean
|
|
||||||
get() = when (videoViewActivity2) {
|
|
||||||
is ViewViewActivity2Variates.Enabled -> true
|
|
||||||
is ViewViewActivity2Variates.Restricted -> (videoViewActivity2 as ViewViewActivity2Variates.Restricted).predicate()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,6 @@ import androidx.compose.ui.unit.sp
|
||||||
import chat.revolt.R
|
import chat.revolt.R
|
||||||
import chat.revolt.activities.media.ImageViewActivity
|
import chat.revolt.activities.media.ImageViewActivity
|
||||||
import chat.revolt.activities.media.VideoViewActivity
|
import chat.revolt.activities.media.VideoViewActivity
|
||||||
import chat.revolt.activities.media.VideoViewActivity2
|
|
||||||
import chat.revolt.api.REVOLT_FILES
|
import chat.revolt.api.REVOLT_FILES
|
||||||
import chat.revolt.api.RevoltAPI
|
import chat.revolt.api.RevoltAPI
|
||||||
import chat.revolt.api.internals.BrushCompat
|
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.routes.microservices.january.asJanuaryProxyUrl
|
||||||
import chat.revolt.api.schemas.AutumnResource
|
import chat.revolt.api.schemas.AutumnResource
|
||||||
import chat.revolt.api.schemas.User
|
import chat.revolt.api.schemas.User
|
||||||
import chat.revolt.api.settings.FeatureFlags
|
|
||||||
import chat.revolt.api.settings.GlobalState
|
import chat.revolt.api.settings.GlobalState
|
||||||
import chat.revolt.api.settings.MessageReplyStyle
|
import chat.revolt.api.settings.MessageReplyStyle
|
||||||
import chat.revolt.callbacks.Action
|
import chat.revolt.callbacks.Action
|
||||||
|
|
@ -389,10 +387,7 @@ fun Message(
|
||||||
attachmentView.launch(
|
attachmentView.launch(
|
||||||
Intent(
|
Intent(
|
||||||
context,
|
context,
|
||||||
when (FeatureFlags.videoViewActivity2Granted) {
|
VideoViewActivity::class.java
|
||||||
true -> VideoViewActivity2::class.java
|
|
||||||
else -> VideoViewActivity::class.java
|
|
||||||
}
|
|
||||||
).apply {
|
).apply {
|
||||||
putExtra("autumnResource", attachment)
|
putExtra("autumnResource", attachment)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue