forked from hardcoresushi/DroidFS
Hide navigation bar in full screen mode
This commit is contained in:
parent
22b1522192
commit
821c853a22
@ -50,7 +50,7 @@
|
||||
<activity android:name=".explorers.ExplorerActivity"/>
|
||||
<activity android:name=".explorers.ExplorerActivityPick"/>
|
||||
<activity android:name=".explorers.ExplorerActivityDrop"/>
|
||||
<activity android:name=".file_viewers.ImageViewer" android:configChanges="screenSize|orientation" /> <!-- don't reload content on configuration change -->
|
||||
<activity android:name=".file_viewers.ImageViewer"/>
|
||||
<activity android:name=".file_viewers.VideoPlayer" android:configChanges="screenSize|orientation" />
|
||||
<activity android:name=".file_viewers.PdfViewer" android:configChanges="screenSize|orientation" android:theme="@style/AppTheme" />
|
||||
<activity android:name=".file_viewers.AudioPlayer" android:configChanges="screenSize|orientation" />
|
||||
|
@ -125,7 +125,7 @@ class ExplorerElementAdapter(
|
||||
volume.loadWholeFile(fullPath, maxSize = adapter.thumbnailMaxSize).first?.let {
|
||||
if (isActive) {
|
||||
withContext(Dispatchers.Main) {
|
||||
if (isActive && !adapter.activity.isFinishing) {
|
||||
if (isActive && !adapter.activity.isFinishing && !adapter.activity.isDestroyed) {
|
||||
target = Glide.with(adapter.activity).load(it).skipMemoryCache(true).into(object : DrawableImageViewTarget(icon) {
|
||||
override fun onResourceReady(
|
||||
resource: Drawable,
|
||||
|
@ -1,10 +1,15 @@
|
||||
package sushi.hardcore.droidfs.file_viewers
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import android.view.WindowInsets
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updateMargins
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.isActive
|
||||
@ -29,10 +34,7 @@ abstract class FileViewerActivity: BaseActivity() {
|
||||
private var wasMapped = false
|
||||
protected val mappedPlaylist = mutableListOf<ExplorerElement>()
|
||||
protected var currentPlaylistIndex = -1
|
||||
protected open var fullscreenMode = true
|
||||
private val legacyMod by lazy {
|
||||
sharedPrefs.getBoolean("legacyMod", false)
|
||||
}
|
||||
private val isLegacyFullscreen = Build.VERSION.SDK_INT <= Build.VERSION_CODES.R
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -44,38 +46,61 @@ abstract class FileViewerActivity: BaseActivity() {
|
||||
windowInsetsController.addOnControllableInsetsChangedListener { _, typeMask ->
|
||||
windowTypeMask = typeMask
|
||||
}
|
||||
if (fullscreenMode) {
|
||||
fixNavBarColor()
|
||||
hideSystemUi()
|
||||
}
|
||||
windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE
|
||||
viewFile()
|
||||
}
|
||||
|
||||
private fun fixNavBarColor() {
|
||||
window.navigationBarColor = ContextCompat.getColor(this, R.color.fullScreenBackgroundColor)
|
||||
open fun showPartialSystemUi() {
|
||||
if (isLegacyFullscreen) {
|
||||
@Suppress("Deprecation")
|
||||
window.decorView.systemUiVisibility =
|
||||
View.SYSTEM_UI_FLAG_FULLSCREEN or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
} else {
|
||||
windowInsetsController.hide(WindowInsetsCompat.Type.statusBars())
|
||||
windowInsetsController.show(WindowInsetsCompat.Type.navigationBars())
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideSystemUi() {
|
||||
if (legacyMod) {
|
||||
open fun hideSystemUi() {
|
||||
if (isLegacyFullscreen) {
|
||||
@Suppress("Deprecation")
|
||||
window.decorView.systemUiVisibility =
|
||||
View.SYSTEM_UI_FLAG_LOW_PROFILE or
|
||||
View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
View.SYSTEM_UI_FLAG_FULLSCREEN or
|
||||
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
|
||||
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
} else {
|
||||
windowInsetsController.hide(WindowInsetsCompat.Type.statusBars())
|
||||
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
window.setDecorFitsSystemWindows(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected fun applyNavigationBarMargin(root: View) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(root) { _, insets ->
|
||||
root.updateLayoutParams<FrameLayout.LayoutParams> {
|
||||
val newInsets = insets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars())
|
||||
this.updateMargins(
|
||||
left = newInsets.left,
|
||||
top = newInsets.top,
|
||||
right = newInsets.right,
|
||||
bottom = newInsets.bottom
|
||||
)
|
||||
}
|
||||
insets
|
||||
}
|
||||
} else {
|
||||
root.fitsSystemWindows = true
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun getFileType(): String
|
||||
abstract fun viewFile()
|
||||
|
||||
override fun onUserInteraction() {
|
||||
super.onUserInteraction()
|
||||
if (fullscreenMode && windowTypeMask and WindowInsetsCompat.Type.statusBars() == 0) {
|
||||
hideSystemUi()
|
||||
}
|
||||
}
|
||||
|
||||
protected fun loadWholeFile(path: String, fileSize: Long? = null, callback: (ByteArray) -> Unit) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val result = encryptedVolume.loadWholeFile(path, size = fileSize)
|
||||
|
@ -10,6 +10,8 @@ import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.Toast
|
||||
import androidx.activity.addCallback
|
||||
import androidx.activity.viewModels
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.RequestBuilder
|
||||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
|
||||
@ -31,18 +33,23 @@ class ImageViewer: FileViewerActivity() {
|
||||
private const val MIN_SWIPE_DISTANCE = 150
|
||||
}
|
||||
|
||||
class ImageViewModel : ViewModel() {
|
||||
var imageBytes: ByteArray? = null
|
||||
var rotationAngle: Float = 0f
|
||||
}
|
||||
|
||||
private lateinit var fileName: String
|
||||
private lateinit var handler: Handler
|
||||
private val imageViewModel: ImageViewModel by viewModels()
|
||||
private var requestBuilder: RequestBuilder<Drawable>? = null
|
||||
private var x1 = 0F
|
||||
private var x2 = 0F
|
||||
private var slideshowActive = false
|
||||
private var originalOrientation: Float = 0f
|
||||
private var rotationAngle: Float = 0F
|
||||
private var orientationTransformation: OrientationTransformation? = null
|
||||
private val hideUI = Runnable {
|
||||
binding.actionButtons.visibility = View.GONE
|
||||
binding.topBar.visibility = View.GONE
|
||||
hideSystemUi()
|
||||
}
|
||||
private val slideshowNext = Runnable {
|
||||
if (slideshowActive){
|
||||
@ -60,6 +67,8 @@ class ImageViewer: FileViewerActivity() {
|
||||
binding = ActivityImageViewerBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
supportActionBar?.hide()
|
||||
showPartialSystemUi()
|
||||
applyNavigationBarMargin(binding.root)
|
||||
handler = Handler(mainLooper)
|
||||
binding.imageViewer.setOnInteractionListener(object : ZoomableImageView.OnInteractionListener {
|
||||
override fun onSingleTap(event: MotionEvent?) {
|
||||
@ -67,6 +76,7 @@ class ImageViewer: FileViewerActivity() {
|
||||
if (binding.actionButtons.visibility == View.GONE) {
|
||||
binding.actionButtons.visibility = View.VISIBLE
|
||||
binding.topBar.visibility = View.VISIBLE
|
||||
showPartialSystemUi()
|
||||
handler.postDelayed(hideUI, hideDelay)
|
||||
} else {
|
||||
hideUI.run()
|
||||
@ -102,7 +112,7 @@ class ImageViewer: FileViewerActivity() {
|
||||
if (mappedPlaylist.size == 0) { //deleted all images of the playlist
|
||||
goBackToExplorer()
|
||||
} else {
|
||||
loadImage()
|
||||
loadImage(true)
|
||||
}
|
||||
} else {
|
||||
CustomAlertDialogBuilder(this, theme)
|
||||
@ -140,14 +150,8 @@ class ImageViewer: FileViewerActivity() {
|
||||
swipeImage(-1F)
|
||||
}
|
||||
}
|
||||
binding.imageRotateRight.setOnClickListener {
|
||||
rotationAngle += 90
|
||||
rotateImage()
|
||||
}
|
||||
binding.imageRotateLeft.setOnClickListener {
|
||||
rotationAngle -= 90
|
||||
rotateImage()
|
||||
}
|
||||
binding.imageRotateRight.setOnClickListener { onClickRotate(90f) }
|
||||
binding.imageRotateLeft.setOnClickListener { onClickRotate(-90f) }
|
||||
onBackPressedDispatcher.addCallback(this) {
|
||||
if (slideshowActive) {
|
||||
stopSlideshow()
|
||||
@ -158,19 +162,27 @@ class ImageViewer: FileViewerActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
loadImage()
|
||||
loadImage(false)
|
||||
handler.postDelayed(hideUI, hideDelay)
|
||||
}
|
||||
|
||||
private fun loadImage(){
|
||||
private fun loadImage(newImage: Boolean) {
|
||||
fileName = File(filePath).name
|
||||
binding.textFilename.text = fileName
|
||||
requestBuilder = null
|
||||
if (newImage || imageViewModel.imageBytes == null) {
|
||||
loadWholeFile(filePath) {
|
||||
originalOrientation = 0f
|
||||
imageViewModel.imageBytes = it
|
||||
requestBuilder = Glide.with(this).load(it)
|
||||
requestBuilder?.into(binding.imageViewer)
|
||||
rotationAngle = originalOrientation
|
||||
imageViewModel.rotationAngle = 0f
|
||||
}
|
||||
} else {
|
||||
requestBuilder = Glide.with(this).load(imageViewModel.imageBytes)
|
||||
if (imageViewModel.rotationAngle.mod(360f) != 0f) {
|
||||
rotateImage()
|
||||
} else {
|
||||
requestBuilder?.into(binding.imageViewer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,9 +192,15 @@ class ImageViewer: FileViewerActivity() {
|
||||
handler.postDelayed(hideUI, hideDelay)
|
||||
}
|
||||
|
||||
private fun onClickRotate(angle: Float) {
|
||||
imageViewModel.rotationAngle += angle
|
||||
binding.imageViewer.restoreZoomNormal()
|
||||
rotateImage()
|
||||
}
|
||||
|
||||
private fun swipeImage(deltaX: Float, slideshowSwipe: Boolean = false){
|
||||
playlistNext(deltaX < 0)
|
||||
loadImage()
|
||||
loadImage(true)
|
||||
if (slideshowActive) {
|
||||
if (!slideshowSwipe) { //reset slideshow delay if user swipes
|
||||
handler.removeCallbacks(slideshowNext)
|
||||
@ -215,13 +233,12 @@ class ImageViewer: FileViewerActivity() {
|
||||
}
|
||||
|
||||
private fun rotateImage() {
|
||||
binding.imageViewer.restoreZoomNormal()
|
||||
orientationTransformation = OrientationTransformation(rotationAngle)
|
||||
orientationTransformation = OrientationTransformation(imageViewModel.rotationAngle)
|
||||
requestBuilder?.transform(orientationTransformation)?.into(binding.imageViewer)
|
||||
}
|
||||
|
||||
private fun askSaveRotation(callback: () -> Unit){
|
||||
if (rotationAngle.mod(360f) != originalOrientation && !slideshowActive) {
|
||||
if (imageViewModel.rotationAngle.mod(360f) != 0f && !slideshowActive) {
|
||||
CustomAlertDialogBuilder(this, theme)
|
||||
.keepFullScreen()
|
||||
.setTitle(R.string.warning)
|
||||
@ -235,7 +252,7 @@ class ImageViewer: FileViewerActivity() {
|
||||
Bitmap.CompressFormat.PNG
|
||||
} else {
|
||||
Bitmap.CompressFormat.JPEG
|
||||
}, 100, outputStream) == true
|
||||
}, 90, outputStream) == true
|
||||
){
|
||||
if (encryptedVolume.importFile(ByteArrayInputStream(outputStream.toByteArray()), filePath)) {
|
||||
Toast.makeText(this, R.string.image_saved_successfully, Toast.LENGTH_SHORT).show()
|
||||
|
@ -10,7 +10,6 @@ class PdfViewer: FileViewerActivity() {
|
||||
init {
|
||||
applyCustomTheme = false
|
||||
}
|
||||
override var fullscreenMode = false
|
||||
private lateinit var pdfViewer: PdfViewer
|
||||
|
||||
override fun getFileType(): String {
|
||||
|
@ -13,7 +13,6 @@ import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder
|
||||
import java.io.File
|
||||
|
||||
class TextEditor: FileViewerActivity() {
|
||||
override var fullscreenMode = false
|
||||
private lateinit var fileName: String
|
||||
private lateinit var editor: EditText
|
||||
private var changedSinceLastSave = false
|
||||
|
@ -2,6 +2,7 @@ package sushi.hardcore.droidfs.file_viewers
|
||||
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.res.Configuration
|
||||
import android.view.View
|
||||
import com.google.android.exoplayer2.ExoPlayer
|
||||
import com.google.android.exoplayer2.ui.StyledPlayerView
|
||||
import sushi.hardcore.droidfs.databinding.ActivityVideoPlayerBinding
|
||||
@ -16,9 +17,15 @@ class VideoPlayer: MediaPlayer() {
|
||||
override fun viewFile() {
|
||||
binding = ActivityVideoPlayerBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
applyNavigationBarMargin(binding.root)
|
||||
binding.videoPlayer.doubleTapOverlay = binding.doubleTapOverlay
|
||||
binding.videoPlayer.setControllerVisibilityListener(StyledPlayerView.ControllerVisibilityListener { visibility ->
|
||||
binding.topBar.visibility = visibility
|
||||
if (visibility == View.VISIBLE) {
|
||||
showPartialSystemUi()
|
||||
} else {
|
||||
hideSystemUi()
|
||||
}
|
||||
})
|
||||
binding.rotateButton.setOnClickListener {
|
||||
requestedOrientation =
|
||||
|
@ -1,6 +0,0 @@
|
||||
<vector android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?attr/colorAccent"
|
||||
android:pathData="M5,16c0,3.87 3.13,7 7,7s7,-3.13 7,-7v-4L5,12v4zM16.12,4.37l2.1,-2.1 -0.82,-0.83 -2.3,2.31C14.16,3.28 13.12,3 12,3s-2.16,0.28 -3.09,0.75L6.6,1.44l-0.82,0.83 2.1,2.1C6.14,5.64 5,7.68 5,10v1h14v-1c0,-2.32 -1.14,-4.36 -2.88,-5.63zM9,9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM15,9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1z"/>
|
||||
</vector>
|
@ -159,8 +159,6 @@
|
||||
<string name="folders_first_summary">إظهار المجلدات في بداية القائمة</string>
|
||||
<string name="auto_fit_title">التدوير التلقائي لشاشة مشغل الفيديو</string>
|
||||
<string name="auto_fit_summary">تدوير الشاشة تلقائيًا لتناسب أبعاد الفيديو</string>
|
||||
<string name="legacy_mod_title">وضع ملء الشاشة القديم</string>
|
||||
<string name="legacy_mod_summary">فعل هذا الخيار كان windowInsetsController لا يعمل بشكل صحيح على جهازك (عادة لا تكون هناك حاجة)</string>
|
||||
<string name="open_tree_failed">لم يتم العثور على مستكشف للملفات. رجاء ثبت واحد ثم أعد المحاولة.</string>
|
||||
<string name="close_volume">إغلاق المجلد المشفر</string>
|
||||
<string name="sort_by">تصنيف حسب</string>
|
||||
|
@ -159,8 +159,6 @@
|
||||
<string name="folders_first_summary">Mostrar las carpetas al principio de la lista</string>
|
||||
<string name="auto_fit_title">Rotación automática de pantalla en el reproductor de vídeo</string>
|
||||
<string name="auto_fit_summary">Rotación automática de la pantalla para adaptarla a las dimensiones del vídeo</string>
|
||||
<string name="legacy_mod_title">Modo de pantalla completa heredado</string>
|
||||
<string name="legacy_mod_summary">Prueba esto si windowInsetsController no funciona correctamente en tu dispositivo (normalmente no es necesario)</string>
|
||||
<string name="open_tree_failed">No se ha encontrado ningún explorador de archivos. Por favor, instala uno y vuelve a intentarlo.</string>
|
||||
<string name="close_volume">Cerrar volumen</string>
|
||||
<string name="sort_by">Ordenar por</string>
|
||||
|
@ -155,8 +155,6 @@
|
||||
<string name="folders_first_summary">Mostrar pastas no início da lista</string>
|
||||
<string name="auto_fit_title">Girar automaticamente a tela ao reproduzir vídeo</string>
|
||||
<string name="auto_fit_summary">Girar automaticamente a tela para encaixar em dimensões de vídeo</string>
|
||||
<string name="legacy_mod_title">Modo legado de tela completa</string>
|
||||
<string name="legacy_mod_summary">Tente isto se windowInsetsController não funciona corretamente no seu dispositivo (geralmente não é necessário)</string>
|
||||
<string name="open_tree_failed">Não foi possível encontrar gerenciador de arquivos. Instale o app e tente novamente.</string>
|
||||
<string name="close_volume">Fechar o volume</string>
|
||||
<string name="sort_by">Ordenar por</string>
|
||||
|
@ -153,8 +153,6 @@
|
||||
<string name="folders_first_summary">Показывать папки в начале списка</string>
|
||||
<string name="auto_fit_title">Автоповорот видео</string>
|
||||
<string name="auto_fit_summary">Автоматический поворот экрана в соответствии с размерами видео</string>
|
||||
<string name="legacy_mod_title">Устаревший полноэкранный режим</string>
|
||||
<string name="legacy_mod_summary">Использовать данный режим, если windowInsetsController не работает должным образом на вашем устройстве (обычно не требуется)</string>
|
||||
<string name="open_tree_failed">Проводник файлов не найден. Установите его и повторите попытку.</string>
|
||||
<string name="close_volume">Закрыть том</string>
|
||||
<string name="sort_by">Сортировка</string>
|
||||
|
@ -160,8 +160,6 @@
|
||||
<string name="folders_first_summary">Show folders at the beginning of the list</string>
|
||||
<string name="auto_fit_title">Video player screen auto-rotation</string>
|
||||
<string name="auto_fit_summary">Auto-rotate the screen to fit video dimensions</string>
|
||||
<string name="legacy_mod_title">Legacy fullscreen mode</string>
|
||||
<string name="legacy_mod_summary">Try this if windowInsetsController doesn\'t work properly on your device (usually not needed)</string>
|
||||
<string name="open_tree_failed">No file explorer found. Please install one and retry.</string>
|
||||
<string name="close_volume">Close volume</string>
|
||||
<string name="sort_by">Sort By</string>
|
||||
|
@ -67,13 +67,6 @@
|
||||
android:defaultValue="false"
|
||||
android:icon="@drawable/icon_screen_rotation"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:title="@string/legacy_mod_title"
|
||||
android:summary="@string/legacy_mod_summary"
|
||||
android:key="legacyMod"
|
||||
android:defaultValue="false"
|
||||
android:icon="@drawable/icon_mod"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:title="@string/password_fallback"
|
||||
android:summary="@string/password_fallback_summary"
|
||||
|
Loading…
Reference in New Issue
Block a user