diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d865cae..fc41a69 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -50,7 +50,7 @@ - + diff --git a/app/src/main/java/sushi/hardcore/droidfs/adapters/ExplorerElementAdapter.kt b/app/src/main/java/sushi/hardcore/droidfs/adapters/ExplorerElementAdapter.kt index aa07fcc..fd75151 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/adapters/ExplorerElementAdapter.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/adapters/ExplorerElementAdapter.kt @@ -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, diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt index 1265264..3663fc5 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt @@ -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() 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 { + 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) diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/ImageViewer.kt b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/ImageViewer.kt index 8e29916..c0ba353 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/ImageViewer.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/ImageViewer.kt @@ -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? = 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 - loadWholeFile(filePath) { - originalOrientation = 0f - requestBuilder = Glide.with(this).load(it) - requestBuilder?.into(binding.imageViewer) - rotationAngle = originalOrientation + if (newImage || imageViewModel.imageBytes == null) { + loadWholeFile(filePath) { + imageViewModel.imageBytes = it + requestBuilder = Glide.with(this).load(it) + requestBuilder?.into(binding.imageViewer) + imageViewModel.rotationAngle = 0f + } + } else { + requestBuilder = Glide.with(this).load(imageViewModel.imageBytes) + if (imageViewModel.rotationAngle.mod(360f) != 0f) { + rotateImage() + } else { + requestBuilder?.into(binding.imageViewer) + } } } @@ -180,10 +192,16 @@ 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() - if (slideshowActive){ + loadImage(true) + if (slideshowActive) { if (!slideshowSwipe) { //reset slideshow delay if user swipes handler.removeCallbacks(slideshowNext) } @@ -214,14 +232,13 @@ class ImageViewer: FileViewerActivity() { } } - private fun rotateImage(){ - binding.imageViewer.restoreZoomNormal() - orientationTransformation = OrientationTransformation(rotationAngle) + private fun rotateImage() { + 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() diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/PdfViewer.kt b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/PdfViewer.kt index c10e859..097a74f 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/PdfViewer.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/PdfViewer.kt @@ -10,7 +10,6 @@ class PdfViewer: FileViewerActivity() { init { applyCustomTheme = false } - override var fullscreenMode = false private lateinit var pdfViewer: PdfViewer override fun getFileType(): String { diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/TextEditor.kt b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/TextEditor.kt index 324aa0b..7e56dd7 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/TextEditor.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/TextEditor.kt @@ -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 diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/VideoPlayer.kt b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/VideoPlayer.kt index caaf306..a785aef 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/VideoPlayer.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/VideoPlayer.kt @@ -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 = diff --git a/app/src/main/res/drawable/icon_mod.xml b/app/src/main/res/drawable/icon_mod.xml deleted file mode 100644 index d0267e7..0000000 --- a/app/src/main/res/drawable/icon_mod.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index fb70504..d6c9195 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -159,8 +159,6 @@ إظهار المجلدات في بداية القائمة التدوير التلقائي لشاشة مشغل الفيديو تدوير الشاشة تلقائيًا لتناسب أبعاد الفيديو - وضع ملء الشاشة القديم - فعل هذا الخيار كان windowInsetsController لا يعمل بشكل صحيح على جهازك (عادة لا تكون هناك حاجة) لم يتم العثور على مستكشف للملفات. رجاء ثبت واحد ثم أعد المحاولة. إغلاق المجلد المشفر تصنيف حسب diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 040e5c6..dce1435 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -159,8 +159,6 @@ Mostrar las carpetas al principio de la lista Rotación automática de pantalla en el reproductor de vídeo Rotación automática de la pantalla para adaptarla a las dimensiones del vídeo - Modo de pantalla completa heredado - Prueba esto si windowInsetsController no funciona correctamente en tu dispositivo (normalmente no es necesario) No se ha encontrado ningún explorador de archivos. Por favor, instala uno y vuelve a intentarlo. Cerrar volumen Ordenar por diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index cca68de..ebfe983 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -155,8 +155,6 @@ Mostrar pastas no início da lista Girar automaticamente a tela ao reproduzir vídeo Girar automaticamente a tela para encaixar em dimensões de vídeo - Modo legado de tela completa - Tente isto se windowInsetsController não funciona corretamente no seu dispositivo (geralmente não é necessário) Não foi possível encontrar gerenciador de arquivos. Instale o app e tente novamente. Fechar o volume Ordenar por diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 09bc126..20409bb 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -153,8 +153,6 @@ Показывать папки в начале списка Автоповорот видео Автоматический поворот экрана в соответствии с размерами видео - Устаревший полноэкранный режим - Использовать данный режим, если windowInsetsController не работает должным образом на вашем устройстве (обычно не требуется) Проводник файлов не найден. Установите его и повторите попытку. Закрыть том Сортировка diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c5b04a7..c08c1ff 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -160,8 +160,6 @@ Show folders at the beginning of the list Video player screen auto-rotation Auto-rotate the screen to fit video dimensions - Legacy fullscreen mode - Try this if windowInsetsController doesn\'t work properly on your device (usually not needed) No file explorer found. Please install one and retry. Close volume Sort By diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml index cbf8b1f..a28bee5 100644 --- a/app/src/main/res/xml/root_preferences.xml +++ b/app/src/main/res/xml/root_preferences.xml @@ -67,13 +67,6 @@ android:defaultValue="false" android:icon="@drawable/icon_screen_rotation"/> - -