diff --git a/app/src/main/java/com/nextcloud/utils/extensions/PlayerViewExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/PlayerViewExtensions.kt new file mode 100644 index 000000000000..78713ba321d6 --- /dev/null +++ b/app/src/main/java/com/nextcloud/utils/extensions/PlayerViewExtensions.kt @@ -0,0 +1,27 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +package com.nextcloud.utils.extensions + +import android.view.View +import androidx.annotation.OptIn +import androidx.core.graphics.Insets +import androidx.core.view.updatePadding +import androidx.media3.common.util.UnstableApi +import androidx.media3.ui.PlayerView + +@OptIn(UnstableApi::class) +fun PlayerView.applyControlsInsets(insets: Insets) { + val controller = findViewById(androidx.media3.ui.R.id.exo_controller) ?: return + controller.updatePadding(left = insets.left, right = insets.right, bottom = insets.bottom) +} + +@OptIn(UnstableApi::class) +fun PlayerView.setFullscreenButton(isFullscreen: Boolean, onClick: () -> Unit) { + setFullscreenButtonClickListener(null) + setFullscreenButtonState(isFullscreen) + setFullscreenButtonClickListener { onClick() } +} diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 061c62a09810..14033d2380cb 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -2403,7 +2403,7 @@ class FileDisplayActivity : is PreviewMediaFragment -> { fragment.updateFile(ocFile) - if (PreviewMediaFragment.canBePreviewed(ocFile)) { + if (PreviewMediaFragment.isAudioOrVideo(ocFile)) { startMediaPreview( ocFile, fragment.position, @@ -2688,7 +2688,7 @@ class FileDisplayActivity : startMediaActivity(file, startPlaybackPosition, autoplay, actualUser) } else { configureToolbarForPreview(file) - val mediaFragment: Fragment = newInstance(file, user.get(), startPlaybackPosition, autoplay, false) + val mediaFragment: Fragment = newInstance(file, user.get(), startPlaybackPosition, autoplay) setLeftFragment(mediaFragment, false) } } else { diff --git a/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.kt b/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.kt index 6fd02e267043..b4f1cdd84f3e 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.kt @@ -17,7 +17,6 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment import com.nextcloud.client.account.User import com.nextcloud.client.di.Injectable import com.nextcloud.client.jobs.download.FileDownloadHelper.Companion.instance @@ -136,7 +135,7 @@ class FileDownloadFragment : private const val ARG_USER = "USER" private val TAG: String = FileDownloadFragment::class.java.simpleName - fun newInstance(file: OCFile?, user: User?, ignoreFirstSavedState: Boolean): Fragment = + fun newInstance(file: OCFile?, user: User?, ignoreFirstSavedState: Boolean): FileDownloadFragment = FileDownloadFragment().apply { arguments = Bundle().apply { putParcelable(ARG_FILE, file) diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt index 385f34b68f03..afcea17eacc1 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt @@ -17,6 +17,10 @@ import android.view.View import androidx.activity.OnBackPressedCallback import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.toDrawable +import androidx.core.view.ViewCompat +import androidx.core.view.WindowCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.WindowInsetsControllerCompat import androidx.drawerlayout.widget.DrawerLayout import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.viewpager2.widget.ViewPager2 @@ -59,7 +63,7 @@ import kotlin.math.max import kotlin.math.min /** - * Holds a swiping gallery where image files contained in an Nextcloud directory are shown. + * Holds a swiping gallery where image and video files contained in a Nextcloud directory are shown. */ @Suppress("TooManyFunctions") class PreviewImageActivity : @@ -70,13 +74,15 @@ class PreviewImageActivity : Injectable { private var livePhotoFile: OCFile? = null private var viewPager: ViewPager2? = null - private var previewImagePagerAdapter: PreviewImagePagerAdapter? = null + private var previewMediaPagerAdapter: PreviewMediaPagerAdapter? = null private var savedPosition: Int? = null private val downloadStartReceiver = DownloadStartReceiver() private val downloadFinishReceiver = DownloadFinishReceiver() - private var fullScreenAnchorView: View? = null + private val windowInsetsController: WindowInsetsControllerCompat by lazy { + WindowCompat.getInsetsController(window, window.decorView) + } private var isDownloadWorkStarted = false private var screenState = PreviewImageActivityState.Idle @@ -115,8 +121,6 @@ class PreviewImageActivity : it.setBackgroundDrawable(R.color.black.toDrawable()) } - fullScreenAnchorView = window.decorView - // to keep our UI controls visibility in line with system bars visibility setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) val requestWaitingForBinder = savedInstanceState?.getBoolean(KEY_WAITING_FOR_BINDER) ?: false @@ -163,7 +167,7 @@ class PreviewImageActivity : if (virtualFolderType != null && virtualFolderType !== VirtualFolderType.NONE) { val type = virtualFolderType as VirtualFolderType - previewImagePagerAdapter = PreviewImagePagerAdapter( + previewMediaPagerAdapter = PreviewMediaPagerAdapter( this, type, user, @@ -174,7 +178,7 @@ class PreviewImageActivity : val parentFolder = file?.let { storageManager.getFileById(it.parentId) } ?: storageManager.getFileByEncryptedRemotePath(OCFile.ROOT_PATH) - previewImagePagerAdapter = PreviewImagePagerAdapter( + previewMediaPagerAdapter = PreviewMediaPagerAdapter( this, livePhotoFile, parentFolder, @@ -192,11 +196,11 @@ class PreviewImageActivity : ) { savedPosition } else { - file?.let { previewImagePagerAdapter?.getFilePosition(it) } + file?.let { previewMediaPagerAdapter?.getFilePosition(it) } } position = position?.toDouble()?.let { max(it, 0.0).toInt() } - viewPager?.adapter = previewImagePagerAdapter + viewPager?.adapter = previewMediaPagerAdapter viewPager?.registerOnPageChangeCallback(object : OnPageChangeCallback() { override fun onPageSelected(position: Int) { selectPage(position) @@ -231,7 +235,7 @@ class PreviewImageActivity : fun updateViewPagerAfterDeletionAndAdvanceForward() { val deletePosition = viewPager?.currentItem ?: return - previewImagePagerAdapter?.let { adapter -> + previewMediaPagerAdapter?.let { adapter -> val nextPosition = min(deletePosition, adapter.itemCount - 1) viewPager?.setCurrentItem(nextPosition, true) adapter.delete(deletePosition) @@ -311,7 +315,7 @@ class PreviewImageActivity : super.onRemoteOperationFinish(operation, result) if (operation is RemoveFileOperation) { - previewImagePagerAdapter?.let { + previewMediaPagerAdapter?.let { if (it.itemCount <= 1) { backToDisplayActivity() return @@ -346,7 +350,7 @@ class PreviewImageActivity : private fun setDownloadedItem() { savedPosition?.let { position -> - previewImagePagerAdapter?.run { + previewMediaPagerAdapter?.run { file?.let { updateFile(position, it) notifyItemChanged(position) @@ -438,7 +442,7 @@ class PreviewImageActivity : if (position == null) return savedPosition = position - val currentFile = previewImagePagerAdapter?.getFileAt(position) + val currentFile = previewMediaPagerAdapter?.getFileAt(position) if (!isDownloadWorkStarted) { screenState = PreviewImageActivityState.WaitingForBinder @@ -446,7 +450,7 @@ class PreviewImageActivity : if (currentFile != null) { if (currentFile.isEncrypted && !currentFile.isDown && - previewImagePagerAdapter?.pendingErrorAt(position) == false + previewMediaPagerAdapter?.pendingErrorAt(position) == false ) { requestForDownload(currentFile) } @@ -507,13 +511,15 @@ class PreviewImageActivity : get() = supportActionBar == null || supportActionBar?.isShowing == true fun toggleFullScreen() { - fullScreenAnchorView?.let { - val visible = (it.systemUiVisibility and View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0 - if (visible) { - hideSystemUI(it) - } else { - showSystemUI(it) - } + val rootInsets = ViewCompat.getRootWindowInsets(window.decorView) ?: return + + // the content is laid out edge to edge so that showing and hiding the bars does not move it + WindowCompat.setDecorFitsSystemWindows(window, false) + + if (rootInsets.isVisible(WindowInsetsCompat.Type.systemBars())) { + windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()) + } else { + windowInsetsController.show(WindowInsetsCompat.Type.systemBars()) } } @@ -542,27 +548,6 @@ class PreviewImageActivity : override fun onBrowsedDownTo(folder: OCFile) = Unit override fun onTransferStateChanged(file: OCFile, downloading: Boolean, uploading: Boolean) = Unit - @Suppress("DEPRECATION") - private fun hideSystemUI(anchorView: View) { - anchorView.systemUiVisibility = ( - View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - or View.SYSTEM_UI_FLAG_FULLSCREEN - or View.SYSTEM_UI_FLAG_IMMERSIVE - or View.SYSTEM_UI_FLAG_LAYOUT_STABLE - or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - ) - } - - @Suppress("DEPRECATION") - private fun showSystemUI(anchorView: View) { - anchorView.systemUiVisibility = ( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE - or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - ) - } - companion object { val TAG: String = PreviewImageActivity::class.java.simpleName const val EXTRA_VIRTUAL_TYPE: String = "EXTRA_VIRTUAL_TYPE" diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt index 128c5fc0a0cc..9326613dd511 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt @@ -164,7 +164,7 @@ class PreviewImageFragment : hideActionBar() - val mediaFragment: Fragment = newInstance(file, accountManager.user, 0, true, true) + val mediaFragment: Fragment = newInstance(file, accountManager.user, autoplay = true, isLivePhoto = true) val fragmentManager = requireActivity().supportFragmentManager fragmentManager.beginTransaction().run { replace(R.id.top, mediaFragment) diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt index 7452877e5ae4..6c285f42e8d9 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt @@ -72,6 +72,7 @@ import com.nextcloud.ui.fileactions.FileActionsBottomSheet.Companion.newInstance import com.nextcloud.ui.fileactions.FileActionsBottomSheet.ResultListener import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.logFileSize +import com.nextcloud.utils.extensions.setFullscreenButton import com.nextcloud.utils.extensions.setTitleColor import com.owncloud.android.R import com.owncloud.android.databinding.ActivityPreviewMediaBinding @@ -488,7 +489,7 @@ class PreviewMediaActivity : } ) it.player = videoPlayer - it.setFullscreenButtonClickListener { startFullScreenVideo() } + it.setFullscreenButton(isFullscreen = false) { startFullScreenVideo() } } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.kt index 2ef7e982fd08..2ef590423d56 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.kt @@ -1,6 +1,7 @@ /* * Nextcloud - Android Client * + * SPDX-FileCopyrightText: 2026 Alper Ozturk * SPDX-FileCopyrightText: 2023 TSI-mc * SPDX-FileCopyrightText: 2023 Parneet Singh * SPDX-FileCopyrightText: 2020 Andy Scherzinger @@ -27,7 +28,6 @@ import android.view.MotionEvent import android.view.View import android.view.View.OnTouchListener import android.view.ViewGroup -import android.widget.FrameLayout import androidx.annotation.OptIn import androidx.annotation.StringRes import androidx.core.net.toUri @@ -35,9 +35,6 @@ import androidx.core.view.MenuHost import androidx.core.view.MenuProvider import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat -import androidx.core.view.marginBottom -import androidx.core.view.updateLayoutParams -import androidx.core.view.updatePadding import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope @@ -46,7 +43,6 @@ import androidx.media3.common.Player import androidx.media3.common.util.UnstableApi import androidx.media3.exoplayer.ExoPlayer import androidx.media3.session.MediaSession -import androidx.media3.ui.DefaultTimeBar import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.di.Injectable @@ -60,8 +56,10 @@ import com.nextcloud.client.network.ClientFactory.CreationException import com.nextcloud.common.NextcloudClient import com.nextcloud.ui.fileactions.FileAction import com.nextcloud.ui.fileactions.FileActionsBottomSheet.Companion.newInstance +import com.nextcloud.utils.extensions.applyControlsInsets import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.getTypedActivity +import com.nextcloud.utils.extensions.setFullscreenButton import com.owncloud.android.R import com.owncloud.android.databinding.FragmentPreviewMediaBinding import com.owncloud.android.datamodel.OCFile @@ -192,24 +190,11 @@ class PreviewMediaFragment : private fun applyWindowInsets() { binding.root.post { val rootInsets = ViewCompat.getRootWindowInsets(binding.root) ?: return@post - val insets = rootInsets.getInsets( - WindowInsetsCompat.Type.systemBars() or - WindowInsetsCompat.Type.displayCutout() + binding.exoplayerView.applyControlsInsets( + rootInsets.getInsets( + WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout() + ) ) - val playerView = binding.exoplayerView - val exoControls = playerView - .findViewById(androidx.media3.ui.R.id.exo_bottom_bar) - val exoProgress = playerView - .findViewById(androidx.media3.ui.R.id.exo_progress) - val progressOriginalMargin = exoProgress?.marginBottom ?: 0 - exoControls?.updateLayoutParams { - bottomMargin = insets.bottom - } - exoProgress?.updateLayoutParams { - bottomMargin = insets.bottom + progressOriginalMargin - } - exoControls?.updatePadding(left = insets.left, right = insets.right) - exoProgress?.updatePadding(left = insets.left, right = insets.right) } } @@ -324,7 +309,7 @@ class PreviewMediaFragment : setShowNextButton(false) setShowPreviousButton(false) player = exoPlayer - setFullscreenButtonClickListener { startFullScreenVideo() } + setFullscreenButton(isFullscreen = false) { startFullScreenVideo() } } } @@ -598,22 +583,12 @@ class PreviewMediaFragment : private const val AUTOPLAY = "AUTOPLAY" private const val IS_LIVE_PHOTO = "IS_LIVE_PHOTO" - /** - * Creates a fragment to preview a file. - * - * - * When 'fileToDetail' or 'user' are null - * - * @param fileToDetail An [OCFile] to preview in the fragment - * @param user Currently active user - */ - @JvmStatic fun newInstance( fileToDetail: OCFile?, user: User?, - startPlaybackPosition: Long, - autoplay: Boolean, - isLivePhoto: Boolean + startPlaybackPosition: Long = 0, + autoplay: Boolean = false, + isLivePhoto: Boolean = false ): PreviewMediaFragment = PreviewMediaFragment().apply { arguments = Bundle().apply { putParcelable(FILE, fileToDetail) @@ -624,14 +599,7 @@ class PreviewMediaFragment : } } - /** - * Helper method to test if an [OCFile] can be passed to a [PreviewMediaFragment] to be previewed. - * - * @param file File to test if can be previewed. - * @return 'True' if the file can be handled by the fragment. - */ - @JvmStatic - fun canBePreviewed(file: OCFile?): Boolean = + fun isAudioOrVideo(file: OCFile?): Boolean = file != null && (MimeTypeUtil.isAudio(file) || MimeTypeUtil.isVideo(file)) } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaPagerAdapter.kt similarity index 78% rename from app/src/main/java/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.kt rename to app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaPagerAdapter.kt index c614ecb2aa17..91237ec84f63 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaPagerAdapter.kt @@ -26,7 +26,7 @@ import com.owncloud.android.utils.FileStorageUtils /** * Adapter class that provides Fragment instances */ -class PreviewImagePagerAdapter : FragmentStateAdapter { +class PreviewMediaPagerAdapter : FragmentStateAdapter { private var selectedFile: OCFile? = null private var imageFiles: MutableList = mutableListOf() @@ -132,15 +132,10 @@ class PreviewImagePagerAdapter : FragmentStateAdapter { notifyItemRemoved(position) } - /** - * Returns the image files handled by the adapter. - * - * @return OCFile desired image or null if position is not in adapter - */ @Suppress("TooGenericExceptionCaught") fun getFileAt(position: Int): OCFile? = try { imageFiles[position] - } catch (exception: IndexOutOfBoundsException) { + } catch (_: IndexOutOfBoundsException) { null } @@ -149,36 +144,40 @@ class PreviewImagePagerAdapter : FragmentStateAdapter { } fun getItem(i: Int): Fragment { - val file = getFileAt(i) - val fragment: Fragment - val ignoreFirstSavedState = mObsoletePositions.contains(i) - - if (file == null) { - fragment = PreviewImageErrorFragment.newInstance() - } else if (file.isDown) { - fragment = PreviewImageFragment.newInstance(file, ignoreFirstSavedState, false) + val fragment = fragmentFor(getFileAt(i), i, mObsoletePositions.contains(i)) + mObsoletePositions.remove(i) + return fragment + } + + private fun fragmentFor(file: OCFile?, position: Int, ignoreFirstSavedState: Boolean): Fragment = when { + file == null -> PreviewImageErrorFragment.newInstance() + file.isDown -> fragmentForDownloaded(file, ignoreFirstSavedState) + else -> fragmentForNotDownloaded(file, position, ignoreFirstSavedState) + } + + private fun fragmentForDownloaded(file: OCFile, ignoreFirstSavedState: Boolean): Fragment = + if (PreviewMediaFragment.isAudioOrVideo(file)) { + PreviewMediaFragment.newInstance(file, user) } else { - addVideoOfLivePhoto(file) - - if (mDownloadErrors.remove(i)) { - fragment = FileDownloadFragment.newInstance(file, user, true) - (fragment as FileDownloadFragment).setError(true) - } else { - fragment = if (file.isEncrypted) { - // The FileDownloadFragment is used exclusively for encrypted files, as they cannot be previewed - // without first being downloaded. - FileDownloadFragment.newInstance(file, user, ignoreFirstSavedState) - } else if (PreviewMediaFragment.canBePreviewed(file)) { - val isLivePhoto = file.livePhotoVideo != null - PreviewMediaFragment.newInstance(file, user, 0, false, isLivePhoto) - } else { - PreviewImageFragment.newInstance(file, ignoreFirstSavedState, true) - } - } + PreviewImageFragment.newInstance(file, ignoreFirstSavedState, false) } - mObsoletePositions.remove(i) - return fragment + private fun fragmentForNotDownloaded(file: OCFile, position: Int, ignoreFirstSavedState: Boolean): Fragment { + addVideoOfLivePhoto(file) + + return when { + mDownloadErrors.remove(position) -> + FileDownloadFragment.newInstance(file, user, true).apply { setError(true) } + + // The FileDownloadFragment is used exclusively for encrypted files, as they cannot be previewed + // without first being downloaded. + file.isEncrypted -> FileDownloadFragment.newInstance(file, user, ignoreFirstSavedState) + + PreviewMediaFragment.isAudioOrVideo(file) -> + PreviewMediaFragment.newInstance(file, user) + + else -> PreviewImageFragment.newInstance(file, ignoreFirstSavedState, true) + } } fun getFilePosition(file: OCFile): Int = imageFiles.indexOf(file) @@ -192,14 +191,6 @@ class PreviewImagePagerAdapter : FragmentStateAdapter { imageFiles[position] = file } - fun updateWithDownloadError(position: Int) { - val fragmentToUpdate = mCachedFragments[position] - if (fragmentToUpdate != null) { - mObsoleteFragments.add(fragmentToUpdate) - } - mDownloadErrors.add(position) - } - fun pendingErrorAt(position: Int): Boolean = mDownloadErrors.contains(position) override fun createFragment(position: Int): Fragment = getItem(position) diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewVideoFullscreenDialog.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewVideoFullscreenDialog.kt index 8fbb7c4bd909..e734cf9dcb33 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewVideoFullscreenDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewVideoFullscreenDialog.kt @@ -1,6 +1,7 @@ /* * Nextcloud - Android Client * + * SPDX-FileCopyrightText: 2026 Alper Ozturk * SPDX-FileCopyrightText: 2022 Álvaro Brey * SPDX-FileCopyrightText: 2022 Nextcloud GmbH * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only @@ -13,6 +14,7 @@ import android.view.ViewGroup import android.view.Window import androidx.activity.addCallback import androidx.annotation.OptIn +import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat @@ -23,6 +25,8 @@ import androidx.media3.ui.PlayerView import com.nextcloud.client.media.ExoplayerListener import com.nextcloud.client.media.NextcloudExoPlayer import com.nextcloud.common.NextcloudClient +import com.nextcloud.utils.extensions.applyControlsInsets +import com.nextcloud.utils.extensions.setFullscreenButton import com.owncloud.android.R import com.owncloud.android.databinding.DialogPreviewVideoBinding import com.owncloud.android.lib.common.utils.Log_OC @@ -97,8 +101,11 @@ class PreviewVideoFullscreenDialog( } setOnShowListener { enableImmersiveMode() + keepControlsClearOfSystemBars() switchTargetViewFromSource() - binding.videoPlayer.setFullscreenButtonClickListener { activity.onBackPressedDispatcher.onBackPressed() } + binding.videoPlayer.setFullscreenButton(isFullscreen = true) { + activity.onBackPressedDispatcher.onBackPressed() + } if (isPlaying) { mExoPlayer.play() } @@ -121,7 +128,6 @@ class PreviewVideoFullscreenDialog( mExoPlayer.pause() } setOnDismissListener { - disableImmersiveMode() playingStateListener?.let { mExoPlayer.removeListener(it) } @@ -145,9 +151,9 @@ class PreviewVideoFullscreenDialog( } private fun enableImmersiveMode() { - activity.window?.let { - hideInset(it, WindowInsetsCompat.Type.systemBars()) - } + val dialogWindow = window ?: return + WindowCompat.setDecorFitsSystemWindows(dialogWindow, false) + hideInset(dialogWindow, WindowInsetsCompat.Type.systemBars()) } private fun hideInset(window: Window, type: Int) { @@ -158,12 +164,16 @@ class PreviewVideoFullscreenDialog( windowInsetsController.hide(type) } - private fun disableImmersiveMode() { - activity.window?.let { - val windowInsetsController = - WindowCompat.getInsetsController(it, it.decorView) - windowInsetsController.show(WindowInsetsCompat.Type.systemBars()) - } ?: return + private fun keepControlsClearOfSystemBars() { + ViewCompat.setOnApplyWindowInsetsListener(binding.videoPlayer) { _, windowInsets -> + binding.videoPlayer.applyControlsInsets( + windowInsets.getInsets( + WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout() + ) + ) + windowInsets + } + ViewCompat.requestApplyInsets(binding.videoPlayer) } companion object {