Merge pull request #23 from SimpleMobileTools/master

upd
This commit is contained in:
solokot 2018-03-15 21:10:10 +03:00 committed by GitHub
commit 418c59dcc6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 82 additions and 27 deletions

View file

@ -46,7 +46,7 @@ ext {
} }
dependencies { 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.theartofdev.edmodo:android-image-cropper:2.6.0'
implementation 'com.android.support:multidex:1.0.3' implementation 'com.android.support:multidex:1.0.3'
implementation 'com.google.code.gson:gson:2.8.2' implementation 'com.google.code.gson:gson:2.8.2'

View file

@ -11,8 +11,8 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import com.simplemobiletools.commons.dialogs.RadioGroupDialog import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.isActivityDestroyed import com.simplemobiletools.commons.extensions.isActivityDestroyed
import com.simplemobiletools.commons.extensions.isNougatPlus
import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.helpers.isNougatPlus
import com.simplemobiletools.commons.models.RadioItem import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.theartofdev.edmodo.cropper.CropImageView import com.theartofdev.edmodo.cropper.CropImageView

View file

@ -2,6 +2,7 @@ package com.simplemobiletools.gallery.activities
import android.animation.Animator import android.animation.Animator
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.annotation.TargetApi
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
@ -522,9 +523,16 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
} }
private fun saveImageToFile(oldPath: String, newPath: String) { private fun saveImageToFile(oldPath: String, newPath: String) {
val newFile = File(newPath)
toast(R.string.saving) toast(R.string.saving)
if (oldPath == newPath && oldPath.isJpg()) {
if (tryRotateByExif(oldPath)) {
return
}
}
val newFile = File(newPath)
val tmpFile = File(filesDir, ".tmp_${newPath.getFilenameFromPath()}") val tmpFile = File(filesDir, ".tmp_${newPath.getFilenameFromPath()}")
try { try {
val bitmap = BitmapFactory.decodeFile(oldPath) val bitmap = BitmapFactory.decodeFile(oldPath)
getFileOutputStream(tmpFile.toFileDirItem(applicationContext)) { getFileOutputStream(tmpFile.toFileDirItem(applicationContext)) {
@ -535,7 +543,8 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
val oldLastModified = getCurrentFile().lastModified() val oldLastModified = getCurrentFile().lastModified()
if (oldPath.isJpg()) { if (oldPath.isJpg()) {
saveRotation(getCurrentFile(), tmpFile) copyFile(getCurrentFile(), tmpFile)
saveExifRotation(ExifInterface(tmpFile.absolutePath))
} else { } else {
saveFile(tmpFile, bitmap, it as FileOutputStream) 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) { private fun copyFile(source: File, destination: File) {
var inputStream: InputStream? = null var inputStream: InputStream? = null
var out: OutputStream? = null var out: OutputStream? = null
@ -594,9 +630,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
bmp.compress(file.absolutePath.getCompressionFormat(), 90, out) bmp.compress(file.absolutePath.getCompressionFormat(), 90, out)
} }
private fun saveRotation(source: File, destination: File) { private fun saveExifRotation(exif: ExifInterface) {
copyFile(source, destination)
val exif = ExifInterface(destination.absolutePath)
val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL) val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
val orientationDegrees = (degreesForRotation(orientation) + mRotationDegrees) % 360 val orientationDegrees = (degreesForRotation(orientation) + mRotationDegrees) % 360
exif.setAttribute(ExifInterface.TAG_ORIENTATION, rotationFromDegrees(orientationDegrees)) exif.setAttribute(ExifInterface.TAG_ORIENTATION, rotationFromDegrees(orientationDegrees))

View file

@ -73,7 +73,6 @@ fun Activity.launchCamera() {
fun SimpleActivity.launchAbout() { fun SimpleActivity.launchAbout() {
val faqItems = arrayListOf( 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_3_title_commons, R.string.faq_3_text_commons),
FAQItem(R.string.faq_1_title, R.string.faq_1_text), FAQItem(R.string.faq_1_title, R.string.faq_1_text),
FAQItem(R.string.faq_2_title, R.string.faq_2_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_6_title, R.string.faq_6_text),
FAQItem(R.string.faq_7_title, R.string.faq_7_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_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) 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) filename.substring(1, filename.length)
} }
val newPath = "$path/$filename" val newPath = "$path$filename"
renameFile(oldPath, newPath) { renameFile(oldPath, newPath) {
callback?.invoke(newPath) callback?.invoke(newPath)
} }

View file

@ -10,6 +10,7 @@ import android.media.ExifInterface.*
import android.net.Uri import android.net.Uri
import android.os.AsyncTask import android.os.AsyncTask
import android.os.Bundle import android.os.Bundle
import android.os.Handler
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -44,6 +45,7 @@ class PhotoFragment : ViewPagerFragment() {
private var isFragmentVisible = false private var isFragmentVisible = false
private var isFullscreen = false private var isFullscreen = false
private var wasInit = false private var wasInit = false
private var useHalfResolution = false
private var imageOrientation = -1 private var imageOrientation = -1
private var gifDrawable: GifDrawable? = null private var gifDrawable: GifDrawable? = null
@ -57,7 +59,7 @@ class PhotoFragment : ViewPagerFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
view = (inflater.inflate(R.layout.pager_photo_item, container, false) as ViewGroup).apply { view = (inflater.inflate(R.layout.pager_photo_item, container, false) as ViewGroup).apply {
subsampling_view.setOnClickListener { photoClicked() } subsampling_view.setOnClickListener { photoClicked() }
gif_view.setOnClickListener { photoClicked() } photo_view.setOnClickListener { photoClicked() }
instant_prev_item.setOnClickListener { listener?.goToPrevItem() } instant_prev_item.setOnClickListener { listener?.goToPrevItem() }
instant_next_item.setOnClickListener { listener?.goToNextItem() } instant_next_item.setOnClickListener { listener?.goToNextItem() }
@ -69,7 +71,7 @@ class PhotoFragment : ViewPagerFragment() {
if (subsampling_view.isVisible()) { if (subsampling_view.isVisible()) {
subsampling_view.sendFakeClick(x, y) subsampling_view.sendFakeClick(x, y)
} else { } else {
gif_view.sendFakeClick(x, y) photo_view.sendFakeClick(x, y)
} }
} }
} }
@ -217,7 +219,7 @@ class PhotoFragment : ViewPagerFragment() {
gifDrawable!!.stop() gifDrawable!!.stop()
} }
view.gif_view.setImageDrawable(gifDrawable) view.photo_view.setImageDrawable(gifDrawable)
} catch (e: Exception) { } catch (e: Exception) {
gifDrawable = null gifDrawable = null
loadBitmap() loadBitmap()
@ -231,6 +233,11 @@ class PhotoFragment : ViewPagerFragment() {
if (degrees == 0f) { if (degrees == 0f) {
var targetWidth = if (ViewPagerActivity.screenWidth == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenWidth var targetWidth = if (ViewPagerActivity.screenWidth == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenWidth
var targetHeight = if (ViewPagerActivity.screenHeight == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenHeight var targetHeight = if (ViewPagerActivity.screenHeight == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenHeight
if (useHalfResolution) {
targetWidth /= 2
targetHeight /= 2
}
if (imageOrientation == ORIENTATION_ROTATE_90) { if (imageOrientation == ORIENTATION_ROTATE_90) {
targetWidth = targetHeight targetWidth = targetHeight
targetHeight = Target.SIZE_ORIGINAL targetHeight = Target.SIZE_ORIGINAL
@ -247,14 +254,22 @@ class PhotoFragment : ViewPagerFragment() {
.load(getPathToLoad(medium)) .load(getPathToLoad(medium))
.apply(options) .apply(options)
.listener(object : RequestListener<Bitmap> { .listener(object : RequestListener<Bitmap> {
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Bitmap>?, isFirstResource: Boolean) = false override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Bitmap>?, 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<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean { override fun onResourceReady(resource: Bitmap?, model: Any?, target: Target<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
if (isFragmentVisible) if (isFragmentVisible)
addZoomableView() addZoomableView()
return false return false
} }
}).into(view.gif_view) }).into(view.photo_view)
} else { } else {
val options = RequestOptions() val options = RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.NONE) .diskCacheStrategy(DiskCacheStrategy.NONE)
@ -265,7 +280,7 @@ class PhotoFragment : ViewPagerFragment() {
.load(getPathToLoad(medium)) .load(getPathToLoad(medium))
.thumbnail(0.2f) .thumbnail(0.2f)
.apply(options) .apply(options)
.into(view.gif_view) .into(view.photo_view)
} }
} }
@ -365,6 +380,7 @@ class PhotoFragment : ViewPagerFragment() {
text = getMediumExtendedDetails(medium) text = getMediumExtendedDetails(medium)
setTextColor(context.config.textColor) setTextColor(context.config.textColor)
beVisibleIf(text.isNotEmpty()) beVisibleIf(text.isNotEmpty())
alpha = if (!context!!.config.hideExtendedDetails || !isFullscreen) 1f else 0f
onGlobalLayout { onGlobalLayout {
if (height != 0 && isAdded) { if (height != 0 && isAdded) {
y = getExtendedDetailsY(height) y = getExtendedDetailsY(height)
@ -379,7 +395,7 @@ class PhotoFragment : ViewPagerFragment() {
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
if (activity?.isActivityDestroyed() == false) { if (activity?.isActivityDestroyed() == false) {
Glide.with(context!!).clear(view.gif_view) Glide.with(context!!).clear(view.photo_view)
view.subsampling_view.recycle() view.subsampling_view.recycle()
} }
} }

View file

@ -14,6 +14,7 @@ import android.view.animation.AnimationUtils
import android.widget.SeekBar import android.widget.SeekBar
import android.widget.TextView import android.widget.TextView
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.isJellyBean1Plus
import com.simplemobiletools.gallery.BuildConfig import com.simplemobiletools.gallery.BuildConfig
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.VideoActivity import com.simplemobiletools.gallery.activities.VideoActivity
@ -27,6 +28,7 @@ import java.io.IOException
class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSeekBarChangeListener { class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSeekBarChangeListener {
private val PROGRESS = "progress" private val PROGRESS = "progress"
private val MIN_SKIP_LENGTH = 2000
private var mMediaPlayer: MediaPlayer? = null private var mMediaPlayer: MediaPlayer? = null
private var mSurfaceView: SurfaceView? = null private var mSurfaceView: SurfaceView? = null
@ -73,12 +75,12 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
mIsFragmentVisible = true mIsFragmentVisible = true
} }
mIsFullscreen = activity!!.window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == View.SYSTEM_UI_FLAG_FULLSCREEN
setupPlayer() setupPlayer()
if (savedInstanceState != null) { if (savedInstanceState != null) {
mCurrTime = savedInstanceState.getInt(PROGRESS) mCurrTime = savedInstanceState.getInt(PROGRESS)
} }
mIsFullscreen = activity!!.window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == View.SYSTEM_UI_FLAG_FULLSCREEN
checkFullscreen() checkFullscreen()
wasInit = true wasInit = true
@ -433,7 +435,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
val screenWidth: Int val screenWidth: Int
val screenHeight: Int val screenHeight: Int
if (activity!!.isJellyBean1Plus()) { if (isJellyBean1Plus()) {
val realMetrics = DisplayMetrics() val realMetrics = DisplayMetrics()
display.getRealMetrics(realMetrics) display.getRealMetrics(realMetrics)
screenWidth = realMetrics.widthPixels screenWidth = realMetrics.widthPixels
@ -463,6 +465,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
text = getMediumExtendedDetails(medium) text = getMediumExtendedDetails(medium)
setTextColor(context.config.textColor) setTextColor(context.config.textColor)
beVisibleIf(text.isNotEmpty()) beVisibleIf(text.isNotEmpty())
alpha = if (!context!!.config.hideExtendedDetails || !mIsFullscreen) 1f else 0f
onGlobalLayout { onGlobalLayout {
if (height != 0 && isAdded) { if (height != 0 && isAdded) {
y = getExtendedDetailsY(height) y = getExtendedDetailsY(height)
@ -480,9 +483,11 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
} }
val curr = mMediaPlayer!!.currentPosition 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 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) { if (!mIsPlaying) {
togglePlayPause() togglePlayPause()
} }

View file

@ -40,7 +40,7 @@ class MediaFetcher(val context: Context) {
directories.remove(it) directories.remove(it)
} }
searchNewFiles(directories, showHidden) //searchNewFiles(directories, showHidden)
return directories return directories
} }
@ -104,7 +104,7 @@ class MediaFetcher(val context: Context) {
private fun getSelectionQuery(path: String): String? { private fun getSelectionQuery(path: String): String? {
val dataQuery = "${MediaStore.Images.Media.DATA} LIKE ?" val dataQuery = "${MediaStore.Images.Media.DATA} LIKE ?"
return if (path.isEmpty()) { return if (path.isEmpty()) {
if (context.isAndroidFour()) if (isAndroidFour())
return null return null
var query = "($dataQuery)" var query = "($dataQuery)"
@ -119,7 +119,7 @@ class MediaFetcher(val context: Context) {
private fun getSelectionArgsQuery(path: String): Array<String>? { private fun getSelectionArgsQuery(path: String): Array<String>? {
return if (path.isEmpty()) { return if (path.isEmpty()) {
if (context.isAndroidFour()) { if (isAndroidFour()) {
return null return null
} }

View file

@ -7,7 +7,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<com.github.chrisbanes.photoview.PhotoView <com.github.chrisbanes.photoview.PhotoView
android:id="@+id/gif_view" android:id="@+id/photo_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:scaleType="fitCenter"/> android:scaleType="fitCenter"/>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<paths> <paths>
<external-path name="external_files" path="."/> <external-path name="external_files" path="."/>
<root-path name="external_files" path="/storage/" /> <root-path name="external_files" path="/" />
</paths> </paths>