diff --git a/CHANGELOG.md b/CHANGELOG.md
index ce87f8506..0b2897c4b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,67 @@
Changelog
==========
+Version 2.17.4 *(2017-11-06)*
+----------------------------
+
+ * Fixed some third party intent handling
+ * Increased max columns count to 20
+ * Allow rotating JPGs in a lossless way (by ltGuillaume)
+
+Version 2.17.3 *(2017-11-02)*
+----------------------------
+
+ * Fixed some corrupt gif file related crashes
+ * Rotate jpgs on the internal storage by exif
+ * Fixed some invisible SD card content
+
+Version 2.17.2 *(2017-10-29)*
+----------------------------
+
+ * Couple more minor fixes
+
+Version 2.17.1 *(2017-10-29)*
+----------------------------
+
+ * Show "Set As" and "Edit" menu buttons at videos and gifs too
+ * Couple other smaller issues fixed
+
+Version 2.17.0 *(2017-10-28)*
+----------------------------
+
+ * Added a toggle for keeping last-modified field at file copy/move/rename
+ * Improved GIF animation speed
+ * Implemented fileprovider support to third party intents
+ * Make rotation by "Device rotation" less sensitive
+ * Automatically append "_1" to filename after saving through the Editor
+ * Added support for Adaptive icons for Android 8 (by fiepi)
+ * Added Dutch translation (by ltGuillaume)
+ * Many other smaller improvements
+
+Version 2.16.1 *(2017-10-24)*
+----------------------------
+
+ * Added a toggle for hiding folder media count on the main screen
+ * Fixed SD card folders not being visible on some devices
+ * Fixed videos not playing properly in some cases
+ * Do not modify last_modified at copy/move/rename
+ * Added support for 3gpp videos
+
+Version 2.16.0 *(2017-10-19)*
+----------------------------
+
+ * Added sorting by path
+ * Added an option to show customizable extended details over fullscreen media
+ * Allow selecting Album cover photos from any folders
+ * Added a checkbox for skipping Delete confirmation dialog
+
+Version 2.15.2 *(2017-10-06)*
+----------------------------
+
+ * Properly display SD card content to Android 4 users
+ * Fix displaying some third party media, like Bluemail attachments
+ * Fix media picking intents if "Show all folders content" is enabled
+
Version 2.15.1 *(2017-10-01)*
----------------------------
diff --git a/app/build.gradle b/app/build.gradle
index 41c499e1e..42f9024db 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -3,15 +3,15 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
- compileSdkVersion 25
- buildToolsVersion "25.0.2"
+ compileSdkVersion 27
+ buildToolsVersion "27.0.1"
defaultConfig {
applicationId "com.simplemobiletools.gallery"
minSdkVersion 16
- targetSdkVersion 23
- versionCode 134
- versionName "2.15.1"
+ targetSdkVersion 27
+ versionCode 142
+ versionName "2.17.4"
}
signingConfigs {
@@ -19,10 +19,14 @@ android {
}
buildTypes {
+ debug {
+ buildConfigField "boolean", "USE_LEAK_CANARY", "true"
+ }
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
+ buildConfigField "boolean", "USE_LEAK_CANARY", "false"
}
}
@@ -36,19 +40,22 @@ android {
}
}
+ext {
+ leakCanaryVersion = '1.5.4'
+}
+
dependencies {
- compile 'com.simplemobiletools:commons:2.29.1'
- compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.6.0'
+ compile 'com.simplemobiletools:commons:2.37.12'
+ compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.7.2'
compile 'com.theartofdev.edmodo:android-image-cropper:2.4.0'
compile 'com.bignerdranch.android:recyclerview-multiselect:0.2'
- compile 'com.google.code.gson:gson:2.8.0'
- compile 'com.github.chrisbanes:PhotoView:2.1.2'
+ compile 'com.google.code.gson:gson:2.8.2'
compile 'it.sephiroth.android.exif:library:1.0.1'
+ compile 'pl.droidsonroids.gif:android-gif-drawable:1.2.8'
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
- debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1'
- releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
- testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
+ debugCompile "com.squareup.leakcanary:leakcanary-android:$leakCanaryVersion"
+ releaseCompile "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryVersion"
}
buildscript {
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 0816ea160..a9c0f371b 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -1,5 +1,2 @@
-keep class com.simplemobiletools.** { *; }
-dontwarn com.simplemobiletools.**
-
--renamesourcefileattribute SourceFile
--keepattributes SourceFile,LineNumberTable
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index fb8ba91aa..ff7ff3399 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -83,16 +83,16 @@
android:label="@string/third_party_licences"
android:parentActivityName="com.simplemobiletools.commons.activities.AboutActivity"/>
-
-
+
+
1
}
menu.findItem(R.id.temporarily_show_hidden).isVisible = !config.shouldShowHidden
@@ -127,30 +128,48 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
override fun onResume() {
super.onResume()
config.isThirdPartyIntent = false
+ if (mStoredUseEnglish != config.useEnglish) {
+ restartActivity()
+ return
+ }
+
if (mStoredAnimateGifs != config.animateGifs) {
- directories_grid.adapter?.notifyDataSetChanged()
+ getDirectoryAdapter()?.updateAnimateGifs(config.animateGifs)
}
if (mStoredCropThumbnails != config.cropThumbnails) {
- directories_grid.adapter?.notifyDataSetChanged()
+ getDirectoryAdapter()?.updateCropThumbnails(config.cropThumbnails)
+ }
+
+ if (mStoredShowMediaCount != config.showMediaCount) {
+ getDirectoryAdapter()?.updateShowMediaCount(config.showMediaCount)
}
if (mStoredScrollHorizontally != config.scrollHorizontally) {
- (directories_grid.adapter as? DirectoryAdapter)?.apply {
- scrollVertically = config.viewTypeFolders == VIEW_TYPE_LIST || !config.scrollHorizontally
- notifyDataSetChanged()
- }
+ getDirectoryAdapter()?.updateScrollHorizontally(config.viewTypeFolders != VIEW_TYPE_LIST && config.scrollHorizontally)
setupScrollDirection()
}
if (mStoredTextColor != config.textColor) {
- (directories_grid.adapter as? DirectoryAdapter)?.updateTextColor(config.textColor)
+ getDirectoryAdapter()?.updateTextColor(config.textColor)
}
- tryloadGallery()
invalidateOptionsMenu()
directories_empty_text_label.setTextColor(config.textColor)
directories_empty_text.setTextColor(config.primaryColor)
+
+ if (mIsPasswordProtectionPending) {
+ handleAppPasswordProtection {
+ if (it) {
+ mIsPasswordProtectionPending = false
+ tryloadGallery()
+ } else {
+ finish()
+ }
+ }
+ } else {
+ tryloadGallery()
+ }
}
override fun onPause() {
@@ -158,13 +177,13 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
storeDirectories()
directories_refresh_layout.isRefreshing = false
mIsGettingDirs = false
- mStoredAnimateGifs = config.animateGifs
- mStoredCropThumbnails = config.cropThumbnails
- mStoredScrollHorizontally = config.scrollHorizontally
- mStoredTextColor = config.textColor
+ storeStateVariables()
directories_grid.listener = null
mLastMediaHandler.removeCallbacksAndMessages(null)
- mCurrAsyncTask?.stopFetching()
+
+ if (!mDirs.isEmpty()) {
+ mCurrAsyncTask?.stopFetching()
+ }
}
override fun onDestroy() {
@@ -173,6 +192,19 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
removeTempFolder()
}
+ private fun getDirectoryAdapter() = directories_grid.adapter as? DirectoryAdapter
+
+ private fun storeStateVariables() {
+ config.apply {
+ mStoredUseEnglish = useEnglish
+ mStoredAnimateGifs = animateGifs
+ mStoredCropThumbnails = cropThumbnails
+ mStoredScrollHorizontally = scrollHorizontally
+ mStoredShowMediaCount = showMediaCount
+ mStoredTextColor = textColor
+ }
+ }
+
private fun removeTempFolder() {
val newFolder = File(config.tempFolderPath)
if (newFolder.exists() && newFolder.isDirectory) {
@@ -184,25 +216,16 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
}
private fun tryloadGallery() {
- if (hasWriteStoragePermission()) {
- if (config.showAll)
- showAllMedia()
- else
- getDirectories()
+ handlePermission(PERMISSION_WRITE_STORAGE) {
+ if (it) {
+ if (config.showAll) {
+ showAllMedia()
+ } else {
+ getDirectories()
+ }
- setupLayoutManager()
- checkIfColorChanged()
- } else {
- ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), STORAGE_PERMISSION)
- }
- }
-
- override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
-
- if (requestCode == STORAGE_PERMISSION) {
- if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- getDirectories()
+ setupLayoutManager()
+ checkIfColorChanged()
} else {
toast(R.string.no_storage_permissions)
finish()
@@ -313,10 +336,11 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
private fun getRecyclerAdapter() = (directories_grid.adapter as DirectoryAdapter)
private fun setupLayoutManager() {
- if (config.viewTypeFolders == VIEW_TYPE_GRID)
+ if (config.viewTypeFolders == VIEW_TYPE_GRID) {
setupGridLayoutManager()
- else
+ } else {
setupListLayoutManager()
+ }
}
private fun setupGridLayoutManager() {
@@ -341,7 +365,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
}
override fun zoomOut() {
- if (layoutManager.spanCount < 10) {
+ if (layoutManager.spanCount < MAX_COLUMN_COUNT) {
increaseColumnCount()
getRecyclerAdapter().actMode?.finish()
}
@@ -428,7 +452,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
}
} else if ((mIsPickImageIntent || mIsPickVideoIntent)) {
val path = resultData.data.path
- val uri = Uri.fromFile(File(path))
+ val uri = getFilePublicUri(File(path), BuildConfig.APPLICATION_ID)
resultIntent.data = uri
resultIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
}
@@ -461,22 +485,23 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
private fun fillPickedPaths(resultData: Intent, resultIntent: Intent) {
val paths = resultData.extras.getStringArrayList(PICKED_PATHS)
- val uris = paths.map { Uri.fromFile(File(it)) } as ArrayList
+ val uris = paths.map { getFilePublicUri(File(it), BuildConfig.APPLICATION_ID) } as ArrayList
val clipData = ClipData("Attachment", arrayOf("image/*", "video/*"), ClipData.Item(uris.removeAt(0)))
uris.forEach {
clipData.addItem(ClipData.Item(it))
}
+ resultIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
resultIntent.clipData = clipData
}
private fun fillIntentPath(resultData: Intent, resultIntent: Intent) {
val path = resultData.data.path
- val uri = Uri.fromFile(File(path))
- val type = File(path).getMimeType("image/jpeg")
+ val uri = getFilePublicUri(File(path), BuildConfig.APPLICATION_ID)
+ val type = path.getMimeTypeFromPath()
resultIntent.setDataAndTypeAndNormalize(uri, type)
- resultIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ resultIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
}
private fun itemClicked(path: String) {
@@ -495,7 +520,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
putExtra(GET_IMAGE_INTENT, mIsPickImageIntent || mIsGetImageContentIntent)
putExtra(GET_VIDEO_INTENT, mIsPickVideoIntent || mIsGetVideoContentIntent)
putExtra(GET_ANY_INTENT, mIsGetAnyContentIntent)
- putExtra(Intent.EXTRA_ALLOW_MULTIPLE, intent.getBooleanExtra(Intent.EXTRA_ALLOW_MULTIPLE, false))
+ putExtra(Intent.EXTRA_ALLOW_MULTIPLE, mAllowPickingMultiple)
startActivityForResult(this, PICK_MEDIA)
}
}
@@ -631,6 +656,9 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
add(Release(125, R.string.release_125))
add(Release(127, R.string.release_127))
add(Release(133, R.string.release_133))
+ add(Release(136, R.string.release_136))
+ add(Release(137, R.string.release_137))
+ add(Release(138, R.string.release_138))
checkWhatsNew(this, BuildConfig.VERSION_CODE)
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt
index 4851c7305..b500af01e 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt
@@ -18,10 +18,11 @@ import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.transition.Transition
import com.google.gson.Gson
-import com.google.gson.reflect.TypeToken
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.*
+import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE
+import com.simplemobiletools.commons.helpers.REQUEST_EDIT_IMAGE
import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.commons.views.MyScalableRecyclerView
import com.simplemobiletools.gallery.R
@@ -49,6 +50,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
private var mAllowPickingMultiple = false
private var mShowAll = false
private var mLoadedInitialPhotos = false
+ private var mStoredUseEnglish = false
private var mStoredAnimateGifs = true
private var mStoredCropThumbnails = true
private var mStoredScrollHorizontally = true
@@ -74,11 +76,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
media_refresh_layout.setOnRefreshListener({ getMedia() })
mPath = intent.getStringExtra(DIRECTORY)
- mStoredAnimateGifs = config.animateGifs
- mStoredCropThumbnails = config.cropThumbnails
- mStoredScrollHorizontally = config.scrollHorizontally
- mStoredTextColor = config.textColor
- mShowAll = config.showAll
+ storeStateVariables()
if (mShowAll)
supportActionBar?.setDisplayHomeAsUpEnabled(false)
@@ -89,24 +87,26 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
override fun onResume() {
super.onResume()
- if (mShowAll && mStoredAnimateGifs != config.animateGifs) {
- media_grid.adapter?.notifyDataSetChanged()
+ if (mStoredUseEnglish != config.useEnglish) {
+ restartActivity()
+ return
+ }
+
+ if (mStoredAnimateGifs != config.animateGifs) {
+ getMediaAdapter()?.updateAnimateGifs(config.animateGifs)
}
if (mStoredCropThumbnails != config.cropThumbnails) {
- media_grid.adapter?.notifyDataSetChanged()
+ getMediaAdapter()?.updateCropThumbnails(config.cropThumbnails)
}
if (mStoredScrollHorizontally != config.scrollHorizontally) {
- (media_grid.adapter as? MediaAdapter)?.apply {
- scrollVertically = config.viewTypeFiles == VIEW_TYPE_LIST || !config.scrollHorizontally
- notifyDataSetChanged()
- }
+ getMediaAdapter()?.updateScrollHorizontally(config.viewTypeFiles != VIEW_TYPE_LIST || !config.scrollHorizontally)
setupScrollDirection()
}
if (mStoredTextColor != config.textColor) {
- (media_grid.adapter as? MediaAdapter)?.updateTextColor(config.textColor)
+ getMediaAdapter()?.updateTextColor(config.textColor)
}
tryloadGallery()
@@ -119,13 +119,13 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
super.onPause()
mIsGettingMedia = false
media_refresh_layout.isRefreshing = false
- mStoredAnimateGifs = config.animateGifs
- mStoredCropThumbnails = config.cropThumbnails
- mStoredScrollHorizontally = config.scrollHorizontally
- mStoredTextColor = config.textColor
+ storeStateVariables()
media_grid.listener = null
mLastMediaHandler.removeCallbacksAndMessages(null)
- mCurrAsyncTask?.stopFetching()
+
+ if (!mMedia.isEmpty()) {
+ mCurrAsyncTask?.stopFetching()
+ }
}
override fun onDestroy() {
@@ -135,18 +135,34 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
mMedia.clear()
}
- private fun tryloadGallery() {
- if (hasWriteStoragePermission()) {
- val dirName = getHumanizedFilename(mPath)
- title = if (mShowAll) resources.getString(R.string.all_folders) else dirName
- getMedia()
- setupLayoutManager()
- checkIfColorChanged()
- } else {
- finish()
+ private fun storeStateVariables() {
+ config.apply {
+ mStoredUseEnglish = useEnglish
+ mStoredAnimateGifs = animateGifs
+ mStoredCropThumbnails = cropThumbnails
+ mStoredScrollHorizontally = scrollHorizontally
+ mStoredTextColor = textColor
+ mShowAll = showAll
}
}
+ private fun tryloadGallery() {
+ handlePermission(PERMISSION_WRITE_STORAGE) {
+ if (it) {
+ val dirName = getHumanizedFilename(mPath)
+ title = if (mShowAll) resources.getString(R.string.all_folders) else dirName
+ getMedia()
+ setupLayoutManager()
+ checkIfColorChanged()
+ } else {
+ toast(R.string.no_storage_permissions)
+ finish()
+ }
+ }
+ }
+
+ private fun getMediaAdapter() = media_grid.adapter as? MediaAdapter
+
private fun checkIfColorChanged() {
if (media_grid.adapter != null && getRecyclerAdapter().primaryColor != config.primaryColor) {
getRecyclerAdapter().primaryColor = config.primaryColor
@@ -161,7 +177,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
val currAdapter = media_grid.adapter
if (currAdapter == null) {
- media_grid.adapter = MediaAdapter(this, mMedia, this, mIsGetAnyIntent, mAllowPickingMultiple) {
+ media_grid.adapter = MediaAdapter(this, mMedia, this, mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent, mAllowPickingMultiple) {
itemClicked(it.path)
}
} else {
@@ -222,7 +238,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
findItem(R.id.temporarily_show_hidden).isVisible = !config.shouldShowHidden
findItem(R.id.stop_showing_hidden).isVisible = config.temporarilyShowHidden
- findItem(R.id.increase_column_count).isVisible = config.viewTypeFiles == VIEW_TYPE_GRID && config.mediaColumnCnt < 10
+ findItem(R.id.increase_column_count).isVisible = config.viewTypeFiles == VIEW_TYPE_GRID && config.mediaColumnCnt < MAX_COLUMN_COUNT
findItem(R.id.reduce_column_count).isVisible = config.viewTypeFiles == VIEW_TYPE_GRID && config.mediaColumnCnt > 1
findItem(R.id.toggle_filename).isVisible = config.viewTypeFiles == VIEW_TYPE_GRID
@@ -340,8 +356,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
return
mIsGettingMedia = true
- val token = object : TypeToken>() {}.type
- val media = Gson().fromJson>(config.loadFolderMedia(mPath), token) ?: ArrayList(1)
+ val media = getCachedMedia(mPath)
if (media.isNotEmpty() && !mLoadedInitialPhotos) {
gotMedia(media, true)
} else {
@@ -411,7 +426,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
}
override fun zoomOut() {
- if (layoutManager.spanCount < 10) {
+ if (layoutManager.spanCount < MAX_COLUMN_COUNT) {
increaseColumnCount()
getRecyclerAdapter().actMode?.finish()
}
@@ -499,10 +514,10 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
val file = File(path)
val isVideo = file.isVideoFast()
if (isVideo) {
- openWith(file, false)
+ openFile(Uri.fromFile(file), false)
} else {
Intent(this, ViewPagerActivity::class.java).apply {
- putExtra(MEDIUM, path)
+ putExtra(PATH, path)
putExtra(SHOW_ALL, mShowAll)
startActivity(this)
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PhotoActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PhotoActivity.kt
index ef309a26d..44e83dbfd 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PhotoActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PhotoActivity.kt
@@ -4,7 +4,7 @@ import android.os.Bundle
class PhotoActivity : PhotoVideoActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
- PhotoVideoActivity.mIsVideo = false
+ mIsVideo = false
super.onCreate(savedInstanceState)
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PhotoVideoActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PhotoVideoActivity.kt
index 4a5b48097..960db4d14 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PhotoVideoActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PhotoVideoActivity.kt
@@ -1,70 +1,72 @@
package com.simplemobiletools.gallery.activities
-import android.Manifest
import android.content.Intent
-import android.content.pm.PackageManager
-import android.database.Cursor
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Bundle
-import android.provider.MediaStore
-import android.support.v4.app.ActivityCompat
import android.view.Menu
import android.view.MenuItem
import android.view.View
-import com.simplemobiletools.commons.extensions.hasWriteStoragePermission
+import com.simplemobiletools.commons.dialogs.PropertiesDialog
+import com.simplemobiletools.commons.extensions.getFilenameFromUri
+import com.simplemobiletools.commons.extensions.getRealPathFromURI
import com.simplemobiletools.commons.extensions.scanPath
import com.simplemobiletools.commons.extensions.toast
+import com.simplemobiletools.commons.helpers.IS_FROM_GALLERY
+import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE
+import com.simplemobiletools.commons.helpers.REAL_FILE_PATH
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.extensions.*
import com.simplemobiletools.gallery.fragments.PhotoFragment
import com.simplemobiletools.gallery.fragments.VideoFragment
import com.simplemobiletools.gallery.fragments.ViewPagerFragment
-import com.simplemobiletools.gallery.helpers.IS_FROM_GALLERY
import com.simplemobiletools.gallery.helpers.IS_VIEW_INTENT
import com.simplemobiletools.gallery.helpers.MEDIUM
+import com.simplemobiletools.gallery.helpers.PATH
import com.simplemobiletools.gallery.models.Medium
import kotlinx.android.synthetic.main.fragment_holder.*
import java.io.File
open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentListener {
- private val STORAGE_PERMISSION = 1
private var mMedium: Medium? = null
private var mIsFullScreen = false
private var mIsFromGallery = false
private var mFragment: ViewPagerFragment? = null
+ private var mUri: Uri? = null
- lateinit var mUri: Uri
-
- companion object {
- var mIsVideo = false
- }
+ var mIsVideo = false
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.fragment_holder)
-
- if (hasWriteStoragePermission()) {
- checkIntent(savedInstanceState)
- } else {
- ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), STORAGE_PERMISSION)
+ handlePermission(PERMISSION_WRITE_STORAGE) {
+ if (it) {
+ checkIntent(savedInstanceState)
+ } else {
+ toast(R.string.no_storage_permissions)
+ finish()
+ }
}
}
private fun checkIntent(savedInstanceState: Bundle? = null) {
mUri = intent.data ?: return
+ if (intent.extras?.containsKey(REAL_FILE_PATH) == true) {
+ mUri = intent.extras.get(REAL_FILE_PATH) as Uri
+ }
+
mIsFromGallery = intent.getBooleanExtra(IS_FROM_GALLERY, false)
- if (mUri.scheme == "file") {
- scanPath(mUri.path) {}
- sendViewPagerIntent(mUri.path)
+ if (mUri!!.scheme == "file") {
+ scanPath(mUri!!.path) {}
+ sendViewPagerIntent(mUri!!.path)
finish()
return
} else {
- val path = applicationContext.getRealPathFromURI(mUri) ?: ""
- scanPath(mUri.path) {}
- if (path.isNotEmpty()) {
+ val path = applicationContext.getRealPathFromURI(mUri!!) ?: ""
+ if (path != mUri.toString() && path.isNotEmpty()) {
+ scanPath(mUri!!.path) {}
sendViewPagerIntent(path)
finish()
return
@@ -74,7 +76,8 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
showSystemUI()
val bundle = Bundle()
val file = File(mUri.toString())
- mMedium = Medium(file.name, mUri.toString(), mIsVideo, 0, 0, file.length())
+ mMedium = Medium(getFilenameFromUri(mUri!!), mUri.toString(), mIsVideo, 0, 0, file.length())
+ title = mMedium!!.name
bundle.putSerializable(MEDIUM, mMedium)
if (savedInstanceState == null) {
@@ -84,22 +87,8 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
supportFragmentManager.beginTransaction().replace(R.id.fragment_holder, mFragment).commit()
}
- if (config.darkBackground)
+ if (config.darkBackground) {
fragment_holder.background = ColorDrawable(Color.BLACK)
-
- val proj = arrayOf(MediaStore.Images.Media.TITLE)
- var cursor: Cursor? = null
- try {
- cursor = contentResolver.query(mUri, proj, null, null, null)
- if (cursor != null && cursor.count != 0) {
- val columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.TITLE)
- cursor.moveToFirst()
- title = cursor.getString(columnIndex)
- }
- } catch (e: Exception) {
- title = mMedium?.name ?: ""
- } finally {
- cursor?.close()
}
window.decorView.setOnSystemUiVisibilityChangeListener { visibility ->
@@ -113,24 +102,11 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
supportActionBar?.setBackgroundDrawable(resources.getDrawable(R.drawable.actionbar_gradient_background))
}
- override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
-
- if (requestCode == STORAGE_PERMISSION) {
- if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- checkIntent()
- } else {
- toast(R.string.no_storage_permissions)
- finish()
- }
- }
- }
-
private fun sendViewPagerIntent(path: String) {
Intent(this, ViewPagerActivity::class.java).apply {
putExtra(IS_VIEW_INTENT, true)
putExtra(IS_FROM_GALLERY, mIsFromGallery)
- putExtra(MEDIUM, path)
+ putExtra(PATH, path)
startActivity(this)
}
}
@@ -139,7 +115,8 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
menuInflater.inflate(R.menu.photo_video_menu, menu)
menu.findItem(R.id.menu_set_as).isVisible = mMedium?.isImage() == true
- menu.findItem(R.id.menu_edit).isVisible = mMedium?.isImage() == true
+ menu.findItem(R.id.menu_edit).isVisible = mMedium?.isImage() == true && mUri?.scheme == "file"
+ menu.findItem(R.id.menu_properties).isVisible = mUri?.scheme == "file"
return true
}
@@ -149,15 +126,20 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
return true
when (item.itemId) {
- R.id.menu_set_as -> trySetAs(File(mMedium!!.path))
- R.id.menu_open_with -> openWith(File(mMedium!!.path))
- R.id.menu_share -> shareUri(mMedium!!, mUri)
- R.id.menu_edit -> openFileEditor(File(mMedium!!.path))
+ R.id.menu_set_as -> setAs(mUri!!)
+ R.id.menu_open_with -> openFile(mUri!!, true)
+ R.id.menu_share -> shareUri(mUri!!)
+ R.id.menu_edit -> openEditor(mUri!!)
+ R.id.menu_properties -> showProperties()
else -> return super.onOptionsItemSelected(item)
}
return true
}
+ private fun showProperties() {
+ PropertiesDialog(this, mUri!!.path)
+ }
+
override fun fragmentClicked() {
mIsFullScreen = !mIsFullScreen
if (mIsFullScreen) {
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SettingsActivity.kt
index 8ba896f00..a09c3bd53 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SettingsActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SettingsActivity.kt
@@ -6,17 +6,21 @@ import android.os.Bundle
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.dialogs.SecurityDialog
+import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.commons.extensions.handleHiddenFolderPasswordProtection
import com.simplemobiletools.commons.extensions.updateTextColors
+import com.simplemobiletools.commons.extensions.useEnglishToggled
import com.simplemobiletools.commons.helpers.PROTECTION_FINGERPRINT
import com.simplemobiletools.commons.helpers.SHOW_ALL_TABS
import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.gallery.R
+import com.simplemobiletools.gallery.dialogs.ManageExtendedDetailsDialog
import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.helpers.ROTATE_BY_ASPECT_RATIO
import com.simplemobiletools.gallery.helpers.ROTATE_BY_DEVICE_ROTATION
import com.simplemobiletools.gallery.helpers.ROTATE_BY_SYSTEM_SETTING
import kotlinx.android.synthetic.main.activity_settings.*
+import java.util.*
class SettingsActivity : SimpleActivity() {
lateinit var res: Resources
@@ -31,6 +35,7 @@ class SettingsActivity : SimpleActivity() {
super.onResume()
setupCustomizeColors()
+ setupUseEnglish()
setupManageIncludedFolders()
setupManageExcludedFolders()
setupShowHiddenFolders()
@@ -45,8 +50,13 @@ class SettingsActivity : SimpleActivity() {
setupHideSystemUI()
setupReplaceShare()
setupPasswordProtection()
+ setupAppPasswordProtection()
setupDeleteEmptyFolders()
setupAllowVideoGestures()
+ setupShowMediaCount()
+ setupKeepLastModified()
+ setupShowExtendedDetails()
+ setupManageExtendedDetails()
updateTextColors(settings_holder)
}
@@ -56,6 +66,16 @@ class SettingsActivity : SimpleActivity() {
}
}
+ private fun setupUseEnglish() {
+ settings_use_english_holder.beVisibleIf(Locale.getDefault().language != "en")
+ settings_use_english.isChecked = config.useEnglish
+ settings_use_english_holder.setOnClickListener {
+ settings_use_english.toggle()
+ config.useEnglish = settings_use_english.isChecked
+ useEnglishToggled()
+ }
+ }
+
private fun setupManageIncludedFolders() {
settings_manage_included_folders_holder.setOnClickListener {
startActivity(Intent(this, IncludedFoldersActivity::class.java))
@@ -162,17 +182,41 @@ class SettingsActivity : SimpleActivity() {
settings_password_protection.isChecked = config.isPasswordProtectionOn
settings_password_protection_holder.setOnClickListener {
val tabToShow = if (config.isPasswordProtectionOn) config.protectionType else SHOW_ALL_TABS
- SecurityDialog(this, config.passwordHash, tabToShow) { hash, type ->
- val hasPasswordProtection = config.isPasswordProtectionOn
- settings_password_protection.isChecked = !hasPasswordProtection
- config.isPasswordProtectionOn = !hasPasswordProtection
- config.passwordHash = if (hasPasswordProtection) "" else hash
- config.protectionType = type
+ SecurityDialog(this, config.passwordHash, tabToShow) { hash, type, success ->
+ if (success) {
+ val hasPasswordProtection = config.isPasswordProtectionOn
+ settings_password_protection.isChecked = !hasPasswordProtection
+ config.isPasswordProtectionOn = !hasPasswordProtection
+ config.passwordHash = if (hasPasswordProtection) "" else hash
+ config.protectionType = type
- if (config.isPasswordProtectionOn) {
- val confirmationTextId = if (config.protectionType == PROTECTION_FINGERPRINT)
- R.string.fingerprint_setup_successfully else R.string.protection_setup_successfully
- ConfirmationDialog(this, "", confirmationTextId, R.string.ok, 0) { }
+ if (config.isPasswordProtectionOn) {
+ val confirmationTextId = if (config.protectionType == PROTECTION_FINGERPRINT)
+ R.string.fingerprint_setup_successfully else R.string.protection_setup_successfully
+ ConfirmationDialog(this, "", confirmationTextId, R.string.ok, 0) { }
+ }
+ }
+ }
+ }
+ }
+
+ private fun setupAppPasswordProtection() {
+ settings_app_password_protection.isChecked = config.appPasswordProtectionOn
+ settings_app_password_protection_holder.setOnClickListener {
+ val tabToShow = if (config.appPasswordProtectionOn) config.appProtectionType else SHOW_ALL_TABS
+ SecurityDialog(this, config.appPasswordHash, tabToShow) { hash, type, success ->
+ if (success) {
+ val hasPasswordProtection = config.appPasswordProtectionOn
+ settings_app_password_protection.isChecked = !hasPasswordProtection
+ config.appPasswordProtectionOn = !hasPasswordProtection
+ config.appPasswordHash = if (hasPasswordProtection) "" else hash
+ config.appProtectionType = type
+
+ if (config.appPasswordProtectionOn) {
+ val confirmationTextId = if (config.appProtectionType == PROTECTION_FINGERPRINT)
+ R.string.fingerprint_setup_successfully else R.string.protection_setup_successfully
+ ConfirmationDialog(this, "", confirmationTextId, R.string.ok, 0) { }
+ }
}
}
}
@@ -194,6 +238,22 @@ class SettingsActivity : SimpleActivity() {
}
}
+ private fun setupShowMediaCount() {
+ settings_show_media_count.isChecked = config.showMediaCount
+ settings_show_media_count_holder.setOnClickListener {
+ settings_show_media_count.toggle()
+ config.showMediaCount = settings_show_media_count.isChecked
+ }
+ }
+
+ private fun setupKeepLastModified() {
+ settings_keep_last_modified.isChecked = config.keepLastModified
+ settings_keep_last_modified_holder.setOnClickListener {
+ settings_keep_last_modified.toggle()
+ config.keepLastModified = settings_keep_last_modified.isChecked
+ }
+ }
+
private fun setupScreenRotation() {
settings_screen_rotation.text = getScreenRotationText()
settings_screen_rotation_holder.setOnClickListener {
@@ -214,4 +274,24 @@ class SettingsActivity : SimpleActivity() {
ROTATE_BY_DEVICE_ROTATION -> R.string.screen_rotation_device_rotation
else -> R.string.screen_rotation_aspect_ratio
})
+
+ private fun setupShowExtendedDetails() {
+ settings_show_extended_details.isChecked = config.showExtendedDetails
+ settings_show_extended_details_holder.setOnClickListener {
+ settings_show_extended_details.toggle()
+ config.showExtendedDetails = settings_show_extended_details.isChecked
+ settings_manage_extended_details_holder.beVisibleIf(config.showExtendedDetails)
+ }
+ }
+
+ private fun setupManageExtendedDetails() {
+ settings_manage_extended_details_holder.beVisibleIf(config.showExtendedDetails)
+ settings_manage_extended_details_holder.setOnClickListener {
+ ManageExtendedDetailsDialog(this) {
+ if (config.extendedDetails == 0) {
+ settings_show_extended_details_holder.callOnClick()
+ }
+ }
+ }
+ }
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/VideoActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/VideoActivity.kt
index fa38734e3..7ca92e902 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/VideoActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/VideoActivity.kt
@@ -5,7 +5,7 @@ import android.os.Bundle
class VideoActivity : PhotoVideoActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
- PhotoVideoActivity.mIsVideo = true
+ mIsVideo = true
super.onCreate(savedInstanceState)
}
}
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 7aacc2376..2a8099959 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt
@@ -23,14 +23,18 @@ import android.support.v4.view.ViewPager
import android.util.DisplayMetrics
import android.view.*
import android.view.animation.DecelerateInterpolator
-import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.dialogs.PropertiesDialog
import com.simplemobiletools.commons.dialogs.RenameItemDialog
import com.simplemobiletools.commons.extensions.*
+import com.simplemobiletools.commons.helpers.IS_FROM_GALLERY
+import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE
+import com.simplemobiletools.commons.helpers.REQUEST_EDIT_IMAGE
+import com.simplemobiletools.commons.helpers.REQUEST_SET_AS
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.MediaActivity.Companion.mMedia
import com.simplemobiletools.gallery.adapters.MyPagerAdapter
import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask
+import com.simplemobiletools.gallery.dialogs.DeleteWithRememberDialog
import com.simplemobiletools.gallery.dialogs.SaveAsDialog
import com.simplemobiletools.gallery.dialogs.SlideshowDialog
import com.simplemobiletools.gallery.extensions.*
@@ -40,12 +44,11 @@ import com.simplemobiletools.gallery.fragments.ViewPagerFragment
import com.simplemobiletools.gallery.helpers.*
import com.simplemobiletools.gallery.models.Medium
import kotlinx.android.synthetic.main.activity_medium.*
-import java.io.File
-import java.io.OutputStream
+import java.io.*
import java.util.*
class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, ViewPagerFragment.FragmentListener {
- lateinit var mOrientationEventListener: OrientationEventListener
+ private var mOrientationEventListener: OrientationEventListener? = null
private var mPath = ""
private var mDirectory = ""
@@ -53,6 +56,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private var mPos = -1
private var mShowAll = false
private var mIsSlideshowActive = false
+ private var mSkipConfirmationDialog = false
private var mRotationDegrees = 0f
private var mLastHandledOrientation = 0
private var mPrevHashcode = 0
@@ -62,6 +66,9 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private var mSlideshowMoveBackwards = false
private var mSlideshowMedia = mutableListOf()
private var mAreSlideShowMediaVisible = false
+ private var mIsOrientationLocked = false
+
+ private var mStoredUseEnglish = false
companion object {
var screenWidth = 0
@@ -72,11 +79,66 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_medium)
- if (!hasWriteStoragePermission()) {
+ handlePermission(PERMISSION_WRITE_STORAGE) {
+ if (it) {
+ initViewPager()
+ } else {
+ toast(R.string.no_storage_permissions)
+ finish()
+ }
+ }
+
+ storeStateVariables()
+ }
+
+ override fun onResume() {
+ super.onResume()
+ if (!hasPermission(PERMISSION_WRITE_STORAGE)) {
finish()
return
}
+ if (mStoredUseEnglish != config.useEnglish) {
+ restartActivity()
+ return
+ }
+
+ supportActionBar?.setBackgroundDrawable(resources.getDrawable(R.drawable.actionbar_gradient_background))
+
+ if (config.maxBrightness) {
+ val attributes = window.attributes
+ attributes.screenBrightness = 1f
+ window.attributes = attributes
+ }
+
+ setupRotation()
+ invalidateOptionsMenu()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ mOrientationEventListener?.disable()
+ stopSlideshow()
+ storeStateVariables()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ if (intent.extras?.containsKey(IS_VIEW_INTENT) == true) {
+ config.temporarilyShowHidden = false
+ }
+
+ if (config.isThirdPartyIntent) {
+ config.isThirdPartyIntent = false
+
+ if (intent.extras == null || !intent.getBooleanExtra(IS_FROM_GALLERY, false)) {
+ mMedia.clear()
+ }
+ }
+ }
+
+ private fun initViewPager() {
+ setupOrientationEventListener()
measureScreen()
val uri = intent.data
if (uri != null) {
@@ -92,7 +154,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
} else {
try {
- mPath = intent.getStringExtra(MEDIUM)
+ mPath = intent.getStringExtra(PATH)
mShowAll = config.showAll
} catch (e: Exception) {
showErrorToast(e)
@@ -122,21 +184,16 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
mDirectory = File(mPath).parent
title = mPath.getFilenameFromPath()
- view_pager.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
- override fun onGlobalLayout() {
- view_pager.viewTreeObserver.removeOnGlobalLayoutListener(this)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && isDestroyed)
- return
-
+ view_pager.onGlobalLayout {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !isDestroyed) {
if (mMedia.isNotEmpty()) {
gotMedia(mMedia)
}
}
- })
+ }
reloadViewPager()
scanPath(mPath) {}
- setupOrientationEventListener()
if (config.darkBackground)
view_pager.background = ColorDrawable(Color.BLACK)
@@ -153,18 +210,15 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
}
- override fun onDestroy() {
- super.onDestroy()
- if (intent.extras?.containsKey(IS_VIEW_INTENT) == true) {
- config.temporarilyShowHidden = false
- }
-
- if (config.isThirdPartyIntent) {
- config.isThirdPartyIntent = false
-
- if (intent.extras == null || !intent.getBooleanExtra(IS_FROM_GALLERY, false)) {
- mMedia.clear()
+ private fun setupRotation() {
+ if (mIsOrientationLocked) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
}
+ } else if (config.screenRotation == ROTATE_BY_DEVICE_ROTATION && mOrientationEventListener?.canDetectOrientation() == true) {
+ mOrientationEventListener?.enable()
+ } else if (config.screenRotation == ROTATE_BY_SYSTEM_SETTING) {
+ requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
}
}
@@ -172,12 +226,12 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
mOrientationEventListener = object : OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {
override fun onOrientationChanged(orientation: Int) {
val currOrient = when (orientation) {
- in 45..134 -> ORIENT_LANDSCAPE_RIGHT
- in 225..314 -> ORIENT_LANDSCAPE_LEFT
+ in 60..134 -> ORIENT_LANDSCAPE_RIGHT
+ in 225..299 -> ORIENT_LANDSCAPE_LEFT
else -> ORIENT_PORTRAIT
}
- if (mLastHandledOrientation != currOrient) {
+ if (!mIsOrientationLocked && mLastHandledOrientation != currOrient) {
mLastHandledOrientation = currOrient
requestedOrientation = when (currOrient) {
@@ -190,34 +244,6 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
}
- override fun onResume() {
- super.onResume()
- if (!hasWriteStoragePermission()) {
- finish()
- }
- supportActionBar?.setBackgroundDrawable(resources.getDrawable(R.drawable.actionbar_gradient_background))
-
- if (config.maxBrightness) {
- val attributes = window.attributes
- attributes.screenBrightness = 1f
- window.attributes = attributes
- }
-
- if (config.screenRotation == ROTATE_BY_DEVICE_ROTATION && mOrientationEventListener.canDetectOrientation()) {
- mOrientationEventListener.enable()
- } else if (config.screenRotation == ROTATE_BY_SYSTEM_SETTING) {
- requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
- }
-
- invalidateOptionsMenu()
- }
-
- override fun onPause() {
- super.onPause()
- mOrientationEventListener.disable()
- stopSlideshow()
- }
-
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_viewpager, menu)
val currentMedium = getCurrentMedium() ?: return true
@@ -225,12 +251,17 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
menu.apply {
findItem(R.id.menu_share_1).isVisible = !config.replaceShare
findItem(R.id.menu_share_2).isVisible = config.replaceShare
- findItem(R.id.menu_set_as).isVisible = currentMedium.isImage()
- findItem(R.id.menu_edit).isVisible = currentMedium.isImage()
findItem(R.id.menu_rotate).isVisible = currentMedium.isImage()
findItem(R.id.menu_save_as).isVisible = mRotationDegrees != 0f
findItem(R.id.menu_hide).isVisible = !currentMedium.name.startsWith('.')
findItem(R.id.menu_unhide).isVisible = currentMedium.name.startsWith('.')
+ findItem(R.id.menu_lock_orientation).title = getString(if (mIsOrientationLocked) R.string.unlock_orientation else R.string.lock_orientation)
+ findItem(R.id.menu_rotate).setShowAsAction(
+ if (mRotationDegrees != 0f) {
+ MenuItem.SHOW_AS_ACTION_ALWAYS
+ } else {
+ MenuItem.SHOW_AS_ACTION_IF_ROOM
+ })
}
return true
@@ -241,34 +272,40 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
return true
when (item.itemId) {
- R.id.menu_set_as -> trySetAs(getCurrentFile())
- R.id.slideshow -> initSlideshow()
+ R.id.menu_set_as -> setAs(Uri.fromFile(getCurrentFile()))
+ R.id.menu_slideshow -> initSlideshow()
R.id.menu_copy_to -> copyMoveTo(true)
R.id.menu_move_to -> copyMoveTo(false)
- R.id.menu_open_with -> openWith(getCurrentFile())
+ R.id.menu_open_with -> openFile(Uri.fromFile(getCurrentFile()), true)
R.id.menu_hide -> toggleFileVisibility(true)
R.id.menu_unhide -> toggleFileVisibility(false)
R.id.menu_share_1 -> shareMedium(getCurrentMedium()!!)
R.id.menu_share_2 -> shareMedium(getCurrentMedium()!!)
- R.id.menu_delete -> askConfirmDelete()
+ R.id.menu_delete -> checkDeleteConfirmation()
R.id.menu_rename -> renameFile()
- R.id.menu_edit -> openFileEditor(getCurrentFile())
+ R.id.menu_edit -> openEditor(Uri.fromFile(getCurrentFile()))
R.id.menu_properties -> showProperties()
- R.id.show_on_map -> showOnMap()
- R.id.menu_rotate -> rotateImage()
+ R.id.menu_show_on_map -> showOnMap()
+ R.id.menu_rotate_right -> rotateImage(90)
+ R.id.menu_rotate_left -> rotateImage(270)
+ R.id.menu_rotate_one_eighty -> rotateImage(180)
+ R.id.menu_lock_orientation -> toggleLockOrientation()
R.id.menu_save_as -> saveImageAs()
- R.id.settings -> launchSettings()
+ R.id.menu_settings -> launchSettings()
else -> return super.onOptionsItemSelected(item)
}
return true
}
+ private fun storeStateVariables() {
+ mStoredUseEnglish = config.useEnglish
+ }
+
private fun updatePagerItems(media: MutableList) {
val pagerAdapter = MyPagerAdapter(this, supportFragmentManager, media)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !isDestroyed) {
view_pager.apply {
adapter = pagerAdapter
- adapter!!.notifyDataSetChanged()
currentItem = mPos
addOnPageChangeListener(this@ViewPagerActivity)
}
@@ -283,12 +320,8 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun startSlideshow() {
if (getMediaForSlideshow()) {
- view_pager.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
- override fun onGlobalLayout() {
- view_pager.viewTreeObserver.removeOnGlobalLayoutListener(this)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && isDestroyed)
- return
-
+ view_pager.onGlobalLayout {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !isDestroyed) {
hideSystemUI()
mSlideshowInterval = config.slideshowInterval
mSlideshowMoveBackwards = config.slideshowMoveBackwards
@@ -296,7 +329,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
scheduleSwipe()
}
- })
+ }
}
}
@@ -327,10 +360,12 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
animator.addUpdateListener(object : ValueAnimator.AnimatorUpdateListener {
var oldDragPosition = 0
override fun onAnimationUpdate(animation: ValueAnimator) {
- val dragPosition = animation.animatedValue as Int
- val dragOffset = dragPosition - oldDragPosition
- oldDragPosition = dragPosition
- view_pager?.fakeDragBy(dragOffset * (if (forward) 1f else -1f))
+ if (view_pager?.isFakeDragging == true) {
+ val dragPosition = animation.animatedValue as Int
+ val dragOffset = dragPosition - oldDragPosition
+ oldDragPosition = dragPosition
+ view_pager.fakeDragBy(dragOffset * (if (forward) 1f else -1f))
+ }
}
})
@@ -436,62 +471,122 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
}
- private fun rotateImage() {
- mRotationDegrees = (mRotationDegrees + 90) % 360
+ private fun rotateImage(degrees: Int) {
+ mRotationDegrees = (mRotationDegrees + degrees) % 360
getCurrentFragment()?.let {
(it as? PhotoFragment)?.rotateImageViewBy(mRotationDegrees)
}
supportInvalidateOptionsMenu()
}
+ private fun toggleLockOrientation() {
+ mIsOrientationLocked = !mIsOrientationLocked
+ if (mIsOrientationLocked) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
+ }
+ } else {
+ setupRotation()
+ }
+ invalidateOptionsMenu()
+ }
+
private fun saveImageAs() {
val currPath = getCurrentPath()
- SaveAsDialog(this, currPath) {
+ SaveAsDialog(this, currPath, false) {
Thread({
- toast(R.string.saving)
val selectedFile = File(it)
- val tmpFile = File(selectedFile.parent, ".tmp_${it.getFilenameFromPath()}")
- try {
- val bitmap = BitmapFactory.decodeFile(currPath)
- getFileOutputStream(tmpFile) {
- if (it == null) {
- toast(R.string.unknown_error_occurred)
- deleteFile(tmpFile) {}
- return@getFileOutputStream
- }
+ handleSAFDialog(selectedFile) {
+ toast(R.string.saving)
+ val tmpFile = File(filesDir, ".tmp_${it.getFilenameFromPath()}")
+ try {
+ val bitmap = BitmapFactory.decodeFile(currPath)
+ getFileOutputStream(tmpFile) {
+ if (it == null) {
+ toast(R.string.unknown_error_occurred)
+ return@getFileOutputStream
+ }
- saveFile(tmpFile, bitmap, it)
- if (needsStupidWritePermissions(selectedFile.absolutePath)) {
- deleteFile(selectedFile) {}
- }
+ val oldLastModified = getCurrentFile().lastModified()
+ if (currPath.isJpg()) {
+ saveRotation(getCurrentFile(), tmpFile)
+ } else {
+ saveFile(tmpFile, bitmap, it as FileOutputStream)
+ }
- renameFile(tmpFile, selectedFile) {
- deleteFile(tmpFile) {}
+ if (tmpFile.length() > 0 && selectedFile.exists()) {
+ deleteFile(selectedFile) {}
+ }
+ copyFile(tmpFile, selectedFile)
+ scanFile(selectedFile) {}
+ toast(R.string.file_saved)
+
+ if (config.keepLastModified) {
+ selectedFile.setLastModified(oldLastModified)
+ updateLastModified(selectedFile, oldLastModified)
+ }
+
+ it.flush()
+ it.close()
+ mRotationDegrees = 0f
+ invalidateOptionsMenu()
}
+ } catch (e: OutOfMemoryError) {
+ toast(R.string.out_of_memory_error)
+ } catch (e: Exception) {
+ showErrorToast(e)
+ } finally {
+ deleteFile(tmpFile) {}
}
- } catch (e: OutOfMemoryError) {
- toast(R.string.out_of_memory_error)
- deleteFile(tmpFile) {}
- } catch (e: Exception) {
- showErrorToast(e)
- deleteFile(tmpFile) {}
}
}).start()
}
}
- private fun saveFile(file: File, bitmap: Bitmap, out: OutputStream) {
+ private fun copyFile(source: File, destination: File) {
+ var inputStream: InputStream? = null
+ var out: OutputStream? = null
+ try {
+ val fileDocument = if (isPathOnSD(destination.absolutePath)) getFileDocument(destination.parent) else null
+ out = getFileOutputStreamSync(destination.absolutePath, source.getMimeType(), fileDocument)
+ inputStream = FileInputStream(source)
+ inputStream.copyTo(out!!)
+ } finally {
+ inputStream?.close()
+ out?.close()
+ }
+ }
+
+ private fun saveFile(file: File, bitmap: Bitmap, out: FileOutputStream) {
val matrix = Matrix()
matrix.postRotate(mRotationDegrees)
val bmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
bmp.compress(file.getCompressionFormat(), 90, out)
- out.flush()
- out.close()
- toast(R.string.file_saved)
- mRotationDegrees = 0f
- invalidateOptionsMenu()
}
+ private fun saveRotation(source: File, destination: File) {
+ copyFile(source, destination)
+ val exif = ExifInterface(destination.absolutePath)
+ val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
+ val orientationDegrees = (degreesForRotation(orientation) + mRotationDegrees) % 360
+ exif.setAttribute(ExifInterface.TAG_ORIENTATION, rotationFromDegrees(orientationDegrees))
+ exif.saveAttributes()
+ }
+
+ private fun degreesForRotation(orientation: Int) = when (orientation) {
+ ExifInterface.ORIENTATION_ROTATE_270 -> 270f
+ ExifInterface.ORIENTATION_ROTATE_180 -> 180f
+ ExifInterface.ORIENTATION_ROTATE_90 -> 90f
+ else -> 0f
+ }
+
+ private fun rotationFromDegrees(degrees: Float) = when (degrees) {
+ 270f -> ExifInterface.ORIENTATION_ROTATE_270
+ 180f -> ExifInterface.ORIENTATION_ROTATE_180
+ 90f -> ExifInterface.ORIENTATION_ROTATE_90
+ else -> ExifInterface.ORIENTATION_NORMAL
+ }.toString()
+
private fun isShowHiddenFlagNeeded(): Boolean {
val file = File(mPath)
if (file.isHidden)
@@ -515,8 +610,9 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun getCurrentFragment() = (view_pager.adapter as MyPagerAdapter).getCurrentFragment(view_pager.currentItem)
private fun showProperties() {
- if (getCurrentMedium() != null)
+ if (getCurrentMedium() != null) {
PropertiesDialog(this, getCurrentPath(), false)
+ }
}
private fun showOnMap() {
@@ -590,11 +686,24 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
super.onActivityResult(requestCode, resultCode, resultData)
}
+ private fun checkDeleteConfirmation() {
+ if (mSkipConfirmationDialog) {
+ deleteConfirmed()
+ } else {
+ askConfirmDelete()
+ }
+ }
+
private fun askConfirmDelete() {
- ConfirmationDialog(this) {
- deleteFileBg(File(getCurrentMedia()[mPos].path)) {
- reloadViewPager()
- }
+ DeleteWithRememberDialog(this) {
+ mSkipConfirmationDialog = it
+ deleteConfirmed()
+ }
+ }
+
+ private fun deleteConfirmed() {
+ deleteFileBg(File(getCurrentMedia()[mPos].path)) {
+ reloadViewPager()
}
}
@@ -603,8 +712,9 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
deleteDirectoryIfEmpty()
finish()
true
- } else
+ } else {
false
+ }
}
private fun renameFile() {
@@ -677,7 +787,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
private fun checkOrientation() {
- if (config.screenRotation == ROTATE_BY_ASPECT_RATIO) {
+ if (!mIsOrientationLocked && config.screenRotation == ROTATE_BY_ASPECT_RATIO) {
val res = getCurrentFile().getResolution()
if (res.x > res.y) {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
@@ -716,10 +826,11 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
private fun getCurrentMedium(): Medium? {
- return if (getCurrentMedia().isEmpty() || mPos == -1)
+ return if (getCurrentMedia().isEmpty() || mPos == -1) {
null
- else
+ } else {
getCurrentMedia()[Math.min(mPos, getCurrentMedia().size - 1)]
+ }
}
private fun getCurrentMedia() = if (mAreSlideShowMediaVisible) mSlideshowMedia else mMedia
@@ -728,9 +839,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun getCurrentFile() = File(getCurrentPath())
- override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
-
- }
+ override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
override fun onPageSelected(position: Int) {
if (view_pager.offscreenPageLimit == 1) {
@@ -744,7 +853,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
override fun onPageScrollStateChanged(state: Int) {
- if (state == ViewPager.SCROLL_STATE_IDLE) {
+ if (state == ViewPager.SCROLL_STATE_IDLE && getCurrentMedium() != null) {
checkOrientation()
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/DirectoryAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/DirectoryAdapter.kt
index 9454f0ca4..b2f585e07 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/DirectoryAdapter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/DirectoryAdapter.kt
@@ -30,24 +30,30 @@ import java.util.*
class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList, val listener: DirOperationsListener?, val isPickIntent: Boolean,
val itemClick: (Directory) -> Unit) : RecyclerView.Adapter() {
- val multiSelector = MultiSelector()
- val config = activity.config
- val isListViewType = config.viewTypeFolders == VIEW_TYPE_LIST
-
+ private val config = activity.config
var actMode: ActionMode? = null
- var itemViews = SparseArray()
- val selectedPositions = HashSet()
var primaryColor = config.primaryColor
- var textColor = config.textColor
- var pinnedFolders = config.pinnedFolders
- var scrollVertically = !config.scrollHorizontally
+
+ private val multiSelector = MultiSelector()
+ private val isListViewType = config.viewTypeFolders == VIEW_TYPE_LIST
+ private var itemViews = SparseArray()
+ private val selectedPositions = HashSet()
+ private var textColor = config.textColor
+ private var pinnedFolders = config.pinnedFolders
+ private var scrollHorizontally = config.scrollHorizontally
+ private var showMediaCount = config.showMediaCount
+ private var animateGifs = config.animateGifs
+ private var cropThumbnails = config.cropThumbnails
fun toggleItemSelection(select: Boolean, pos: Int) {
if (select) {
- itemViews[pos]?.dir_check?.background?.setColorFilter(primaryColor, PorterDuff.Mode.SRC_IN)
- selectedPositions.add(pos)
- } else
+ if (itemViews[pos] != null) {
+ itemViews[pos].dir_check?.background?.setColorFilter(primaryColor, PorterDuff.Mode.SRC_IN)
+ selectedPositions.add(pos)
+ }
+ } else {
selectedPositions.remove(pos)
+ }
itemViews[pos]?.dir_check?.beVisibleIf(select)
@@ -123,10 +129,11 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList 0
@@ -138,10 +145,11 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList 0
@@ -215,10 +223,11 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList newItems.put(curIndex, itemViews[i]) }
itemViews = newItems
+ actMode?.finish()
}
}
@@ -302,20 +311,30 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList) {
activity.config.albumCovers = Gson().toJson(albumCovers)
actMode?.finish()
@@ -336,7 +355,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList (Unit)) :
SwappingHolder(view, MultiSelector()) {
- fun bindView(directory: Directory, isPinned: Boolean, scrollVertically: Boolean, isListView: Boolean, textColor: Int): View {
+ fun bindView(directory: Directory, isPinned: Boolean, scrollHorizontally: Boolean, isListView: Boolean, textColor: Int, showMediaCount: Boolean,
+ animateGifs: Boolean, cropThumbnails: Boolean): View {
itemView.apply {
dir_name.text = directory.name
dir_path?.text = "${directory.path.substringBeforeLast("/")}/"
photo_cnt.text = directory.mediaCnt.toString()
- activity.loadImage(directory.tmb, dir_thumbnail, scrollVertically)
+ activity.loadImage(directory.tmb, dir_thumbnail, scrollHorizontally, animateGifs, cropThumbnails)
dir_pin.beVisibleIf(isPinned)
dir_sd_card.beVisibleIf(activity.isPathOnSD(directory.path))
+ photo_cnt.beVisibleIf(showMediaCount)
if (isListView) {
dir_name.setTextColor(textColor)
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MediaAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MediaAdapter.kt
index 7296f51d7..039ac332a 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MediaAdapter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MediaAdapter.kt
@@ -1,6 +1,7 @@
package com.simplemobiletools.gallery.adapters
import android.graphics.PorterDuff
+import android.net.Uri
import android.os.Build
import android.support.v7.view.ActionMode
import android.support.v7.widget.RecyclerView
@@ -10,13 +11,13 @@ import com.bignerdranch.android.multiselector.ModalMultiSelectorCallback
import com.bignerdranch.android.multiselector.MultiSelector
import com.bignerdranch.android.multiselector.SwappingHolder
import com.bumptech.glide.Glide
-import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.dialogs.PropertiesDialog
import com.simplemobiletools.commons.dialogs.RenameItemDialog
import com.simplemobiletools.commons.extensions.beGone
import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
+import com.simplemobiletools.gallery.dialogs.DeleteWithRememberDialog
import com.simplemobiletools.gallery.extensions.*
import com.simplemobiletools.gallery.helpers.VIEW_TYPE_LIST
import com.simplemobiletools.gallery.models.Medium
@@ -24,27 +25,34 @@ import kotlinx.android.synthetic.main.photo_video_item_grid.view.*
import java.io.File
import java.util.*
-class MediaAdapter(val activity: SimpleActivity, var media: MutableList, val listener: MediaOperationsListener?, val isPickIntent: Boolean,
+class MediaAdapter(val activity: SimpleActivity, var media: MutableList, val listener: MediaOperationsListener?, val isAGetIntent: Boolean,
val allowMultiplePicks: Boolean, val itemClick: (Medium) -> Unit) : RecyclerView.Adapter() {
- val multiSelector = MultiSelector()
- val config = activity.config
- val isListViewType = config.viewTypeFiles == VIEW_TYPE_LIST
-
+ private val config = activity.config
var actMode: ActionMode? = null
- var itemViews = SparseArray()
- val selectedPositions = HashSet()
var primaryColor = config.primaryColor
- var textColor = config.textColor
- var displayFilenames = config.displayFileNames
- var scrollVertically = !config.scrollHorizontally
+
+ private val multiSelector = MultiSelector()
+ private val isListViewType = config.viewTypeFiles == VIEW_TYPE_LIST
+ private var skipConfirmationDialog = false
+
+ private var itemViews = SparseArray()
+ private val selectedPositions = HashSet()
+ private var scrollHorizontally = config.scrollHorizontally
+ private var animateGifs = config.animateGifs
+ private var cropThumbnails = config.cropThumbnails
+ private var textColor = config.textColor
+ private var displayFilenames = config.displayFileNames
fun toggleItemSelection(select: Boolean, pos: Int) {
if (select) {
- itemViews[pos]?.medium_check?.background?.setColorFilter(primaryColor, PorterDuff.Mode.SRC_IN)
- selectedPositions.add(pos)
- } else
+ if (itemViews[pos] != null) {
+ itemViews[pos].medium_check?.background?.setColorFilter(primaryColor, PorterDuff.Mode.SRC_IN)
+ selectedPositions.add(pos)
+ }
+ } else {
selectedPositions.remove(pos)
+ }
itemViews[pos]?.medium_check?.beVisibleIf(select)
@@ -82,7 +90,9 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList,
R.id.cab_copy_to -> copyMoveTo(true)
R.id.cab_move_to -> copyMoveTo(false)
R.id.cab_select_all -> selectAll()
- R.id.cab_delete -> askConfirmDelete()
+ R.id.cab_open_with -> activity.openFile(Uri.fromFile(getCurrentFile()), true)
+ R.id.cab_set_as -> activity.setAs(Uri.fromFile(getCurrentFile()))
+ R.id.cab_delete -> checkDeleteConfirmation()
else -> return false
}
return true
@@ -96,9 +106,9 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList,
}
override fun onPrepareActionMode(actionMode: ActionMode?, menu: Menu): Boolean {
- menu.findItem(R.id.cab_rename).isVisible = selectedPositions.size <= 1
- menu.findItem(R.id.cab_edit).isVisible = selectedPositions.size == 1 && media.size > selectedPositions.first() && media[selectedPositions.first()].isImage()
- menu.findItem(R.id.cab_confirm_selection).isVisible = isPickIntent && allowMultiplePicks && selectedPositions.size > 0
+ menu.findItem(R.id.cab_rename).isVisible = selectedPositions.size == 1
+ menu.findItem(R.id.cab_open_with).isVisible = selectedPositions.size == 1
+ menu.findItem(R.id.cab_confirm_selection).isVisible = isAGetIntent && allowMultiplePicks && selectedPositions.size > 0
checkHideBtnVisibility(menu)
@@ -118,10 +128,11 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList,
var hiddenCnt = 0
var unhiddenCnt = 0
selectedPositions.mapNotNull { media.getOrNull(it) }.forEach {
- if (it.name.startsWith('.'))
+ if (it.name.startsWith('.')) {
hiddenCnt++
- else
+ } else {
unhiddenCnt++
+ }
}
menu.findItem(R.id.cab_hide).isVisible = unhiddenCnt > 0
@@ -154,7 +165,7 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList,
}
private fun editFile() {
- activity.openFileEditor(getCurrentFile())
+ activity.openEditor(Uri.fromFile(getCurrentFile()))
actMode?.finish()
}
@@ -202,18 +213,31 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList,
updateTitle(cnt)
}
- private fun askConfirmDelete() {
- ConfirmationDialog(activity) {
- deleteFiles()
- actMode?.finish()
+ private fun checkDeleteConfirmation() {
+ if (skipConfirmationDialog) {
+ deleteConfirmed()
+ } else {
+ askConfirmDelete()
}
}
+ private fun askConfirmDelete() {
+ DeleteWithRememberDialog(activity) {
+ skipConfirmationDialog = it
+ deleteConfirmed()
+ }
+ }
+
+ private fun deleteConfirmed() {
+ deleteFiles()
+ }
+
private fun getCurrentFile() = File(media[selectedPositions.first()].path)
private fun deleteFiles() {
- if (selectedPositions.isEmpty())
+ if (selectedPositions.isEmpty()) {
return
+ }
val files = ArrayList(selectedPositions.size)
val removeMedia = ArrayList(selectedPositions.size)
@@ -242,6 +266,7 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList,
.forEachIndexed { curIndex, i -> newItems.put(curIndex, itemViews[i]) }
itemViews = newItems
+ actMode?.finish()
}
}
@@ -254,11 +279,11 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList,
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
val layoutType = if (isListViewType) R.layout.photo_video_item_list else R.layout.photo_video_item_grid
val view = LayoutInflater.from(parent?.context).inflate(layoutType, parent, false)
- return ViewHolder(view, adapterListener, activity, multiSelectorMode, multiSelector, listener, allowMultiplePicks || !isPickIntent, itemClick)
+ return ViewHolder(view, adapterListener, activity, multiSelectorMode, multiSelector, listener, allowMultiplePicks || !isAGetIntent, itemClick)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- itemViews.put(position, holder.bindView(media[position], displayFilenames, scrollVertically, isListViewType, textColor))
+ itemViews.put(position, holder.bindView(media[position], displayFilenames, scrollHorizontally, isListViewType, textColor, animateGifs, cropThumbnails))
toggleItemSelection(selectedPositions.contains(position), position)
holder.itemView.tag = holder
}
@@ -276,8 +301,23 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList,
actMode?.finish()
}
- fun updateDisplayFilenames(display: Boolean) {
- displayFilenames = display
+ fun updateDisplayFilenames(displayFilenames: Boolean) {
+ this.displayFilenames = displayFilenames
+ notifyDataSetChanged()
+ }
+
+ fun updateAnimateGifs(animateGifs: Boolean) {
+ this.animateGifs = animateGifs
+ notifyDataSetChanged()
+ }
+
+ fun updateCropThumbnails(cropThumbnails: Boolean) {
+ this.cropThumbnails = cropThumbnails
+ notifyDataSetChanged()
+ }
+
+ fun updateScrollHorizontally(scrollHorizontally: Boolean) {
+ this.scrollHorizontally = scrollHorizontally
notifyDataSetChanged()
}
@@ -329,12 +369,13 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList,
val multiSelector: MultiSelector, val listener: MediaOperationsListener?, val allowMultiplePicks: Boolean,
val itemClick: (Medium) -> (Unit)) :
SwappingHolder(view, MultiSelector()) {
- fun bindView(medium: Medium, displayFilenames: Boolean, scrollVertically: Boolean, isListViewType: Boolean, textColor: Int): View {
+ fun bindView(medium: Medium, displayFilenames: Boolean, scrollHorizontally: Boolean, isListViewType: Boolean, textColor: Int,
+ animateGifs: Boolean, cropThumbnails: Boolean): View {
itemView.apply {
play_outline.visibility = if (medium.video) View.VISIBLE else View.GONE
photo_name.beVisibleIf(displayFilenames || isListViewType)
photo_name.text = medium.name
- activity.loadImage(medium.path, medium_thumbnail, scrollVertically)
+ activity.loadImage(medium.path, medium_thumbnail, scrollHorizontally, animateGifs, cropThumbnails)
if (isListViewType) {
photo_name.setTextColor(textColor)
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MyPagerAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MyPagerAdapter.kt
index b7e5640ad..69c389d9e 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MyPagerAdapter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MyPagerAdapter.kt
@@ -23,10 +23,10 @@ class MyPagerAdapter(val activity: ViewPagerActivity, fm: FragmentManager, val m
bundle.putSerializable(MEDIUM, medium)
val fragment: ViewPagerFragment
- if (medium.video) {
- fragment = VideoFragment()
+ fragment = if (medium.video) {
+ VideoFragment()
} else {
- fragment = PhotoFragment()
+ PhotoFragment()
}
fragment.arguments = bundle
@@ -34,15 +34,15 @@ class MyPagerAdapter(val activity: ViewPagerActivity, fm: FragmentManager, val m
return fragment
}
- override fun getItemPosition(item: Any?) = PagerAdapter.POSITION_NONE
+ override fun getItemPosition(item: Any) = PagerAdapter.POSITION_NONE
- override fun instantiateItem(container: ViewGroup?, position: Int): Any {
+ override fun instantiateItem(container: ViewGroup, position: Int): Any {
val fragment = super.instantiateItem(container, position) as ViewPagerFragment
mFragments.put(position, fragment)
return fragment
}
- override fun destroyItem(container: ViewGroup?, position: Int, any: Any?) {
+ override fun destroyItem(container: ViewGroup, position: Int, any: Any) {
mFragments.remove(position)
super.destroyItem(container, position, any)
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetDirectoriesAsynctask.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetDirectoriesAsynctask.kt
index 676b45f8b..d1767ce4a 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetDirectoriesAsynctask.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetDirectoriesAsynctask.kt
@@ -3,9 +3,10 @@ package com.simplemobiletools.gallery.asynctasks
import android.content.Context
import android.os.AsyncTask
import com.simplemobiletools.commons.extensions.getFilenameFromPath
-import com.simplemobiletools.commons.extensions.hasWriteStoragePermission
+import com.simplemobiletools.commons.extensions.hasPermission
import com.simplemobiletools.commons.extensions.internalStoragePath
import com.simplemobiletools.commons.extensions.sdCardPath
+import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE
import com.simplemobiletools.commons.helpers.SORT_DESCENDING
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.extensions.config
@@ -21,7 +22,7 @@ class GetDirectoriesAsynctask(val context: Context, val isPickVideo: Boolean, va
val mediaFetcher = MediaFetcher(context)
override fun doInBackground(vararg params: Void): ArrayList {
- if (!context.hasWriteStoragePermission())
+ if (!context.hasPermission(PERMISSION_WRITE_STORAGE))
return ArrayList()
val config = context.config
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetMediaAsynctask.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetMediaAsynctask.kt
index 2c99f54d6..a3b8a2b5d 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetMediaAsynctask.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetMediaAsynctask.kt
@@ -10,14 +10,15 @@ import java.util.*
class GetMediaAsynctask(val context: Context, val mPath: String, val isPickVideo: Boolean = false, val isPickImage: Boolean = false,
val showAll: Boolean, val callback: (media: ArrayList) -> Unit) :
AsyncTask>() {
- val mediaFetcher = MediaFetcher(context)
+ private val mediaFetcher = MediaFetcher(context)
override fun doInBackground(vararg params: Void): ArrayList {
return if (showAll) {
val mediaMap = mediaFetcher.getMediaByDirectories(isPickVideo, isPickImage)
val media = ArrayList()
- for ((path, curMedia) in mediaMap) {
- media.addAll(curMedia)
+
+ mediaMap.values.forEach {
+ media.addAll(it)
}
Medium.sorting = context.config.getFileSorting("")
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ChangeSortingDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ChangeSortingDialog.kt
index f7020498d..95513a98e 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ChangeSortingDialog.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ChangeSortingDialog.kt
@@ -42,12 +42,12 @@ class ChangeSortingDialog(val activity: SimpleActivity, val isDirectorySorting:
val sortingRadio = view.sorting_dialog_radio_sorting
var sortBtn = sortingRadio.sorting_dialog_radio_name
- if (currSorting and SORT_BY_SIZE != 0) {
- sortBtn = sortingRadio.sorting_dialog_radio_size
- } else if (currSorting and SORT_BY_DATE_MODIFIED != 0) {
- sortBtn = sortingRadio.sorting_dialog_radio_last_modified
- } else if (currSorting and SORT_BY_DATE_TAKEN != 0)
- sortBtn = sortingRadio.sorting_dialog_radio_date_taken
+ when {
+ currSorting and SORT_BY_PATH != 0 -> sortBtn = sortingRadio.sorting_dialog_radio_path
+ currSorting and SORT_BY_SIZE != 0 -> sortBtn = sortingRadio.sorting_dialog_radio_size
+ currSorting and SORT_BY_DATE_MODIFIED != 0 -> sortBtn = sortingRadio.sorting_dialog_radio_last_modified
+ currSorting and SORT_BY_DATE_TAKEN != 0 -> sortBtn = sortingRadio.sorting_dialog_radio_date_taken
+ }
sortBtn.isChecked = true
}
@@ -65,6 +65,7 @@ class ChangeSortingDialog(val activity: SimpleActivity, val isDirectorySorting:
val sortingRadio = view.sorting_dialog_radio_sorting
var sorting = when (sortingRadio.checkedRadioButtonId) {
R.id.sorting_dialog_radio_name -> SORT_BY_NAME
+ R.id.sorting_dialog_radio_path -> SORT_BY_PATH
R.id.sorting_dialog_radio_size -> SORT_BY_SIZE
R.id.sorting_dialog_radio_last_modified -> SORT_BY_DATE_MODIFIED
else -> SORT_BY_DATE_TAKEN
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/DeleteWithRememberDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/DeleteWithRememberDialog.kt
new file mode 100644
index 000000000..05a240577
--- /dev/null
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/DeleteWithRememberDialog.kt
@@ -0,0 +1,28 @@
+package com.simplemobiletools.gallery.dialogs
+
+import android.content.Context
+import android.support.v7.app.AlertDialog
+import android.view.LayoutInflater
+import com.simplemobiletools.commons.extensions.setupDialogStuff
+import com.simplemobiletools.gallery.R
+import kotlinx.android.synthetic.main.dialog_delete_with_remember.view.*
+
+class DeleteWithRememberDialog(val context: Context, val callback: (remember: Boolean) -> Unit) {
+ var dialog: AlertDialog
+ val view = LayoutInflater.from(context).inflate(R.layout.dialog_delete_with_remember, null)
+
+ init {
+ val builder = AlertDialog.Builder(context)
+ .setPositiveButton(R.string.yes, { dialog, which -> dialogConfirmed() })
+ .setNegativeButton(R.string.no, null)
+
+ dialog = builder.create().apply {
+ context.setupDialogStuff(view, this)
+ }
+ }
+
+ private fun dialogConfirmed() {
+ dialog.dismiss()
+ callback(view.delete_remember_checkbox.isChecked)
+ }
+}
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ManageExtendedDetailsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ManageExtendedDetailsDialog.kt
new file mode 100644
index 000000000..3d8c5e3a7
--- /dev/null
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ManageExtendedDetailsDialog.kt
@@ -0,0 +1,70 @@
+package com.simplemobiletools.gallery.dialogs
+
+import android.support.v7.app.AlertDialog
+import android.view.LayoutInflater
+import android.view.View
+import com.simplemobiletools.commons.extensions.setupDialogStuff
+import com.simplemobiletools.gallery.R
+import com.simplemobiletools.gallery.activities.SimpleActivity
+import com.simplemobiletools.gallery.extensions.config
+import com.simplemobiletools.gallery.helpers.*
+import kotlinx.android.synthetic.main.dialog_manage_extended_details.view.*
+
+class ManageExtendedDetailsDialog(val activity: SimpleActivity, val callback: (result: Int) -> Unit) {
+ private var view: View = LayoutInflater.from(activity).inflate(R.layout.dialog_manage_extended_details, null)
+
+ init {
+ val details = activity.config.extendedDetails
+ view.apply {
+ manage_extended_details_name.isChecked = details and EXT_NAME != 0
+ manage_extended_details_path.isChecked = details and EXT_PATH != 0
+ manage_extended_details_size.isChecked = details and EXT_SIZE != 0
+ manage_extended_details_resolution.isChecked = details and EXT_RESOLUTION != 0
+ manage_extended_details_last_modified.isChecked = details and EXT_LAST_MODIFIED != 0
+ manage_extended_details_date_taken.isChecked = details and EXT_DATE_TAKEN != 0
+ manage_extended_details_camera.isChecked = details and EXT_CAMERA_MODEL != 0
+ manage_extended_details_exif.isChecked = details and EXT_EXIF_PROPERTIES != 0
+ manage_extended_details_duration.isChecked = details and EXT_DURATION != 0
+ manage_extended_details_artist.isChecked = details and EXT_ARTIST != 0
+ manage_extended_details_album.isChecked = details and EXT_ALBUM != 0
+ }
+
+ AlertDialog.Builder(activity)
+ .setPositiveButton(R.string.ok, { dialog, which -> dialogConfirmed() })
+ .setNegativeButton(R.string.cancel, null)
+ .create().apply {
+ activity.setupDialogStuff(view, this)
+ }
+ }
+
+ private fun dialogConfirmed() {
+ var result = 0
+ view.apply {
+ if (manage_extended_details_name.isChecked)
+ result += EXT_NAME
+ if (manage_extended_details_path.isChecked)
+ result += EXT_PATH
+ if (manage_extended_details_size.isChecked)
+ result += EXT_SIZE
+ if (manage_extended_details_resolution.isChecked)
+ result += EXT_RESOLUTION
+ if (manage_extended_details_last_modified.isChecked)
+ result += EXT_LAST_MODIFIED
+ if (manage_extended_details_date_taken.isChecked)
+ result += EXT_DATE_TAKEN
+ if (manage_extended_details_camera.isChecked)
+ result += EXT_CAMERA_MODEL
+ if (manage_extended_details_exif.isChecked)
+ result += EXT_EXIF_PROPERTIES
+ if (manage_extended_details_duration.isChecked)
+ result += EXT_DURATION
+ if (manage_extended_details_artist.isChecked)
+ result += EXT_ARTIST
+ if (manage_extended_details_album.isChecked)
+ result += EXT_ALBUM
+ }
+
+ activity.config.extendedDetails = result
+ callback(result)
+ }
+}
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickDirectoryDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickDirectoryDialog.kt
index 1d53684cb..e72a3395c 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickDirectoryDialog.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickDirectoryDialog.kt
@@ -3,7 +3,6 @@ package com.simplemobiletools.gallery.dialogs
import android.support.v7.app.AlertDialog
import android.support.v7.widget.GridLayoutManager
import android.view.LayoutInflater
-import android.view.View
import com.simplemobiletools.commons.dialogs.FilePickerDialog
import com.simplemobiletools.commons.extensions.beGoneIf
import com.simplemobiletools.commons.extensions.beVisibleIf
@@ -22,8 +21,8 @@ import kotlinx.android.synthetic.main.dialog_directory_picker.view.*
class PickDirectoryDialog(val activity: SimpleActivity, val sourcePath: String, val callback: (path: String) -> Unit) {
var dialog: AlertDialog
- var shownDirectories: ArrayList = ArrayList()
- var view: View = LayoutInflater.from(activity).inflate(R.layout.dialog_directory_picker, null)
+ var shownDirectories = ArrayList()
+ var view = LayoutInflater.from(activity).inflate(R.layout.dialog_directory_picker, null)
var isGridViewType = activity.config.viewTypeFolders == VIEW_TYPE_GRID
init {
@@ -38,16 +37,16 @@ class PickDirectoryDialog(val activity: SimpleActivity, val sourcePath: String,
.setNeutralButton(R.string.other_folder, { dialogInterface, i -> showOtherFolder() })
.create().apply {
activity.setupDialogStuff(view, this, R.string.select_destination)
-
- val dirs = activity.getCachedDirectories()
- if (dirs.isNotEmpty()) {
- gotDirectories(activity.addTempFolderIfNeeded(dirs))
- }
-
- GetDirectoriesAsynctask(activity, false, false) {
- gotDirectories(activity.addTempFolderIfNeeded(it))
- }.execute()
}
+
+ val dirs = activity.getCachedDirectories()
+ if (dirs.isNotEmpty()) {
+ gotDirectories(activity.addTempFolderIfNeeded(dirs))
+ }
+
+ GetDirectoriesAsynctask(activity, false, false) {
+ gotDirectories(activity.addTempFolderIfNeeded(it))
+ }.execute()
}
private fun showOtherFolder() {
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickMediumDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickMediumDialog.kt
index fe0a86add..3596a6907 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickMediumDialog.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickMediumDialog.kt
@@ -1,44 +1,55 @@
package com.simplemobiletools.gallery.dialogs
import android.support.v7.app.AlertDialog
-import android.support.v7.widget.RecyclerView
+import android.support.v7.widget.GridLayoutManager
import android.view.LayoutInflater
-import com.google.gson.Gson
-import com.google.gson.reflect.TypeToken
+import com.simplemobiletools.commons.extensions.beGoneIf
+import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
import com.simplemobiletools.gallery.adapters.MediaAdapter
import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask
import com.simplemobiletools.gallery.extensions.config
+import com.simplemobiletools.gallery.extensions.getCachedMedia
+import com.simplemobiletools.gallery.helpers.VIEW_TYPE_GRID
import com.simplemobiletools.gallery.models.Medium
import kotlinx.android.synthetic.main.dialog_medium_picker.view.*
class PickMediumDialog(val activity: SimpleActivity, val path: String, val callback: (path: String) -> Unit) {
var dialog: AlertDialog
- var mediaGrid: RecyclerView
- var shownMedia: ArrayList = ArrayList()
+ var shownMedia = ArrayList()
+ val view = LayoutInflater.from(activity).inflate(R.layout.dialog_medium_picker, null)
+ var isGridViewType = activity.config.viewTypeFiles == VIEW_TYPE_GRID
init {
- val view = LayoutInflater.from(activity).inflate(R.layout.dialog_medium_picker, null)
- mediaGrid = view.media_grid
+ (view.media_grid.layoutManager as GridLayoutManager).apply {
+ orientation = if (activity.config.scrollHorizontally && isGridViewType) GridLayoutManager.HORIZONTAL else GridLayoutManager.VERTICAL
+ spanCount = if (isGridViewType) activity.config.mediaColumnCnt else 1
+ }
dialog = AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
+ .setNeutralButton(R.string.other_folder, { dialogInterface, i -> showOtherFolder() })
.create().apply {
activity.setupDialogStuff(view, this, R.string.select_photo)
+ }
- val token = object : TypeToken>() {}.type
- val media = Gson().fromJson>(activity.config.loadFolderMedia(path), token) ?: ArrayList(1)
+ val media = activity.getCachedMedia(path).filter { !it.video } as ArrayList
+ if (media.isNotEmpty()) {
+ gotMedia(media)
+ }
- if (media.isNotEmpty()) {
- gotMedia(media)
- }
+ GetMediaAsynctask(activity, path, false, true, false) {
+ gotMedia(it)
+ }.execute()
+ }
- GetMediaAsynctask(activity, path, false, true, false) {
- gotMedia(it)
- }.execute()
+ private fun showOtherFolder() {
+ PickDirectoryDialog(activity, path) {
+ callback(it)
+ dialog.dismiss()
}
}
@@ -51,6 +62,22 @@ class PickMediumDialog(val activity: SimpleActivity, val path: String, val callb
callback(it.path)
dialog.dismiss()
}
- mediaGrid.adapter = adapter
+
+ val scrollHorizontally = activity.config.scrollHorizontally && isGridViewType
+ view.apply {
+ media_grid.adapter = adapter
+
+ media_vertical_fastscroller.isHorizontal = false
+ media_vertical_fastscroller.beGoneIf(scrollHorizontally)
+
+ media_horizontal_fastscroller.isHorizontal = true
+ media_horizontal_fastscroller.beVisibleIf(scrollHorizontally)
+
+ if (scrollHorizontally) {
+ media_horizontal_fastscroller.setViews(media_grid)
+ } else {
+ media_vertical_fastscroller.setViews(media_grid)
+ }
+ }
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SaveAsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SaveAsDialog.kt
index 503e0f741..f97e2fb99 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SaveAsDialog.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SaveAsDialog.kt
@@ -11,7 +11,7 @@ import com.simplemobiletools.gallery.activities.SimpleActivity
import kotlinx.android.synthetic.main.dialog_save_as.view.*
import java.io.File
-class SaveAsDialog(val activity: SimpleActivity, val path: String, val callback: (savePath: String) -> Unit) {
+class SaveAsDialog(val activity: SimpleActivity, val path: String, val appendFilename: Boolean, val callback: (savePath: String) -> Unit) {
init {
var realPath = File(path).parent.trimEnd('/')
@@ -28,6 +28,10 @@ class SaveAsDialog(val activity: SimpleActivity, val path: String, val callback:
save_as_extension.setText(extension)
}
+ if (appendFilename) {
+ name += "_1"
+ }
+
save_as_name.setText(name)
save_as_path.setOnClickListener {
FilePickerDialog(activity, realPath, false, false, true) {
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 756f9578b..200b2897b 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/activity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/activity.kt
@@ -2,16 +2,11 @@ package com.simplemobiletools.gallery.extensions
import android.app.Activity
import android.content.Intent
-import android.database.Cursor
import android.net.Uri
-import android.os.Build
import android.provider.MediaStore
import android.support.v7.app.AppCompatActivity
-import android.util.DisplayMetrics
-import android.view.KeyCharacterMap
-import android.view.KeyEvent
import android.view.View
-import android.view.ViewConfiguration
+import android.widget.ImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.load.engine.DiskCacheStrategy
@@ -24,165 +19,42 @@ import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.gallery.BuildConfig
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
-import com.simplemobiletools.gallery.helpers.IS_FROM_GALLERY
import com.simplemobiletools.gallery.helpers.NOMEDIA
-import com.simplemobiletools.gallery.helpers.REQUEST_EDIT_IMAGE
-import com.simplemobiletools.gallery.helpers.REQUEST_SET_AS
import com.simplemobiletools.gallery.models.Directory
import com.simplemobiletools.gallery.models.Medium
import com.simplemobiletools.gallery.views.MySquareImageView
+import pl.droidsonroids.gif.GifDrawable
import java.io.File
import java.util.*
-fun Activity.shareUri(medium: Medium, uri: Uri) {
- val shareTitle = resources.getString(R.string.share_via)
- Intent().apply {
- action = Intent.ACTION_SEND
- putExtra(Intent.EXTRA_STREAM, uri)
- type = medium.getMimeType()
- addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
- startActivity(Intent.createChooser(this, shareTitle))
- }
+fun Activity.shareUri(uri: Uri) {
+ shareUri(uri, BuildConfig.APPLICATION_ID)
+}
+
+fun Activity.shareUris(uris: ArrayList) {
+ shareUris(uris, BuildConfig.APPLICATION_ID)
}
fun Activity.shareMedium(medium: Medium) {
- val shareTitle = resources.getString(R.string.share_via)
val file = File(medium.path)
- val uri = Uri.fromFile(file)
-
- Intent().apply {
- action = Intent.ACTION_SEND
- putExtra(Intent.EXTRA_STREAM, uri)
- type = medium.getMimeType()
- addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
- startActivity(Intent.createChooser(this, shareTitle))
- }
+ shareUri(Uri.fromFile(file))
}
fun Activity.shareMedia(media: List) {
- val shareTitle = resources.getString(R.string.share_via)
- val uris = media.map { Uri.fromFile(File(it.path)) } as ArrayList
-
- Intent().apply {
- action = Intent.ACTION_SEND_MULTIPLE
- type = "image/* video/*"
- addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
- putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
- startActivity(Intent.createChooser(this, shareTitle))
- }
+ val uris = media.map { getFilePublicUri(File(it.path), BuildConfig.APPLICATION_ID) } as ArrayList
+ shareUris(uris)
}
-fun Activity.trySetAs(file: File) {
- try {
- var uri = Uri.fromFile(file)
- if (!setAs(uri, file)) {
- uri = getFileContentUri(file)
- setAs(uri, file, false)
- }
- } catch (e: Exception) {
- toast(R.string.unknown_error_occurred)
- }
+fun Activity.setAs(uri: Uri) {
+ setAs(uri, BuildConfig.APPLICATION_ID)
}
-fun Activity.setAs(uri: Uri, file: File, showToast: Boolean = true): Boolean {
- var success = false
- Intent().apply {
- action = Intent.ACTION_ATTACH_DATA
- setDataAndType(uri, file.getMimeType("image/*"))
- addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
- val chooser = Intent.createChooser(this, getString(R.string.set_as))
-
- success = if (resolveActivity(packageManager) != null) {
- startActivityForResult(chooser, REQUEST_SET_AS)
- true
- } else {
- if (showToast) {
- toast(R.string.no_capable_app_found)
- }
- false
- }
- }
-
- return success
+fun Activity.openFile(uri: Uri, forceChooser: Boolean) {
+ openFile(uri, forceChooser, BuildConfig.APPLICATION_ID)
}
-fun Activity.getFileContentUri(file: File): Uri? {
- val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
- val projection = arrayOf(MediaStore.Images.Media._ID)
- val selection = "${MediaStore.Images.Media.DATA} = ?"
- val selectionArgs = arrayOf(file.absolutePath)
-
- var cursor: Cursor? = null
- try {
- cursor = contentResolver.query(uri, projection, selection, selectionArgs, null)
- if (cursor?.moveToFirst() == true) {
- val id = cursor.getIntValue(MediaStore.Images.Media._ID)
- return Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "$id")
- }
- } finally {
- cursor?.close()
- }
- return null
-}
-
-fun Activity.openWith(file: File, forceChooser: Boolean = true) {
- val uri = Uri.fromFile(file)
- Intent().apply {
- action = Intent.ACTION_VIEW
- setDataAndType(uri, file.getMimeType())
- addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
- putExtra(IS_FROM_GALLERY, true)
-
- if (resolveActivity(packageManager) != null) {
- val chooser = Intent.createChooser(this, getString(R.string.open_with))
- startActivity(if (forceChooser) chooser else this)
- } else {
- toast(R.string.no_app_found)
- }
- }
-}
-
-fun Activity.openFileEditor(file: File) {
- openEditor(Uri.fromFile(file))
-}
-
-fun Activity.openEditor(uri: Uri, forceChooser: Boolean = false) {
- Intent().apply {
- action = Intent.ACTION_EDIT
- setDataAndType(uri, "image/*")
- addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
-
- if (resolveActivity(packageManager) != null) {
- val chooser = Intent.createChooser(this, getString(R.string.edit_image_with))
- startActivityForResult(if (forceChooser) chooser else this, REQUEST_EDIT_IMAGE)
- } else {
- toast(R.string.no_editor_found)
- }
- }
-}
-
-fun Activity.hasNavBar(): Boolean {
- return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- val display = windowManager.defaultDisplay
-
- val realDisplayMetrics = DisplayMetrics()
- display.getRealMetrics(realDisplayMetrics)
-
- val realHeight = realDisplayMetrics.heightPixels
- val realWidth = realDisplayMetrics.widthPixels
-
- val displayMetrics = DisplayMetrics()
- display.getMetrics(displayMetrics)
-
- val displayHeight = displayMetrics.heightPixels
- val displayWidth = displayMetrics.widthPixels
-
- realWidth - displayWidth > 0 || realHeight - displayHeight > 0
- } else {
- val hasMenuKey = ViewConfiguration.get(applicationContext).hasPermanentMenuKey()
- val hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK)
- !hasMenuKey && !hasBackKey
- }
+fun Activity.openEditor(uri: Uri) {
+ openEditor(uri, BuildConfig.APPLICATION_ID)
}
fun Activity.launchCamera() {
@@ -196,7 +68,7 @@ fun Activity.launchCamera() {
fun SimpleActivity.launchAbout() {
startAboutActivity(R.string.app_name, LICENSE_KOTLIN or LICENSE_GLIDE or LICENSE_CROPPER or LICENSE_MULTISELECT or LICENSE_RTL
- or LICENSE_PHOTOVIEW or LICENSE_SUBSAMPLING or LICENSE_PATTERN, BuildConfig.VERSION_NAME)
+ or LICENSE_SUBSAMPLING or LICENSE_PATTERN or LICENSE_REPRINT or LICENSE_GIF_DRAWABLE, BuildConfig.VERSION_NAME)
}
fun AppCompatActivity.showSystemUI() {
@@ -224,9 +96,10 @@ fun SimpleActivity.addNoMedia(path: String, callback: () -> Unit) {
if (needsStupidWritePermissions(path)) {
handleSAFDialog(file) {
- try {
- getFileDocument(path)?.createFile("", NOMEDIA)
- } catch (e: Exception) {
+ val fileDocument = getFileDocument(path)
+ if (fileDocument?.exists() == true && fileDocument.isDirectory) {
+ fileDocument.createFile("", NOMEDIA)
+ } else {
toast(R.string.unknown_error_occurred)
}
}
@@ -234,9 +107,10 @@ fun SimpleActivity.addNoMedia(path: String, callback: () -> Unit) {
try {
file.createNewFile()
} catch (e: Exception) {
- toast(R.string.unknown_error_occurred)
+ showErrorToast(e)
}
}
+
scanFile(file) {
callback()
}
@@ -259,29 +133,36 @@ fun SimpleActivity.toggleFileVisibility(oldFile: File, hide: Boolean, callback:
}
val newFile = File(path, filename)
renameFile(oldFile, newFile) {
- newFile.setLastModified(System.currentTimeMillis())
callback(newFile)
}
}
-fun Activity.loadImage(path: String, target: MySquareImageView, verticalScroll: Boolean) {
- target.isVerticalScrolling = verticalScroll
+fun Activity.loadImage(path: String, target: MySquareImageView, horizontalScroll: Boolean, animateGifs: Boolean, cropThumbnails: Boolean) {
+ target.isHorizontalScrolling = horizontalScroll
if (path.isImageFast() || path.isVideoFast()) {
if (path.isPng()) {
- loadPng(path, target)
+ loadPng(path, target, cropThumbnails)
} else {
- loadJpg(path, target)
+ loadJpg(path, target, cropThumbnails)
}
} else if (path.isGif()) {
- if (config.animateGifs) {
- loadAnimatedGif(path, target)
- } else {
- loadStaticGif(path, target)
+ try {
+ val gifDrawable = GifDrawable(path)
+ target.setImageDrawable(gifDrawable)
+ if (animateGifs) {
+ gifDrawable.start()
+ } else {
+ gifDrawable.stop()
+ }
+
+ target.scaleType = if (cropThumbnails) ImageView.ScaleType.CENTER_CROP else ImageView.ScaleType.FIT_CENTER
+ } catch (e: Exception) {
+ loadJpg(path, target, cropThumbnails)
}
}
}
-fun Activity.loadPng(path: String, target: MySquareImageView) {
+fun Activity.loadPng(path: String, target: MySquareImageView, cropThumbnails: Boolean) {
val options = RequestOptions()
.signature(path.getFileSignature())
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
@@ -291,11 +172,11 @@ fun Activity.loadPng(path: String, target: MySquareImageView) {
.asBitmap()
.load(path)
- if (config.cropThumbnails) options.centerCrop() else options.fitCenter()
+ if (cropThumbnails) options.centerCrop() else options.fitCenter()
builder.apply(options).into(target)
}
-fun Activity.loadJpg(path: String, target: MySquareImageView) {
+fun Activity.loadJpg(path: String, target: MySquareImageView, cropThumbnails: Boolean) {
val options = RequestOptions()
.signature(path.getFileSignature())
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
@@ -303,37 +184,16 @@ fun Activity.loadJpg(path: String, target: MySquareImageView) {
val builder = Glide.with(applicationContext)
.load(path)
- if (config.cropThumbnails) options.centerCrop() else options.fitCenter()
+ if (cropThumbnails) options.centerCrop() else options.fitCenter()
builder.apply(options).transition(DrawableTransitionOptions.withCrossFade()).into(target)
}
-fun Activity.loadAnimatedGif(path: String, target: MySquareImageView) {
- val options = RequestOptions()
- .signature(path.getFileSignature())
- .diskCacheStrategy(DiskCacheStrategy.NONE)
-
- val builder = Glide.with(applicationContext)
- .asGif()
- .load(path)
-
- if (config.cropThumbnails) options.centerCrop() else options.fitCenter()
- builder.apply(options).transition(DrawableTransitionOptions.withCrossFade()).into(target)
-}
-
-fun Activity.loadStaticGif(path: String, target: MySquareImageView) {
- val options = RequestOptions()
- .signature(path.getFileSignature())
- .diskCacheStrategy(DiskCacheStrategy.DATA)
-
- val builder = Glide.with(applicationContext)
- .asBitmap()
- .load(path)
-
- if (config.cropThumbnails) options.centerCrop() else options.fitCenter()
- builder.apply(options).into(target)
-}
-
fun Activity.getCachedDirectories(): ArrayList {
val token = object : TypeToken>() {}.type
return Gson().fromJson>(config.directories, token) ?: ArrayList(1)
}
+
+fun Activity.getCachedMedia(path: String): ArrayList {
+ val token = object : TypeToken>() {}.type
+ return Gson().fromJson>(config.loadFolderMedia(path), token) ?: ArrayList(1)
+}
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/context.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/context.kt
index f7cd61529..d91b80885 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/context.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/context.kt
@@ -3,12 +3,9 @@ package com.simplemobiletools.gallery.extensions
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
-import android.database.Cursor
import android.graphics.Point
import android.media.AudioManager
-import android.net.Uri
import android.os.Build
-import android.provider.MediaStore
import android.view.WindowManager
import com.simplemobiletools.commons.extensions.humanizePath
import com.simplemobiletools.gallery.activities.SettingsActivity
@@ -44,32 +41,16 @@ val Context.realScreenSize: Point
return size
}
-fun Context.getRealPathFromURI(uri: Uri): String? {
- var cursor: Cursor? = null
- try {
- val projection = arrayOf(MediaStore.Images.Media.DATA)
- cursor = contentResolver.query(uri, projection, null, null, null)
- if (cursor?.moveToFirst() == true) {
- val index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
- return cursor.getString(index)
- }
- } catch (e: Exception) {
- } finally {
- cursor?.close()
- }
- return null
-}
-
fun Context.getHumanizedFilename(path: String): String {
val humanized = humanizePath(path)
return humanized.substring(humanized.lastIndexOf("/") + 1)
}
fun Context.launchSettings() {
- startActivity(Intent(this, SettingsActivity::class.java))
+ startActivity(Intent(applicationContext, SettingsActivity::class.java))
}
-val Context.config: Config get() = Config.newInstance(this)
+val Context.config: Config get() = Config.newInstance(applicationContext)
fun Context.movePinnedDirectoriesToFront(dirs: ArrayList): ArrayList {
val foundFolders = ArrayList()
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 108cf9bc9..345ca57e4 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt
@@ -13,112 +13,129 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.bumptech.glide.Glide
-import com.bumptech.glide.Priority
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.engine.GlideException
-import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
-import com.simplemobiletools.commons.extensions.beGone
-import com.simplemobiletools.commons.extensions.beVisible
-import com.simplemobiletools.commons.extensions.toast
+import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.gallery.R
+import com.simplemobiletools.gallery.activities.PhotoActivity
import com.simplemobiletools.gallery.activities.ViewPagerActivity
-import com.simplemobiletools.gallery.extensions.config
-import com.simplemobiletools.gallery.extensions.getFileSignature
-import com.simplemobiletools.gallery.extensions.getRealPathFromURI
-import com.simplemobiletools.gallery.extensions.portrait
+import com.simplemobiletools.gallery.extensions.*
import com.simplemobiletools.gallery.helpers.GlideRotateTransformation
import com.simplemobiletools.gallery.helpers.MEDIUM
import com.simplemobiletools.gallery.models.Medium
import it.sephiroth.android.library.exif2.ExifInterface
import kotlinx.android.synthetic.main.pager_photo_item.view.*
+import pl.droidsonroids.gif.GifDrawable
import java.io.File
import java.io.FileOutputStream
-import java.io.IOException
class PhotoFragment : ViewPagerFragment() {
- lateinit var medium: Medium
- lateinit var view: ViewGroup
private var isFragmentVisible = false
private var wasInit = false
+ private var storedShowExtendedDetails = false
+ private var storedExtendedDetails = 0
+ private var gifDrawable: GifDrawable? = null
+
+ lateinit var view: ViewGroup
+ lateinit var medium: Medium
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
view = inflater.inflate(R.layout.pager_photo_item, container, false) as ViewGroup
- medium = arguments.getSerializable(MEDIUM) as Medium
+ if (!isFragmentVisible && activity is PhotoActivity) {
+ isFragmentVisible = true
+ }
+ medium = arguments!!.getSerializable(MEDIUM) as Medium
if (medium.path.startsWith("content://")) {
val originalPath = medium.path
- medium.path = context.getRealPathFromURI(Uri.parse(medium.path)) ?: ""
+ medium.path = context!!.getRealPathFromURI(Uri.parse(originalPath)) ?: medium.path
if (medium.path.isEmpty()) {
var out: FileOutputStream? = null
try {
- var inputStream = context.contentResolver.openInputStream(Uri.parse(originalPath))
+ var inputStream = context!!.contentResolver.openInputStream(Uri.parse(originalPath))
val exif = ExifInterface()
exif.readExif(inputStream, ExifInterface.Options.OPTION_ALL)
val tag = exif.getTag(ExifInterface.TAG_ORIENTATION)
val orientation = tag?.getValueAsInt(-1) ?: -1
-
- inputStream = context.contentResolver.openInputStream(Uri.parse(originalPath))
+ inputStream = context!!.contentResolver.openInputStream(Uri.parse(originalPath))
val original = BitmapFactory.decodeStream(inputStream)
val rotated = rotateViaMatrix(original, orientation)
exif.setTagValue(ExifInterface.TAG_ORIENTATION, 1)
exif.removeCompressedThumbnail()
- val file = File(context.externalCacheDir, Uri.parse(originalPath).lastPathSegment)
+ val file = File(context!!.externalCacheDir, Uri.parse(originalPath).lastPathSegment)
out = FileOutputStream(file)
rotated.compress(Bitmap.CompressFormat.JPEG, 100, out)
medium.path = file.absolutePath
} catch (e: Exception) {
- activity.toast(R.string.unknown_error_occurred)
+ activity!!.toast(R.string.unknown_error_occurred)
return view
} finally {
- try {
- out?.close()
- } catch (e: IOException) {
- }
+ out?.close()
}
}
}
- view.subsampling_view.setOnClickListener({ photoClicked() })
- view.photo_view.apply {
- maximumScale = 8f
- mediumScale = 3f
- setOnOutsidePhotoTapListener {
- photoClicked()
- }
-
- setOnPhotoTapListener { view, x, y ->
- photoClicked()
- }
- }
+ view.subsampling_view.setOnClickListener { photoClicked() }
+ view.gif_view.setOnClickListener { photoClicked() }
loadImage()
+ checkExtendedDetails()
wasInit = true
return view
}
+ override fun onPause() {
+ super.onPause()
+ storedShowExtendedDetails = context!!.config.showExtendedDetails
+ storedExtendedDetails = context!!.config.extendedDetails
+ }
+
+ override fun onResume() {
+ super.onResume()
+ if (wasInit && (context!!.config.showExtendedDetails != storedShowExtendedDetails || context!!.config.extendedDetails != storedExtendedDetails)) {
+ checkExtendedDetails()
+ }
+ }
+
override fun setMenuVisibility(menuVisible: Boolean) {
super.setMenuVisibility(menuVisible)
isFragmentVisible = menuVisible
if (wasInit) {
- if (menuVisible) {
- addZoomableView()
+ if (medium.isGif()) {
+ gifFragmentVisibilityChanged(menuVisible)
} else {
- view.subsampling_view.apply {
- recycle()
- beGone()
- background = ColorDrawable(Color.TRANSPARENT)
- }
+ photoFragmentVisibilityChanged(menuVisible)
+ }
+ }
+ }
+
+ private fun gifFragmentVisibilityChanged(isVisible: Boolean) {
+ if (isVisible) {
+ gifDrawable?.start()
+ } else {
+ gifDrawable?.stop()
+ }
+ }
+
+ private fun photoFragmentVisibilityChanged(isVisible: Boolean) {
+ if (isVisible) {
+ addZoomableView()
+ } else {
+ view.subsampling_view.apply {
+ recycle()
+ beGone()
+ background = ColorDrawable(Color.TRANSPARENT)
}
}
}
@@ -143,21 +160,31 @@ class PhotoFragment : ViewPagerFragment() {
private fun loadImage() {
if (medium.isGif()) {
- val options = RequestOptions()
- .priority(if (isFragmentVisible) Priority.IMMEDIATE else Priority.LOW)
- .diskCacheStrategy(DiskCacheStrategy.DATA)
-
- Glide.with(this)
- .asGif()
- .load(medium.path)
- .transition(DrawableTransitionOptions.withCrossFade())
- .apply(options)
- .into(view.photo_view)
+ loadGif()
} else {
loadBitmap()
}
}
+ private fun loadGif() {
+ try {
+ gifDrawable = if (medium.path.startsWith("content://") || medium.path.startsWith("file://")) {
+ GifDrawable(context!!.contentResolver, Uri.parse(medium.path))
+ } else {
+ GifDrawable(medium.path)
+ }
+
+ if (!isFragmentVisible) {
+ gifDrawable!!.stop()
+ }
+
+ view.gif_view.setImageDrawable(gifDrawable)
+ } catch (e: Exception) {
+ gifDrawable = null
+ loadBitmap()
+ }
+ }
+
private fun loadBitmap(degrees: Float = 0f) {
if (degrees == 0f) {
val targetWidth = if (ViewPagerActivity.screenWidth == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenWidth
@@ -181,25 +208,25 @@ class PhotoFragment : ViewPagerFragment() {
addZoomableView()
return false
}
- }).into(view.photo_view)
+ }).into(view.gif_view)
} else {
val options = RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.NONE)
- .transform(GlideRotateTransformation(context, degrees))
+ .transform(GlideRotateTransformation(context!!, degrees))
Glide.with(this)
.asBitmap()
.load(medium.path)
.thumbnail(0.2f)
.apply(options)
- .into(view.photo_view)
+ .into(view.gif_view)
}
}
private fun addZoomableView() {
if ((medium.isImage()) && isFragmentVisible && view.subsampling_view.visibility == View.GONE) {
view.subsampling_view.apply {
- //setBitmapDecoderClass(GlideDecoder::class.java) // causing random crashes on Android 7+
+ //setBitmapDecoderClass(GlideDecoder::class.java) // causing random crashes on Android 7+, at rotating
maxScale = 10f
beVisible()
setImage(ImageSource.uri(medium.path))
@@ -244,9 +271,9 @@ class PhotoFragment : ViewPagerFragment() {
if (context == null)
return 2f
- return if (context.portrait && bitmapAspectRatio <= 1f) {
+ return if (context!!.portrait && bitmapAspectRatio <= 1f) {
ViewPagerActivity.screenHeight / height.toFloat()
- } else if (!context.portrait && bitmapAspectRatio >= 1f) {
+ } else if (!context!!.portrait && bitmapAspectRatio >= 1f) {
ViewPagerActivity.screenWidth / width.toFloat()
} else {
2f
@@ -258,16 +285,35 @@ class PhotoFragment : ViewPagerFragment() {
loadBitmap(degrees)
}
+ private fun checkExtendedDetails() {
+ if (context!!.config.showExtendedDetails) {
+ view.photo_details.apply {
+ text = getMediumExtendedDetails(medium)
+ setTextColor(context.config.textColor)
+ beVisibleIf(text.isNotEmpty())
+ onGlobalLayout {
+ if (height != 0) {
+ val smallMargin = resources.getDimension(R.dimen.small_margin)
+ y = context.usableScreenSize.y - height - if (context.navigationBarHeight == 0) smallMargin else 0f
+ }
+ }
+ }
+ } else {
+ view.photo_details.beGone()
+ }
+ }
+
override fun onDestroyView() {
super.onDestroyView()
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && !activity.isDestroyed) {
- Glide.with(context).clear(view.photo_view)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && !activity!!.isDestroyed) {
+ Glide.with(context).clear(view.gif_view)
}
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
loadImage()
+ checkExtendedDetails()
}
private fun photoClicked() {
@@ -275,6 +321,13 @@ class PhotoFragment : ViewPagerFragment() {
}
override fun fullscreenToggled(isFullscreen: Boolean) {
-
+ view.photo_details.apply {
+ if (visibility == View.VISIBLE) {
+ val smallMargin = resources.getDimension(R.dimen.small_margin)
+ val fullscreenOffset = context.navigationBarHeight.toFloat() - smallMargin
+ val newY = context.usableScreenSize.y - height + if (isFullscreen) fullscreenOffset else -(if (context.navigationBarHeight == 0) smallMargin else 0f)
+ animate().y(newY)
+ }
+ }
}
}
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 1e945a15e..e6433e246 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt
@@ -9,16 +9,13 @@ import android.os.Bundle
import android.os.Handler
import android.provider.Settings
import android.util.DisplayMetrics
-import android.util.Log
import android.view.*
import android.view.animation.AnimationUtils
import android.widget.SeekBar
import android.widget.TextView
-import com.simplemobiletools.commons.extensions.beVisibleIf
-import com.simplemobiletools.commons.extensions.getFormattedDuration
-import com.simplemobiletools.commons.extensions.toast
-import com.simplemobiletools.commons.extensions.updateTextColors
+import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.gallery.R
+import com.simplemobiletools.gallery.activities.VideoActivity
import com.simplemobiletools.gallery.activities.ViewPagerActivity
import com.simplemobiletools.gallery.extensions.*
import com.simplemobiletools.gallery.helpers.MEDIUM
@@ -29,6 +26,7 @@ import java.io.IOException
class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSeekBarChangeListener {
private val CLICK_MAX_DURATION = 150
private val SLIDE_INFO_FADE_DELAY = 1000L
+ private val PROGRESS = "progress"
private var mMediaPlayer: MediaPlayer? = null
private var mSurfaceView: SurfaceView? = null
@@ -36,13 +34,16 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
private var mCurrTimeView: TextView? = null
private var mTimerHandler: Handler? = null
private var mSeekBar: SeekBar? = null
- private var mTimeHolder: View? = null
private var mIsPlaying = false
private var mIsDragged = false
private var mIsFullscreen = false
private var mIsFragmentVisible = false
private var mPlayOnPrepare = false
+ private var mStoredShowExtendedDetails = false
+ private var wasEncoded = false
+ private var wasInit = false
+ private var mStoredExtendedDetails = 0
private var mCurrTime = 0
private var mDuration = 0
@@ -59,32 +60,53 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
lateinit var mView: View
lateinit var medium: Medium
-
- companion object {
- private val TAG = VideoFragment::class.java.simpleName
- private val PROGRESS = "progress"
- }
+ lateinit var mTimeHolder: View
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
mView = inflater.inflate(R.layout.pager_video_item, container, false)
- setupPlayer()
+ mTimeHolder = mView.video_time_holder
+ medium = arguments!!.getSerializable(MEDIUM) as Medium
- medium = arguments.getSerializable(MEDIUM) as Medium
+ // setMenuVisibility is not called at VideoActivity (third party intent)
+ if (!mIsFragmentVisible && activity is VideoActivity) {
+ mIsFragmentVisible = true
+ }
+
+ setupPlayer()
if (savedInstanceState != null) {
mCurrTime = savedInstanceState.getInt(PROGRESS)
}
- mIsFullscreen = activity.window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == View.SYSTEM_UI_FLAG_FULLSCREEN
+ mIsFullscreen = activity!!.window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == View.SYSTEM_UI_FLAG_FULLSCREEN
checkFullscreen()
+ wasInit = true
return mView
}
override fun onResume() {
super.onResume()
- activity.updateTextColors(mView.video_holder)
- mView.video_volume_controller.beVisibleIf(context.config.allowVideoGestures)
- mView.video_brightness_controller.beVisibleIf(context.config.allowVideoGestures)
+ activity!!.updateTextColors(mView.video_holder)
+ mView.video_volume_controller.beVisibleIf(context!!.config.allowVideoGestures)
+ mView.video_brightness_controller.beVisibleIf(context!!.config.allowVideoGestures)
+
+ if (context!!.config.showExtendedDetails != mStoredShowExtendedDetails || context!!.config.extendedDetails != mStoredExtendedDetails) {
+ checkExtendedDetails()
+ }
+ }
+
+ override fun onPause() {
+ super.onPause()
+ pauseVideo()
+ mStoredShowExtendedDetails = context!!.config.showExtendedDetails
+ mStoredExtendedDetails = context!!.config.extendedDetails
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ if (activity?.isChangingConfigurations == false) {
+ cleanup()
+ }
}
private fun setupPlayer() {
@@ -109,21 +131,22 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
}
initTimeHolder()
+ checkExtendedDetails()
+ initMediaPlayer()
}
override fun setMenuVisibility(menuVisible: Boolean) {
super.setMenuVisibility(menuVisible)
+ if (mIsFragmentVisible && !menuVisible) {
+ pauseVideo()
+ releaseMediaPlayer()
+ }
mIsFragmentVisible = menuVisible
- if (menuVisible) {
- if (mSurfaceView != null && mSurfaceHolder!!.surface.isValid) {
- initMediaPlayer()
- }
-
+ if (menuVisible && wasInit) {
+ initMediaPlayer()
if (context?.config?.autoplayVideos == true) {
playVideo()
}
- } else if (mIsPlaying) {
- pauseVideo()
}
}
@@ -131,6 +154,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
super.onConfigurationChanged(newConfig)
setVideoSize()
initTimeHolder()
+ checkExtendedDetails()
}
private fun toggleFullscreen() {
@@ -214,17 +238,17 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
mView.video_holder
}
- private fun getCurrentVolume() = context.audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
+ private fun getCurrentVolume() = context!!.audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
- private fun getCurrentBrightness() = Settings.System.getInt(activity.contentResolver, Settings.System.SCREEN_BRIGHTNESS)
+ private fun getCurrentBrightness() = Settings.System.getInt(activity!!.contentResolver, Settings.System.SCREEN_BRIGHTNESS)
private fun volumePercentChanged(percent: Int) {
val stream = AudioManager.STREAM_MUSIC
- val maxVolume = context.audioManager.getStreamMaxVolume(stream)
+ val maxVolume = context!!.audioManager.getStreamMaxVolume(stream)
val percentPerPoint = 100 / maxVolume
val addPoints = percent / percentPerPoint
val newVolume = Math.min(maxVolume, Math.max(0, mTouchDownVolume + addPoints))
- context.audioManager.setStreamVolume(stream, newVolume, 0)
+ context!!.audioManager.setStreamVolume(stream, newVolume, 0)
val absolutePercent = ((newVolume / maxVolume.toFloat()) * 100).toInt()
mView.slide_info.apply {
@@ -250,9 +274,9 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
alpha = 1f
}
- val attributes = activity.window.attributes
+ val attributes = activity!!.window.attributes
attributes.screenBrightness = absolutePercent / 100f
- activity.window.attributes = attributes
+ activity!!.window.attributes = attributes
mSlideInfoFadeHandler.removeCallbacksAndMessages(null)
mSlideInfoFadeHandler.postDelayed({
@@ -261,22 +285,21 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
}
private fun initTimeHolder() {
- mTimeHolder = mView.video_time_holder
val res = resources
- val height = res.getNavBarHeight()
- val left = mTimeHolder!!.paddingLeft
- val top = mTimeHolder!!.paddingTop
+ val height = context!!.navigationBarHeight
+ val left = mTimeHolder.paddingLeft
+ val top = mTimeHolder.paddingTop
var right = res.getDimension(R.dimen.timer_padding).toInt()
var bottom = 0
- if (activity.hasNavBar()) {
+ if (hasNavBar()) {
if (res.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
bottom += height
} else {
right += height
- bottom += context.navigationBarHeight
+ bottom += context!!.navigationBarHeight
}
- mTimeHolder!!.setPadding(left, top, right, bottom)
+ mTimeHolder.setPadding(left, top, right, bottom)
}
mCurrTimeView = mView.video_curr_time
@@ -284,7 +307,31 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
mSeekBar!!.setOnSeekBarChangeListener(this)
if (mIsFullscreen)
- mTimeHolder!!.visibility = View.INVISIBLE
+ mTimeHolder.beInvisible()
+ }
+
+ private fun hasNavBar(): Boolean {
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ val display = context!!.windowManager.defaultDisplay
+
+ val realDisplayMetrics = DisplayMetrics()
+ display.getRealMetrics(realDisplayMetrics)
+
+ val realHeight = realDisplayMetrics.heightPixels
+ val realWidth = realDisplayMetrics.widthPixels
+
+ val displayMetrics = DisplayMetrics()
+ display.getMetrics(displayMetrics)
+
+ val displayHeight = displayMetrics.heightPixels
+ val displayWidth = displayMetrics.widthPixels
+
+ realWidth - displayWidth > 0 || realHeight - displayHeight > 0
+ } else {
+ val hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey()
+ val hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK)
+ !hasMenuKey && !hasBackKey
+ }
}
private fun setupTimeHolder() {
@@ -295,7 +342,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
}
private fun setupTimer() {
- activity.runOnUiThread(object : Runnable {
+ activity!!.runOnUiThread(object : Runnable {
override fun run() {
if (mMediaPlayer != null && !mIsDragged && mIsPlaying) {
mCurrTime = mMediaPlayer!!.currentPosition / 1000
@@ -328,7 +375,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
AnimationUtils.loadAnimation(activity, anim).apply {
duration = 150
fillAfter = true
- mTimeHolder!!.startAnimation(this)
+ mTimeHolder.startAnimation(this)
}
}
@@ -336,6 +383,8 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
if (activity == null || !isAdded)
return
+ initMediaPlayer()
+
mIsPlaying = !mIsPlaying
if (mIsPlaying) {
playVideo()
@@ -352,19 +401,20 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
mPlayOnPrepare = true
}
mView.video_play_outline.setImageDrawable(null)
- activity.window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+ activity!!.window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
private fun pauseVideo() {
mIsPlaying = false
mMediaPlayer?.pause()
mView.video_play_outline.setImageDrawable(resources.getDrawable(R.drawable.img_play_outline_big))
- activity.window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+ activity!!.window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
private fun initMediaPlayer() {
- if (mMediaPlayer != null)
+ if (mMediaPlayer != null || !mIsFragmentVisible) {
return
+ }
try {
mMediaPlayer = MediaPlayer().apply {
@@ -374,10 +424,18 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
setOnVideoSizeChangedListener({ mediaPlayer, width, height -> setVideoSize() })
setOnPreparedListener { videoPrepared(it) }
setAudioStreamType(AudioManager.STREAM_MUSIC)
- prepareAsync()
+ prepare()
}
} catch (e: IOException) {
- Log.e(TAG, "init media player failed $e")
+ medium.path = Uri.encode(medium.path)
+ if (wasEncoded) {
+ releaseMediaPlayer()
+ } else {
+ wasEncoded = true
+ mMediaPlayer = null
+ initMediaPlayer()
+ }
+ } catch (e: Exception) {
releaseMediaPlayer()
}
}
@@ -393,19 +451,6 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
mMediaPlayer!!.pause()
}
- override fun onPause() {
- super.onPause()
- pauseVideo()
- mIsFragmentVisible = false
- }
-
- override fun onDestroy() {
- super.onDestroy()
- if (activity?.isChangingConfigurations == false) {
- cleanup()
- }
- }
-
private fun cleanup() {
pauseVideo()
mCurrTimeView?.text = 0.getFormattedDuration()
@@ -425,12 +470,16 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
setupTimeHolder()
setProgress(mCurrTime)
- if (mIsFragmentVisible && (context.config.autoplayVideos || mPlayOnPrepare))
+ if (mIsFragmentVisible && (context!!.config.autoplayVideos || mPlayOnPrepare))
playVideo()
}
private fun videoCompleted() {
- if (listener?.videoEnded() == false && context.config.loopVideos) {
+ if (!isAdded) {
+ return
+ }
+
+ if (listener?.videoEnded() == false && context!!.config.loopVideos) {
playVideo()
} else {
mSeekBar!!.progress = mSeekBar!!.max
@@ -440,7 +489,9 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
}
override fun surfaceCreated(holder: SurfaceHolder) {
-
+ mSurfaceHolder = holder
+ if (mIsFragmentVisible)
+ initMediaPlayer()
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
@@ -461,12 +512,11 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
initMediaPlayer()
if (mMediaPlayer == null) {
- activity.toast(R.string.unknown_error_occurred)
return
}
val videoProportion = mMediaPlayer!!.videoWidth.toFloat() / mMediaPlayer!!.videoHeight.toFloat()
- val display = activity.windowManager.defaultDisplay
+ val display = activity!!.windowManager.defaultDisplay
val screenWidth: Int
val screenHeight: Int
@@ -494,6 +544,25 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
}
}
+ private fun checkExtendedDetails() {
+ if (context!!.config.showExtendedDetails) {
+ mView.video_details.apply {
+ text = getMediumExtendedDetails(medium)
+ setTextColor(context.config.textColor)
+ beVisibleIf(text.isNotEmpty())
+ onGlobalLayout {
+ if (height != 0) {
+ val smallMargin = resources.getDimension(R.dimen.small_margin)
+ val timeHolderHeight = mTimeHolder.height - context.navigationBarHeight
+ y = context.usableScreenSize.y - height - timeHolderHeight - if (context.navigationBarHeight == 0) smallMargin else 0f
+ }
+ }
+ }
+ } else {
+ mView.video_details.beGone()
+ }
+ }
+
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (mMediaPlayer != null && fromUser) {
setProgress(progress)
@@ -522,5 +591,14 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
override fun fullscreenToggled(isFullscreen: Boolean) {
mIsFullscreen = isFullscreen
checkFullscreen()
+ mView.video_details.apply {
+ if (visibility == View.VISIBLE) {
+ val smallMargin = resources.getDimension(R.dimen.small_margin)
+ val timeHolderHeight = mTimeHolder.height - context.navigationBarHeight.toFloat()
+ val fullscreenOffset = context.navigationBarHeight.toFloat() - smallMargin
+ val newY = context.usableScreenSize.y - height + if (mIsFullscreen) fullscreenOffset else -(timeHolderHeight + if (context.navigationBarHeight == 0) smallMargin else 0f)
+ animate().y(newY)
+ }
+ }
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/ViewPagerFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/ViewPagerFragment.kt
index 6121151ba..7ccb83d45 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/ViewPagerFragment.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/ViewPagerFragment.kt
@@ -1,6 +1,11 @@
package com.simplemobiletools.gallery.fragments
import android.support.v4.app.Fragment
+import com.simplemobiletools.commons.extensions.*
+import com.simplemobiletools.gallery.extensions.config
+import com.simplemobiletools.gallery.helpers.*
+import com.simplemobiletools.gallery.models.Medium
+import java.io.File
abstract class ViewPagerFragment : Fragment() {
var listener: FragmentListener? = null
@@ -12,4 +17,48 @@ abstract class ViewPagerFragment : Fragment() {
fun videoEnded(): Boolean
}
+
+ fun getMediumExtendedDetails(medium: Medium): String {
+ val file = File(medium.path)
+ if (!file.exists()) {
+ return ""
+ }
+
+ val path = "${file.parent.trimEnd('/')}/"
+ val exif = android.media.ExifInterface(medium.path)
+ val details = StringBuilder()
+ val detailsFlag = context!!.config.extendedDetails
+ if (detailsFlag and EXT_NAME != 0) {
+ medium.name.let { if (it.isNotEmpty()) details.appendln(it) }
+ }
+
+ if (detailsFlag and EXT_PATH != 0) {
+ path.let { if (it.isNotEmpty()) details.appendln(it) }
+ }
+
+ if (detailsFlag and EXT_SIZE != 0) {
+ file.length().formatSize().let { if (it.isNotEmpty()) details.appendln(it) }
+ }
+
+ if (detailsFlag and EXT_RESOLUTION != 0) {
+ file.getResolution().formatAsResolution().let { if (it.isNotEmpty()) details.appendln(it) }
+ }
+
+ if (detailsFlag and EXT_LAST_MODIFIED != 0) {
+ file.lastModified().formatLastModified().let { if (it.isNotEmpty()) details.appendln(it) }
+ }
+
+ if (detailsFlag and EXT_DATE_TAKEN != 0) {
+ path.getExifDateTaken(exif).let { if (it.isNotEmpty()) details.appendln(it) }
+ }
+
+ if (detailsFlag and EXT_CAMERA_MODEL != 0) {
+ path.getExifCameraModel(exif).let { if (it.isNotEmpty()) details.appendln(it) }
+ }
+
+ if (detailsFlag and EXT_EXIF_PROPERTIES != 0) {
+ path.getExifProperties(exif).let { if (it.isNotEmpty()) details.appendln(it) }
+ }
+ return details.toString().trim()
+ }
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Config.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Config.kt
index 26f679028..5df4ae0b5 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Config.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Config.kt
@@ -245,6 +245,10 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getBoolean(ALLOW_VIDEO_GESTURES, true)
set(allowVideoGestures) = prefs.edit().putBoolean(ALLOW_VIDEO_GESTURES, allowVideoGestures).apply()
+ var showMediaCount: Boolean
+ get() = prefs.getBoolean(SHOW_MEDIA_COUNT, true)
+ set(showMediaCount) = prefs.edit().putBoolean(SHOW_MEDIA_COUNT, showMediaCount).apply()
+
var slideshowInterval: Int
get() = prefs.getInt(SLIDESHOW_INTERVAL, SLIDESHOW_DEFAULT_INTERVAL)
set(slideshowInterval) = prefs.edit().putInt(SLIDESHOW_INTERVAL, slideshowInterval).apply()
@@ -288,4 +292,12 @@ class Config(context: Context) : BaseConfig(context) {
var viewTypeFiles: Int
get() = prefs.getInt(VIEW_TYPE_FILES, VIEW_TYPE_GRID)
set(viewTypeFiles) = prefs.edit().putInt(VIEW_TYPE_FILES, viewTypeFiles).apply()
+
+ var showExtendedDetails: Boolean
+ get() = prefs.getBoolean(SHOW_EXTENDED_DETAILS, false)
+ set(showExtendedDetails) = prefs.edit().putBoolean(SHOW_EXTENDED_DETAILS, showExtendedDetails).apply()
+
+ var extendedDetails: Int
+ get() = prefs.getInt(EXTENDED_DETAILS, EXT_RESOLUTION or EXT_LAST_MODIFIED or EXT_EXIF_PROPERTIES)
+ set(extendedDetails) = prefs.edit().putInt(EXTENDED_DETAILS, extendedDetails).apply()
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Constants.kt
index d875a0f18..b9ebd1071 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Constants.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Constants.kt
@@ -36,9 +36,12 @@ val HIDE_SYSTEM_UI = "hide_system_ui"
val REPLACE_SHARE_WITH_ROTATE = "replace_share_with_rotate"
val DELETE_EMPTY_FOLDERS = "delete_empty_folders"
val ALLOW_VIDEO_GESTURES = "allow_video_gestures"
+val SHOW_MEDIA_COUNT = "show_media_count"
val TEMP_FOLDER_PATH = "temp_folder_path"
val VIEW_TYPE_FOLDERS = "view_type_folders"
val VIEW_TYPE_FILES = "view_type_files"
+val SHOW_EXTENDED_DETAILS = "show_extended_details"
+val EXTENDED_DETAILS = "extended_details"
// slideshow
val SLIDESHOW_INTERVAL = "slideshow_interval"
@@ -53,21 +56,19 @@ val SLIDESHOW_DEFAULT_INTERVAL = 5
val SLIDESHOW_SCROLL_DURATION = 500L
val NOMEDIA = ".nomedia"
+val MAX_COLUMN_COUNT = 20
val DIRECTORY = "directory"
val MEDIUM = "medium"
+val PATH = "path"
val GET_IMAGE_INTENT = "get_image_intent"
val GET_VIDEO_INTENT = "get_video_intent"
val GET_ANY_INTENT = "get_any_intent"
val SET_WALLPAPER_INTENT = "set_wallpaper_intent"
val DIRECTORIES = "directories2"
val IS_VIEW_INTENT = "is_view_intent"
-val IS_FROM_GALLERY = "is_from_gallery"
val PICKED_PATHS = "picked_paths"
-val REQUEST_EDIT_IMAGE = 1
-val REQUEST_SET_AS = 2
-
// rotations
val ROTATE_BY_SYSTEM_SETTING = 0
val ROTATE_BY_DEVICE_ROTATION = 1
@@ -85,3 +86,16 @@ val GIFS = 4
// view types
val VIEW_TYPE_GRID = 1
val VIEW_TYPE_LIST = 2
+
+// extended details values
+val EXT_NAME = 1
+val EXT_PATH = 2
+val EXT_SIZE = 4
+val EXT_RESOLUTION = 8
+val EXT_LAST_MODIFIED = 16
+val EXT_DATE_TAKEN = 32
+val EXT_CAMERA_MODEL = 64
+val EXT_EXIF_PROPERTIES = 128
+val EXT_DURATION = 256
+val EXT_ARTIST = 512
+val EXT_ALBUM = 1024
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/GlideDecoder.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/GlideDecoder.kt
index fbddb788b..78ea3c9dc 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/GlideDecoder.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/GlideDecoder.kt
@@ -42,10 +42,8 @@ class GlideDecoder : ImageDecoder {
}
private fun drawableToBitmap(drawable: Drawable): Bitmap {
- if (drawable is BitmapDrawable) {
- if (drawable.bitmap != null) {
- return drawable.bitmap
- }
+ if (drawable is BitmapDrawable && drawable.bitmap != null) {
+ return drawable.bitmap
}
val bitmap = if (drawable.intrinsicWidth <= 0 || drawable.intrinsicHeight <= 0) {
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 ac3178dc7..c42db1b4e 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaFetcher.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaFetcher.kt
@@ -62,9 +62,12 @@ class MediaFetcher(val context: Context) {
}
}
- private fun getSelectionQuery(path: String): String {
+ private fun getSelectionQuery(path: String): String? {
val dataQuery = "${MediaStore.Images.Media.DATA} LIKE ?"
return if (path.isEmpty()) {
+ if (context.isAndroidFour())
+ return null
+
var query = "($dataQuery)"
if (context.hasExternalSDCard()) {
query += " OR ($dataQuery)"
@@ -75,9 +78,16 @@ class MediaFetcher(val context: Context) {
}
}
- private fun getSelectionArgsQuery(path: String): Array {
+ private fun getSelectionArgsQuery(path: String): Array? {
return if (path.isEmpty()) {
- if (context.hasExternalSDCard()) arrayOf("${context.internalStoragePath}/%", "${context.sdCardPath}/%") else arrayOf("${context.internalStoragePath}/%")
+ if (context.isAndroidFour())
+ return null
+
+ if (context.hasExternalSDCard()) {
+ arrayOf("${context.internalStoragePath}/%", "${context.sdCardPath}/%")
+ } else {
+ arrayOf("${context.internalStoragePath}/%")
+ }
} else {
arrayOf("$path/%", "$path/%/%")
}
@@ -100,8 +110,8 @@ class MediaFetcher(val context: Context) {
if (shouldStop)
break
- val path = cur.getStringValue(MediaStore.Images.Media.DATA)
- var filename = cur.getStringValue(MediaStore.Images.Media.DISPLAY_NAME) ?: ""
+ val path = cur.getStringValue(MediaStore.Images.Media.DATA).trim()
+ var filename = cur.getStringValue(MediaStore.Images.Media.DISPLAY_NAME)?.trim() ?: ""
if (filename.isEmpty())
filename = path.getFilenameFromPath()
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/models/Directory.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/models/Directory.kt
index 7271dc2e8..d03b4d1be 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/models/Directory.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/models/Directory.kt
@@ -4,20 +4,17 @@ import com.simplemobiletools.commons.helpers.*
import java.io.Serializable
data class Directory(val path: String, val tmb: String, val name: String, var mediaCnt: Int, val modified: Long, val taken: Long,
- var size: Long) : Serializable, Comparable {
+ val size: Long) : Serializable, Comparable {
companion object {
private val serialVersionUID = -6553345863555455L
var sorting: Int = 0
}
- fun addSize(bytes: Long) {
- size += bytes
- }
-
override fun compareTo(other: Directory): Int {
var result: Int
when {
sorting and SORT_BY_NAME != 0 -> result = AlphanumericComparator().compare(name.toLowerCase(), other.name.toLowerCase())
+ sorting and SORT_BY_PATH != 0 -> result = AlphanumericComparator().compare(path.toLowerCase(), other.path.toLowerCase())
sorting and SORT_BY_SIZE != 0 -> result = when {
size == other.size -> 0
size > other.size -> 1
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/models/Medium.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/models/Medium.kt
index fadf715ea..bf15cd20c 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/models/Medium.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/models/Medium.kt
@@ -1,10 +1,9 @@
package com.simplemobiletools.gallery.models
-import com.simplemobiletools.commons.extensions.getMimeType
+import com.simplemobiletools.commons.extensions.getMimeTypeFromPath
import com.simplemobiletools.commons.extensions.isGif
import com.simplemobiletools.commons.extensions.isPng
import com.simplemobiletools.commons.helpers.*
-import java.io.File
import java.io.Serializable
data class Medium(var name: String, var path: String, val video: Boolean, val modified: Long, val taken: Long, val size: Long) : Serializable, Comparable {
@@ -21,7 +20,7 @@ data class Medium(var name: String, var path: String, val video: Boolean, val mo
fun isImage() = !isGif() && !video
- fun getMimeType() = File(path).getMimeType()
+ fun getMimeType() = path.getMimeTypeFromPath()
override fun compareTo(other: Medium): Int {
var result: Int
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/views/MySquareImageView.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/views/MySquareImageView.kt
index f254d4183..39a2f74be 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/views/MySquareImageView.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/views/MySquareImageView.kt
@@ -5,7 +5,7 @@ import android.util.AttributeSet
import android.widget.ImageView
class MySquareImageView : ImageView {
- var isVerticalScrolling = true
+ var isHorizontalScrolling = false
constructor(context: Context) : super(context)
@@ -14,7 +14,7 @@ class MySquareImageView : ImageView {
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
- val spec = if (isVerticalScrolling) widthMeasureSpec else heightMeasureSpec
+ val spec = if (isHorizontalScrolling) heightMeasureSpec else widthMeasureSpec
super.onMeasure(spec, spec)
}
}
diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml
index ab5bd8f0e..509679282 100644
--- a/app/src/main/res/layout/activity_settings.xml
+++ b/app/src/main/res/layout/activity_settings.xml
@@ -68,6 +68,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/dialog_manage_extended_details.xml b/app/src/main/res/layout/dialog_manage_extended_details.xml
new file mode 100644
index 000000000..a31a684a6
--- /dev/null
+++ b/app/src/main/res/layout/dialog_manage_extended_details.xml
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/dialog_medium_picker.xml b/app/src/main/res/layout/dialog_medium_picker.xml
index 60207b4c9..f3c41d8f0 100644
--- a/app/src/main/res/layout/dialog_medium_picker.xml
+++ b/app/src/main/res/layout/dialog_medium_picker.xml
@@ -1,10 +1,54 @@
-
-
+ android:paddingTop="@dimen/activity_margin">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/pager_photo_item.xml b/app/src/main/res/layout/pager_photo_item.xml
index 1c4d2d76a..6e2f333c8 100644
--- a/app/src/main/res/layout/pager_photo_item.xml
+++ b/app/src/main/res/layout/pager_photo_item.xml
@@ -1,14 +1,16 @@
-
+ android:layout_height="match_parent"
+ android:scaleType="fitCenter"/>
+
+
diff --git a/app/src/main/res/layout/pager_video_item.xml b/app/src/main/res/layout/pager_video_item.xml
index 3d88f52f7..d0be9b3d2 100644
--- a/app/src/main/res/layout/pager_video_item.xml
+++ b/app/src/main/res/layout/pager_video_item.xml
@@ -1,6 +1,7 @@
@@ -50,6 +51,19 @@
android:textColor="@android:color/white"
android:textSize="@dimen/extra_big_text_size"/>
+
+
+
+
+ app:showAsAction="ifRoom">
+
+
+
diff --git a/app/src/main/res/menu/photo_video_menu.xml b/app/src/main/res/menu/photo_video_menu.xml
index 5911eebf5..584e40c29 100644
--- a/app/src/main/res/menu/photo_video_menu.xml
+++ b/app/src/main/res/menu/photo_video_menu.xml
@@ -6,6 +6,11 @@
android:icon="@drawable/ic_share"
android:title="@string/share"
app:showAsAction="ifRoom"/>
+
-
+
+
+
+
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 000000000..f4091292b
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-nodpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-nodpi/ic_launcher_foreground.png
new file mode 100644
index 000000000..24b7f2986
Binary files /dev/null and b/app/src/main/res/mipmap-nodpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml
index ddc156702..e15f4800d 100644
--- a/app/src/main/res/values-ca/strings.xml
+++ b/app/src/main/res/values-ca/strings.xml
@@ -4,8 +4,6 @@
Gallery
Edit
Open camera
- Open with
- No valid app found
(hidden)
Pin folder
Unpin folder
@@ -22,9 +20,11 @@
Change cover image
Select photo
Use default
- Set as
Volume
Brightness
+ Do not ask again in this session
+ Lock orientation
+ Unlock orientation
Filter media
@@ -49,7 +49,7 @@
Included folders
Manage included folders
Add folder
- If you have some folders which contain media, but were not recognized by the app, you can add them manually here.
+ If you have some folders which contain media, but were not recognized by the app, you can add them manually here.\n\nAdding some items here will not exclude any other folder.
Resize
@@ -124,7 +124,10 @@
Automatically hide system UI at fullscreen media
Delete empty folders after deleting their content
Allow controlling video volume and brightness with vertical gestures
+ Show folder media count on the main view
Replace Share with Rotate at fullscreen menu
+ Show extended details over fullscreen media
+ Manage extended details
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index af7703ab4..4252e7953 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -4,8 +4,6 @@
Galerie
Upravit
Spustit fotoaparát
- Otevřít pomocí
- Nebyla nalezena žádná vhodná aplikace
(skryté)
Připnout složku
Odepnout složku
@@ -22,9 +20,11 @@
Change cover image
Select photo
Use default
- Nastavit jako
Volume
Brightness
+ Do not ask again in this session
+ Lock orientation
+ Unlock orientation
Filter media
@@ -124,7 +124,10 @@
Automatically hide system UI at fullscreen media
Delete empty folders after deleting their content
Allow controlling video volume and brightness with vertical gestures
+ Show folder media count on the main view
Replace Share with Rotate at fullscreen menu
+ Show extended details over fullscreen media
+ Manage extended details
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 96580f927..0a90b0dcd 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -4,8 +4,6 @@
Galerie
Bearbeiten
Kamera öffnen
- Öffnen mit
- Keine passende App gefunden
(versteckt)
Ordner anheften
Ordner loslösen
@@ -14,7 +12,7 @@
Ansicht: Als Ordner
Ordner wählen
Auf Karte zeigen
- Unbekannter Ort
+ Unbekannter Pfad
Keine Karten-App gefunden
Keine Kamera-App gefunden
Kacheln verkleinern
@@ -22,12 +20,14 @@
Coverbild ändern
Auswählen
Standard
- Festlegen als
Lautstärke
Helligkeit
+ Nicht erneut fragen (in dieser Sitzung)
+ Lock orientation
+ Unlock orientation
- Medienfilter
+ Filter
Bilder
Videos
GIFs
@@ -35,11 +35,11 @@
Filter ändern
- Diese Funktion versteckt ausgewählte Ordner (auch für andere Apps), indem dort im Dateisystem eine \'.nomedia\'-Datei abgelegt wird. Dadurch werden auch deren Unterordner versteckt. Solche Ordner werden nur gezeigt, wenn die Einstellung \'Versteckte Ordner zeigen\' aktiv ist (auch andere Apps bieten üblicherweise eine solche Option). Fortfahren?
+ Diese Funktion versteckt die ausgewählten Ordner (auch für andere Apps), indem dort im Dateisystem eine \'.nomedia\'-Datei abgelegt wird. Dadurch werden auch deren Unterordner versteckt. Solche Ordner werden nur gezeigt, wenn die Einstellung \'Versteckte Ordner zeigen\' aktiv ist (auch andere Apps bieten üblicherweise eine solche Option). Fortfahren?
Ordner ausblenden
Ausgeblendete Ordner
Ausgeblendete Ordner verwalten
- Diese Funktion blendet ausgewählte Ordner und deren Unterordner aus (nur in dieser App). Ausgeblendete Ordner können in den Einstellungen verwaltet werden.
+ Diese Funktion blendet die ausgewählten Ordner und deren Unterordner aus (nur in dieser App). Ausgeblendete Ordner können in den Einstellungen verwaltet werden.
Möchten Sie stattdessen einen höherliegenden Ordner ausblenden?
\'Ordner ausblenden\' wird ausgewählte Ordner und deren Unterordner nur in dieser App ausblenden. Andere Apps werden solche Ordner weiterhin anzeigen.\\n\\nWenn Sie Ordner auch für andere Apps verstecken wollen, verwenden Sie dafür die Funktion \'Ordner verstecken\'.
Alle entfernen
@@ -68,7 +68,7 @@
Bildbearbeitung fehlgeschlagen
Bild bearbeiten mit
Keine Bildeditor-App gefunden
- Unbekannter Dateiort
+ Unbekannter Dateipfad
Konnte Quelldatei nicht überschreiben
Nach links drehen
Nach rechts drehen
@@ -103,9 +103,9 @@
Keine Medien für Diashow gefunden
- Change view type
- Grid
- List
+ Darstellung ändern
+ Gitter
+ Liste
Versteckte Ordner zeigen
@@ -124,17 +124,20 @@
Systemleisten ausblenden im Vollbild
Nach Löschen leere Ordner löschen
Gesten für Videolautstärke/Helligkeit
+ Medienanzahl bei Ordnern anzeigen
Teilen/Drehen im Vollbild-Menü vertauschen
+ Eigenschaften anzeigen im Vollbild
+ Eigenschaften auswählen
Eine schlichte Galerie zum Betrachten von Bildern und Videos ohne Werbung.
- Ein schlichtes Tool zum Betrachten von Bildern und Videos. Die Medien können nach Datum, Größe, Name sowie auf- oder absteigend sortiert angezeigt werden, in Bilder kann hineingezoomt werden. Die Vorschau-Kacheln werden in mehreren Spalten abhängig von der Displaygröße angezeigt, die Spaltenanzahl ist mit Zweifingergesten änderbar. Die Medien können umbenannt, geteilt, gelöscht, kopiert, verschoben werden. Bilder können zugeschnitten, gedreht oder als Hintergrund festgelegt werden, direkt aus der App heraus.
+ Eine schlichte App zum Betrachten von Bildern und Videos. Die Medien können nach Datum, Größe, Name sowie auf- oder absteigend sortiert werden, in Bilder kann auch hineingezoomt werden. Die Vorschau-Kacheln werden in mehreren Spalten abhängig von der Displaygröße angezeigt, die Spaltenanzahl ist mit Zweifingergesten änderbar. Die Medien können umbenannt, geteilt, gelöscht, kopiert und verschoben werden. Bilder können direkt aus der App heraus zugeschnitten, gedreht oder als Hintergrund festgelegt werden.
- Die Galerie bietet auch für Drittparteien einige Funktionen an: zum Vorschauen von Bildern / Videos, zum Hinzufügen von Anhängen bei eMail-Clients, etc. Sie ist perfekt für den täglichen Gebrauch.
+ Diese Galerie bietet auch für Drittanbieter einige Funktionen an: zum Vorschauen von Bildern / Videos, zum Hinzufügen von Anhängen bei Email-Apps, etc. Sie ist perfekt für den täglichen Gebrauch.
- Beinhaltet keine Werbung oder unnötige Berechtigungen. Sie ist komplett Open Source, verwendete Farben sind anpassbar.
+ Beinhaltet keine Werbung oder unnötigen Berechtigungen. Sie ist komplett Open Source, verwendete Farben sind anpassbar.
Diese App ist nur eine aus einer größeren Serie von schlichten Apps. Der Rest davon findet sich auf http://www.simplemobiletools.com
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 5b5350d6c..5cb108458 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -4,8 +4,6 @@
Galería
Editar
Abrir cámara
- Abrir con…
- No se encontró una aplicación válida
(oculto)
Fijar carpeta
No fijar carpeta
@@ -22,9 +20,11 @@
Cambiar imagen de portada
Seleccionar imagen
Uso por defecto
- Establecer como
Volume
Brightness
+ Do not ask again in this session
+ Lock orientation
+ Unlock orientation
Filter media
@@ -124,7 +124,10 @@
Ocultar automáticamente la interfaz de usuario del sistema en medios de pantalla completa
Delete empty folders after deleting their content
Allow controlling video volume and brightness with vertical gestures
+ Show folder media count on the main view
Reemplazar Compartir con Girar en el menú de pantalla completa
+ Show extended details over fullscreen media
+ Manage extended details
diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml
new file mode 100644
index 000000000..39a1625af
--- /dev/null
+++ b/app/src/main/res/values-fi/strings.xml
@@ -0,0 +1,149 @@
+
+
+ Simple Gallery
+ Galleria
+ Muokkaa
+ Avaa kamera
+ (piilotettu)
+ Kiinnitä kansio
+ Poista kiinnitys
+ Näytä kaikkien kansioiden sisältö
+ Kaikki kansiot
+ Vaihda kansionäkymään
+ Muu kansio
+ Näytä kartalla
+ Tuntematon sijainti
+ Karttasovellusta ei löytynyt
+ Kamerasovellusta ei löytynyt
+ Increase column count
+ Reduce column count
+ Vaihda kansikuva
+ Valitse kuva
+ Käytä oletuksia
+ Äänenvoimakkuus
+ Kirkkaus
+ Do not ask again in this session
+ Lock orientation
+ Unlock orientation
+
+
+ Suodata media
+ Kuvat
+ Videot
+ GIFit
+ Mediaa ei löytynyt valituilla suotimilla.
+ Muuta suotimia
+
+
+ Tämä piilottaa kansion ja alikansiot lisäämällä \'.nomedia\' tiedoston kansioon. Näet ne valitsemalla \'Näytä piilotetut kansiot\' asetuksissa. Continue?
+ Poissulje
+ Poissuljetut kansiot
+ Hallitse poissuljettuja kansioita
+ Tämä poissulkee valitun ja alikansiot vain Simple Gallerysta. Voit hallinnoida poissuljettuja kansioita asetuksista.
+ Poissulje yläkansio tämän sijaan?
+ Kansion poissulkeminen piilottaa kansion alikansioineen vain Simple Galleryssa, ne jäävät näkyviin muihin sovelluksiin.\n\nJos haluat piilottaa kansion myös muissa sovelluksissa, käytä piilota-funktiota.
+ Poista kaikki
+ Poista kaikki kansiot poissuljettujen listasta? Tämä ei poista kansioita.
+
+
+ Sisällytä kansiot
+ Hallitse sisällettyjä kansioita
+ Lisää kansio
+ Jos sinulla on kansioita, jotka sisältää mediaa, mutta sovellus ei tunnistanut, voit lisätä ne manuaalisesti tähän.\n\Lisääminen ei poissulje muita kansioita.
+
+
+ Rajaa
+ Rajaa valinta ja tallenna
+ Leveys
+ Korkeus
+ Säilytä kuvasuhde
+ Aseta oikea resoluutio.
+
+
+ Editori
+ Tallenna
+ Käännä
+ Polku
+ Kuvan polkua ei ole
+ Kuvan muokkaus epäonnistui
+ Muokkaa kuvaa:
+ Kuvamuokkainta ei löytynyt
+ Tuntematon tiedostosijainti
+ Lähdetiedoston ylikirjoitus epäonnistui
+ Käännä vasemmalle
+ Käännä oikealle
+ Käännä 180º
+ Pyöräytä
+ Pyöräytä vaakasuoraan
+ Pyöräytä pystysuoraan
+ Muokkaa sovelluksella
+
+
+ Simple Wallpaper
+ Aseta taustakuvaksi
+ Taustakuvan asetus epäonnistui
+ Aseta taustakuvaksi sovelluksella:
+ Toimivaa sovellusta ei löydetty
+ Asetetaan taustakuvaa…
+ Taustakuva asetettu onnistuneesti
+ Kuvasuhde pystyssä
+ Kuvasuhde vaakatasossa
+
+
+ Diaesitys
+ Aikaväli (sekunteja):
+ Sisällytä Kuvat
+ Sisällytä Videot
+ Sisällytä GIFit
+ Satunnainen järjestys
+ Käytä häivitys-animaatiota
+ Liiku takaisinpäin
+ Jatkuva diaesitys
+ Diaesitys päättyi
+ Mediaa diaesitykseen ei löytynyt
+
+
+ Vaihda näkymää
+ Ruudukko
+ Lista
+
+
+ Näytä piilotettu media
+ Toista videot automaattisesti
+ Tiedostonimien näkyvyys
+ Jatkuvat videot
+ Animoi GIFit pienoiskuvissa
+ Täysi kirkkaus mediaa katsoessa
+ Leikkaa pienoiskuvat neliöiksi
+ Käännä koko ruudun mediaa
+ Järjestelmän asetukset
+ Laitteen kierto
+ Kuvasuhde
+ Tumma tausta koko ruudun medioissa
+ Vieritä pienoiskuvia vaakasuorassa
+ Piilota järjestelmän UI automaattisesti koko näytön mediassa
+ Poista tyhjät kansiot kansion tyhjennyksen jälkeen
+ Salli videon äänenvoimakkuuden ja kirkkauden säätö pystysuorilla eleillä
+ Show folder media count on the main view
+ Korvaa jakaminen kääntämisellä koko näytön tilassa
+ Show extended details over fullscreen media
+ Manage extended details
+
+
+
+ Galleria kuvien ja videoiden katsomiseen ilman mainoksia.
+
+ Yksinkertainen työkalu kuvien ja videoiden katsomiseen. Kohteita voidaan lajitella päivän, koon, nimen mukaan, nousevassa ja laskevassa järjestyksessä. Kuvia voidaan zoomata. Mediatiedostot näkyvät useissa sarakkeissa joiden määrää muutetaan nipistys-eleellä. Tiedostoja voidaan uudelleennimetä, jakaa, poistaa, kopioida. Kuvia voi rajata, pyörittää tai asettaa taustakuvaksi suoraan sovelluksesta.
+
+ Galleriaa tarjotaan myös kolmansille osapuolille kuvien / videoiden tarkasteluun, liitteiden lisäämiseksi sähköpostiin yms. Täydellinen jokapäiväiseen käyttöön.
+
+ Ei sisällä mainoksia tai turhia käyttöoikeuksia. Täysin avointa lähdekoodia, tarjoaa muokattavat värit.
+
+ Tämä sovellus on vain yksi osa suurempaa kokoelmaa. Löydät loput osoitteesta http://www.simplemobiletools.com
+
+
+
+
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index ca60589f2..4029cf872 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -4,10 +4,8 @@
Galerie
Édition
Ouvrir appareil photo
- Ouvrir avec
- Aucune application valide trouvée
(caché)
- Épingler les dossiers
+ Épingler le dossier
Désépingler le dossier
Afficher le contenu de tous les dossiers
Tous les dossiers
@@ -15,22 +13,24 @@
Autre dossier
Afficher sur la carte
Position inconnue
- Aucune application de cartes n\'a été trouvée
- Aucune application d\\appareil photo n\'a été trouvée
+ Aucune application de carte n\'a été trouvée
+ Aucune application d\'appareil photo n\'a été trouvée
Augmenter le nombre de colonnes
Réduire le nombre de colonnes
- Change cover image
+ Changer l\'image de couverture
Sélectionner une photo
- Use default
- Set as
+ Utiliser par défaut
Volume
Luminosité
+ Ne pas redemander pour cette session
+ Lock orientation
+ Unlock orientation
- Filtrer medias
+ Filtrer les médias
Images
Vidéos
- GIFs
+ GIF
Aucun fichier média trouvé avec les filtres sélectionnés.
Changer les filtres
@@ -49,7 +49,7 @@
Dossiers inclus
Gérer les dossiers inclus
Ajouter un dossier
- Si vous avez des dossiers contenant du media et qui ne sont pas reconnus par l\'application alors, vous pouvez les ajouter manuellement ici.
+ Si vous avez des dossiers contenant des médias et qui ne sont pas reconnus par l\'application alors, vous pouvez les ajouter manuellement ici.
Redimensionner
@@ -57,7 +57,7 @@
Largeur
Hauteur
Garder le ratio
- Veuillez entrez une résolution valide
+ Veuillez entrer une résolution valide
Éditeur
@@ -86,33 +86,33 @@
Aucune application trouvée pour continuer cette action
Paramètres de fond d\'écran…
Fond d\'écran défini avec succès
- Ratio aspect Portrait
- Ratio aspect Paysage
+ Ratio d\'aspect portrait
+ Ratio d\'aspect paysage
Diaporama
- Intervalle (secondes):
+ Intervalle (secondes) :
Inclure photos
Inclure vidéos
- Inclure GIFs
+ Inclure GIF
Ordre aléatoire
Utiliser un fondu
Revenir en arrière
- Loop slideshow
+ Diaporama en boucle
Diaporama terminé
Aucun média trouvé pour le diaporama
- Change view type
- Grid
- List
+ Changer le type de vue
+ Grille
+ Liste
Afficher les dossiers cachés
Lecture automatique des vidéos
Permuter la visibilité des noms de fichier
- Tourner en boucle les vidéos
- GIFs animés sur les miniatures
+ Lire en boucle les vidéos
+ GIF animés sur les miniatures
Luminosité maximale lors de l\'affichage de media
Rogner les miniatures en carrés
Pivoter les medias plein écran selon
@@ -120,11 +120,14 @@
Rotation de l\'appareil
Ratio d\'aspect
Arrière-plan sombre pour média plein écran
- Défilement des mignatures horizontalement
+ Défilement des miniatures horizontalement
Masquer automatiquement l\'interface utilisateur si média plein écran
Supprimer les dossiers vides après avoir supprimé leur contenu
Permettre le contrôle du volume vidéo et de la luminosité avec des gestes verticaux
+ Afficher le nombre de fichiers dans les dossiers sur l\'écran principal
Remplacer Partager par Pivoter si menu en plein écran
+ Afficher les détails supplémentaires par dessus le média en plein écran
+ Gérer les détails supplémentaires
@@ -132,9 +135,9 @@
Un simple outil pour visionner les photos et les vidéos. Elles peuvent être triées par dates, tailles, noms dans les deux sens (alphabétique comme désalphabétique), il est possible de zoomer sur les photos. Les fichiers sont affichés sur de multiple colonnes en fonction de la taille de l\'écran, vous pouvez changer le nombre de colonnes par pincement. Elles peuvent être renommées, partagées, supprimées, copiées et déplacées. Les images peuvent en plus être tournées, rognées ou être définies comme fond d\'écran directement depuis l\'application.
- La galerie est aussi offerte pour l\'utiliser comme une tierce partie pour de la prévisualisation des images/vidéos, joindre aux clients mail etc. C\'est parfait pour un usage au quotidien.
+ La galerie est également proposée pour une utilisation comme tierce partie pour la prévisualisation des images/vidéos, ajouter des pièces jointes aux clients email etc. C\'est parfait pour un usage au quotidien.
- L\'application ne contient ni de publicité ni d\'autorisation inutile. Elle est totalement OpenSource et est aussi fournie avec un thème sombre.
+ L\'application ne contient ni publicité ni autorisation inutile. Elle est totalement opensource et est aussi fournie avec des couleurs personnalisables.
Cette application est juste l\'une des applications d\'une plus grande suite. Vous pouvez trouver les autres sur http://www.simplemobiletools.com
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index c42d41e12..8b1a9efc7 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -4,8 +4,6 @@
Gallery
Edit
Open camera
- Open with
- No valid app found
(hidden)
Pin folder
Unpin folder
@@ -22,9 +20,11 @@
Change cover image
Select photo
Use default
- Set as
Volume
Brightness
+ Do not ask again in this session
+ Lock orientation
+ Unlock orientation
Filter media
@@ -49,7 +49,7 @@
Included folders
Manage included folders
Add folder
- If you have some folders which contain media, but were not recognized by the app, you can add them manually here.
+ If you have some folders which contain media, but were not recognized by the app, you can add them manually here.\n\nAdding some items here will not exclude any other folder.
Resize
@@ -124,7 +124,10 @@
Automatically hide system UI at fullscreen media
Delete empty folders after deleting their content
Allow controlling video volume and brightness with vertical gestures
+ Show folder media count on the main view
Replace Share with Rotate at fullscreen menu
+ Show extended details over fullscreen media
+ Manage extended details
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index e77d073ef..7f9f0e294 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -4,8 +4,6 @@
Galleria
Modifica
Apri fotocamera
- Apri con
- Nessun app valida trovata
(nascosta)
Blocca cartella
Sblocca cartella
@@ -22,9 +20,11 @@
Cambia immagine copertina
Seleziona foto
Usa predefinita
- Imposta come
Volume
Luminosità
+ Non chiedere nuovamente in questa sessione
+ Lock orientation
+ Unlock orientation
Filtra i media
@@ -103,9 +103,9 @@
Nessun media trovato per la presentazione
- Change view type
- Grid
- List
+ Cambia modalità visualizzazione
+ Griglia
+ Elenco
Mostra cartelle nascoste
@@ -124,7 +124,10 @@
Nascondi UI di sistema con media a schermo intero
Elimina cartelle vuote dopo averne eliminato il contenuto
Gestisci il volume e la luminosità dei video con gesti verticali
+ Mostra numero elementi nella cartella
Sostituisci Condividi con Ruota a schermo intero
+ Mostra informazioni estese su media a schermo intero
+ Gestisci le informazioni estese
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index ef90a0d11..8ab7eebc6 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -4,8 +4,6 @@
ギャラリー
編集
カメラを開く
- 別のアプリで開く
- 有効なアプリが見つかりません
(非表示)
フォルダーをピン留めする
フォルダーのピン留めを外す
@@ -22,9 +20,11 @@
カバー画像を変更
写真を選択
デフォルトに戻す
- 他で使う
音量
明るさ
+ Do not ask again in this session
+ Lock orientation
+ Unlock orientation
表示メディア種
@@ -124,7 +124,10 @@
フルスクリーン時にシステムUIを非表示にする
メディアの削除後にフォルダーが空になった場合、そのフォルダーを削除する
ビデオ再生中に、音量と明るさを縦方向のジェスチャーで変更する
+ Show folder media count on the main view
フルスクリーンメニューの「共有」を「回転」に置き換える
+ Show extended details over fullscreen media
+ Manage extended details
diff --git a/app/src/main/res/values-ms/strings.xml b/app/src/main/res/values-ms/strings.xml
new file mode 100644
index 000000000..e15f4800d
--- /dev/null
+++ b/app/src/main/res/values-ms/strings.xml
@@ -0,0 +1,149 @@
+
+
+ Simple Gallery
+ Gallery
+ Edit
+ Open camera
+ (hidden)
+ Pin folder
+ Unpin folder
+ Show all folders content
+ All folders
+ Switch to folder view
+ Other folder
+ Show on map
+ Unknown location
+ No application with maps has been found
+ No Camera app has been found
+ Increase column count
+ Reduce column count
+ Change cover image
+ Select photo
+ Use default
+ Volume
+ Brightness
+ Do not ask again in this session
+ Lock orientation
+ Unlock orientation
+
+
+ Filter media
+ Images
+ Videos
+ GIFs
+ No media files have been found with the selected filters.
+ Change filters
+
+
+ This function hides the folder by adding a \'.nomedia\' file into it, it will hide all subfolders too. You can see them by toggling the \'Show hidden folders\' option in Settings. Continue?
+ Exclude
+ Excluded folders
+ Manage excluded folders
+ This will exclude the selection together with its subfolders from Simple Gallery only. You can manage excluded folders in Settings.
+ Exclude a parent instead?
+ Excluding folders will make them together with their subfolders hidden just in Simple Gallery, they will still be visible in other applications.\n\nIf you want to hide them from other apps too, use the Hide function.
+ Remove all
+ Remove all folders from the list of excluded? This will not delete the folders.
+
+
+ Included folders
+ Manage included folders
+ Add folder
+ If you have some folders which contain media, but were not recognized by the app, you can add them manually here.\n\nAdding some items here will not exclude any other folder.
+
+
+ Resize
+ Resize selection and save
+ Width
+ Height
+ Keep aspect ratio
+ Please enter a valid resolution
+
+
+ Editor
+ Save
+ Rotate
+ Path
+ Invalid image path
+ Image editing failed
+ Edit image with:
+ No image editor found
+ Unknown file location
+ Could not overwrite the source file
+ Rotate left
+ Rotate right
+ Rotate by 180º
+ Flip
+ Flip horizontally
+ Flip vertically
+ Edit with
+
+
+ Simple Wallpaper
+ Set as Wallpaper
+ Setting as Wallpaper failed
+ Set as wallpaper with:
+ No app capable of it has been found
+ Setting wallpaper…
+ Wallpaper set successfully
+ Portrait aspect ratio
+ Landscape aspect ratio
+
+
+ Slideshow
+ Interval (seconds):
+ Include photos
+ Include videos
+ Include GIFs
+ Random order
+ Use fade animations
+ Move backwards
+ Loop slideshow
+ The slideshow ended
+ No media for the slideshow have been found
+
+
+ Change view type
+ Grid
+ List
+
+
+ Show hidden media
+ Play videos automatically
+ Toggle filename visibility
+ Loop videos
+ Animate GIFs at thumbnails
+ Max brightness when viewing media
+ Crop thumbnails into squares
+ Rotate fullscreen media by
+ System setting
+ Device rotation
+ Aspect ratio
+ Dark background at fullscreen media
+ Scroll thumbnails horizontally
+ Automatically hide system UI at fullscreen media
+ Delete empty folders after deleting their content
+ Allow controlling video volume and brightness with vertical gestures
+ Show folder media count on the main view
+ Replace Share with Rotate at fullscreen menu
+ Show extended details over fullscreen media
+ Manage extended details
+
+
+
+ A gallery for viewing photos and videos without ads.
+
+ A simple tool usable for viewing photos and videos. Items can be sorted by date, size, name both ascending or descending, photos can be zoomed in. Media files are shown in multiple columns depending on the size of the display, you can change the column count by pinch gestures. They can be renamed, shared, deleted, copied, moved. Images can also be cropped, rotated, flipped or set as Wallpaper directly from the app.
+
+ The Gallery is also offered for third party usage for previewing images / videos, adding attachments at email clients etc. It\'s perfect for everyday usage.
+
+ Contains no ads or unnecessary permissions. It is fully opensource, provides customizable colors.
+
+ This app is just one piece of a bigger series of apps. You can find the rest of them at http://www.simplemobiletools.com
+
+
+
+
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
new file mode 100644
index 000000000..1f49212f3
--- /dev/null
+++ b/app/src/main/res/values-nl/strings.xml
@@ -0,0 +1,149 @@
+
+
+ Eenvoudige Galerij
+ Galerij
+ Bewerken
+ Camera
+ (verborgen)
+ Map vastzetten
+ Map losmaken
+ Platte weergave
+ Alle mappen
+ Mapweergave
+ Andere map
+ Op kaart tonen
+ Locatie onbekend
+ Geen app voor kaarten gevonden
+ Geen app voor camera gevonden
+ Meer kolommen
+ Minder kolommen
+ Afbeelding voor omslag veranderen
+ Foto selecteren
+ Standaard gebruiken
+ Volume
+ Helderheid
+ Onthouden voor deze sessie
+ Schermrotatie vergrendelen
+ Schermrotatie ontgrendelen
+
+
+ Media kiezen
+ Afbeeldingen
+ Video\'s
+ GIF-bestanden
+ Geen bestanden gevonden met de huidige filters.
+ Media kiezen
+
+
+ Deze functie verbergt de map door het bestand \'.nomedia\' toe te voegen. Alle submappen zullen ook worden verborgen. Kies \'Verborgen mappen tonen\' in de instellingen om toch verborgen mappen te kunnen inzien. Doorgaan?
+ Uitsluiten
+ Uitgesloten mappen
+ Uitgesloten mappen beheren
+ De selectie en submappen uitsluiten van deze galerij. Uitgesloten mappen kunnen worden beheerd in de instellingen.
+ Map die dit item bevat uitsluiten?
+ Uitsluiten zal mappen en hun submappen verbergen voor deze galerij, maar niet voor andere apps.\n\nAls u de mappen ook in andere apps wilt verbergen, kies dan voor de functie Verbergen.
+ Alles verwijderen
+ Verwijder alles uit de lijst van uitgesloten mappen? Dit zal de mappen zelf niet verwijderen.
+
+
+ Ingesloten mappen
+ Ingesloten mappen beheren
+ Map toevoegen
+ Als er mappen zijn die wel media bevatten, maar niet niet door de galerij worden herkend, voeg deze mappen dan hier handmatig toe.\n\nHet hier toevoegen van mappen zal andere mappen niet uitsluiten.
+
+
+ Grootte aanpassen
+ Grootte aanpassen en opslaan
+ Breedte
+ Hoogte
+ Verhouding vergrendelen
+ Voer geldige afmetingen in
+
+
+ Bewerken
+ Opslaan
+ Draaien
+ Pad
+ Ongeldig pad naar afbeelding
+ Fout bij bewerken van afbeelding
+ Afbeelding bewerken met:
+ Geen app gevonden voor bewerking
+ Onbekende bestandslocatie
+ Kan het bronbestand niet overschrijven
+ Linksom draaien
+ Rechtsom draaien
+ 180º draaien
+ Kantelen
+ Horizontaal kantelen
+ Verticaal kantelen
+ Bewerken met
+
+
+ Achtergrond
+ Als achtergrond instellen
+ Achtergrond instellen mislukt
+ Achtergrond instellen met:
+ Geen app gevonden voor instellen achtergrond
+ Achtergrond instellen…
+ Achtergrond is ingesteld
+ Verhouding in portretmodus
+ Verhouding in landschapsmodus
+
+
+ Diavoorstelling
+ Interval (seconden):
+ Afbeeldingen weergeven
+ Video\'s weergeven
+ GIF-bestanden weergeven
+ Willekeurige volgorde
+ Animaties gebruiken (vervagen)
+ Omgekeerde volgorde
+ Voorstelling herhalen
+ De diavoorstelling is beëindigd
+ Geen media gevonden voor diavoorstelling
+
+
+ Weergave
+ Rooster
+ Lijst
+
+
+ Verborgen mappen tonen
+ Video\'s automatisch afspelen
+ Bestandsnamen tonen
+ Video\'s herhalen
+ GIF-bestanden afspelen in overzicht
+ Maximale helderheid in volledige weergave
+ Voorbeelden vierkant bijsnijden
+ Media in volledige weergave roteren volgens
+ Systeeminstelling
+ Rotatie van apparaat
+ Afmetingen van bestand
+ Donkere achtergrond bij volledige weergave
+ Horizontaal scrollen
+ Automatisch de statusbalk verbergen in volledige weergave
+ Lege mappen verwijderen na het verwijderen van hun inhoud
+ Volume en helderheid aanpassen met verticale sleepgebaren
+ Aantallen in mappen tonen
+ Menu-item Draaien vastzetten in volledige weergave (in plaats van Delen)
+ Uitgebreide informatie tonen in volledige weergave
+ Uitgebreide informatie
+
+
+
+ Een galerij voor afbeeldingen en video\'s, zonder advertenties.
+
+ Een eenvoudige galerij voor afbeeldingen en video\'s. Bestanden kunnen worden gesorteerd op datum, grootte en naam. Afbeeldingen kunnen in- en uitgezoomd worden. Bestanden worden afhankelijk van de schermgrootte weergegeven in kolommen, waarbij het aantal kolommen kan worden aangepast via knijpgebaren. Bestanden kunnen worden gedeeld, hernoemd, gekopieerd, verplaatst en verwijderd. Afbeeldingen kunnen ook worden bijgesneden, gedraaid, gekanteld of direct vanuit de app als achtergrond worden ingesteld.
+
+ De galerij kan ook worden gebruikt voor het bekijken van afbeeldingen of video\'s vanuit andere apps, om bijlagen toe te voegen in e-mail, etc. Perfect voor dagelijks gebruik.
+
+ Bevat geen advertenties of onnodige permissies. Volledig open-source. Kleuren van de app kunnen worden aangepast.
+
+ Deze app is onderdeel van een grotere verzameling. Vind de andere apps op http://www.simplemobiletools.com
+
+
+
+
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 1e4c90da8..c6b18239b 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -4,8 +4,6 @@
Simple Gallery
Edytuj
Uruchom aplikację aparatu
- Otwórz w
- Nie znaleziono danych aplikacji
(ukryty)
Przypnij folder
Wypakuj folder
@@ -22,9 +20,11 @@
Zmień okładkę
Wybierz obraz
Użyj domyślnej
- Ustaw jako
Głośność
Jasność
+ Nie pytaj więcej w tej sesji
+ Lock orientation
+ Unlock orientation
Filtruj multimedia
@@ -124,7 +124,10 @@
Ukrywaj interfejs przy pełnoekranowym podglądzie
Usuwaj puste foldery po usunięciu ich zawartości
Zezwalaj na kontrolę jasności i głośności filmów pionowymi gestami
+ Pokazuj liczbę elementów w folderach w głównym widoku
Zamień funkcję udostępniania na obracanie w menu pełnoekranowym
+ Dodatkowe szczegóły przy podglądzie pełnoekranowym
+ Zarządzaj dodatkowymi szczegółami
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index e549de037..a4c29aca1 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -4,8 +4,6 @@
Galeria
Editar
Abrir câmera
- Abrir com
- Nenhum aplicativo encontrado
(oculto)
Fixar pasta
Desfixar pasta
@@ -22,17 +20,19 @@
Trocar imagem de capa
Selecionar foto
Usar padrão
- Set as
Volume
- Brightness
+ Brilho
+ Não perguntar novamente por enquanto
+ Lock orientation
+ Unlock orientation
- Filter media
- Images
- Videos
+ Filtrar mídia
+ Imagens
+ Vídeos
GIFs
- No media files have been found with the selected filters.
- Change filters
+ Nenhum arquivo de mídia encontrado a partir dos filtros selecionados.
+ Mudar filtros
Esta opção oculta uma pasta com a adição de um arquivo \'.nomedia\' dentro dela, e irá ocultar todas as subpastas que estejam dentro da mesma. Você poderá rever essas pastas com a opção \'Mostrar pastas ocultas\'. Continuar?
@@ -76,7 +76,7 @@
Inverter
Horizontalmente
Verticalmente
- Edit with
+ Editar com
Simple Wallpaper
@@ -91,21 +91,21 @@
Slideshow
- Interval (seconds):
- Include photos
- Include videos
- Include GIFs
- Random order
- Use fade animations
- Move backwards
- Loop slideshow
- The slideshow ended
- No media for the slideshow have been found
+ Intervalo (segundos):
+ Incluir fotos
+ Incluir videos
+ Incluir GIFs
+ Ordem aleatória
+ Usar animação de esmaecimento
+ Retroceder
+ Apresentação em ciclo
+ Fim da apresentação
+ Nenhuma mídia encontrada para a apresentação
- Change view type
- Grid
- List
+ Alterar modo de visualização
+ Grade
+ Lista
Mostrar pastas ocultas
@@ -121,10 +121,13 @@
Proporção da mídia
Fundo de tela escuro em mídia tela cheia
Rolar miniaturas horizontalmente
- Automatically hide system UI at fullscreen media
- Delete empty folders after deleting their content
- Allow controlling video volume and brightness with vertical gestures
- Replace Share with Rotate at fullscreen menu
+ Esconder interface do sistema automaticamente quando em tela cheia
+ Apagar pastas vazias após deleter seu conteúdo
+ Permitir controle do volume e brilho com gestos na vertical
+ Mostrar quantidade de arquivos das pastas
+ Substituir botão "Compartilhar" por "Rotação de tela" quando em tela cheia
+ Exibir detalhes extendidos quando em tela cheia
+ Gerenciar detalhes extendidos
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index 5128dfaf4..e5a41ece4 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -4,8 +4,6 @@
Galeria
Editar
Abrir câmara
- Abrir com
- Nenhuma aplicação encontrada
(oculta)
Fixar pasta
Desafixar pasta
@@ -19,12 +17,14 @@
Não existe uma aplicação adequeada
Aumentar número de colunas
Diminuir número de colunas
- Alterar imagem da capa
+ Alterar imagem de capa
Selecionar foto
Predefinição
- Definir como
Volume
Brilho
+ Não perguntar de novo para esta sessão
+ Lock orientation
+ Unlock orientation
Filtrar multimédia
@@ -103,9 +103,9 @@
Não foram encontrados ficheiros para a apresentação
- Change view type
- Grid
- List
+ Tipo de exibição
+ Grelha
+ Lista
Mostrar pastas ocultas
@@ -124,7 +124,10 @@
Ocultar interface do sistema se em ecrã completo
Apagar as pastas vazias depois de remover o seu conteúdo
Permitir controlo do volume e brilho dos vídeos através de gestos verticais
+ Mostrar número de ficheiros na vista principal
Substituir a opção Partilhar pela opção Rodar se em ecrã completo
+ Mostrar detalhes se em ecrã completo
+ Gerir detalhes exibidos
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 7cdae2f86..b325afe64 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -4,8 +4,6 @@
Галерея
Редактировать
Открыть камеру
- Открыть в
- Приложение не найдено
(Скрытый)
Закрепить папку
Открепить папку
@@ -17,14 +15,16 @@
Место съёмки не указано
Не найдено приложений с картами
Не найдено приложения камеры
- Добавить 1 столбец
- Убрать 1 столбец
+ Добавить столбец
+ Убрать столбец
Изменить обложку
Выбрать изображение
Использовать по умолчанию
- Установить как...
Громкость
Яркость
+ Не спрашивать снова (до следующего запуска)
+ Lock orientation
+ Unlock orientation
Фильтр медиа
@@ -84,10 +84,10 @@
Установить не удалось
Установить в качестве обоев в:
Приложение не найдено
- Установка обоев…
+ Установка обоев…
Обои успешно установлены
- Формат изображения
- Пейзажное соотношение сторон
+ Портрет
+ Ландшафт
Слайдшоу
@@ -124,7 +124,10 @@
Автоматически скрывать системный интерфейс в полноэкранном режиме
Удалять пустые папки после удаления их содержимого
Управлять громкостью и яркостью видео с помощью вертикальных жестов
+ Показывать количество файлов в папках
Заменить \'Поделиться\' на \'Повернуть\' в меню полноэкранного режима
+ Показывать детали файла
+ Выбрать детали файла
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index 89a8fe5bb..fbc43e87d 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -4,8 +4,6 @@
Galéria
Upraviť
Otvoriť fotoaparát
- Otvoriť pomocou
- Nenašla sa žiadna vhodná aplikácia
(skryté)
Pripnúť priečinok
Odopnúť priečinok
@@ -22,9 +20,11 @@
Zmeniť obal albumu
Zvoliť foto
Použiť predvolený
- Nastaviť ako
Hlasitosť
Jas
+ Nepýtať sa už v tomto spustení
+ Uzamknúť otočenie obrazovky
+ Odomknúť otočenie obrazovky
Filter médií
@@ -49,7 +49,7 @@
Pridané priečinky
Spravovať pridané priečinky
Pridať priečinok
- Ak máte nejaké priečinky obsahujúce médiá, ale neboli rozpoznané aplikáciou, môžete ich tu manuálne pridať.
+ Ak máte nejaké priečinky obsahujúce médiá, ale neboli rozpoznané aplikáciou, môžete ich tu manuálne pridať.\n\nPridanie nových položiek sem nevylúči žiadny iný priečinok.
Zmeniť veľkosť
@@ -124,13 +124,16 @@
Automaticky skrývať systémové lišty pri celoobrazovkových médiách
Odstrániť prázdne priečinky po vymazaní ich obsahu
Povoliť ovládanie hlasitosti a jasu videí vertikálnymi ťahmi
+ Zobraziť počet médií v priečinku na hlavnej obrazovke
Nahradiť Zdieľanie s Otočením v celoobrazovkovom menu
+ Zobraziť rozšírené vlastnosti ponad celoobrazovkové médiá
+ Spravovať rozšírené vlastnosti
Galéria na prezeranie obrázkov a videí bez reklám.
- Jednoduchá nástroj použiteľný na prezeranie obrázkov a videí. Položky môžu byť zoradené podľa dátumu, veľkosti, názvu oboma smermi, obrázky je možné aj priblížiť. Položky sú zobrazované vo viacerých stĺpcoch v závislosti od veľkosti displeja, počet stĺpcov je možné meniť pomocou gesta prstami. Súbory môžete premenovať, zdieľať, mazať, kopírovať, premiestňovaŤ. Obrázky môžete orezať, otočiť, alebo nastaviť ako tapeta priamo v aplikácií.
+ Jednoduchá nástroj použiteľný na prezeranie obrázkov a videí. Položky môžu byť zoradené podľa dátumu, veľkosti, názvu oboma smermi, obrázky je možné aj priblížiť. Položky sú zobrazované vo viacerých stĺpcoch v závislosti od veľkosti displeja, počet stĺpcov je možné meniť pomocou gesta prstami. Súbory môžete premenovať, zdieľať, mazať, kopírovať, premiestňovať. Obrázky môžete orezať, otočiť, alebo nastaviť ako tapeta priamo v aplikácií.
Galéria je tiež poskytovaná pre použitie treťou stranou pre prehliadanie fotiek a videí, pridávanie príloh v emailových klientoch. Je perfektná na každodenné použitie.
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index 834755adf..dbdf99823 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -4,8 +4,6 @@
Galleri
Redigera
Starta kameran
- Öppna med
- Hittade ingen giltig app
(dold)
Fäst mappen
Släpp mappen
@@ -22,9 +20,11 @@
Byt omslagsbild
Välj foto
Använd standard
- Ange som
Volym
Ljusstyrka
+ Do not ask again in this session
+ Lock orientation
+ Unlock orientation
Filtrera media
@@ -124,7 +124,10 @@
Dölj systemanvändargränssnittet automatiskt när media visas i helskärmsläge
Ta bort tomma mappar när deras innehåll tas bort
Tillåt styrning av videovolym och videoljusstyrka med vertikala gester
+ Show folder media count on the main view
Ersätt Dela med Rotera i helskärmsmenyn
+ Show extended details over fullscreen media
+ Manage extended details
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index e98004c41..a93d22dcf 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -4,8 +4,6 @@
Galeri
Düzenle
Kamerayı aç
- Bununla aç
- Geçerli bir uygulama bulunamadı
(gizli)
Pin klasör
Klasörü çöz
@@ -22,9 +20,11 @@
Change cover image
Select photo
Use default
- Set as
Volume
Brightness
+ Do not ask again in this session
+ Lock orientation
+ Unlock orientation
Filter media
@@ -124,7 +124,10 @@
Automatically hide system UI at fullscreen media
Delete empty folders after deleting their content
Allow controlling video volume and brightness with vertical gestures
+ Show folder media count on the main view
Replace Share with Rotate at fullscreen menu
+ Show extended details over fullscreen media
+ Manage extended details
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index 1b6a61f9e..e6b3ceaf9 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -1,11 +1,9 @@
- Simple Gallery
+ 简约图库
简约图库
编辑
打开相机
- 打开方式
- 未找到可用应用
(隐藏)
锁定目录
解除锁定目录
@@ -22,28 +20,30 @@
更改封面图片
选择图片
使用默认
- 设置为
音量
亮度
+ 不再提醒
+ Lock orientation
+ Unlock orientation
- Filter media
- Images
- Videos
+ 要显示的媒体文件
+ 图片
+ 视频
GIFs
- No media files have been found with the selected filters.
- Change filters
+ 所选的过滤器没有找到媒体文件。
+ 更改过滤器
通过添加文件 \'.nomedia\' 到目录,可以防止目录及其子目录下的所有媒体被扫描。您可以通过设置中的 \'显示隐藏目录\' 选项改变设置,是否继续?
排除
排除目录
管理排除目录
- 目录及其子目录中的媒体将不会在 Simple Gallery 中显示,您可以在设置更改。
+ 目录及其子目录中的媒体将不会在“简约图库”中显示,您可以在设置更改。
是否排除父目录?
- 此目录及其子目录中的媒体将不会在 Simple Gallery 中显示,但是其它应用可以访问。如果您想对其它应用隐藏,请使用隐藏功能。
+ 此目录及其子目录中的媒体将不会在“简约图库”中显示,但是其它应用可以访问。如果您想对其它应用隐藏,请使用隐藏功能。
移除全部
- 是否移除列表中的全部目录?目录不会被物理删除。
+ 是否删除排除列表中的所有项目?此操作不会删除文件夹本身。
包含目录
@@ -79,7 +79,7 @@
编辑方式
- Simple Wallpaper
+ 简约壁纸
设为壁纸
壁纸设置失败
设为壁纸...
@@ -92,20 +92,20 @@
幻灯片
间隔(秒):
- Include photos
- 包含视频
- Include GIFs
+ 包括照片
+ 包括视频
+ 包括 GIFs
随机顺序
使用渐变动画
倒播
- Loop slideshow
+ 循环幻灯片
幻灯片结束
未发现可用媒体
- Change view type
- Grid
- List
+ 更改视图类型
+ 网格
+ 列表
显示所有
@@ -115,16 +115,19 @@
GIF 缩略图
浏览时最大亮度
裁剪缩略图
- 全屏时方向
+ 全屏方向
系统设置
设备方向
根据长宽比
全屏时黑色背景
水平滚动缩略图
全屏时自动隐藏状态栏
- Delete empty folders after deleting their content
- Allow controlling video volume and brightness with vertical gestures
+ 删除没有内容的空文件夹
+ 使用纵向滑动手势控制视频音量和亮度
+ 在主界面显示文件夹媒体计数
替换全屏时菜单栏的“分享”为“旋转”
+ 全屏浏览媒体时显示详细信息
+ 要显示的详细信息项目
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 6f7ec0dc1..aa12be2c9 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -4,8 +4,6 @@
簡易相簿
編輯
開啟相機
- 以其他應用程式開啟
- 找不到應用程式
(隱藏)
釘選資料夾
取消釘選資料夾
@@ -22,9 +20,11 @@
更換封面圖片
選擇相片
使用預設
- 設為
音量
亮度
+ Do not ask again in this session
+ Lock orientation
+ Unlock orientation
篩選媒體檔案
@@ -124,7 +124,10 @@
全螢幕時自動隱藏系統介面
刪除內容後刪除空白資料夾
允許用上下手勢來控制影片的音量和亮度
+ Show folder media count on the main view
將全螢幕選單的分享取代為旋轉
+ Show extended details over fullscreen media
+ Manage extended details
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 8cb25a2bb..ee1e5614a 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -7,4 +7,6 @@
@color/default_dark_theme_text_color
@color/default_dark_theme_background_color
+
+ @color/color_primary
diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml
index 10ac92ba7..a8c998266 100644
--- a/app/src/main/res/values/donottranslate.xml
+++ b/app/src/main/res/values/donottranslate.xml
@@ -2,6 +2,9 @@
+ Added an option to keep last-modified field at file copy/move/rename
+ Added an option to hide folder media count on the main screen
+ Added an option to show customizable extended details over fullscreen media
Added fingerprint to hidden item protection\n
Added a new List view type
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ddc156702..e15f4800d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -4,8 +4,6 @@
Gallery
Edit
Open camera
- Open with
- No valid app found
(hidden)
Pin folder
Unpin folder
@@ -22,9 +20,11 @@
Change cover image
Select photo
Use default
- Set as
Volume
Brightness
+ Do not ask again in this session
+ Lock orientation
+ Unlock orientation
Filter media
@@ -49,7 +49,7 @@
Included folders
Manage included folders
Add folder
- If you have some folders which contain media, but were not recognized by the app, you can add them manually here.
+ If you have some folders which contain media, but were not recognized by the app, you can add them manually here.\n\nAdding some items here will not exclude any other folder.
Resize
@@ -124,7 +124,10 @@
Automatically hide system UI at fullscreen media
Delete empty folders after deleting their content
Allow controlling video volume and brightness with vertical gestures
+ Show folder media count on the main view
Replace Share with Rotate at fullscreen menu
+ Show extended details over fullscreen media
+ Manage extended details
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index f7114219d..54db9f7d0 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,8 +1,6 @@
-
+