Merge pull request #4 from SimpleMobileTools/master

update
This commit is contained in:
solokot 2017-11-19 23:27:38 +03:00 committed by GitHub
commit 5ac1fdb787
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 676 additions and 872 deletions

View file

@ -1,6 +1,22 @@
Changelog Changelog
========== ==========
Version 2.18.1 *(2017-11-16)*
----------------------------
* Fixed some double-tap zoom issues
* Misc smaller fixes and improvements here and there
Version 2.18.0 *(2017-11-09)*
----------------------------
* Added an option to use english language on non-english devices
* Added an option to password protect the whole app
* Added an option to lock screen orientation at fullscreen view
* Split the Rotate button to 3 buttons per degrees
* Changed the way fullscreen images are loaded for better quality
* Fixed many memory leaks and smaller issues
Version 2.17.4 *(2017-11-06)* Version 2.17.4 *(2017-11-06)*
---------------------------- ----------------------------

View file

@ -10,8 +10,10 @@ android {
applicationId "com.simplemobiletools.gallery" applicationId "com.simplemobiletools.gallery"
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 27 targetSdkVersion 27
versionCode 142 versionCode 144
versionName "2.17.4" versionName "2.18.1"
multiDexEnabled true
setProperty("archivesBaseName", "gallery")
} }
signingConfigs { signingConfigs {
@ -45,10 +47,10 @@ ext {
} }
dependencies { dependencies {
compile 'com.simplemobiletools:commons:2.37.12' compile 'com.simplemobiletools:commons:2.39.10'
compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.7.2' compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.8.0'
compile 'com.theartofdev.edmodo:android-image-cropper:2.4.0' compile 'com.theartofdev.edmodo:android-image-cropper:2.4.0'
compile 'com.bignerdranch.android:recyclerview-multiselect:0.2' compile 'com.android.support:multidex:1.0.2'
compile 'com.google.code.gson:gson:2.8.2' compile 'com.google.code.gson:gson:2.8.2'
compile 'it.sephiroth.android.exif:library:1.0.1' compile 'it.sephiroth.android.exif:library:1.0.1'
compile 'pl.droidsonroids.gif:android-gif-drawable:1.2.8' compile 'pl.droidsonroids.gif:android-gif-drawable:1.2.8'
@ -59,7 +61,7 @@ dependencies {
} }
buildscript { buildscript {
ext.kotlin_version = '1.1.51' ext.kotlin_version = '1.1.60'
repositories { repositories {
mavenCentral() mavenCentral()
} }

View file

@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.SET_WALLPAPER"/> <uses-permission android:name="android.permission.SET_WALLPAPER"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<application <application
android:name=".App" android:name=".App"

View file

@ -1,13 +1,13 @@
package com.simplemobiletools.gallery package com.simplemobiletools.gallery
import android.app.Application import android.support.multidex.MultiDexApplication
import com.github.ajalt.reprint.core.Reprint import com.github.ajalt.reprint.core.Reprint
import com.simplemobiletools.gallery.BuildConfig.USE_LEAK_CANARY import com.simplemobiletools.gallery.BuildConfig.USE_LEAK_CANARY
import com.simplemobiletools.gallery.extensions.config import com.simplemobiletools.gallery.extensions.config
import com.squareup.leakcanary.LeakCanary import com.squareup.leakcanary.LeakCanary
import java.util.* import java.util.*
class App : Application() { class App : MultiDexApplication() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
if (USE_LEAK_CANARY) { if (USE_LEAK_CANARY) {

View file

@ -1,45 +1,33 @@
package com.simplemobiletools.gallery.activities package com.simplemobiletools.gallery.activities
import android.graphics.PorterDuff
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import com.simplemobiletools.commons.dialogs.FilePickerDialog import com.simplemobiletools.commons.dialogs.FilePickerDialog
import com.simplemobiletools.commons.extensions.beVisibleIf import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.commons.interfaces.RefreshRecyclerViewListener
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.adapters.ManageFoldersAdapter
import com.simplemobiletools.gallery.extensions.config import com.simplemobiletools.gallery.extensions.config
import kotlinx.android.synthetic.main.activity_excluded_folders.* import kotlinx.android.synthetic.main.activity_manage_folders.*
import kotlinx.android.synthetic.main.item_manage_folder.view.*
class ExcludedFoldersActivity : SimpleActivity() { class ExcludedFoldersActivity : SimpleActivity(), RefreshRecyclerViewListener {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_excluded_folders) setContentView(R.layout.activity_manage_folders)
updateExcludedFolders() updateExcludedFolders()
} }
private fun updateExcludedFolders() { private fun updateExcludedFolders() {
excluded_folders_holder.removeAllViews() val folders = ArrayList<String>()
val folders = config.excludedFolders config.excludedFolders.mapTo(folders, { it })
excluded_folders_placeholder.beVisibleIf(folders.isEmpty()) manage_folders_placeholder.text = getString(R.string.excluded_activity_placeholder)
excluded_folders_placeholder.setTextColor(config.textColor) manage_folders_placeholder.beVisibleIf(folders.isEmpty())
manage_folders_placeholder.setTextColor(config.textColor)
for (folder in folders) { val adapter = ManageFoldersAdapter(this, folders, true, this, manage_folders_list) {}
layoutInflater.inflate(R.layout.item_manage_folder, null, false).apply { adapter.setupDragListener(true)
managed_folder_title.apply { manage_folders_list.adapter = adapter
text = folder
setTextColor(config.textColor)
}
managed_folders_icon.apply {
setColorFilter(config.textColor, PorterDuff.Mode.SRC_IN)
setOnClickListener {
config.removeExcludedFolder(folder)
updateExcludedFolders()
}
}
excluded_folders_holder.addView(this)
}
}
} }
override fun onCreateOptionsMenu(menu: Menu?): Boolean { override fun onCreateOptionsMenu(menu: Menu?): Boolean {
@ -55,6 +43,10 @@ class ExcludedFoldersActivity : SimpleActivity() {
return true return true
} }
override fun refreshItems() {
updateExcludedFolders()
}
private fun addExcludedFolder() { private fun addExcludedFolder() {
FilePickerDialog(this, pickFile = false, showHidden = config.shouldShowHidden) { FilePickerDialog(this, pickFile = false, showHidden = config.shouldShowHidden) {
config.addExcludedFolder(it) config.addExcludedFolder(it)

View file

@ -1,46 +1,34 @@
package com.simplemobiletools.gallery.activities package com.simplemobiletools.gallery.activities
import android.graphics.PorterDuff
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import com.simplemobiletools.commons.dialogs.FilePickerDialog import com.simplemobiletools.commons.dialogs.FilePickerDialog
import com.simplemobiletools.commons.extensions.beVisibleIf import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.commons.extensions.scanPath import com.simplemobiletools.commons.extensions.scanPath
import com.simplemobiletools.commons.interfaces.RefreshRecyclerViewListener
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.adapters.ManageFoldersAdapter
import com.simplemobiletools.gallery.extensions.config import com.simplemobiletools.gallery.extensions.config
import kotlinx.android.synthetic.main.activity_included_folders.* import kotlinx.android.synthetic.main.activity_manage_folders.*
import kotlinx.android.synthetic.main.item_manage_folder.view.*
class IncludedFoldersActivity : SimpleActivity() { class IncludedFoldersActivity : SimpleActivity(), RefreshRecyclerViewListener {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_included_folders) setContentView(R.layout.activity_manage_folders)
updateIncludedFolders() updateIncludedFolders()
} }
private fun updateIncludedFolders() { private fun updateIncludedFolders() {
included_folders_holder.removeAllViews() val folders = ArrayList<String>()
val folders = config.includedFolders config.includedFolders.mapTo(folders, { it })
included_folders_placeholder.beVisibleIf(folders.isEmpty()) manage_folders_placeholder.text = getString(R.string.included_activity_placeholder)
included_folders_placeholder.setTextColor(config.textColor) manage_folders_placeholder.beVisibleIf(folders.isEmpty())
manage_folders_placeholder.setTextColor(config.textColor)
for (folder in folders) { val adapter = ManageFoldersAdapter(this, folders, false, this, manage_folders_list) {}
layoutInflater.inflate(R.layout.item_manage_folder, null, false).apply { adapter.setupDragListener(true)
managed_folder_title.apply { manage_folders_list.adapter = adapter
text = folder
setTextColor(config.textColor)
}
managed_folders_icon.apply {
setColorFilter(config.textColor, PorterDuff.Mode.SRC_IN)
setOnClickListener {
config.removeIncludedFolder(folder)
updateIncludedFolders()
}
}
included_folders_holder.addView(this)
}
}
} }
override fun onCreateOptionsMenu(menu: Menu?): Boolean { override fun onCreateOptionsMenu(menu: Menu?): Boolean {
@ -56,11 +44,15 @@ class IncludedFoldersActivity : SimpleActivity() {
return true return true
} }
override fun refreshItems() {
updateIncludedFolders()
}
private fun addIncludedFolder() { private fun addIncludedFolder() {
FilePickerDialog(this, pickFile = false, showHidden = config.shouldShowHidden) { FilePickerDialog(this, pickFile = false, showHidden = config.shouldShowHidden) {
config.addIncludedFolder(it) config.addIncludedFolder(it)
updateIncludedFolders() updateIncludedFolders()
scanPath(it) {} scanPath(it)
} }
} }
} }

View file

@ -4,7 +4,6 @@ import android.app.Activity
import android.content.ClipData import android.content.ClipData
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.provider.MediaStore import android.provider.MediaStore
@ -23,7 +22,7 @@ import com.simplemobiletools.commons.helpers.SORT_BY_DATE_MODIFIED
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_TAKEN import com.simplemobiletools.commons.helpers.SORT_BY_DATE_TAKEN
import com.simplemobiletools.commons.models.RadioItem import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.commons.models.Release import com.simplemobiletools.commons.models.Release
import com.simplemobiletools.commons.views.MyScalableRecyclerView import com.simplemobiletools.commons.views.MyRecyclerView
import com.simplemobiletools.gallery.BuildConfig import com.simplemobiletools.gallery.BuildConfig
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.adapters.DirectoryAdapter import com.simplemobiletools.gallery.adapters.DirectoryAdapter
@ -64,6 +63,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
private var mLatestMediaId = 0L private var mLatestMediaId = 0L
private var mLastMediaHandler = Handler() private var mLastMediaHandler = Handler()
private var mCurrAsyncTask: GetDirectoriesAsynctask? = null private var mCurrAsyncTask: GetDirectoriesAsynctask? = null
private var mZoomListener: MyRecyclerView.MyZoomListener? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -178,7 +178,6 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
directories_refresh_layout.isRefreshing = false directories_refresh_layout.isRefreshing = false
mIsGettingDirs = false mIsGettingDirs = false
storeStateVariables() storeStateVariables()
directories_grid.listener = null
mLastMediaHandler.removeCallbacksAndMessages(null) mLastMediaHandler.removeCallbacksAndMessages(null)
if (!mDirs.isEmpty()) { if (!mDirs.isEmpty()) {
@ -209,7 +208,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
val newFolder = File(config.tempFolderPath) val newFolder = File(config.tempFolderPath)
if (newFolder.exists() && newFolder.isDirectory) { if (newFolder.exists() && newFolder.isDirectory) {
if (newFolder.list()?.isEmpty() == true) { if (newFolder.list()?.isEmpty() == true) {
deleteFileBg(newFolder, true) { } deleteFileBg(newFolder, true)
} }
} }
config.tempFolderPath = "" config.tempFolderPath = ""
@ -341,6 +340,11 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
} else { } else {
setupListLayoutManager() setupListLayoutManager()
} }
getDirectoryAdapter()?.apply {
setupZoomListener(mZoomListener)
setupDragListener(true)
}
} }
private fun setupGridLayoutManager() { private fun setupGridLayoutManager() {
@ -353,42 +357,30 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
directories_refresh_layout.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) directories_refresh_layout.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
} }
directories_grid.isDragSelectionEnabled = true
directories_grid.isZoomingEnabled = true
layoutManager.spanCount = config.dirColumnCnt layoutManager.spanCount = config.dirColumnCnt
directories_grid.listener = object : MyScalableRecyclerView.MyScalableRecyclerViewListener { mZoomListener = object : MyRecyclerView.MyZoomListener {
override fun zoomIn() { override fun zoomIn() {
if (layoutManager.spanCount > 1) { if (layoutManager.spanCount > 1) {
reduceColumnCount() reduceColumnCount()
getRecyclerAdapter().actMode?.finish() getRecyclerAdapter().finishActMode()
} }
} }
override fun zoomOut() { override fun zoomOut() {
if (layoutManager.spanCount < MAX_COLUMN_COUNT) { if (layoutManager.spanCount < MAX_COLUMN_COUNT) {
increaseColumnCount() increaseColumnCount()
getRecyclerAdapter().actMode?.finish() getRecyclerAdapter().finishActMode()
} }
} }
override fun selectItem(position: Int) {
getRecyclerAdapter().selectItem(position)
}
override fun selectRange(initialSelection: Int, lastDraggedIndex: Int, minReached: Int, maxReached: Int) {
getRecyclerAdapter().selectRange(initialSelection, lastDraggedIndex, minReached, maxReached)
}
} }
} }
private fun setupListLayoutManager() { private fun setupListLayoutManager() {
directories_grid.isDragSelectionEnabled = true
directories_grid.isZoomingEnabled = false
val layoutManager = directories_grid.layoutManager as GridLayoutManager val layoutManager = directories_grid.layoutManager as GridLayoutManager
layoutManager.spanCount = 1 layoutManager.spanCount = 1
layoutManager.orientation = GridLayoutManager.VERTICAL layoutManager.orientation = GridLayoutManager.VERTICAL
directories_refresh_layout.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) directories_refresh_layout.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
mZoomListener = null
} }
private fun createNewFolder() { private fun createNewFolder() {
@ -451,7 +443,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
else -> fillIntentPath(resultData, resultIntent) else -> fillIntentPath(resultData, resultIntent)
} }
} else if ((mIsPickImageIntent || mIsPickVideoIntent)) { } else if ((mIsPickImageIntent || mIsPickVideoIntent)) {
val path = resultData.data.path val path = resultData.data?.path
val uri = getFilePublicUri(File(path), BuildConfig.APPLICATION_ID) val uri = getFilePublicUri(File(path), BuildConfig.APPLICATION_ID)
resultIntent.data = uri resultIntent.data = uri
resultIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION resultIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
@ -560,8 +552,8 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
private fun setupAdapter() { private fun setupAdapter() {
val currAdapter = directories_grid.adapter val currAdapter = directories_grid.adapter
if (currAdapter == null) { if (currAdapter == null) {
directories_grid.adapter = DirectoryAdapter(this, mDirs, this, isPickIntent(intent) || isGetAnyContentIntent(intent)) { directories_grid.adapter = DirectoryAdapter(this, mDirs, this, directories_grid, isPickIntent(intent) || isGetAnyContentIntent(intent)) {
itemClicked(it.path) itemClicked((it as Directory).path)
} }
} else { } else {
(currAdapter as DirectoryAdapter).updateDirs(mDirs) (currAdapter as DirectoryAdapter).updateDirs(mDirs)
@ -587,7 +579,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
} }
private fun checkLastMediaChanged() { private fun checkLastMediaChanged() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && isDestroyed) if (isActivityDestroyed())
return return
mLastMediaHandler.removeCallbacksAndMessages(null) mLastMediaHandler.removeCallbacksAndMessages(null)
@ -610,10 +602,6 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
getDirectories() getDirectories()
} }
override fun itemLongClicked(position: Int) {
directories_grid.setDragSelectActive(position)
}
override fun recheckPinnedFolders() { override fun recheckPinnedFolders() {
gotDirectories(movePinnedDirectoriesToFront(mDirs), true) gotDirectories(movePinnedDirectoriesToFront(mDirs), true)
} }
@ -659,6 +647,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
add(Release(136, R.string.release_136)) add(Release(136, R.string.release_136))
add(Release(137, R.string.release_137)) add(Release(137, R.string.release_137))
add(Release(138, R.string.release_138)) add(Release(138, R.string.release_138))
add(Release(143, R.string.release_143))
checkWhatsNew(this, BuildConfig.VERSION_CODE) checkWhatsNew(this, BuildConfig.VERSION_CODE)
} }
} }

View file

@ -5,7 +5,6 @@ import android.app.WallpaperManager
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.support.v7.widget.GridLayoutManager import android.support.v7.widget.GridLayoutManager
@ -24,7 +23,7 @@ import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE
import com.simplemobiletools.commons.helpers.REQUEST_EDIT_IMAGE import com.simplemobiletools.commons.helpers.REQUEST_EDIT_IMAGE
import com.simplemobiletools.commons.models.RadioItem import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.commons.views.MyScalableRecyclerView import com.simplemobiletools.commons.views.MyRecyclerView
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.adapters.MediaAdapter import com.simplemobiletools.gallery.adapters.MediaAdapter
import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask
@ -59,6 +58,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
private var mLatestMediaId = 0L private var mLatestMediaId = 0L
private var mLastMediaHandler = Handler() private var mLastMediaHandler = Handler()
private var mCurrAsyncTask: GetMediaAsynctask? = null private var mCurrAsyncTask: GetMediaAsynctask? = null
private var mZoomListener: MyRecyclerView.MyZoomListener? = null
companion object { companion object {
var mMedia = ArrayList<Medium>() var mMedia = ArrayList<Medium>()
@ -120,7 +120,6 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
mIsGettingMedia = false mIsGettingMedia = false
media_refresh_layout.isRefreshing = false media_refresh_layout.isRefreshing = false
storeStateVariables() storeStateVariables()
media_grid.listener = null
mLastMediaHandler.removeCallbacksAndMessages(null) mLastMediaHandler.removeCallbacksAndMessages(null)
if (!mMedia.isEmpty()) { if (!mMedia.isEmpty()) {
@ -177,8 +176,8 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
val currAdapter = media_grid.adapter val currAdapter = media_grid.adapter
if (currAdapter == null) { if (currAdapter == null) {
media_grid.adapter = MediaAdapter(this, mMedia, this, mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent, mAllowPickingMultiple) { media_grid.adapter = MediaAdapter(this, mMedia, this, mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent, mAllowPickingMultiple, media_grid) {
itemClicked(it.path) itemClicked((it as Medium).path)
} }
} else { } else {
(currAdapter as MediaAdapter).updateMedia(mMedia) (currAdapter as MediaAdapter).updateMedia(mMedia)
@ -204,7 +203,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
} }
private fun checkLastMediaChanged() { private fun checkLastMediaChanged() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && isDestroyed) if (isActivityDestroyed())
return return
mLastMediaHandler.removeCallbacksAndMessages(null) mLastMediaHandler.removeCallbacksAndMessages(null)
@ -347,7 +346,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
private fun deleteDirectoryIfEmpty() { private fun deleteDirectoryIfEmpty() {
val file = File(mPath) val file = File(mPath)
if (config.deleteEmptyFolders && !file.isDownloadsFolder() && file.isDirectory && file.listFiles()?.isEmpty() == true) { if (config.deleteEmptyFolders && !file.isDownloadsFolder() && file.isDirectory && file.listFiles()?.isEmpty() == true) {
deleteFile(file, true) {} deleteFile(file, true)
} }
} }
@ -398,10 +397,16 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
private fun getRecyclerAdapter() = (media_grid.adapter as MediaAdapter) private fun getRecyclerAdapter() = (media_grid.adapter as MediaAdapter)
private fun setupLayoutManager() { private fun setupLayoutManager() {
if (config.viewTypeFiles == VIEW_TYPE_GRID) if (config.viewTypeFiles == VIEW_TYPE_GRID) {
setupGridLayoutManager() setupGridLayoutManager()
else } else {
setupListLayoutManager() setupListLayoutManager()
}
getMediaAdapter()?.apply {
setupZoomListener(mZoomListener)
setupDragListener(true)
}
} }
private fun setupGridLayoutManager() { private fun setupGridLayoutManager() {
@ -414,42 +419,30 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
media_refresh_layout.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) media_refresh_layout.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
} }
media_grid.isDragSelectionEnabled = true
media_grid.isZoomingEnabled = true
layoutManager.spanCount = config.mediaColumnCnt layoutManager.spanCount = config.mediaColumnCnt
media_grid.listener = object : MyScalableRecyclerView.MyScalableRecyclerViewListener { mZoomListener = object : MyRecyclerView.MyZoomListener {
override fun zoomIn() { override fun zoomIn() {
if (layoutManager.spanCount > 1) { if (layoutManager.spanCount > 1) {
reduceColumnCount() reduceColumnCount()
getRecyclerAdapter().actMode?.finish() getRecyclerAdapter().finishActMode()
} }
} }
override fun zoomOut() { override fun zoomOut() {
if (layoutManager.spanCount < MAX_COLUMN_COUNT) { if (layoutManager.spanCount < MAX_COLUMN_COUNT) {
increaseColumnCount() increaseColumnCount()
getRecyclerAdapter().actMode?.finish() getRecyclerAdapter().finishActMode()
} }
} }
override fun selectItem(position: Int) {
getRecyclerAdapter().selectItem(position)
}
override fun selectRange(initialSelection: Int, lastDraggedIndex: Int, minReached: Int, maxReached: Int) {
getRecyclerAdapter().selectRange(initialSelection, lastDraggedIndex, minReached, maxReached)
}
} }
} }
private fun setupListLayoutManager() { private fun setupListLayoutManager() {
media_grid.isDragSelectionEnabled = true
media_grid.isZoomingEnabled = false
val layoutManager = media_grid.layoutManager as GridLayoutManager val layoutManager = media_grid.layoutManager as GridLayoutManager
layoutManager.spanCount = 1 layoutManager.spanCount = 1
layoutManager.orientation = GridLayoutManager.VERTICAL layoutManager.orientation = GridLayoutManager.VERTICAL
media_refresh_layout.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) media_refresh_layout.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
mZoomListener = null
} }
private fun increaseColumnCount() { private fun increaseColumnCount() {
@ -575,10 +568,6 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
}, 1000) }, 1000)
} }
override fun itemLongClicked(position: Int) {
media_grid.setDragSelectActive(position)
}
override fun selectedPaths(paths: ArrayList<String>) { override fun selectedPaths(paths: ArrayList<String>) {
Intent().apply { Intent().apply {
putExtra(PICKED_PATHS, paths) putExtra(PICKED_PATHS, paths)

View file

@ -59,14 +59,14 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
mIsFromGallery = intent.getBooleanExtra(IS_FROM_GALLERY, false) mIsFromGallery = intent.getBooleanExtra(IS_FROM_GALLERY, false)
if (mUri!!.scheme == "file") { if (mUri!!.scheme == "file") {
scanPath(mUri!!.path) {} scanPath(mUri!!.path)
sendViewPagerIntent(mUri!!.path) sendViewPagerIntent(mUri!!.path)
finish() finish()
return return
} else { } else {
val path = applicationContext.getRealPathFromURI(mUri!!) ?: "" val path = applicationContext.getRealPathFromURI(mUri!!) ?: ""
if (path != mUri.toString() && path.isNotEmpty()) { if (path != mUri.toString() && path.isNotEmpty()) {
scanPath(mUri!!.path) {} scanPath(mUri!!.path)
sendViewPagerIntent(path) sendViewPagerIntent(path)
finish() finish()
return return
@ -114,9 +114,11 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.photo_video_menu, menu) menuInflater.inflate(R.menu.photo_video_menu, menu)
menu.findItem(R.id.menu_set_as).isVisible = mMedium?.isImage() == true menu.apply {
menu.findItem(R.id.menu_edit).isVisible = mMedium?.isImage() == true && mUri?.scheme == "file" findItem(R.id.menu_set_as).isVisible = mMedium?.isImage() == true
menu.findItem(R.id.menu_properties).isVisible = mUri?.scheme == "file" findItem(R.id.menu_edit).isVisible = mMedium?.isImage() == true && mUri?.scheme == "file"
findItem(R.id.menu_properties).isVisible = mUri?.scheme == "file"
}
return true return true
} }

View file

@ -5,10 +5,10 @@ import android.app.WallpaperManager
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import com.simplemobiletools.commons.extensions.isActivityDestroyed
import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.theartofdev.edmodo.cropper.CropImageView import com.theartofdev.edmodo.cropper.CropImageView
@ -61,8 +61,10 @@ class SetWallpaperActivity : SimpleActivity(), CropImageView.OnCropImageComplete
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_set_wallpaper, menu) menuInflater.inflate(R.menu.menu_set_wallpaper, menu)
menu.findItem(R.id.portrait_aspect_ratio).isVisible = isLandscapeRatio menu.apply {
menu.findItem(R.id.landscape_aspect_ratio).isVisible = !isLandscapeRatio findItem(R.id.portrait_aspect_ratio).isVisible = isLandscapeRatio
findItem(R.id.landscape_aspect_ratio).isVisible = !isLandscapeRatio
}
return true return true
} }
@ -84,7 +86,7 @@ class SetWallpaperActivity : SimpleActivity(), CropImageView.OnCropImageComplete
} }
override fun onCropImageComplete(view: CropImageView?, result: CropImageView.CropResult) { override fun onCropImageComplete(view: CropImageView?, result: CropImageView.CropResult) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && isDestroyed) if (isActivityDestroyed())
return return
if (result.error == null) { if (result.error == null) {

View file

@ -67,7 +67,7 @@ class SettingsActivity : SimpleActivity() {
} }
private fun setupUseEnglish() { private fun setupUseEnglish() {
settings_use_english_holder.beVisibleIf(Locale.getDefault().language != "en") settings_use_english_holder.beVisibleIf(config.wasUseEnglishToggled || Locale.getDefault().language != "en")
settings_use_english.isChecked = config.useEnglish settings_use_english.isChecked = config.useEnglish
settings_use_english_holder.setOnClickListener { settings_use_english_holder.setOnClickListener {
settings_use_english.toggle() settings_use_english.toggle()

View file

@ -1,36 +1,5 @@
package com.simplemobiletools.gallery.activities package com.simplemobiletools.gallery.activities
import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.getFilenameFromPath
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.dialogs.PickDirectoryDialog
import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.models.Directory
import java.io.File
import java.util.*
open class SimpleActivity : BaseSimpleActivity() { open class SimpleActivity : BaseSimpleActivity()
fun tryCopyMoveFilesTo(files: ArrayList<File>, isCopyOperation: Boolean, callback: () -> Unit) {
if (files.isEmpty()) {
toast(R.string.unknown_error_occurred)
return
}
val source = if (files[0].isFile) files[0].parent else files[0].absolutePath
PickDirectoryDialog(this, source) {
copyMoveFilesTo(files, source.trimEnd('/'), it, isCopyOperation, true, callback)
}
}
fun addTempFolderIfNeeded(dirs: ArrayList<Directory>): ArrayList<Directory> {
val directories = ArrayList<Directory>()
val tempFolderPath = config.tempFolderPath
if (tempFolderPath.isNotEmpty()) {
val newFolder = Directory(tempFolderPath, "", tempFolderPath.getFilenameFromPath(), 0, 0, 0, 0L)
directories.add(newFolder)
}
directories.addAll(dirs)
return directories
}
}

View file

@ -23,6 +23,7 @@ import android.support.v4.view.ViewPager
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.view.* import android.view.*
import android.view.animation.DecelerateInterpolator import android.view.animation.DecelerateInterpolator
import com.bumptech.glide.Glide
import com.simplemobiletools.commons.dialogs.PropertiesDialog import com.simplemobiletools.commons.dialogs.PropertiesDialog
import com.simplemobiletools.commons.dialogs.RenameItemDialog import com.simplemobiletools.commons.dialogs.RenameItemDialog
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
@ -73,6 +74,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
companion object { companion object {
var screenWidth = 0 var screenWidth = 0
var screenHeight = 0 var screenHeight = 0
var wasDecodedByGlide = false
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -185,7 +187,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
title = mPath.getFilenameFromPath() title = mPath.getFilenameFromPath()
view_pager.onGlobalLayout { view_pager.onGlobalLayout {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !isDestroyed) { if (!isActivityDestroyed()) {
if (mMedia.isNotEmpty()) { if (mMedia.isNotEmpty()) {
gotMedia(mMedia) gotMedia(mMedia)
} }
@ -193,7 +195,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
} }
reloadViewPager() reloadViewPager()
scanPath(mPath) {} scanPath(mPath)
if (config.darkBackground) if (config.darkBackground)
view_pager.background = ColorDrawable(Color.BLACK) view_pager.background = ColorDrawable(Color.BLACK)
@ -226,8 +228,8 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
mOrientationEventListener = object : OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) { mOrientationEventListener = object : OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {
override fun onOrientationChanged(orientation: Int) { override fun onOrientationChanged(orientation: Int) {
val currOrient = when (orientation) { val currOrient = when (orientation) {
in 60..134 -> ORIENT_LANDSCAPE_RIGHT in 75..134 -> ORIENT_LANDSCAPE_RIGHT
in 225..299 -> ORIENT_LANDSCAPE_LEFT in 225..285 -> ORIENT_LANDSCAPE_LEFT
else -> ORIENT_PORTRAIT else -> ORIENT_PORTRAIT
} }
@ -303,7 +305,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun updatePagerItems(media: MutableList<Medium>) { private fun updatePagerItems(media: MutableList<Medium>) {
val pagerAdapter = MyPagerAdapter(this, supportFragmentManager, media) val pagerAdapter = MyPagerAdapter(this, supportFragmentManager, media)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !isDestroyed) { if (!isActivityDestroyed()) {
view_pager.apply { view_pager.apply {
adapter = pagerAdapter adapter = pagerAdapter
currentItem = mPos currentItem = mPos
@ -321,7 +323,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun startSlideshow() { private fun startSlideshow() {
if (getMediaForSlideshow()) { if (getMediaForSlideshow()) {
view_pager.onGlobalLayout { view_pager.onGlobalLayout {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !isDestroyed) { if (!isActivityDestroyed()) {
hideSystemUI() hideSystemUI()
mSlideshowInterval = config.slideshowInterval mSlideshowInterval = config.slideshowInterval
mSlideshowMoveBackwards = config.slideshowMoveBackwards mSlideshowMoveBackwards = config.slideshowMoveBackwards
@ -401,7 +403,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
if (mIsSlideshowActive) { if (mIsSlideshowActive) {
if (getCurrentMedium()!!.isImage() || getCurrentMedium()!!.isGif()) { if (getCurrentMedium()!!.isImage() || getCurrentMedium()!!.isGif()) {
mSlideshowHandler.postDelayed({ mSlideshowHandler.postDelayed({
if (mIsSlideshowActive && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && !isDestroyed) { if (mIsSlideshowActive && !isActivityDestroyed()) {
swipeToNextMedium() swipeToNextMedium()
} }
}, mSlideshowInterval * 1000L) }, mSlideshowInterval * 1000L)
@ -494,52 +496,64 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun saveImageAs() { private fun saveImageAs() {
val currPath = getCurrentPath() val currPath = getCurrentPath()
SaveAsDialog(this, currPath, false) { SaveAsDialog(this, currPath, false) {
Thread({ val selectedFile = File(it)
val selectedFile = File(it) handleSAFDialog(selectedFile) {
handleSAFDialog(selectedFile) { Thread({
toast(R.string.saving) saveImageToFile(currPath, it)
val tmpFile = File(filesDir, ".tmp_${it.getFilenameFromPath()}") }).start()
try { }
val bitmap = BitmapFactory.decodeFile(currPath) }
getFileOutputStream(tmpFile) { }
if (it == null) {
toast(R.string.unknown_error_occurred)
return@getFileOutputStream
}
val oldLastModified = getCurrentFile().lastModified() private fun saveImageToFile(oldPath: String, newPath: String) {
if (currPath.isJpg()) { val newFile = File(newPath)
saveRotation(getCurrentFile(), tmpFile) toast(R.string.saving)
} else { val tmpFile = File(filesDir, ".tmp_${newPath.getFilenameFromPath()}")
saveFile(tmpFile, bitmap, it as FileOutputStream) try {
} val bitmap = BitmapFactory.decodeFile(oldPath)
getFileOutputStream(tmpFile) {
if (tmpFile.length() > 0 && selectedFile.exists()) { if (it == null) {
deleteFile(selectedFile) {} toast(R.string.unknown_error_occurred)
} return@getFileOutputStream
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) {}
}
} }
}).start()
val oldLastModified = getCurrentFile().lastModified()
if (oldPath.isJpg()) {
saveRotation(getCurrentFile(), tmpFile)
} else {
saveFile(tmpFile, bitmap, it as FileOutputStream)
}
if (tmpFile.length() > 0 && newFile.exists()) {
deleteFile(newFile)
}
copyFile(tmpFile, newFile)
scanFile(newFile)
toast(R.string.file_saved)
if (config.keepLastModified) {
newFile.setLastModified(oldLastModified)
updateLastModified(newFile, oldLastModified)
}
it.flush()
it.close()
mRotationDegrees = 0f
invalidateOptionsMenu()
// we cannot refresh a specific image in Glide Cache, so just clear it all
val glide = Glide.get(applicationContext)
glide.clearDiskCache()
runOnUiThread {
glide.clearMemory()
}
}
} catch (e: OutOfMemoryError) {
toast(R.string.out_of_memory_error)
} catch (e: Exception) {
showErrorToast(e)
} finally {
deleteFile(tmpFile)
} }
} }
@ -780,10 +794,10 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun deleteDirectoryIfEmpty() { private fun deleteDirectoryIfEmpty() {
val file = File(mDirectory) val file = File(mDirectory)
if (config.deleteEmptyFolders && !file.isDownloadsFolder() && file.isDirectory && file.listFiles()?.isEmpty() == true) { if (config.deleteEmptyFolders && !file.isDownloadsFolder() && file.isDirectory && file.listFiles()?.isEmpty() == true) {
deleteFile(file, true) {} deleteFile(file, true)
} }
scanPath(mDirectory) {} scanPath(mDirectory)
} }
private fun checkOrientation() { private fun checkOrientation() {

View file

@ -1,22 +1,20 @@
package com.simplemobiletools.gallery.adapters package com.simplemobiletools.gallery.adapters
import android.graphics.PorterDuff import android.graphics.PorterDuff
import android.os.Build
import android.support.v7.view.ActionMode
import android.support.v7.widget.RecyclerView
import android.util.SparseArray import android.util.SparseArray
import android.view.* import android.view.Menu
import com.bignerdranch.android.multiselector.ModalMultiSelectorCallback import android.view.View
import com.bignerdranch.android.multiselector.MultiSelector import android.view.ViewGroup
import com.bignerdranch.android.multiselector.SwappingHolder
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.google.gson.Gson import com.google.gson.Gson
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.dialogs.PropertiesDialog import com.simplemobiletools.commons.dialogs.PropertiesDialog
import com.simplemobiletools.commons.dialogs.RenameItemDialog import com.simplemobiletools.commons.dialogs.RenameItemDialog
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.views.MyRecyclerView
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
import com.simplemobiletools.gallery.dialogs.ExcludeFolderDialog import com.simplemobiletools.gallery.dialogs.ExcludeFolderDialog
import com.simplemobiletools.gallery.dialogs.PickMediumDialog import com.simplemobiletools.gallery.dialogs.PickMediumDialog
import com.simplemobiletools.gallery.extensions.* import com.simplemobiletools.gallery.extensions.*
@ -27,134 +25,103 @@ import kotlinx.android.synthetic.main.directory_item_list.view.*
import java.io.File import java.io.File
import java.util.* import java.util.*
class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Directory>, val listener: DirOperationsListener?, val isPickIntent: Boolean, class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: MutableList<Directory>, val listener: DirOperationsListener?, recyclerView: MyRecyclerView,
val itemClick: (Directory) -> Unit) : RecyclerView.Adapter<DirectoryAdapter.ViewHolder>() { val isPickIntent: Boolean, itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, itemClick) {
private val config = activity.config private val config = activity.config
var actMode: ActionMode? = null
var primaryColor = config.primaryColor
private val multiSelector = MultiSelector()
private val isListViewType = config.viewTypeFolders == VIEW_TYPE_LIST private val isListViewType = config.viewTypeFolders == VIEW_TYPE_LIST
private var itemViews = SparseArray<View>()
private val selectedPositions = HashSet<Int>()
private var textColor = config.textColor
private var pinnedFolders = config.pinnedFolders private var pinnedFolders = config.pinnedFolders
private var scrollHorizontally = config.scrollHorizontally private var scrollHorizontally = config.scrollHorizontally
private var showMediaCount = config.showMediaCount private var showMediaCount = config.showMediaCount
private var animateGifs = config.animateGifs private var animateGifs = config.animateGifs
private var cropThumbnails = config.cropThumbnails private var cropThumbnails = config.cropThumbnails
fun toggleItemSelection(select: Boolean, pos: Int) { init {
if (select) { selectableItemCount = dirs.count()
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)
if (selectedPositions.isEmpty()) {
actMode?.finish()
return
}
updateTitle(selectedPositions.size)
} }
private fun updateTitle(cnt: Int) { override fun getActionMenuId() = R.menu.cab_directories
actMode?.title = "$cnt / ${dirs.size}"
actMode?.invalidate() override fun prepareItemSelection(view: View) {
view.dir_check?.background?.applyColorFilter(primaryColor)
} }
private val adapterListener = object : MyAdapterListener { override fun markItemSelection(select: Boolean, view: View?) {
override fun toggleItemSelectionAdapter(select: Boolean, position: Int) { view?.dir_check?.beVisibleIf(select)
toggleItemSelection(select, position)
}
override fun getSelectedPositions(): HashSet<Int> = selectedPositions
} }
private val multiSelectorMode = object : ModalMultiSelectorCallback(multiSelector) { override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { val layoutType = if (isListViewType) R.layout.directory_item_list else R.layout.directory_item_grid
when (item.itemId) { return createViewHolder(layoutType, parent)
R.id.cab_properties -> showProperties() }
R.id.cab_rename -> renameDir()
R.id.cab_pin -> pinFolders(true) override fun onBindViewHolder(holder: MyRecyclerViewAdapter.ViewHolder, position: Int) {
R.id.cab_unpin -> pinFolders(false) val dir = dirs[position]
R.id.cab_hide -> toggleFoldersVisibility(true) val view = holder.bindView(dir, !isPickIntent) {
R.id.cab_unhide -> toggleFoldersVisibility(false) setupView(it, dir)
R.id.cab_exclude -> tryExcludeFolder() }
R.id.cab_copy_to -> copyMoveTo(true) bindViewHolder(holder, position, view)
R.id.cab_move_to -> copyMoveTo(false) }
R.id.cab_select_all -> selectAll()
R.id.cab_delete -> askConfirmDelete() override fun getItemCount() = dirs.size
R.id.cab_select_photo -> changeAlbumCover(false)
R.id.cab_use_default -> changeAlbumCover(true) override fun prepareActionMode(menu: Menu) {
else -> return false menu.apply {
findItem(R.id.cab_rename).isVisible = selectedPositions.size == 1
findItem(R.id.cab_change_cover_image).isVisible = selectedPositions.size == 1
checkHideBtnVisibility(this)
checkPinBtnVisibility(this)
}
}
override fun actionItemPressed(id: Int) {
when (id) {
R.id.cab_properties -> showProperties()
R.id.cab_rename -> renameDir()
R.id.cab_pin -> pinFolders(true)
R.id.cab_unpin -> pinFolders(false)
R.id.cab_hide -> toggleFoldersVisibility(true)
R.id.cab_unhide -> toggleFoldersVisibility(false)
R.id.cab_exclude -> tryExcludeFolder()
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_select_photo -> changeAlbumCover(false)
R.id.cab_use_default -> changeAlbumCover(true)
}
}
private fun checkHideBtnVisibility(menu: Menu) {
var hiddenCnt = 0
var unhiddenCnt = 0
selectedPositions.mapNotNull { dirs.getOrNull(it)?.path }.forEach {
if (File(it).containsNoMedia()) {
hiddenCnt++
} else {
unhiddenCnt++
} }
return true
} }
override fun onCreateActionMode(actionMode: ActionMode?, menu: Menu?): Boolean { menu.findItem(R.id.cab_hide).isVisible = unhiddenCnt > 0
super.onCreateActionMode(actionMode, menu) menu.findItem(R.id.cab_unhide).isVisible = hiddenCnt > 0
actMode = actionMode }
activity.menuInflater.inflate(R.menu.cab_directories, menu)
return true
}
override fun onPrepareActionMode(actionMode: ActionMode?, menu: Menu): Boolean { private fun checkPinBtnVisibility(menu: Menu) {
menu.findItem(R.id.cab_rename).isVisible = selectedPositions.size <= 1 val pinnedFolders = config.pinnedFolders
menu.findItem(R.id.cab_change_cover_image).isVisible = selectedPositions.size <= 1 var pinnedCnt = 0
var unpinnedCnt = 0
checkHideBtnVisibility(menu) selectedPositions.mapNotNull { dirs.getOrNull(it)?.path }.forEach {
checkPinBtnVisibility(menu) if (pinnedFolders.contains(it)) {
pinnedCnt++
return true } else {
} unpinnedCnt++
override fun onDestroyActionMode(actionMode: ActionMode?) {
super.onDestroyActionMode(actionMode)
selectedPositions.forEach {
itemViews[it]?.dir_check?.beGone()
} }
selectedPositions.clear()
actMode = null
} }
fun checkHideBtnVisibility(menu: Menu) { menu.findItem(R.id.cab_pin).isVisible = unpinnedCnt > 0
var hiddenCnt = 0 menu.findItem(R.id.cab_unpin).isVisible = pinnedCnt > 0
var unhiddenCnt = 0
selectedPositions.mapNotNull { dirs.getOrNull(it)?.path }.forEach {
if (File(it).containsNoMedia()) {
hiddenCnt++
} else {
unhiddenCnt++
}
}
menu.findItem(R.id.cab_hide).isVisible = unhiddenCnt > 0
menu.findItem(R.id.cab_unhide).isVisible = hiddenCnt > 0
}
fun checkPinBtnVisibility(menu: Menu) {
val pinnedFolders = config.pinnedFolders
var pinnedCnt = 0
var unpinnedCnt = 0
selectedPositions.mapNotNull { dirs.getOrNull(it)?.path }.forEach {
if (pinnedFolders.contains(it)) {
pinnedCnt++
} else {
unpinnedCnt++
}
}
menu.findItem(R.id.cab_pin).isVisible = unpinnedCnt > 0
menu.findItem(R.id.cab_unpin).isVisible = pinnedCnt > 0
}
} }
private fun showProperties() { private fun showProperties() {
@ -178,7 +145,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
RenameItemDialog(activity, dir.absolutePath) { RenameItemDialog(activity, dir.absolutePath) {
activity.runOnUiThread { activity.runOnUiThread {
listener?.refreshItems() listener?.refreshItems()
actMode?.finish() finishActMode()
} }
} }
} }
@ -211,14 +178,14 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
private fun tryExcludeFolder() { private fun tryExcludeFolder() {
ExcludeFolderDialog(activity, getSelectedPaths().toList()) { ExcludeFolderDialog(activity, getSelectedPaths().toList()) {
listener?.refreshItems() listener?.refreshItems()
actMode?.finish() finishActMode()
} }
} }
private fun noMediaHandled() { private fun noMediaHandled() {
activity.runOnUiThread { activity.runOnUiThread {
listener?.refreshItems() listener?.refreshItems()
actMode?.finish() finishActMode()
} }
} }
@ -232,7 +199,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
pinnedFolders = config.pinnedFolders pinnedFolders = config.pinnedFolders
listener?.recheckPinnedFolders() listener?.recheckPinnedFolders()
notifyDataSetChanged() notifyDataSetChanged()
actMode?.finish() finishActMode()
} }
private fun copyMoveTo(isCopyOperation: Boolean) { private fun copyMoveTo(isCopyOperation: Boolean) {
@ -248,19 +215,10 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
activity.tryCopyMoveFilesTo(files, isCopyOperation) { activity.tryCopyMoveFilesTo(files, isCopyOperation) {
config.tempFolderPath = "" config.tempFolderPath = ""
listener?.refreshItems() listener?.refreshItems()
actMode?.finish() finishActMode()
} }
} }
fun selectAll() {
val cnt = dirs.size
for (i in 0 until cnt) {
selectedPositions.add(i)
notifyItemChanged(i)
}
updateTitle(cnt)
}
private fun askConfirmDelete() { private fun askConfirmDelete() {
ConfirmationDialog(activity) { ConfirmationDialog(activity) {
deleteFiles() deleteFiles()
@ -302,7 +260,8 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
.forEachIndexed { curIndex, i -> newItems.put(curIndex, itemViews[i]) } .forEachIndexed { curIndex, i -> newItems.put(curIndex, itemViews[i]) }
itemViews = newItems itemViews = newItems
actMode?.finish() selectableItemCount = dirs.size
finishActMode()
} }
} }
@ -337,7 +296,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
private fun storeCovers(albumCovers: ArrayList<AlbumCover>) { private fun storeCovers(albumCovers: ArrayList<AlbumCover>) {
activity.config.albumCovers = Gson().toJson(albumCovers) activity.config.albumCovers = Gson().toJson(albumCovers)
actMode?.finish() finishActMode()
listener?.refreshItems() listener?.refreshItems()
} }
@ -347,30 +306,18 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
return paths return paths
} }
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
val layoutType = if (isListViewType) R.layout.directory_item_list else R.layout.directory_item_grid
val view = LayoutInflater.from(parent?.context).inflate(layoutType, parent, false)
return ViewHolder(view, adapterListener, activity, multiSelectorMode, multiSelector, listener, isPickIntent, itemClick)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val dir = dirs[position]
itemViews.put(position, holder.bindView(dir, pinnedFolders.contains(dir.path), scrollHorizontally, isListViewType, textColor, showMediaCount, animateGifs, cropThumbnails))
toggleItemSelection(selectedPositions.contains(position), position)
holder.itemView.tag = holder
}
override fun onViewRecycled(holder: ViewHolder?) { override fun onViewRecycled(holder: ViewHolder?) {
super.onViewRecycled(holder) super.onViewRecycled(holder)
holder?.stopLoad() if (!activity.isActivityDestroyed()) {
Glide.with(activity).clear(holder?.itemView?.dir_thumbnail)
}
} }
override fun getItemCount() = dirs.size
fun updateDirs(newDirs: ArrayList<Directory>) { fun updateDirs(newDirs: ArrayList<Directory>) {
dirs = newDirs dirs = newDirs
selectableItemCount = dirs.size
notifyDataSetChanged() notifyDataSetChanged()
actMode?.finish() finishActMode()
} }
fun updateAnimateGifs(animateGifs: Boolean) { fun updateAnimateGifs(animateGifs: Boolean) {
@ -393,117 +340,31 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
notifyDataSetChanged() notifyDataSetChanged()
} }
fun updateTextColor(textColor: Int) { private fun setupView(view: View, directory: Directory) {
this.textColor = textColor view.apply {
notifyDataSetChanged() dir_name.text = directory.name
} dir_path?.text = "${directory.path.substringBeforeLast("/")}/"
photo_cnt.text = directory.mediaCnt.toString()
activity.loadImage(directory.tmb, dir_thumbnail, scrollHorizontally, animateGifs, cropThumbnails)
dir_pin.beVisibleIf(pinnedFolders.contains(directory.path))
dir_sd_card.beVisibleIf(activity.isPathOnSD(directory.path))
photo_cnt.beVisibleIf(showMediaCount)
fun selectItem(pos: Int) { if (isListViewType) {
toggleItemSelection(true, pos) dir_name.setTextColor(textColor)
} dir_path.setTextColor(textColor)
photo_cnt.setTextColor(textColor)
fun selectRange(from: Int, to: Int, min: Int, max: Int) { dir_pin.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
if (from == to) { dir_sd_card.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
(min..max).filter { it != from }
.forEach { toggleItemSelection(false, it) }
return
}
if (to < from) {
for (i in to..from)
toggleItemSelection(true, i)
if (min > -1 && min < to) {
(min until to).filter { it != from }
.forEach { toggleItemSelection(false, it) }
}
if (max > -1) {
for (i in from + 1..max)
toggleItemSelection(false, i)
}
} else {
for (i in from..to)
toggleItemSelection(true, i)
if (max > -1 && max > to) {
(to + 1..max).filter { it != from }
.forEach { toggleItemSelection(false, it) }
}
if (min > -1) {
for (i in min until from)
toggleItemSelection(false, i)
} }
} }
} }
class ViewHolder(val view: View, val adapterListener: MyAdapterListener, val activity: SimpleActivity, val multiSelectorCallback: ModalMultiSelectorCallback,
val multiSelector: MultiSelector, val listener: DirOperationsListener?, val isPickIntent: Boolean, val itemClick: (Directory) -> (Unit)) :
SwappingHolder(view, MultiSelector()) {
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, 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)
dir_path.setTextColor(textColor)
photo_cnt.setTextColor(textColor)
dir_pin.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
dir_sd_card.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
}
setOnClickListener { viewClicked(directory) }
setOnLongClickListener { if (isPickIntent) viewClicked(directory) else viewLongClicked(); true }
}
return itemView
}
private fun viewClicked(directory: Directory) {
if (multiSelector.isSelectable) {
val isSelected = adapterListener.getSelectedPositions().contains(adapterPosition)
adapterListener.toggleItemSelectionAdapter(!isSelected, adapterPosition)
} else {
itemClick(directory)
}
}
private fun viewLongClicked() {
if (listener != null) {
if (!multiSelector.isSelectable) {
activity.startSupportActionMode(multiSelectorCallback)
adapterListener.toggleItemSelectionAdapter(true, adapterPosition)
}
listener.itemLongClicked(adapterPosition)
}
}
fun stopLoad() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !activity.isDestroyed)
Glide.with(activity).clear(view.dir_thumbnail)
}
}
interface MyAdapterListener {
fun toggleItemSelectionAdapter(select: Boolean, position: Int)
fun getSelectedPositions(): HashSet<Int>
}
interface DirOperationsListener { interface DirOperationsListener {
fun refreshItems() fun refreshItems()
fun tryDeleteFolders(folders: ArrayList<File>) fun tryDeleteFolders(folders: ArrayList<File>)
fun itemLongClicked(position: Int)
fun recheckPinnedFolders() fun recheckPinnedFolders()
} }
} }

View file

@ -0,0 +1,99 @@
package com.simplemobiletools.gallery.adapters
import android.util.SparseArray
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.interfaces.RefreshRecyclerViewListener
import com.simplemobiletools.commons.views.MyRecyclerView
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.extensions.config
import kotlinx.android.synthetic.main.item_manage_folder.view.*
import java.util.*
class ManageFoldersAdapter(activity: BaseSimpleActivity, var folders: ArrayList<String>, val isShowingExcludedFolders: Boolean, val listener: RefreshRecyclerViewListener?,
recyclerView: MyRecyclerView, itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, itemClick) {
private val config = activity.config
init {
selectableItemCount = folders.size
}
override fun getActionMenuId() = R.menu.cab_delete_only
override fun prepareActionMode(menu: Menu) {}
override fun prepareItemSelection(view: View) {}
override fun markItemSelection(select: Boolean, view: View?) {
view?.manage_folder_holder?.isSelected = select
}
override fun actionItemPressed(id: Int) {
when (id) {
R.id.cab_delete -> askConfirmDelete()
}
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int) = createViewHolder(R.layout.item_manage_folder, parent)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val folder = folders[position]
val view = holder.bindView(folder) {
setupView(it, folder)
}
bindViewHolder(holder, position, view)
}
override fun getItemCount() = folders.size
private fun setupView(view: View, folder: String) {
view.apply {
manage_folder_title.apply {
text = folder
setTextColor(config.textColor)
}
}
}
private fun askConfirmDelete() {
ConfirmationDialog(activity) {
deleteSelection()
}
}
private fun deleteSelection() {
val removeFolders = ArrayList<String>(selectedPositions.size)
selectedPositions.sortedDescending().forEach {
val folder = folders[it]
removeFolders.add(folder)
notifyItemRemoved(it)
itemViews.put(it, null)
if (isShowingExcludedFolders) {
config.removeExcludedFolder(folder)
} else {
config.removeIncludedFolder(folder)
}
}
folders.removeAll(removeFolders)
selectedPositions.clear()
val newItems = SparseArray<View>()
(0 until itemViews.size())
.filter { itemViews[it] != null }
.forEachIndexed { curIndex, i -> newItems.put(curIndex, itemViews[i]) }
itemViews = newItems
selectableItemCount = folders.size
finishActMode()
if (folders.isEmpty()) {
listener?.refreshItems()
}
}
}

View file

@ -2,21 +2,20 @@ package com.simplemobiletools.gallery.adapters
import android.graphics.PorterDuff import android.graphics.PorterDuff
import android.net.Uri import android.net.Uri
import android.os.Build
import android.support.v7.view.ActionMode
import android.support.v7.widget.RecyclerView
import android.util.SparseArray import android.util.SparseArray
import android.view.* import android.view.Menu
import com.bignerdranch.android.multiselector.ModalMultiSelectorCallback import android.view.View
import com.bignerdranch.android.multiselector.MultiSelector import android.view.ViewGroup
import com.bignerdranch.android.multiselector.SwappingHolder
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
import com.simplemobiletools.commons.dialogs.PropertiesDialog import com.simplemobiletools.commons.dialogs.PropertiesDialog
import com.simplemobiletools.commons.dialogs.RenameItemDialog import com.simplemobiletools.commons.dialogs.RenameItemDialog
import com.simplemobiletools.commons.extensions.beGone import com.simplemobiletools.commons.extensions.applyColorFilter
import com.simplemobiletools.commons.extensions.beVisibleIf import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.commons.extensions.isActivityDestroyed
import com.simplemobiletools.commons.views.MyRecyclerView
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
import com.simplemobiletools.gallery.dialogs.DeleteWithRememberDialog import com.simplemobiletools.gallery.dialogs.DeleteWithRememberDialog
import com.simplemobiletools.gallery.extensions.* import com.simplemobiletools.gallery.extensions.*
import com.simplemobiletools.gallery.helpers.VIEW_TYPE_LIST import com.simplemobiletools.gallery.helpers.VIEW_TYPE_LIST
@ -25,119 +24,88 @@ import kotlinx.android.synthetic.main.photo_video_item_grid.view.*
import java.io.File import java.io.File
import java.util.* import java.util.*
class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>, val listener: MediaOperationsListener?, val isAGetIntent: Boolean, class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>, val listener: MediaOperationsListener?, val isAGetIntent: Boolean,
val allowMultiplePicks: Boolean, val itemClick: (Medium) -> Unit) : RecyclerView.Adapter<MediaAdapter.ViewHolder>() { val allowMultiplePicks: Boolean, recyclerView: MyRecyclerView, itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, itemClick) {
private val config = activity.config private val config = activity.config
var actMode: ActionMode? = null
var primaryColor = config.primaryColor
private val multiSelector = MultiSelector()
private val isListViewType = config.viewTypeFiles == VIEW_TYPE_LIST private val isListViewType = config.viewTypeFiles == VIEW_TYPE_LIST
private var skipConfirmationDialog = false private var skipConfirmationDialog = false
private var itemViews = SparseArray<View>()
private val selectedPositions = HashSet<Int>()
private var scrollHorizontally = config.scrollHorizontally private var scrollHorizontally = config.scrollHorizontally
private var animateGifs = config.animateGifs private var animateGifs = config.animateGifs
private var cropThumbnails = config.cropThumbnails private var cropThumbnails = config.cropThumbnails
private var textColor = config.textColor
private var displayFilenames = config.displayFileNames private var displayFilenames = config.displayFileNames
fun toggleItemSelection(select: Boolean, pos: Int) { init {
if (select) { selectableItemCount = media.count()
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)
if (selectedPositions.isEmpty()) {
actMode?.finish()
return
}
updateTitle(selectedPositions.size)
} }
private fun updateTitle(cnt: Int) { override fun getActionMenuId() = R.menu.cab_media
actMode?.title = "$cnt / ${media.size}"
actMode?.invalidate() override fun prepareItemSelection(view: View) {
view.medium_check?.background?.applyColorFilter(primaryColor)
} }
private val adapterListener = object : MyAdapterListener { override fun markItemSelection(select: Boolean, view: View?) {
override fun toggleItemSelectionAdapter(select: Boolean, position: Int) { view?.medium_check?.beVisibleIf(select)
toggleItemSelection(select, position)
}
override fun getSelectedPositions(): HashSet<Int> = selectedPositions
} }
private val multiSelectorMode = object : ModalMultiSelectorCallback(multiSelector) { override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { val layoutType = if (isListViewType) R.layout.photo_video_item_list else R.layout.photo_video_item_grid
when (item.itemId) { return createViewHolder(layoutType, parent)
R.id.cab_confirm_selection -> confirmSelection() }
R.id.cab_properties -> showProperties()
R.id.cab_rename -> renameFile() override fun onBindViewHolder(holder: MyRecyclerViewAdapter.ViewHolder, position: Int) {
R.id.cab_edit -> editFile() val medium = media[position]
R.id.cab_hide -> toggleFileVisibility(true) val view = holder.bindView(medium, !allowMultiplePicks) {
R.id.cab_unhide -> toggleFileVisibility(false) setupView(it, medium)
R.id.cab_share -> shareMedia() }
R.id.cab_copy_to -> copyMoveTo(true) bindViewHolder(holder, position, view)
R.id.cab_move_to -> copyMoveTo(false) }
R.id.cab_select_all -> selectAll()
R.id.cab_open_with -> activity.openFile(Uri.fromFile(getCurrentFile()), true) override fun getItemCount() = media.size
R.id.cab_set_as -> activity.setAs(Uri.fromFile(getCurrentFile()))
R.id.cab_delete -> checkDeleteConfirmation() override fun prepareActionMode(menu: Menu) {
else -> return false menu.apply {
findItem(R.id.cab_rename).isVisible = selectedPositions.size == 1
findItem(R.id.cab_open_with).isVisible = selectedPositions.size == 1
findItem(R.id.cab_confirm_selection).isVisible = isAGetIntent && allowMultiplePicks && selectedPositions.size > 0
checkHideBtnVisibility(this)
}
}
override fun actionItemPressed(id: Int) {
when (id) {
R.id.cab_confirm_selection -> confirmSelection()
R.id.cab_properties -> showProperties()
R.id.cab_rename -> renameFile()
R.id.cab_edit -> editFile()
R.id.cab_hide -> toggleFileVisibility(true)
R.id.cab_unhide -> toggleFileVisibility(false)
R.id.cab_share -> shareMedia()
R.id.cab_copy_to -> copyMoveTo(true)
R.id.cab_move_to -> copyMoveTo(false)
R.id.cab_select_all -> selectAll()
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()
}
}
private fun checkHideBtnVisibility(menu: Menu) {
var hiddenCnt = 0
var unhiddenCnt = 0
selectedPositions.mapNotNull { media.getOrNull(it) }.forEach {
if (it.name.startsWith('.')) {
hiddenCnt++
} else {
unhiddenCnt++
} }
return true
} }
override fun onCreateActionMode(actionMode: ActionMode?, menu: Menu?): Boolean { menu.findItem(R.id.cab_hide).isVisible = unhiddenCnt > 0
super.onCreateActionMode(actionMode, menu) menu.findItem(R.id.cab_unhide).isVisible = hiddenCnt > 0
actMode = actionMode
activity.menuInflater.inflate(R.menu.cab_media, menu)
return true
}
override fun onPrepareActionMode(actionMode: ActionMode?, menu: Menu): Boolean {
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)
return true
}
override fun onDestroyActionMode(actionMode: ActionMode?) {
super.onDestroyActionMode(actionMode)
selectedPositions.forEach {
itemViews[it]?.medium_check?.beGone()
}
selectedPositions.clear()
actMode = null
}
fun checkHideBtnVisibility(menu: Menu) {
var hiddenCnt = 0
var unhiddenCnt = 0
selectedPositions.mapNotNull { media.getOrNull(it) }.forEach {
if (it.name.startsWith('.')) {
hiddenCnt++
} else {
unhiddenCnt++
}
}
menu.findItem(R.id.cab_hide).isVisible = unhiddenCnt > 0
menu.findItem(R.id.cab_unhide).isVisible = hiddenCnt > 0
}
} }
private fun confirmSelection() { private fun confirmSelection() {
@ -159,25 +127,25 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
RenameItemDialog(activity, getCurrentFile().absolutePath) { RenameItemDialog(activity, getCurrentFile().absolutePath) {
activity.runOnUiThread { activity.runOnUiThread {
listener?.refreshItems() listener?.refreshItems()
actMode?.finish() finishActMode()
} }
} }
} }
private fun editFile() { private fun editFile() {
activity.openEditor(Uri.fromFile(getCurrentFile())) activity.openEditor(Uri.fromFile(getCurrentFile()))
actMode?.finish() finishActMode()
} }
private fun toggleFileVisibility(hide: Boolean) { private fun toggleFileVisibility(hide: Boolean) {
Thread({ Thread({
getSelectedMedia().forEach { getSelectedMedia().forEach {
val oldFile = File(it.path) val oldFile = File(it.path)
activity.toggleFileVisibility(oldFile, hide) {} activity.toggleFileVisibility(oldFile, hide)
} }
activity.runOnUiThread { activity.runOnUiThread {
listener?.refreshItems() listener?.refreshItems()
actMode?.finish() finishActMode()
} }
}).start() }).start()
} }
@ -199,20 +167,10 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
if (!isCopyOperation) { if (!isCopyOperation) {
listener?.refreshItems() listener?.refreshItems()
} }
actMode?.finish() finishActMode()
} }
} }
fun selectAll() {
val cnt = media.size
for (i in 0 until cnt) {
selectedPositions.add(i)
multiSelector.setSelected(i, 0, true)
notifyItemChanged(i)
}
updateTitle(cnt)
}
private fun checkDeleteConfirmation() { private fun checkDeleteConfirmation() {
if (skipConfirmationDialog) { if (skipConfirmationDialog) {
deleteConfirmed() deleteConfirmed()
@ -243,7 +201,7 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
val removeMedia = ArrayList<Medium>(selectedPositions.size) val removeMedia = ArrayList<Medium>(selectedPositions.size)
if (media.size <= selectedPositions.first()) { if (media.size <= selectedPositions.first()) {
actMode?.finish() finishActMode()
return return
} }
@ -257,7 +215,6 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
} }
media.removeAll(removeMedia) media.removeAll(removeMedia)
selectedPositions.clear()
listener?.deleteFiles(files) listener?.deleteFiles(files)
val newItems = SparseArray<View>() val newItems = SparseArray<View>()
@ -266,7 +223,8 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
.forEachIndexed { curIndex, i -> newItems.put(curIndex, itemViews[i]) } .forEachIndexed { curIndex, i -> newItems.put(curIndex, itemViews[i]) }
itemViews = newItems itemViews = newItems
actMode?.finish() selectableItemCount = media.size
finishActMode()
} }
} }
@ -276,29 +234,18 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
return selectedMedia return selectedMedia
} }
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 || !isAGetIntent, itemClick)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
itemViews.put(position, holder.bindView(media[position], displayFilenames, scrollHorizontally, isListViewType, textColor, animateGifs, cropThumbnails))
toggleItemSelection(selectedPositions.contains(position), position)
holder.itemView.tag = holder
}
override fun onViewRecycled(holder: ViewHolder?) { override fun onViewRecycled(holder: ViewHolder?) {
super.onViewRecycled(holder) super.onViewRecycled(holder)
holder?.stopLoad() if (!activity.isActivityDestroyed()) {
Glide.with(activity).clear(holder?.itemView?.medium_thumbnail)
}
} }
override fun getItemCount() = media.size
fun updateMedia(newMedia: ArrayList<Medium>) { fun updateMedia(newMedia: ArrayList<Medium>) {
media = newMedia media = newMedia
selectableItemCount = media.size
notifyDataSetChanged() notifyDataSetChanged()
actMode?.finish() finishActMode()
} }
fun updateDisplayFilenames(displayFilenames: Boolean) { fun updateDisplayFilenames(displayFilenames: Boolean) {
@ -321,112 +268,25 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
notifyDataSetChanged() notifyDataSetChanged()
} }
fun updateTextColor(textColor: Int) { private fun setupView(view: View, medium: Medium) {
this.textColor = textColor view.apply {
notifyDataSetChanged() play_outline.beVisibleIf(medium.video)
} photo_name.beVisibleIf(displayFilenames || isListViewType)
photo_name.text = medium.name
activity.loadImage(medium.path, medium_thumbnail, scrollHorizontally, animateGifs, cropThumbnails)
fun selectItem(pos: Int) { if (isListViewType) {
toggleItemSelection(true, pos) photo_name.setTextColor(textColor)
} play_outline.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
fun selectRange(from: Int, to: Int, min: Int, max: Int) {
if (from == to) {
(min..max).filter { it != from }
.forEach { toggleItemSelection(false, it) }
return
}
if (to < from) {
for (i in to..from)
toggleItemSelection(true, i)
if (min > -1 && min < to) {
(min until to).filter { it != from }
.forEach { toggleItemSelection(false, it) }
}
if (max > -1) {
for (i in from + 1..max)
toggleItemSelection(false, i)
}
} else {
for (i in from..to)
toggleItemSelection(true, i)
if (max > -1 && max > to) {
(to + 1..max).filter { it != from }
.forEach { toggleItemSelection(false, it) }
}
if (min > -1) {
for (i in min until from)
toggleItemSelection(false, i)
} }
} }
} }
class ViewHolder(val view: View, val adapterListener: MyAdapterListener, val activity: SimpleActivity, val multiSelectorCallback: ModalMultiSelectorCallback,
val multiSelector: MultiSelector, val listener: MediaOperationsListener?, val allowMultiplePicks: Boolean,
val itemClick: (Medium) -> (Unit)) :
SwappingHolder(view, MultiSelector()) {
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, scrollHorizontally, animateGifs, cropThumbnails)
if (isListViewType) {
photo_name.setTextColor(textColor)
play_outline.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
}
setOnClickListener { viewClicked(medium) }
setOnLongClickListener { if (allowMultiplePicks) viewLongClicked() else viewClicked(medium); true }
}
return itemView
}
private fun viewClicked(medium: Medium) {
if (multiSelector.isSelectable) {
val isSelected = adapterListener.getSelectedPositions().contains(adapterPosition)
adapterListener.toggleItemSelectionAdapter(!isSelected, adapterPosition)
} else {
itemClick(medium)
}
}
private fun viewLongClicked() {
if (listener != null) {
if (!multiSelector.isSelectable) {
activity.startSupportActionMode(multiSelectorCallback)
adapterListener.toggleItemSelectionAdapter(true, adapterPosition)
}
listener.itemLongClicked(adapterPosition)
}
}
fun stopLoad() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !activity.isDestroyed)
Glide.with(activity).clear(view.medium_thumbnail)
}
}
interface MyAdapterListener {
fun toggleItemSelectionAdapter(select: Boolean, position: Int)
fun getSelectedPositions(): HashSet<Int>
}
interface MediaOperationsListener { interface MediaOperationsListener {
fun refreshItems() fun refreshItems()
fun deleteFiles(files: ArrayList<File>) fun deleteFiles(files: ArrayList<File>)
fun itemLongClicked(position: Int)
fun selectedPaths(paths: ArrayList<String>) fun selectedPaths(paths: ArrayList<String>)
} }
} }

View file

@ -4,15 +4,15 @@ import android.content.DialogInterface
import android.support.v7.app.AlertDialog import android.support.v7.app.AlertDialog
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.beVisibleIf import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
import com.simplemobiletools.gallery.extensions.config import com.simplemobiletools.gallery.extensions.config
import kotlinx.android.synthetic.main.dialog_change_sorting.view.* import kotlinx.android.synthetic.main.dialog_change_sorting.view.*
class ChangeSortingDialog(val activity: SimpleActivity, val isDirectorySorting: Boolean, showFolderCheckbox: Boolean, class ChangeSortingDialog(val activity: BaseSimpleActivity, val isDirectorySorting: Boolean, showFolderCheckbox: Boolean,
val path: String = "", val callback: () -> Unit) : val path: String = "", val callback: () -> Unit) :
DialogInterface.OnClickListener { DialogInterface.OnClickListener {
private var currSorting = 0 private var currSorting = 0

View file

@ -5,15 +5,15 @@ import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.RadioButton import android.widget.RadioButton
import android.widget.RadioGroup import android.widget.RadioGroup
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.beVisibleIf import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.commons.extensions.getBasePath import com.simplemobiletools.commons.extensions.getBasePath
import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
import com.simplemobiletools.gallery.extensions.config import com.simplemobiletools.gallery.extensions.config
import kotlinx.android.synthetic.main.dialog_exclude_folder.view.* import kotlinx.android.synthetic.main.dialog_exclude_folder.view.*
class ExcludeFolderDialog(val activity: SimpleActivity, val selectedPaths: List<String>, val callback: () -> Unit) { class ExcludeFolderDialog(val activity: BaseSimpleActivity, val selectedPaths: List<String>, val callback: () -> Unit) {
val alternativePaths = getAlternativePathsList() val alternativePaths = getAlternativePathsList()
var radioGroup: RadioGroup? = null var radioGroup: RadioGroup? = null

View file

@ -3,16 +3,16 @@ package com.simplemobiletools.gallery.dialogs
import android.support.v7.app.AlertDialog import android.support.v7.app.AlertDialog
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
import com.simplemobiletools.gallery.extensions.config import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.helpers.GIFS import com.simplemobiletools.gallery.helpers.GIFS
import com.simplemobiletools.gallery.helpers.IMAGES import com.simplemobiletools.gallery.helpers.IMAGES
import com.simplemobiletools.gallery.helpers.VIDEOS import com.simplemobiletools.gallery.helpers.VIDEOS
import kotlinx.android.synthetic.main.dialog_filter_media.view.* import kotlinx.android.synthetic.main.dialog_filter_media.view.*
class FilterMediaDialog(val activity: SimpleActivity, val callback: (result: Int) -> Unit) { class FilterMediaDialog(val activity: BaseSimpleActivity, val callback: (result: Int) -> Unit) {
private var view: View = LayoutInflater.from(activity).inflate(R.layout.dialog_filter_media, null) private var view: View = LayoutInflater.from(activity).inflate(R.layout.dialog_filter_media, null)
init { init {

View file

@ -3,6 +3,7 @@ package com.simplemobiletools.gallery.dialogs
import android.support.v7.app.AlertDialog import android.support.v7.app.AlertDialog
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity import com.simplemobiletools.gallery.activities.SimpleActivity
@ -10,7 +11,7 @@ import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.helpers.* import com.simplemobiletools.gallery.helpers.*
import kotlinx.android.synthetic.main.dialog_manage_extended_details.view.* import kotlinx.android.synthetic.main.dialog_manage_extended_details.view.*
class ManageExtendedDetailsDialog(val activity: SimpleActivity, val callback: (result: Int) -> Unit) { class ManageExtendedDetailsDialog(val activity: BaseSimpleActivity, val callback: (result: Int) -> Unit) {
private var view: View = LayoutInflater.from(activity).inflate(R.layout.dialog_manage_extended_details, null) private var view: View = LayoutInflater.from(activity).inflate(R.layout.dialog_manage_extended_details, null)
init { init {

View file

@ -3,15 +3,16 @@ package com.simplemobiletools.gallery.dialogs
import android.support.v7.app.AlertDialog import android.support.v7.app.AlertDialog
import android.support.v7.widget.GridLayoutManager import android.support.v7.widget.GridLayoutManager
import android.view.LayoutInflater import android.view.LayoutInflater
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.dialogs.FilePickerDialog import com.simplemobiletools.commons.dialogs.FilePickerDialog
import com.simplemobiletools.commons.extensions.beGoneIf import com.simplemobiletools.commons.extensions.beGoneIf
import com.simplemobiletools.commons.extensions.beVisibleIf import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
import com.simplemobiletools.gallery.adapters.DirectoryAdapter import com.simplemobiletools.gallery.adapters.DirectoryAdapter
import com.simplemobiletools.gallery.asynctasks.GetDirectoriesAsynctask import com.simplemobiletools.gallery.asynctasks.GetDirectoriesAsynctask
import com.simplemobiletools.gallery.extensions.addTempFolderIfNeeded
import com.simplemobiletools.gallery.extensions.config import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.extensions.getCachedDirectories import com.simplemobiletools.gallery.extensions.getCachedDirectories
import com.simplemobiletools.gallery.extensions.getSortedDirectories import com.simplemobiletools.gallery.extensions.getSortedDirectories
@ -19,7 +20,7 @@ import com.simplemobiletools.gallery.helpers.VIEW_TYPE_GRID
import com.simplemobiletools.gallery.models.Directory import com.simplemobiletools.gallery.models.Directory
import kotlinx.android.synthetic.main.dialog_directory_picker.view.* import kotlinx.android.synthetic.main.dialog_directory_picker.view.*
class PickDirectoryDialog(val activity: SimpleActivity, val sourcePath: String, val callback: (path: String) -> Unit) { class PickDirectoryDialog(val activity: BaseSimpleActivity, val sourcePath: String, val callback: (path: String) -> Unit) {
var dialog: AlertDialog var dialog: AlertDialog
var shownDirectories = ArrayList<Directory>() var shownDirectories = ArrayList<Directory>()
var view = LayoutInflater.from(activity).inflate(R.layout.dialog_directory_picker, null) var view = LayoutInflater.from(activity).inflate(R.layout.dialog_directory_picker, null)
@ -62,8 +63,8 @@ class PickDirectoryDialog(val activity: SimpleActivity, val sourcePath: String,
return return
shownDirectories = dirs shownDirectories = dirs
val adapter = DirectoryAdapter(activity, dirs, null, true) { val adapter = DirectoryAdapter(activity, dirs, null, view.directories_grid, true) {
if (it.path.trimEnd('/') == sourcePath) { if ((it as Directory).path.trimEnd('/') == sourcePath) {
activity.toast(R.string.source_and_destination_same) activity.toast(R.string.source_and_destination_same)
return@DirectoryAdapter return@DirectoryAdapter
} else { } else {

View file

@ -3,11 +3,11 @@ package com.simplemobiletools.gallery.dialogs
import android.support.v7.app.AlertDialog import android.support.v7.app.AlertDialog
import android.support.v7.widget.GridLayoutManager import android.support.v7.widget.GridLayoutManager
import android.view.LayoutInflater import android.view.LayoutInflater
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.beGoneIf import com.simplemobiletools.commons.extensions.beGoneIf
import com.simplemobiletools.commons.extensions.beVisibleIf import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
import com.simplemobiletools.gallery.adapters.MediaAdapter import com.simplemobiletools.gallery.adapters.MediaAdapter
import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask
import com.simplemobiletools.gallery.extensions.config import com.simplemobiletools.gallery.extensions.config
@ -16,7 +16,7 @@ import com.simplemobiletools.gallery.helpers.VIEW_TYPE_GRID
import com.simplemobiletools.gallery.models.Medium import com.simplemobiletools.gallery.models.Medium
import kotlinx.android.synthetic.main.dialog_medium_picker.view.* import kotlinx.android.synthetic.main.dialog_medium_picker.view.*
class PickMediumDialog(val activity: SimpleActivity, val path: String, val callback: (path: String) -> Unit) { class PickMediumDialog(val activity: BaseSimpleActivity, val path: String, val callback: (path: String) -> Unit) {
var dialog: AlertDialog var dialog: AlertDialog
var shownMedia = ArrayList<Medium>() var shownMedia = ArrayList<Medium>()
val view = LayoutInflater.from(activity).inflate(R.layout.dialog_medium_picker, null) val view = LayoutInflater.from(activity).inflate(R.layout.dialog_medium_picker, null)
@ -58,8 +58,8 @@ class PickMediumDialog(val activity: SimpleActivity, val path: String, val callb
return return
shownMedia = media shownMedia = media
val adapter = MediaAdapter(activity, media, null, true, false) { val adapter = MediaAdapter(activity, media, null, true, false, view.media_grid) {
callback(it.path) callback((it as Medium).path)
dialog.dismiss() dialog.dismiss()
} }

View file

@ -7,14 +7,14 @@ import android.text.TextWatcher
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.WindowManager import android.view.WindowManager
import android.widget.EditText import android.widget.EditText
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.extensions.value import com.simplemobiletools.commons.extensions.value
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
import kotlinx.android.synthetic.main.resize_image.view.* import kotlinx.android.synthetic.main.resize_image.view.*
class ResizeDialog(val activity: SimpleActivity, val size: Point, val callback: (newSize: Point) -> Unit) { class ResizeDialog(val activity: BaseSimpleActivity, val size: Point, val callback: (newSize: Point) -> Unit) {
init { init {
val view = LayoutInflater.from(activity).inflate(R.layout.resize_image, null) val view = LayoutInflater.from(activity).inflate(R.layout.resize_image, null)
val widthView = view.image_width val widthView = view.image_width

View file

@ -3,15 +3,15 @@ package com.simplemobiletools.gallery.dialogs
import android.support.v7.app.AlertDialog import android.support.v7.app.AlertDialog
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.WindowManager import android.view.WindowManager
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.dialogs.FilePickerDialog import com.simplemobiletools.commons.dialogs.FilePickerDialog
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
import kotlinx.android.synthetic.main.dialog_save_as.view.* import kotlinx.android.synthetic.main.dialog_save_as.view.*
import java.io.File import java.io.File
class SaveAsDialog(val activity: SimpleActivity, val path: String, val appendFilename: Boolean, val callback: (savePath: String) -> Unit) { class SaveAsDialog(val activity: BaseSimpleActivity, val path: String, val appendFilename: Boolean, val callback: (savePath: String) -> Unit) {
init { init {
var realPath = File(path).parent.trimEnd('/') var realPath = File(path).parent.trimEnd('/')

View file

@ -4,16 +4,16 @@ import android.support.v7.app.AlertDialog
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.hideKeyboard import com.simplemobiletools.commons.extensions.hideKeyboard
import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
import com.simplemobiletools.gallery.extensions.config import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.helpers.SLIDESHOW_DEFAULT_INTERVAL import com.simplemobiletools.gallery.helpers.SLIDESHOW_DEFAULT_INTERVAL
import kotlinx.android.synthetic.main.dialog_slideshow.view.* import kotlinx.android.synthetic.main.dialog_slideshow.view.*
class SlideshowDialog(val activity: SimpleActivity, val callback: () -> Unit) { class SlideshowDialog(val activity: BaseSimpleActivity, val callback: () -> Unit) {
val view: View val view: View
init { init {

View file

@ -14,11 +14,13 @@ import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.gallery.BuildConfig import com.simplemobiletools.gallery.BuildConfig
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity import com.simplemobiletools.gallery.activities.SimpleActivity
import com.simplemobiletools.gallery.dialogs.PickDirectoryDialog
import com.simplemobiletools.gallery.helpers.NOMEDIA import com.simplemobiletools.gallery.helpers.NOMEDIA
import com.simplemobiletools.gallery.models.Directory import com.simplemobiletools.gallery.models.Directory
import com.simplemobiletools.gallery.models.Medium import com.simplemobiletools.gallery.models.Medium
@ -89,7 +91,7 @@ fun AppCompatActivity.hideSystemUI() {
View.SYSTEM_UI_FLAG_IMMERSIVE View.SYSTEM_UI_FLAG_IMMERSIVE
} }
fun SimpleActivity.addNoMedia(path: String, callback: () -> Unit) { fun BaseSimpleActivity.addNoMedia(path: String, callback: () -> Unit) {
val file = File(path, NOMEDIA) val file = File(path, NOMEDIA)
if (file.exists()) if (file.exists())
return return
@ -116,14 +118,14 @@ fun SimpleActivity.addNoMedia(path: String, callback: () -> Unit) {
} }
} }
fun SimpleActivity.removeNoMedia(path: String, callback: () -> Unit) { fun BaseSimpleActivity.removeNoMedia(path: String, callback: (() -> Unit)? = null) {
val file = File(path, NOMEDIA) val file = File(path, NOMEDIA)
deleteFile(file) { deleteFile(file) {
callback() callback?.invoke()
} }
} }
fun SimpleActivity.toggleFileVisibility(oldFile: File, hide: Boolean, callback: (newFile: File) -> Unit) { fun BaseSimpleActivity.toggleFileVisibility(oldFile: File, hide: Boolean, callback: ((newFile: File) -> Unit)? = null) {
val path = oldFile.parent val path = oldFile.parent
var filename = oldFile.name var filename = oldFile.name
filename = if (hide) { filename = if (hide) {
@ -133,7 +135,7 @@ fun SimpleActivity.toggleFileVisibility(oldFile: File, hide: Boolean, callback:
} }
val newFile = File(path, filename) val newFile = File(path, filename)
renameFile(oldFile, newFile) { renameFile(oldFile, newFile) {
callback(newFile) callback?.invoke(newFile)
} }
} }
@ -158,10 +160,35 @@ fun Activity.loadImage(path: String, target: MySquareImageView, horizontalScroll
target.scaleType = if (cropThumbnails) ImageView.ScaleType.CENTER_CROP else ImageView.ScaleType.FIT_CENTER target.scaleType = if (cropThumbnails) ImageView.ScaleType.CENTER_CROP else ImageView.ScaleType.FIT_CENTER
} catch (e: Exception) { } catch (e: Exception) {
loadJpg(path, target, cropThumbnails) loadJpg(path, target, cropThumbnails)
} catch (e: OutOfMemoryError) {
loadJpg(path, target, cropThumbnails)
} }
} }
} }
fun BaseSimpleActivity.tryCopyMoveFilesTo(files: ArrayList<File>, isCopyOperation: Boolean, callback: () -> Unit) {
if (files.isEmpty()) {
toast(R.string.unknown_error_occurred)
return
}
val source = if (files[0].isFile) files[0].parent else files[0].absolutePath
PickDirectoryDialog(this, source) {
copyMoveFilesTo(files, source.trimEnd('/'), it, isCopyOperation, true, callback)
}
}
fun BaseSimpleActivity.addTempFolderIfNeeded(dirs: ArrayList<Directory>): ArrayList<Directory> {
val directories = ArrayList<Directory>()
val tempFolderPath = config.tempFolderPath
if (tempFolderPath.isNotEmpty()) {
val newFolder = Directory(tempFolderPath, "", tempFolderPath.getFilenameFromPath(), 0, 0, 0, 0L)
directories.add(newFolder)
}
directories.addAll(dirs)
return directories
}
fun Activity.loadPng(path: String, target: MySquareImageView, cropThumbnails: Boolean) { fun Activity.loadPng(path: String, target: MySquareImageView, cropThumbnails: Boolean) {
val options = RequestOptions() val options = RequestOptions()
.signature(path.getFileSignature()) .signature(path.getFileSignature())

View file

@ -7,7 +7,6 @@ import android.graphics.Color
import android.graphics.Matrix import android.graphics.Matrix
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -27,6 +26,7 @@ import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.PhotoActivity import com.simplemobiletools.gallery.activities.PhotoActivity
import com.simplemobiletools.gallery.activities.ViewPagerActivity import com.simplemobiletools.gallery.activities.ViewPagerActivity
import com.simplemobiletools.gallery.extensions.* import com.simplemobiletools.gallery.extensions.*
import com.simplemobiletools.gallery.helpers.GlideDecoder
import com.simplemobiletools.gallery.helpers.GlideRotateTransformation import com.simplemobiletools.gallery.helpers.GlideRotateTransformation
import com.simplemobiletools.gallery.helpers.MEDIUM import com.simplemobiletools.gallery.helpers.MEDIUM
import com.simplemobiletools.gallery.models.Medium import com.simplemobiletools.gallery.models.Medium
@ -37,7 +37,9 @@ import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
class PhotoFragment : ViewPagerFragment() { class PhotoFragment : ViewPagerFragment() {
private var DEFAULT_DOUBLE_TAP_ZOOM = 5f
private var isFragmentVisible = false private var isFragmentVisible = false
private var isFullscreen = false
private var wasInit = false private var wasInit = false
private var storedShowExtendedDetails = false private var storedShowExtendedDetails = false
private var storedExtendedDetails = 0 private var storedExtendedDetails = 0
@ -85,6 +87,7 @@ class PhotoFragment : ViewPagerFragment() {
} }
} }
isFullscreen = activity!!.window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == View.SYSTEM_UI_FLAG_FULLSCREEN
view.subsampling_view.setOnClickListener { photoClicked() } view.subsampling_view.setOnClickListener { photoClicked() }
view.gif_view.setOnClickListener { photoClicked() } view.gif_view.setOnClickListener { photoClicked() }
loadImage() loadImage()
@ -131,12 +134,6 @@ class PhotoFragment : ViewPagerFragment() {
private fun photoFragmentVisibilityChanged(isVisible: Boolean) { private fun photoFragmentVisibilityChanged(isVisible: Boolean) {
if (isVisible) { if (isVisible) {
addZoomableView() addZoomableView()
} else {
view.subsampling_view.apply {
recycle()
beGone()
background = ColorDrawable(Color.TRANSPARENT)
}
} }
} }
@ -224,9 +221,10 @@ class PhotoFragment : ViewPagerFragment() {
} }
private fun addZoomableView() { private fun addZoomableView() {
if ((medium.isImage()) && isFragmentVisible && view.subsampling_view.visibility == View.GONE) { if ((medium.isImage()) && isFragmentVisible && view.subsampling_view.isGone()) {
ViewPagerActivity.wasDecodedByGlide = false
view.subsampling_view.apply { view.subsampling_view.apply {
//setBitmapDecoderClass(GlideDecoder::class.java) // causing random crashes on Android 7+, at rotating setBitmapDecoderClass(GlideDecoder::class.java)
maxScale = 10f maxScale = 10f
beVisible() beVisible()
setImage(ImageSource.uri(medium.path)) setImage(ImageSource.uri(medium.path))
@ -268,20 +266,28 @@ class PhotoFragment : ViewPagerFragment() {
val height = bitmapOptions.outHeight val height = bitmapOptions.outHeight
val bitmapAspectRatio = height / (width).toFloat() val bitmapAspectRatio = height / (width).toFloat()
if (context == null) return if (context == null) {
return 2f DEFAULT_DOUBLE_TAP_ZOOM
} else if (ViewPagerActivity.screenHeight / ViewPagerActivity.screenWidth.toFloat() == bitmapAspectRatio) {
return if (context!!.portrait && bitmapAspectRatio <= 1f) { DEFAULT_DOUBLE_TAP_ZOOM
} else if (ViewPagerActivity.wasDecodedByGlide) {
1f
} else if (context!!.portrait && bitmapAspectRatio <= 1f) {
ViewPagerActivity.screenHeight / height.toFloat() ViewPagerActivity.screenHeight / height.toFloat()
} else if (context!!.portrait && bitmapAspectRatio > 1f) {
ViewPagerActivity.screenHeight / width.toFloat()
} else if (!context!!.portrait && bitmapAspectRatio >= 1f) { } else if (!context!!.portrait && bitmapAspectRatio >= 1f) {
ViewPagerActivity.screenWidth / width.toFloat() ViewPagerActivity.screenWidth / width.toFloat()
} else if (!context!!.portrait && bitmapAspectRatio < 1f) {
ViewPagerActivity.screenWidth / height.toFloat()
} else { } else {
2f DEFAULT_DOUBLE_TAP_ZOOM
} }
} }
fun rotateImageViewBy(degrees: Float) { fun rotateImageViewBy(degrees: Float) {
view.subsampling_view.beGone() // do not make Subsampling view Gone, because it gets recycled and can crash with "Error, cannot access an invalid/free'd bitmap here!"
view.subsampling_view.beInvisible()
loadBitmap(degrees) loadBitmap(degrees)
} }
@ -292,9 +298,8 @@ class PhotoFragment : ViewPagerFragment() {
setTextColor(context.config.textColor) setTextColor(context.config.textColor)
beVisibleIf(text.isNotEmpty()) beVisibleIf(text.isNotEmpty())
onGlobalLayout { onGlobalLayout {
if (height != 0) { if (height != 0 && isAdded) {
val smallMargin = resources.getDimension(R.dimen.small_margin) y = getExtendedDetailsY(height)
y = context.usableScreenSize.y - height - if (context.navigationBarHeight == 0) smallMargin else 0f
} }
} }
} }
@ -305,7 +310,7 @@ class PhotoFragment : ViewPagerFragment() {
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && !activity!!.isDestroyed) { if (activity?.isActivityDestroyed() == false) {
Glide.with(context).clear(view.gif_view) Glide.with(context).clear(view.gif_view)
} }
} }
@ -321,13 +326,17 @@ class PhotoFragment : ViewPagerFragment() {
} }
override fun fullscreenToggled(isFullscreen: Boolean) { override fun fullscreenToggled(isFullscreen: Boolean) {
this.isFullscreen = isFullscreen
view.photo_details.apply { view.photo_details.apply {
if (visibility == View.VISIBLE) { if (isVisible()) {
val smallMargin = resources.getDimension(R.dimen.small_margin) animate().y(getExtendedDetailsY(height))
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)
} }
} }
} }
private fun getExtendedDetailsY(height: Int): Float {
val smallMargin = resources.getDimension(R.dimen.small_margin)
val fullscreenOffset = context!!.navigationBarHeight.toFloat() - smallMargin
return context!!.usableScreenSize.y - height + if (isFullscreen) fullscreenOffset else -(if (context!!.navigationBarHeight == 0) smallMargin else 0f)
}
} }

View file

@ -34,6 +34,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
private var mCurrTimeView: TextView? = null private var mCurrTimeView: TextView? = null
private var mTimerHandler: Handler? = null private var mTimerHandler: Handler? = null
private var mSeekBar: SeekBar? = null private var mSeekBar: SeekBar? = null
private var mTimeHolder: View? = null
private var mIsPlaying = false private var mIsPlaying = false
private var mIsDragged = false private var mIsDragged = false
@ -60,7 +61,6 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
lateinit var mView: View lateinit var mView: View
lateinit var medium: Medium lateinit var medium: Medium
lateinit var mTimeHolder: View
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
mView = inflater.inflate(R.layout.pager_video_item, container, false) mView = inflater.inflate(R.layout.pager_video_item, container, false)
@ -287,8 +287,8 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
private fun initTimeHolder() { private fun initTimeHolder() {
val res = resources val res = resources
val height = context!!.navigationBarHeight val height = context!!.navigationBarHeight
val left = mTimeHolder.paddingLeft val left = mTimeHolder!!.paddingLeft
val top = mTimeHolder.paddingTop val top = mTimeHolder!!.paddingTop
var right = res.getDimension(R.dimen.timer_padding).toInt() var right = res.getDimension(R.dimen.timer_padding).toInt()
var bottom = 0 var bottom = 0
@ -299,7 +299,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
right += height 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 mCurrTimeView = mView.video_curr_time
@ -307,7 +307,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
mSeekBar!!.setOnSeekBarChangeListener(this) mSeekBar!!.setOnSeekBarChangeListener(this)
if (mIsFullscreen) if (mIsFullscreen)
mTimeHolder.beInvisible() mTimeHolder!!.beInvisible()
} }
private fun hasNavBar(): Boolean { private fun hasNavBar(): Boolean {
@ -375,7 +375,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
AnimationUtils.loadAnimation(activity, anim).apply { AnimationUtils.loadAnimation(activity, anim).apply {
duration = 150 duration = 150
fillAfter = true fillAfter = true
mTimeHolder.startAnimation(this) mTimeHolder?.startAnimation(this)
} }
} }
@ -457,9 +457,13 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
releaseMediaPlayer() releaseMediaPlayer()
mSeekBar?.progress = 0 mSeekBar?.progress = 0
mTimerHandler?.removeCallbacksAndMessages(null) mTimerHandler?.removeCallbacksAndMessages(null)
mSurfaceView = null
mSurfaceHolder?.removeCallback(this)
mSurfaceHolder = null
} }
private fun releaseMediaPlayer() { private fun releaseMediaPlayer() {
mMediaPlayer?.setSurface(null)
mMediaPlayer?.release() mMediaPlayer?.release()
mMediaPlayer = null mMediaPlayer = null
} }
@ -551,10 +555,8 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
setTextColor(context.config.textColor) setTextColor(context.config.textColor)
beVisibleIf(text.isNotEmpty()) beVisibleIf(text.isNotEmpty())
onGlobalLayout { onGlobalLayout {
if (height != 0) { if (height != 0 && isAdded) {
val smallMargin = resources.getDimension(R.dimen.small_margin) y = getExtendedDetailsY(height)
val timeHolderHeight = mTimeHolder.height - context.navigationBarHeight
y = context.usableScreenSize.y - height - timeHolderHeight - if (context.navigationBarHeight == 0) smallMargin else 0f
} }
} }
} }
@ -592,13 +594,16 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
mIsFullscreen = isFullscreen mIsFullscreen = isFullscreen
checkFullscreen() checkFullscreen()
mView.video_details.apply { mView.video_details.apply {
if (visibility == View.VISIBLE) { if (isVisible()) {
val smallMargin = resources.getDimension(R.dimen.small_margin) animate().y(getExtendedDetailsY(height))
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)
} }
} }
} }
private fun getExtendedDetailsY(height: Int): Float {
val smallMargin = resources.getDimension(R.dimen.small_margin)
val timeHolderHeight = mTimeHolder!!.height - context!!.navigationBarHeight.toFloat()
val fullscreenOffset = context!!.navigationBarHeight.toFloat() - smallMargin
return context!!.usableScreenSize.y - height + if (mIsFullscreen) fullscreenOffset else -(timeHolderHeight + if (context!!.navigationBarHeight == 0) smallMargin else 0f)
}
} }

View file

@ -23,6 +23,7 @@ class GlideDecoder : ImageDecoder {
val targetWidth = if (ViewPagerActivity.screenWidth == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenWidth val targetWidth = if (ViewPagerActivity.screenWidth == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenWidth
val targetHeight = if (ViewPagerActivity.screenHeight == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenHeight val targetHeight = if (ViewPagerActivity.screenHeight == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenHeight
ViewPagerActivity.wasDecodedByGlide = true
val options = RequestOptions() val options = RequestOptions()
.signature(uri.path.getFileSignature()) .signature(uri.path.getFileSignature())
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) .diskCacheStrategy(DiskCacheStrategy.RESOURCE)

View file

@ -247,7 +247,6 @@ class MediaFetcher(val context: Context) {
private fun isThisOrParentExcluded(path: String, excludedPaths: MutableSet<String>, includedPaths: MutableSet<String>) = private fun isThisOrParentExcluded(path: String, excludedPaths: MutableSet<String>, includedPaths: MutableSet<String>) =
includedPaths.none { path.startsWith(it) } && excludedPaths.any { path.startsWith(it) } includedPaths.none { path.startsWith(it) } && excludedPaths.any { path.startsWith(it) }
private fun getMediaInFolder(folder: String, curMedia: ArrayList<Medium>, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int) { private fun getMediaInFolder(folder: String, curMedia: ArrayList<Medium>, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int) {
val files = File(folder).listFiles() ?: return val files = File(folder).listFiles() ?: return
for (file in files) { for (file in files) {
@ -282,7 +281,7 @@ class MediaFetcher(val context: Context) {
val isAlreadyAdded = curMedia.any { it.path == file.absolutePath } val isAlreadyAdded = curMedia.any { it.path == file.absolutePath }
if (!isAlreadyAdded) { if (!isAlreadyAdded) {
curMedia.add(medium) curMedia.add(medium)
context.scanPath(file.absolutePath) {} context.scanPath(file.absolutePath)
} }
} }
} }
@ -296,10 +295,11 @@ class MediaFetcher(val context: Context) {
else -> MediaStore.Images.Media.DATE_TAKEN else -> MediaStore.Images.Media.DATE_TAKEN
} }
return if (sorting and SORT_DESCENDING > 0) return if (sorting and SORT_DESCENDING > 0) {
"$sortValue DESC" "$sortValue DESC"
else } else {
"$sortValue ASC" "$sortValue ASC"
}
} }
private fun getNoMediaFolders(): ArrayList<String> { private fun getNoMediaFolders(): ArrayList<String> {

View file

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/excluded_folders_scrollview"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:id="@+id/exclude_folders_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/excluded_folders_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/excluded_folders_placeholder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingLeft="@dimen/big_margin"
android:paddingRight="@dimen/big_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/excluded_activity_placeholder"
android:visibility="gone"/>
</RelativeLayout>
</ScrollView>

View file

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/included_folders_scrollview"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:id="@+id/include_folders_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/included_folders_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/included_folders_placeholder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingLeft="@dimen/big_margin"
android:paddingRight="@dimen/big_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/included_activity_placeholder"
android:visibility="gone"/>
</RelativeLayout>
</ScrollView>

View file

@ -33,7 +33,7 @@
android:text="@string/change_filters_underlined" android:text="@string/change_filters_underlined"
android:visibility="gone"/> android:visibility="gone"/>
<com.simplemobiletools.commons.views.MyScalableRecyclerView <com.simplemobiletools.commons.views.MyRecyclerView
android:id="@+id/directories_grid" android:id="@+id/directories_grid"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/manage_folders_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.simplemobiletools.commons.views.MyRecyclerView
android:id="@+id/manage_folders_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"/>
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/manage_folders_placeholder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingLeft="@dimen/big_margin"
android:paddingRight="@dimen/big_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/excluded_activity_placeholder"
android:visibility="gone"/>
</RelativeLayout>

View file

@ -33,7 +33,7 @@
android:text="@string/change_filters_underlined" android:text="@string/change_filters_underlined"
android:visibility="gone"/> android:visibility="gone"/>
<com.simplemobiletools.commons.views.MyScalableRecyclerView <com.simplemobiletools.commons.views.MyRecyclerView
android:id="@+id/media_grid" android:id="@+id/media_grid"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View file

@ -7,7 +7,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="@dimen/activity_margin"> android:paddingTop="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MyScalableRecyclerView <com.simplemobiletools.commons.views.MyRecyclerView
android:id="@+id/directories_grid" android:id="@+id/directories_grid"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"

View file

@ -6,7 +6,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="@dimen/activity_margin"> android:paddingTop="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MyScalableRecyclerView <com.simplemobiletools.commons.views.MyRecyclerView
android:id="@+id/media_grid" android:id="@+id/media_grid"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"

View file

@ -4,6 +4,8 @@
android:id="@+id/dir_holder" android:id="@+id/dir_holder"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:padding="1px"> android:padding="1px">
<com.simplemobiletools.gallery.views.MySquareImageView <com.simplemobiletools.gallery.views.MySquareImageView
@ -21,7 +23,8 @@
android:layout_margin="@dimen/small_margin" android:layout_margin="@dimen/small_margin"
android:background="@drawable/circle_background" android:background="@drawable/circle_background"
android:padding="@dimen/tiny_margin" android:padding="@dimen/tiny_margin"
android:src="@drawable/ic_check"/> android:src="@drawable/ic_check"
android:visibility="gone"/>
<ImageView <ImageView
android:id="@+id/dir_pin" android:id="@+id/dir_pin"
@ -33,7 +36,8 @@
android:layout_margin="@dimen/small_margin" android:layout_margin="@dimen/small_margin"
android:background="@drawable/circle_black_background" android:background="@drawable/circle_black_background"
android:padding="@dimen/small_margin" android:padding="@dimen/small_margin"
android:src="@drawable/ic_pin"/> android:src="@drawable/ic_pin"
android:visibility="gone"/>
<ImageView <ImageView
android:id="@+id/dir_shadow_holder" android:id="@+id/dir_shadow_holder"

View file

@ -5,6 +5,8 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingLeft="@dimen/small_margin" android:paddingLeft="@dimen/small_margin"
android:clickable="true"
android:focusable="true"
android:paddingTop="@dimen/small_margin"> android:paddingTop="@dimen/small_margin">
<com.simplemobiletools.gallery.views.MySquareImageView <com.simplemobiletools.gallery.views.MySquareImageView
@ -22,7 +24,8 @@
android:layout_margin="@dimen/small_margin" android:layout_margin="@dimen/small_margin"
android:background="@drawable/circle_background" android:background="@drawable/circle_background"
android:padding="@dimen/tiny_margin" android:padding="@dimen/tiny_margin"
android:src="@drawable/ic_check"/> android:src="@drawable/ic_check"
android:visibility="gone"/>
<TextView <TextView
android:id="@+id/dir_name" android:id="@+id/dir_name"

View file

@ -1,29 +1,22 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/managed_folder_holder" android:id="@+id/manage_folder_holder"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:foreground="@drawable/selector"
android:padding="@dimen/activity_margin"> android:padding="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MyTextView <com.simplemobiletools.commons.views.MyTextView
android:id="@+id/managed_folder_title" android:id="@+id/manage_folder_title"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/medium_margin" android:layout_marginLeft="@dimen/medium_margin"
android:layout_marginRight="@dimen/medium_margin" android:layout_marginRight="@dimen/medium_margin"
android:layout_toLeftOf="@+id/managed_folders_icon" android:layout_marginTop="@dimen/medium_margin"/>
android:layout_toStartOf="@+id/managed_folders_icon"/>
<ImageView
android:id="@+id/managed_folders_icon"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="@dimen/normal_icon_size"
android:layout_height="@dimen/normal_icon_size"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_cross"/>
</RelativeLayout> </RelativeLayout>

View file

@ -4,6 +4,8 @@
android:id="@+id/media_item_holder" android:id="@+id/media_item_holder"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:padding="1px"> android:padding="1px">
<com.simplemobiletools.gallery.views.MySquareImageView <com.simplemobiletools.gallery.views.MySquareImageView

View file

@ -4,6 +4,8 @@
android:id="@+id/media_item_holder" android:id="@+id/media_item_holder"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:paddingLeft="@dimen/small_margin" android:paddingLeft="@dimen/small_margin"
android:paddingTop="@dimen/small_margin"> android:paddingTop="@dimen/small_margin">

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/> <background android:drawable="@color/color_primary"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/> <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon> </adaptive-icon>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/> <background android:drawable="@color/color_primary"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/> <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon> </adaptive-icon>

View file

@ -23,8 +23,8 @@
<string name="volume">Lautstärke</string> <string name="volume">Lautstärke</string>
<string name="brightness">Helligkeit</string> <string name="brightness">Helligkeit</string>
<string name="do_not_ask_again">Nicht erneut fragen (in dieser Sitzung)</string> <string name="do_not_ask_again">Nicht erneut fragen (in dieser Sitzung)</string>
<string name="lock_orientation">Lock orientation</string> <string name="lock_orientation">Bildschirmausrichtung sperren</string>
<string name="unlock_orientation">Unlock orientation</string> <string name="unlock_orientation">Bildschirmausrichtung entsperren</string>
<!-- Filter --> <!-- Filter -->
<string name="filter_media">Filter</string> <string name="filter_media">Filter</string>

View file

@ -23,8 +23,8 @@
<string name="volume">Volume</string> <string name="volume">Volume</string>
<string name="brightness">Luminosità</string> <string name="brightness">Luminosità</string>
<string name="do_not_ask_again">Non chiedere nuovamente in questa sessione</string> <string name="do_not_ask_again">Non chiedere nuovamente in questa sessione</string>
<string name="lock_orientation">Lock orientation</string> <string name="lock_orientation">Blocca orientamento</string>
<string name="unlock_orientation">Unlock orientation</string> <string name="unlock_orientation">Sblocca orientamento</string>
<!-- Filter --> <!-- Filter -->
<string name="filter_media">Filtra i media</string> <string name="filter_media">Filtra i media</string>
@ -115,7 +115,7 @@
<string name="animate_gifs">Anima le GIF in miniatura</string> <string name="animate_gifs">Anima le GIF in miniatura</string>
<string name="max_brightness">Luminosità max durante visualizzazione</string> <string name="max_brightness">Luminosità max durante visualizzazione</string>
<string name="crop_thumbnails">Ritaglia le miniature in quadrati</string> <string name="crop_thumbnails">Ritaglia le miniature in quadrati</string>
<string name="screen_rotation_by">Ruota a schermo intero per</string> <string name="screen_rotation_by">Ruota schermo per</string>
<string name="screen_rotation_system_setting">Impostazione di sistema</string> <string name="screen_rotation_system_setting">Impostazione di sistema</string>
<string name="screen_rotation_device_rotation">Rotazione dispositivo</string> <string name="screen_rotation_device_rotation">Rotazione dispositivo</string>
<string name="screen_rotation_aspect_ratio">Proporzioni</string> <string name="screen_rotation_aspect_ratio">Proporzioni</string>
@ -133,7 +133,7 @@
<!-- Short description has to have less than 80 chars --> <!-- Short description has to have less than 80 chars -->
<string name="app_short_description">Una galleria per visualizzare foto e video senza pubblicità.</string> <string name="app_short_description">Una galleria per visualizzare foto e video senza pubblicità.</string>
<string name="app_long_description"> <string name="app_long_description">
Un semplice strumento per visualizzare foto e video. Gli elementi possono essere ordinati per data, dimensioni, nome sia ascendente che discendente; le foto possono essere ingrandite. I file sono mostrati in colonne multiple a seconda delle dimensioni dello schermo, puoi modificare il numero di colonne con il tocco. Possono essere rinominate, condivise, eliminate, copiate, spostate. Le immagini possono anche essere ritagliate, ruotate o impostate come sfondo direttamente dall\'app. Un semplice strumento per visualizzare foto e video. Gli elementi possono essere ordinati per data, dimensioni, nome sia ascendente che discendente; le foto possono essere ingrandite. I file sono mostrati in colonne multiple a seconda delle dimensioni dello schermo, puoi modificare il numero di colonne con il tocco. Possono essere rinominate, condivise, eliminate, copiate, spostate. Le immagini possono anche essere ritagliate, ruotate o impostate come sfondo direttamente dalla app.
Simple Gallery è anche offerta per utilizzo di terze parti per anteprime di immagini / video, aggiunta di allegati ai client email, ecc. È perfetta per un uso quotidiano. Simple Gallery è anche offerta per utilizzo di terze parti per anteprime di immagini / video, aggiunta di allegati ai client email, ecc. È perfetta per un uso quotidiano.

View file

@ -27,12 +27,12 @@
<string name="unlock_orientation">Schermrotatie ontgrendelen</string> <string name="unlock_orientation">Schermrotatie ontgrendelen</string>
<!-- Filter --> <!-- Filter -->
<string name="filter_media">Media kiezen</string> <string name="filter_media">Filter media</string>
<string name="images">Afbeeldingen</string> <string name="images">Afbeeldingen</string>
<string name="videos">Video\'s</string> <string name="videos">Video\'s</string>
<string name="gifs">GIF-bestanden</string> <string name="gifs">GIF-bestanden</string>
<string name="no_media_with_filters">Geen bestanden gevonden met de huidige filters.</string> <string name="no_media_with_filters">Geen bestanden gevonden met de huidige filters.</string>
<string name="change_filters_underlined"><u>Media kiezen</u></string> <string name="change_filters_underlined"><u>Filters aanpassen</u></string>
<!-- Hide / Exclude --> <!-- Hide / Exclude -->
<string name="hide_folder_description">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?</string> <string name="hide_folder_description">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?</string>
@ -46,8 +46,8 @@
<string name="remove_all_description">Verwijder alles uit de lijst van uitgesloten mappen? Dit zal de mappen zelf niet verwijderen.</string> <string name="remove_all_description">Verwijder alles uit de lijst van uitgesloten mappen? Dit zal de mappen zelf niet verwijderen.</string>
<!-- Include folders --> <!-- Include folders -->
<string name="include_folders">Ingesloten mappen</string> <string name="include_folders">Toegevoegde mappen</string>
<string name="manage_included_folders">Ingesloten mappen beheren</string> <string name="manage_included_folders">Toegevoegde mappen beheren</string>
<string name="add_folder">Map toevoegen</string> <string name="add_folder">Map toevoegen</string>
<string name="included_activity_placeholder">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.</string> <string name="included_activity_placeholder">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.</string>

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">Simple Gallery</string> <string name="app_name">Prosta Galeria</string>
<string name="app_launcher_name">Simple Gallery</string> <string name="app_launcher_name">Galeria</string>
<string name="edit">Edytuj</string> <string name="edit">Edytuj</string>
<string name="open_camera">Uruchom aplikację aparatu</string> <string name="open_camera">Uruchom aplikację aparatu</string>
<string name="hidden">(ukryty)</string> <string name="hidden">(ukryty)</string>
@ -23,8 +23,8 @@
<string name="volume">Głośność</string> <string name="volume">Głośność</string>
<string name="brightness">Jasność</string> <string name="brightness">Jasność</string>
<string name="do_not_ask_again">Nie pytaj więcej w tej sesji</string> <string name="do_not_ask_again">Nie pytaj więcej w tej sesji</string>
<string name="lock_orientation">Lock orientation</string> <string name="lock_orientation">Zablokuj orientację ekranu</string>
<string name="unlock_orientation">Unlock orientation</string> <string name="unlock_orientation">Odblokuj orientację ekranu</string>
<!-- Filter --> <!-- Filter -->
<string name="filter_media">Filtruj multimedia</string> <string name="filter_media">Filtruj multimedia</string>
@ -35,7 +35,7 @@
<string name="change_filters_underlined"><u>Zmień filtry</u></string> <string name="change_filters_underlined"><u>Zmień filtry</u></string>
<!-- Hide / Exclude --> <!-- Hide / Exclude -->
<string name="hide_folder_description">Ta funkcja ukrywa foldery dodając do nich pusty plik .nomedia. Aby móc je zobaczyć, należy włączyć opcję \'Pokazuj ukryte foldery\' w ustawieniach. Kontyntynuować?</string> <string name="hide_folder_description">Ta funkcja ukrywa foldery, dodając do nich pusty plik .nomedia. Aby móc je zobaczyć, należy włączyć opcję \'Pokazuj ukryte foldery\' w ustawieniach. Kontynuować?</string>
<string name="exclude">Wyklucz</string> <string name="exclude">Wyklucz</string>
<string name="excluded_folders">Wykluczone foldery</string> <string name="excluded_folders">Wykluczone foldery</string>
<string name="manage_excluded_folders">Zarządzaj wykluczonymi folderami</string> <string name="manage_excluded_folders">Zarządzaj wykluczonymi folderami</string>
@ -49,7 +49,7 @@
<string name="include_folders">Dołączone foldery</string> <string name="include_folders">Dołączone foldery</string>
<string name="manage_included_folders">Zarządzaj dołączonymi folderami</string> <string name="manage_included_folders">Zarządzaj dołączonymi folderami</string>
<string name="add_folder">Dodaj folder</string> <string name="add_folder">Dodaj folder</string>
<string name="included_activity_placeholder">Jeśli masz jakieś foldery z multimediami, ale aplikacja ich nie wykryła, możesz je tutaj dodać ręcznie.</string> <string name="included_activity_placeholder">Jeśli masz jakieś foldery z multimediami, ale aplikacja ich nie wykryła, możesz je dodać ręcznie tutaj.</string>
<!-- Resizing --> <!-- Resizing -->
<string name="resize">Zmień rozmiar</string> <string name="resize">Zmień rozmiar</string>
@ -131,13 +131,13 @@
<!-- Strings displayed only on Google Playstore. Optional, but good to have --> <!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars --> <!-- Short description has to have less than 80 chars -->
<string name="app_short_description">Darmowa galeria bez reklam do przeglądania obrazów i filmów.</string> <string name="app_short_description">Prosta galeria bez reklam do przeglądania obrazów i filmów.</string>
<string name="app_long_description"> <string name="app_long_description">
Prosta aplikacja galerii do oglądania obrazów i filmów. Pliki mogą być sortowane według daty, rozmiaru i nazwy, zarówno w porządku rosnącym, jak i malejącym. W zależności od wielkości ekranu wyświetlane mogą być w wielu kolumnach. Liczbę kolumn można zmieniać za pomocą gestów. Zdjęcia mogą być powiększane, przycinane, obracane lub ustawiane jako tapeta bezpośrednio z poziomu aplikacji. Kolory aplikacji można dowolnie ustawiać. Prosta aplikacja galerii do oglądania obrazów i filmów. Pliki mogą być sortowane według daty, rozmiaru i nazwy, zarówno w porządku rosnącym, jak i malejącym. W zależności od wielkości ekranu, wyświetlane mogą być w wielu kolumnach. Liczbę kolumn można zmieniać za pomocą gestów, a zdjęcia mogą być powiększane, przycinane, obracane lub ustawiane jako tapeta bezpośrednio z poziomu Prostej Galerii. Kolory aplikacji można dowolnie ustawiać.
Aplikacja nie zawiera żadnych reklam ani niepotrzebnych uprawnień. Jest też w pełni otawrtoźrodłowa. Nie zawiera natomiast żadnych reklam i nie potrzebuje całej masy uprawnień. Jest w pełni otwartoźródłowa i w pełni podatna na kolorowanie.
Niniejsza aplikacja jest tylko częścią naszego zestawu prostych aplikacji. Znajdziecie je na stronie http://www.simplemobiletools.com. Niniejsza aplikacja jest tylko częścią naszej kolekcji prostych narzędzi. Ta, jak i pozostałe, dostępne są na stronie http://www.simplemobiletools.com
</string> </string>
<!-- <!--

View file

@ -23,8 +23,8 @@
<string name="volume">音量</string> <string name="volume">音量</string>
<string name="brightness">亮度</string> <string name="brightness">亮度</string>
<string name="do_not_ask_again">不再提醒</string> <string name="do_not_ask_again">不再提醒</string>
<string name="lock_orientation">Lock orientation</string> <string name="lock_orientation">锁定方向</string>
<string name="unlock_orientation">Unlock orientation</string> <string name="unlock_orientation">解锁方向</string>
<!-- Filter --> <!-- Filter -->
<string name="filter_media">要显示的媒体文件</string> <string name="filter_media">要显示的媒体文件</string>

View file

@ -7,6 +7,4 @@
<!-- Default colors --> <!-- Default colors -->
<color name="default_text_color">@color/default_dark_theme_text_color</color> <color name="default_text_color">@color/default_dark_theme_text_color</color>
<color name="default_background_color">@color/default_dark_theme_background_color</color> <color name="default_background_color">@color/default_dark_theme_background_color</color>
<color name="ic_launcher_background">@color/color_primary</color>
</resources> </resources>

View file

@ -2,6 +2,9 @@
<resources> <resources>
<!-- Release notes --> <!-- Release notes -->
<string name="release_143">
Added new options to use english language on non-english devices, to password protect whole app and to lock screen orientation at fullscreen view
</string>
<string name="release_138">Added an option to keep last-modified field at file copy/move/rename</string> <string name="release_138">Added an option to keep last-modified field at file copy/move/rename</string>
<string name="release_137">Added an option to hide folder media count on the main screen</string> <string name="release_137">Added an option to hide folder media count on the main screen</string>
<string name="release_136">Added an option to show customizable extended details over fullscreen media</string> <string name="release_136">Added an option to show customizable extended details over fullscreen media</string>