Skip to content

Commit 5a1f596

Browse files
feat: Migrate fullscreen media player
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
1 parent 20f9eed commit 5a1f596

7 files changed

Lines changed: 279 additions & 168 deletions

File tree

app/src/main/java/com/nextcloud/talk/fullscreenfile/FullScreenMediaActivity.kt

Lines changed: 60 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -12,137 +12,94 @@ package com.nextcloud.talk.fullscreenfile
1212

1313
import android.content.Intent
1414
import android.os.Bundle
15-
import android.view.Menu
16-
import android.view.MenuItem
17-
import android.view.ViewGroup.MarginLayoutParams
1815
import android.view.WindowManager
1916
import android.widget.FrameLayout
17+
import androidx.activity.SystemBarStyle
18+
import androidx.activity.enableEdgeToEdge
2019
import androidx.annotation.OptIn
2120
import androidx.appcompat.app.AppCompatActivity
21+
import androidx.compose.material3.MaterialTheme
22+
import androidx.compose.material3.darkColorScheme
23+
import androidx.compose.runtime.getValue
24+
import androidx.compose.runtime.mutableStateOf
25+
import androidx.compose.runtime.setValue
26+
import androidx.compose.ui.platform.ComposeView
27+
import androidx.compose.ui.platform.ViewCompositionStrategy
2228
import androidx.core.content.FileProvider
2329
import androidx.core.net.toUri
24-
import androidx.core.view.ViewCompat
2530
import androidx.core.view.WindowCompat
2631
import androidx.core.view.WindowInsetsCompat
2732
import androidx.core.view.WindowInsetsControllerCompat
28-
import androidx.core.view.marginBottom
29-
import androidx.core.view.updateLayoutParams
30-
import androidx.core.view.updatePadding
3133
import androidx.fragment.app.DialogFragment
3234
import androidx.media3.common.AudioAttributes
3335
import androidx.media3.common.MediaItem
3436
import androidx.media3.common.util.UnstableApi
3537
import androidx.media3.exoplayer.ExoPlayer
36-
import androidx.media3.ui.DefaultTimeBar
37-
import androidx.media3.ui.PlayerView
3838
import autodagger.AutoInjector
3939
import com.nextcloud.talk.BuildConfig
4040
import com.nextcloud.talk.R
4141
import com.nextcloud.talk.application.NextcloudTalkApplication
42-
import com.nextcloud.talk.databinding.ActivityFullScreenMediaBinding
4342
import com.nextcloud.talk.ui.SwipeToCloseLayout
4443
import com.nextcloud.talk.ui.dialog.SaveToStorageDialogFragment
4544
import com.nextcloud.talk.utils.Mimetype.VIDEO_PREFIX_GENERIC
4645
import java.io.File
4746

4847
@AutoInjector(NextcloudTalkApplication::class)
4948
class FullScreenMediaActivity : AppCompatActivity() {
50-
lateinit var binding: ActivityFullScreenMediaBinding
5149

5250
private lateinit var path: String
53-
private var player: ExoPlayer? = null
54-
51+
private lateinit var fileName: String
52+
private var player: ExoPlayer? by mutableStateOf(null)
5553
private var playWhenReadyState: Boolean = true
5654
private var playBackPosition: Long = 0L
5755
private lateinit var windowInsetsController: WindowInsetsControllerCompat
5856

59-
override fun onCreateOptionsMenu(menu: Menu): Boolean {
60-
menuInflater.inflate(R.menu.menu_preview, menu)
61-
return true
62-
}
63-
64-
override fun onOptionsItemSelected(item: MenuItem): Boolean =
65-
when (item.itemId) {
66-
android.R.id.home -> {
67-
onBackPressedDispatcher.onBackPressed()
68-
true
69-
}
70-
71-
R.id.share -> {
72-
val shareUri = FileProvider.getUriForFile(
73-
this,
74-
BuildConfig.APPLICATION_ID,
75-
File(path)
76-
)
77-
78-
val shareIntent: Intent = Intent().apply {
79-
action = Intent.ACTION_SEND
80-
putExtra(Intent.EXTRA_STREAM, shareUri)
81-
type = VIDEO_PREFIX_GENERIC
82-
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
83-
}
84-
startActivity(Intent.createChooser(shareIntent, resources.getText(R.string.send_to)))
85-
86-
true
87-
}
88-
89-
R.id.save -> {
90-
val saveFragment: DialogFragment = SaveToStorageDialogFragment.newInstance(
91-
intent.getStringExtra("FILE_NAME").toString()
92-
)
93-
saveFragment.show(
94-
supportFragmentManager,
95-
SaveToStorageDialogFragment.TAG
96-
)
97-
true
98-
}
99-
100-
else -> {
101-
super.onOptionsItemSelected(item)
102-
}
103-
}
104-
105-
@OptIn(UnstableApi::class)
10657
override fun onCreate(savedInstanceState: Bundle?) {
10758
super.onCreate(savedInstanceState)
108-
WindowCompat.setDecorFitsSystemWindows(window, false)
109-
val fileName = intent.getStringExtra("FILE_NAME")
110-
val isAudioOnly = intent.getBooleanExtra("AUDIO_ONLY", false)
11159

60+
fileName = intent.getStringExtra("FILE_NAME").orEmpty()
61+
val isAudioOnly = intent.getBooleanExtra("AUDIO_ONLY", false)
11262
path = applicationContext.cacheDir.absolutePath + "/" + fileName
11363

114-
binding = ActivityFullScreenMediaBinding.inflate(layoutInflater)
115-
setContentView(binding.root)
116-
117-
setSupportActionBar(binding.mediaviewToolbar)
118-
supportActionBar?.title = fileName
119-
supportActionBar?.setDisplayHomeAsUpEnabled(true)
120-
121-
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
122-
123-
binding.playerView.showController()
124-
if (isAudioOnly) {
125-
binding.playerView.controllerShowTimeoutMs = 0
126-
}
127-
128-
initWindowInsetsController()
129-
applyWindowInsets()
130-
131-
binding.playerView.setControllerVisibilityListener(
132-
PlayerView.ControllerVisibilityListener { v ->
133-
if (v != 0) {
134-
enterImmersiveMode()
135-
} else {
136-
exitImmersiveMode()
137-
}
138-
}
64+
enableEdgeToEdge(
65+
statusBarStyle = SystemBarStyle.dark(android.graphics.Color.TRANSPARENT),
66+
navigationBarStyle = SystemBarStyle.dark(android.graphics.Color.TRANSPARENT)
13967
)
68+
initWindowInsetsController()
14069

141-
binding.swipeToCloseLayout.setOnSwipeToCloseListener(object : SwipeToCloseLayout.OnSwipeToCloseListener {
70+
val swipeToCloseLayout = SwipeToCloseLayout(this)
71+
swipeToCloseLayout.setOnSwipeToCloseListener(object : SwipeToCloseLayout.OnSwipeToCloseListener {
14272
override fun onSwipeToClose() {
14373
finish()
14474
}
14575
})
76+
77+
val composeView = ComposeView(this).apply {
78+
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
79+
setContent {
80+
MaterialTheme(colorScheme = darkColorScheme()) {
81+
FullScreenMediaScreen(
82+
title = fileName,
83+
player = player,
84+
isAudioOnly = isAudioOnly,
85+
actions = FullScreenMediaActions(
86+
onShare = { shareFile() },
87+
onSave = { showSaveDialog() },
88+
onEnterImmersive = { enterImmersiveMode() },
89+
onExitImmersive = { exitImmersiveMode() }
90+
)
91+
)
92+
}
93+
}
94+
}
95+
96+
swipeToCloseLayout.addView(
97+
composeView,
98+
FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
99+
)
100+
setContentView(swipeToCloseLayout)
101+
102+
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
146103
}
147104

148105
override fun onStart() {
@@ -156,12 +113,12 @@ class FullScreenMediaActivity : AppCompatActivity() {
156113
releasePlayer()
157114
}
158115

116+
@OptIn(UnstableApi::class)
159117
private fun initializePlayer() {
160118
player = ExoPlayer.Builder(applicationContext)
161119
.setAudioAttributes(AudioAttributes.DEFAULT, true)
162120
.setHandleAudioBecomingNoisy(true)
163121
.build()
164-
binding.playerView.player = player
165122
}
166123

167124
private fun preparePlayer() {
@@ -190,39 +147,25 @@ class FullScreenMediaActivity : AppCompatActivity() {
190147

191148
private fun enterImmersiveMode() {
192149
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
193-
supportActionBar?.hide()
194150
}
195151

196152
private fun exitImmersiveMode() {
197153
windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
198-
supportActionBar?.show()
199154
}
200155

201-
@OptIn(UnstableApi::class)
202-
private fun applyWindowInsets() {
203-
val playerView = binding.playerView
204-
val exoControls = playerView.findViewById<FrameLayout>(R.id.exo_bottom_bar)
205-
val exoProgress = playerView.findViewById<DefaultTimeBar>(R.id.exo_progress)
206-
val progressBottomMargin = exoProgress.marginBottom
207-
208-
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets ->
209-
val insets = windowInsets.getInsets(
210-
WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type
211-
.displayCutout()
212-
)
213-
binding.mediaviewToolbar.updateLayoutParams<MarginLayoutParams> {
214-
topMargin = insets.top
215-
}
216-
exoControls.updateLayoutParams<MarginLayoutParams> {
217-
bottomMargin = insets.bottom
218-
}
219-
exoProgress.updateLayoutParams<MarginLayoutParams> {
220-
bottomMargin = insets.bottom + progressBottomMargin
221-
}
222-
exoControls.updatePadding(left = insets.left, right = insets.right)
223-
exoProgress.updatePadding(left = insets.left, right = insets.right)
224-
binding.mediaviewToolbar.updatePadding(left = insets.left, right = insets.right)
225-
WindowInsetsCompat.CONSUMED
156+
private fun shareFile() {
157+
val shareUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID, File(path))
158+
val shareIntent = Intent().apply {
159+
action = Intent.ACTION_SEND
160+
putExtra(Intent.EXTRA_STREAM, shareUri)
161+
type = VIDEO_PREFIX_GENERIC
162+
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
226163
}
164+
startActivity(Intent.createChooser(shareIntent, resources.getText(R.string.send_to)))
165+
}
166+
167+
private fun showSaveDialog() {
168+
val saveFragment: DialogFragment = SaveToStorageDialogFragment.newInstance(fileName)
169+
saveFragment.show(supportFragmentManager, SaveToStorageDialogFragment.TAG)
227170
}
228171
}

0 commit comments

Comments
 (0)