diff --git a/app/build.gradle b/app/build.gradle index c21621d37..8d84e7283 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -46,7 +46,7 @@ ext { } dependencies { - implementation 'com.simplemobiletools:commons:3.14.12' + implementation 'com.simplemobiletools:commons:3.16.1' implementation 'com.theartofdev.edmodo:android-image-cropper:2.6.0' implementation 'com.android.support:multidex:1.0.3' implementation 'com.google.code.gson:gson:2.8.2' diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SetWallpaperActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SetWallpaperActivity.kt index 9f149647c..763ec25c8 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SetWallpaperActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SetWallpaperActivity.kt @@ -11,8 +11,8 @@ import android.view.Menu import android.view.MenuItem import com.simplemobiletools.commons.dialogs.RadioGroupDialog import com.simplemobiletools.commons.extensions.isActivityDestroyed -import com.simplemobiletools.commons.extensions.isNougatPlus import com.simplemobiletools.commons.extensions.toast +import com.simplemobiletools.commons.helpers.isNougatPlus import com.simplemobiletools.commons.models.RadioItem import com.simplemobiletools.gallery.R import com.theartofdev.edmodo.cropper.CropImageView diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt index 5077999da..f65de839c 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt @@ -2,6 +2,7 @@ package com.simplemobiletools.gallery.activities import android.animation.Animator import android.animation.ValueAnimator +import android.annotation.TargetApi import android.app.Activity import android.content.Intent import android.content.pm.ActivityInfo @@ -522,9 +523,16 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View } private fun saveImageToFile(oldPath: String, newPath: String) { - val newFile = File(newPath) toast(R.string.saving) + if (oldPath == newPath && oldPath.isJpg()) { + if (tryRotateByExif(oldPath)) { + return + } + } + + val newFile = File(newPath) val tmpFile = File(filesDir, ".tmp_${newPath.getFilenameFromPath()}") + try { val bitmap = BitmapFactory.decodeFile(oldPath) getFileOutputStream(tmpFile.toFileDirItem(applicationContext)) { @@ -535,7 +543,8 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View val oldLastModified = getCurrentFile().lastModified() if (oldPath.isJpg()) { - saveRotation(getCurrentFile(), tmpFile) + copyFile(getCurrentFile(), tmpFile) + saveExifRotation(ExifInterface(tmpFile.absolutePath)) } else { saveFile(tmpFile, bitmap, it as FileOutputStream) } @@ -573,6 +582,33 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View } } + @TargetApi(Build.VERSION_CODES.N) + private fun tryRotateByExif(path: String): Boolean { + try { + if (!isPathOnSD(path)) { + saveExifRotation(ExifInterface(path)) + mRotationDegrees = 0f + invalidateOptionsMenu() + toast(R.string.file_saved) + return true + } else if (isNougatPlus()) { + val documentFile = getSomeDocumentFile(path) + if (documentFile != null) { + val parcelFileDescriptor = contentResolver.openFileDescriptor(documentFile.uri, "rw") + val fileDescriptor = parcelFileDescriptor.fileDescriptor + saveExifRotation(ExifInterface(fileDescriptor)) + mRotationDegrees = 0f + invalidateOptionsMenu() + toast(R.string.file_saved) + return true + } + } + } catch (e: Exception) { + showErrorToast(e) + } + return false + } + private fun copyFile(source: File, destination: File) { var inputStream: InputStream? = null var out: OutputStream? = null @@ -594,9 +630,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View bmp.compress(file.absolutePath.getCompressionFormat(), 90, out) } - private fun saveRotation(source: File, destination: File) { - copyFile(source, destination) - val exif = ExifInterface(destination.absolutePath) + private fun saveExifRotation(exif: ExifInterface) { val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL) val orientationDegrees = (degreesForRotation(orientation) + mRotationDegrees) % 360 exif.setAttribute(ExifInterface.TAG_ORIENTATION, rotationFromDegrees(orientationDegrees)) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/Activity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/Activity.kt index 87a1b6971..c1c0e0dbd 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/Activity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/Activity.kt @@ -73,7 +73,6 @@ fun Activity.launchCamera() { fun SimpleActivity.launchAbout() { val faqItems = arrayListOf( - FAQItem(R.string.faq_2_title_commons, R.string.faq_2_text_commons), FAQItem(R.string.faq_3_title_commons, R.string.faq_3_text_commons), FAQItem(R.string.faq_1_title, R.string.faq_1_text), FAQItem(R.string.faq_2_title, R.string.faq_2_text), @@ -83,9 +82,10 @@ fun SimpleActivity.launchAbout() { FAQItem(R.string.faq_6_title, R.string.faq_6_text), FAQItem(R.string.faq_7_title, R.string.faq_7_text), FAQItem(R.string.faq_8_title, R.string.faq_8_text), - FAQItem(R.string.faq_9_title, R.string.faq_9_text)) + FAQItem(R.string.faq_9_title, R.string.faq_9_text), + FAQItem(R.string.faq_2_title_commons, R.string.faq_2_text_commons)) - startAboutActivity(R.string.app_name, LICENSE_KOTLIN or LICENSE_GLIDE or LICENSE_CROPPER or LICENSE_MULTISELECT or LICENSE_RTL + startAboutActivity(R.string.app_name, LICENSE_GLIDE or LICENSE_CROPPER or LICENSE_MULTISELECT or LICENSE_RTL or LICENSE_SUBSAMPLING or LICENSE_PATTERN or LICENSE_REPRINT or LICENSE_GIF_DRAWABLE or LICENSE_PHOTOVIEW, BuildConfig.VERSION_NAME, faqItems) } @@ -150,7 +150,7 @@ fun BaseSimpleActivity.toggleFileVisibility(oldPath: String, hide: Boolean, call filename.substring(1, filename.length) } - val newPath = "$path/$filename" + val newPath = "$path$filename" renameFile(oldPath, newPath) { callback?.invoke(newPath) } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt index 8a5a3560e..4554ee3eb 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt @@ -10,6 +10,7 @@ import android.media.ExifInterface.* import android.net.Uri import android.os.AsyncTask import android.os.Bundle +import android.os.Handler import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -44,6 +45,7 @@ class PhotoFragment : ViewPagerFragment() { private var isFragmentVisible = false private var isFullscreen = false private var wasInit = false + private var useHalfResolution = false private var imageOrientation = -1 private var gifDrawable: GifDrawable? = null @@ -57,7 +59,7 @@ class PhotoFragment : ViewPagerFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { view = (inflater.inflate(R.layout.pager_photo_item, container, false) as ViewGroup).apply { subsampling_view.setOnClickListener { photoClicked() } - gif_view.setOnClickListener { photoClicked() } + photo_view.setOnClickListener { photoClicked() } instant_prev_item.setOnClickListener { listener?.goToPrevItem() } instant_next_item.setOnClickListener { listener?.goToNextItem() } @@ -69,7 +71,7 @@ class PhotoFragment : ViewPagerFragment() { if (subsampling_view.isVisible()) { subsampling_view.sendFakeClick(x, y) } else { - gif_view.sendFakeClick(x, y) + photo_view.sendFakeClick(x, y) } } } @@ -217,7 +219,7 @@ class PhotoFragment : ViewPagerFragment() { gifDrawable!!.stop() } - view.gif_view.setImageDrawable(gifDrawable) + view.photo_view.setImageDrawable(gifDrawable) } catch (e: Exception) { gifDrawable = null loadBitmap() @@ -231,6 +233,11 @@ class PhotoFragment : ViewPagerFragment() { if (degrees == 0f) { var targetWidth = if (ViewPagerActivity.screenWidth == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenWidth var targetHeight = if (ViewPagerActivity.screenHeight == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenHeight + if (useHalfResolution) { + targetWidth /= 2 + targetHeight /= 2 + } + if (imageOrientation == ORIENTATION_ROTATE_90) { targetWidth = targetHeight targetHeight = Target.SIZE_ORIGINAL @@ -247,14 +254,22 @@ class PhotoFragment : ViewPagerFragment() { .load(getPathToLoad(medium)) .apply(options) .listener(object : RequestListener { - override fun onLoadFailed(e: GlideException?, model: Any?, target: Target?, isFirstResource: Boolean) = false + override fun onLoadFailed(e: GlideException?, model: Any?, target: Target?, isFirstResource: Boolean): Boolean { + if (!useHalfResolution && e?.rootCauses?.first() is OutOfMemoryError) { + useHalfResolution = true + Handler().post { + loadBitmap(degrees) + } + } + return false + } override fun onResourceReady(resource: Bitmap?, model: Any?, target: Target?, dataSource: DataSource?, isFirstResource: Boolean): Boolean { if (isFragmentVisible) addZoomableView() return false } - }).into(view.gif_view) + }).into(view.photo_view) } else { val options = RequestOptions() .diskCacheStrategy(DiskCacheStrategy.NONE) @@ -265,7 +280,7 @@ class PhotoFragment : ViewPagerFragment() { .load(getPathToLoad(medium)) .thumbnail(0.2f) .apply(options) - .into(view.gif_view) + .into(view.photo_view) } } @@ -365,6 +380,7 @@ class PhotoFragment : ViewPagerFragment() { text = getMediumExtendedDetails(medium) setTextColor(context.config.textColor) beVisibleIf(text.isNotEmpty()) + alpha = if (!context!!.config.hideExtendedDetails || !isFullscreen) 1f else 0f onGlobalLayout { if (height != 0 && isAdded) { y = getExtendedDetailsY(height) @@ -379,7 +395,7 @@ class PhotoFragment : ViewPagerFragment() { override fun onDestroyView() { super.onDestroyView() if (activity?.isActivityDestroyed() == false) { - Glide.with(context!!).clear(view.gif_view) + Glide.with(context!!).clear(view.photo_view) view.subsampling_view.recycle() } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt index f704912b6..4349441ec 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt @@ -14,6 +14,7 @@ import android.view.animation.AnimationUtils import android.widget.SeekBar import android.widget.TextView import com.simplemobiletools.commons.extensions.* +import com.simplemobiletools.commons.helpers.isJellyBean1Plus import com.simplemobiletools.gallery.BuildConfig import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.activities.VideoActivity @@ -27,6 +28,7 @@ import java.io.IOException class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSeekBarChangeListener { private val PROGRESS = "progress" + private val MIN_SKIP_LENGTH = 2000 private var mMediaPlayer: MediaPlayer? = null private var mSurfaceView: SurfaceView? = null @@ -73,12 +75,12 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee mIsFragmentVisible = true } + mIsFullscreen = activity!!.window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == View.SYSTEM_UI_FLAG_FULLSCREEN setupPlayer() if (savedInstanceState != null) { mCurrTime = savedInstanceState.getInt(PROGRESS) } - mIsFullscreen = activity!!.window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == View.SYSTEM_UI_FLAG_FULLSCREEN checkFullscreen() wasInit = true @@ -433,7 +435,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee val screenWidth: Int val screenHeight: Int - if (activity!!.isJellyBean1Plus()) { + if (isJellyBean1Plus()) { val realMetrics = DisplayMetrics() display.getRealMetrics(realMetrics) screenWidth = realMetrics.widthPixels @@ -463,6 +465,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee text = getMediumExtendedDetails(medium) setTextColor(context.config.textColor) beVisibleIf(text.isNotEmpty()) + alpha = if (!context!!.config.hideExtendedDetails || !mIsFullscreen) 1f else 0f onGlobalLayout { if (height != 0 && isAdded) { y = getExtendedDetailsY(height) @@ -480,9 +483,11 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee } val curr = mMediaPlayer!!.currentPosition - val twoPercents = mMediaPlayer!!.duration / 50 + val twoPercents = Math.max(mMediaPlayer!!.duration / 50, MIN_SKIP_LENGTH) val newProgress = if (forward) curr + twoPercents else curr - twoPercents - setProgress(Math.round(newProgress / 1000f)) + val roundProgress = Math.round(newProgress / 1000f) + val limitedProgress = Math.max(Math.min(mMediaPlayer!!.duration / 1000, roundProgress), 0) + setProgress(limitedProgress) if (!mIsPlaying) { togglePlayPause() } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaFetcher.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaFetcher.kt index c4ae2a234..6c89cbf6f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaFetcher.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaFetcher.kt @@ -40,7 +40,7 @@ class MediaFetcher(val context: Context) { directories.remove(it) } - searchNewFiles(directories, showHidden) + //searchNewFiles(directories, showHidden) return directories } @@ -104,7 +104,7 @@ class MediaFetcher(val context: Context) { private fun getSelectionQuery(path: String): String? { val dataQuery = "${MediaStore.Images.Media.DATA} LIKE ?" return if (path.isEmpty()) { - if (context.isAndroidFour()) + if (isAndroidFour()) return null var query = "($dataQuery)" @@ -119,7 +119,7 @@ class MediaFetcher(val context: Context) { private fun getSelectionArgsQuery(path: String): Array? { return if (path.isEmpty()) { - if (context.isAndroidFour()) { + if (isAndroidFour()) { return null } diff --git a/app/src/main/res/layout/pager_photo_item.xml b/app/src/main/res/layout/pager_photo_item.xml index bf3b9eb2d..b8bff9183 100644 --- a/app/src/main/res/layout/pager_photo_item.xml +++ b/app/src/main/res/layout/pager_photo_item.xml @@ -7,7 +7,7 @@ android:layout_height="match_parent"> diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml index ad4a8140d..06493350f 100644 --- a/app/src/main/res/xml/provider_paths.xml +++ b/app/src/main/res/xml/provider_paths.xml @@ -1,5 +1,5 @@ - +