diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b2897c4b..6e90ef9f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,22 @@ 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)* ---------------------------- diff --git a/app/build.gradle b/app/build.gradle index 42f9024db..38604d2c2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,10 @@ android { applicationId "com.simplemobiletools.gallery" minSdkVersion 16 targetSdkVersion 27 - versionCode 142 - versionName "2.17.4" + versionCode 144 + versionName "2.18.1" + multiDexEnabled true + setProperty("archivesBaseName", "gallery") } signingConfigs { @@ -45,10 +47,10 @@ ext { } dependencies { - compile 'com.simplemobiletools:commons:2.37.12' - compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.7.2' + compile 'com.simplemobiletools:commons:2.39.10' + compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.8.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 'it.sephiroth.android.exif:library:1.0.1' compile 'pl.droidsonroids.gif:android-gif-drawable:1.2.8' @@ -59,7 +61,7 @@ dependencies { } buildscript { - ext.kotlin_version = '1.1.51' + ext.kotlin_version = '1.1.60' repositories { mavenCentral() } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ff7ff3399..e0e44d1c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ + () + config.excludedFolders.mapTo(folders, { it }) + manage_folders_placeholder.text = getString(R.string.excluded_activity_placeholder) + manage_folders_placeholder.beVisibleIf(folders.isEmpty()) + manage_folders_placeholder.setTextColor(config.textColor) - for (folder in folders) { - layoutInflater.inflate(R.layout.item_manage_folder, null, false).apply { - managed_folder_title.apply { - 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) - } - } + val adapter = ManageFoldersAdapter(this, folders, true, this, manage_folders_list) {} + adapter.setupDragListener(true) + manage_folders_list.adapter = adapter } override fun onCreateOptionsMenu(menu: Menu?): Boolean { @@ -55,6 +43,10 @@ class ExcludedFoldersActivity : SimpleActivity() { return true } + override fun refreshItems() { + updateExcludedFolders() + } + private fun addExcludedFolder() { FilePickerDialog(this, pickFile = false, showHidden = config.shouldShowHidden) { config.addExcludedFolder(it) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/IncludedFoldersActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/IncludedFoldersActivity.kt index f69f4f987..3f4067312 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/IncludedFoldersActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/IncludedFoldersActivity.kt @@ -1,46 +1,34 @@ package com.simplemobiletools.gallery.activities -import android.graphics.PorterDuff import android.os.Bundle import android.view.Menu import android.view.MenuItem import com.simplemobiletools.commons.dialogs.FilePickerDialog import com.simplemobiletools.commons.extensions.beVisibleIf import com.simplemobiletools.commons.extensions.scanPath +import com.simplemobiletools.commons.interfaces.RefreshRecyclerViewListener import com.simplemobiletools.gallery.R +import com.simplemobiletools.gallery.adapters.ManageFoldersAdapter import com.simplemobiletools.gallery.extensions.config -import kotlinx.android.synthetic.main.activity_included_folders.* -import kotlinx.android.synthetic.main.item_manage_folder.view.* +import kotlinx.android.synthetic.main.activity_manage_folders.* -class IncludedFoldersActivity : SimpleActivity() { +class IncludedFoldersActivity : SimpleActivity(), RefreshRecyclerViewListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_included_folders) + setContentView(R.layout.activity_manage_folders) updateIncludedFolders() } private fun updateIncludedFolders() { - included_folders_holder.removeAllViews() - val folders = config.includedFolders - included_folders_placeholder.beVisibleIf(folders.isEmpty()) - included_folders_placeholder.setTextColor(config.textColor) + val folders = ArrayList() + config.includedFolders.mapTo(folders, { it }) + manage_folders_placeholder.text = getString(R.string.included_activity_placeholder) + manage_folders_placeholder.beVisibleIf(folders.isEmpty()) + manage_folders_placeholder.setTextColor(config.textColor) - for (folder in folders) { - layoutInflater.inflate(R.layout.item_manage_folder, null, false).apply { - managed_folder_title.apply { - 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) - } - } + val adapter = ManageFoldersAdapter(this, folders, false, this, manage_folders_list) {} + adapter.setupDragListener(true) + manage_folders_list.adapter = adapter } override fun onCreateOptionsMenu(menu: Menu?): Boolean { @@ -56,11 +44,15 @@ class IncludedFoldersActivity : SimpleActivity() { return true } + override fun refreshItems() { + updateIncludedFolders() + } + private fun addIncludedFolder() { FilePickerDialog(this, pickFile = false, showHidden = config.shouldShowHidden) { config.addIncludedFolder(it) updateIncludedFolders() - scanPath(it) {} + scanPath(it) } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MainActivity.kt index 62c143735..25806c41e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MainActivity.kt @@ -4,7 +4,6 @@ import android.app.Activity import android.content.ClipData import android.content.Intent import android.net.Uri -import android.os.Build import android.os.Bundle import android.os.Handler 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.models.RadioItem 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.R import com.simplemobiletools.gallery.adapters.DirectoryAdapter @@ -64,6 +63,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { private var mLatestMediaId = 0L private var mLastMediaHandler = Handler() private var mCurrAsyncTask: GetDirectoriesAsynctask? = null + private var mZoomListener: MyRecyclerView.MyZoomListener? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -178,7 +178,6 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { directories_refresh_layout.isRefreshing = false mIsGettingDirs = false storeStateVariables() - directories_grid.listener = null mLastMediaHandler.removeCallbacksAndMessages(null) if (!mDirs.isEmpty()) { @@ -209,7 +208,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { val newFolder = File(config.tempFolderPath) if (newFolder.exists() && newFolder.isDirectory) { if (newFolder.list()?.isEmpty() == true) { - deleteFileBg(newFolder, true) { } + deleteFileBg(newFolder, true) } } config.tempFolderPath = "" @@ -341,6 +340,11 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { } else { setupListLayoutManager() } + + getDirectoryAdapter()?.apply { + setupZoomListener(mZoomListener) + setupDragListener(true) + } } 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_grid.isDragSelectionEnabled = true - directories_grid.isZoomingEnabled = true layoutManager.spanCount = config.dirColumnCnt - directories_grid.listener = object : MyScalableRecyclerView.MyScalableRecyclerViewListener { + mZoomListener = object : MyRecyclerView.MyZoomListener { override fun zoomIn() { if (layoutManager.spanCount > 1) { reduceColumnCount() - getRecyclerAdapter().actMode?.finish() + getRecyclerAdapter().finishActMode() } } override fun zoomOut() { if (layoutManager.spanCount < MAX_COLUMN_COUNT) { 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() { - directories_grid.isDragSelectionEnabled = true - directories_grid.isZoomingEnabled = false - val layoutManager = directories_grid.layoutManager as GridLayoutManager layoutManager.spanCount = 1 layoutManager.orientation = GridLayoutManager.VERTICAL directories_refresh_layout.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + mZoomListener = null } private fun createNewFolder() { @@ -451,7 +443,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { else -> fillIntentPath(resultData, resultIntent) } } else if ((mIsPickImageIntent || mIsPickVideoIntent)) { - val path = resultData.data.path + val path = resultData.data?.path val uri = getFilePublicUri(File(path), BuildConfig.APPLICATION_ID) resultIntent.data = uri resultIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION @@ -560,8 +552,8 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { private fun setupAdapter() { val currAdapter = directories_grid.adapter if (currAdapter == null) { - directories_grid.adapter = DirectoryAdapter(this, mDirs, this, isPickIntent(intent) || isGetAnyContentIntent(intent)) { - itemClicked(it.path) + directories_grid.adapter = DirectoryAdapter(this, mDirs, this, directories_grid, isPickIntent(intent) || isGetAnyContentIntent(intent)) { + itemClicked((it as Directory).path) } } else { (currAdapter as DirectoryAdapter).updateDirs(mDirs) @@ -587,7 +579,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { } private fun checkLastMediaChanged() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && isDestroyed) + if (isActivityDestroyed()) return mLastMediaHandler.removeCallbacksAndMessages(null) @@ -610,10 +602,6 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { getDirectories() } - override fun itemLongClicked(position: Int) { - directories_grid.setDragSelectActive(position) - } - override fun recheckPinnedFolders() { gotDirectories(movePinnedDirectoriesToFront(mDirs), true) } @@ -659,6 +647,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { add(Release(136, R.string.release_136)) add(Release(137, R.string.release_137)) add(Release(138, R.string.release_138)) + add(Release(143, R.string.release_143)) checkWhatsNew(this, BuildConfig.VERSION_CODE) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt index b500af01e..d4fdd4955 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt @@ -5,7 +5,6 @@ import android.app.WallpaperManager import android.content.Intent import android.graphics.Bitmap import android.net.Uri -import android.os.Build import android.os.Bundle import android.os.Handler 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.REQUEST_EDIT_IMAGE 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.adapters.MediaAdapter import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask @@ -59,6 +58,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { private var mLatestMediaId = 0L private var mLastMediaHandler = Handler() private var mCurrAsyncTask: GetMediaAsynctask? = null + private var mZoomListener: MyRecyclerView.MyZoomListener? = null companion object { var mMedia = ArrayList() @@ -120,7 +120,6 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { mIsGettingMedia = false media_refresh_layout.isRefreshing = false storeStateVariables() - media_grid.listener = null mLastMediaHandler.removeCallbacksAndMessages(null) if (!mMedia.isEmpty()) { @@ -177,8 +176,8 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { val currAdapter = media_grid.adapter if (currAdapter == null) { - media_grid.adapter = MediaAdapter(this, mMedia, this, mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent, mAllowPickingMultiple) { - itemClicked(it.path) + media_grid.adapter = MediaAdapter(this, mMedia, this, mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent, mAllowPickingMultiple, media_grid) { + itemClicked((it as Medium).path) } } else { (currAdapter as MediaAdapter).updateMedia(mMedia) @@ -204,7 +203,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { } private fun checkLastMediaChanged() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && isDestroyed) + if (isActivityDestroyed()) return mLastMediaHandler.removeCallbacksAndMessages(null) @@ -347,7 +346,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { private fun deleteDirectoryIfEmpty() { val file = File(mPath) 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 setupLayoutManager() { - if (config.viewTypeFiles == VIEW_TYPE_GRID) + if (config.viewTypeFiles == VIEW_TYPE_GRID) { setupGridLayoutManager() - else + } else { setupListLayoutManager() + } + + getMediaAdapter()?.apply { + setupZoomListener(mZoomListener) + setupDragListener(true) + } } 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_grid.isDragSelectionEnabled = true - media_grid.isZoomingEnabled = true layoutManager.spanCount = config.mediaColumnCnt - media_grid.listener = object : MyScalableRecyclerView.MyScalableRecyclerViewListener { + mZoomListener = object : MyRecyclerView.MyZoomListener { override fun zoomIn() { if (layoutManager.spanCount > 1) { reduceColumnCount() - getRecyclerAdapter().actMode?.finish() + getRecyclerAdapter().finishActMode() } } override fun zoomOut() { if (layoutManager.spanCount < MAX_COLUMN_COUNT) { 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() { - media_grid.isDragSelectionEnabled = true - media_grid.isZoomingEnabled = false - val layoutManager = media_grid.layoutManager as GridLayoutManager layoutManager.spanCount = 1 layoutManager.orientation = GridLayoutManager.VERTICAL media_refresh_layout.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + mZoomListener = null } private fun increaseColumnCount() { @@ -575,10 +568,6 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { }, 1000) } - override fun itemLongClicked(position: Int) { - media_grid.setDragSelectActive(position) - } - override fun selectedPaths(paths: ArrayList) { Intent().apply { putExtra(PICKED_PATHS, paths) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PhotoVideoActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PhotoVideoActivity.kt index 960db4d14..e92593e3b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PhotoVideoActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PhotoVideoActivity.kt @@ -59,14 +59,14 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList mIsFromGallery = intent.getBooleanExtra(IS_FROM_GALLERY, false) if (mUri!!.scheme == "file") { - scanPath(mUri!!.path) {} + scanPath(mUri!!.path) sendViewPagerIntent(mUri!!.path) finish() return } else { val path = applicationContext.getRealPathFromURI(mUri!!) ?: "" if (path != mUri.toString() && path.isNotEmpty()) { - scanPath(mUri!!.path) {} + scanPath(mUri!!.path) sendViewPagerIntent(path) finish() return @@ -114,9 +114,11 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.photo_video_menu, menu) - menu.findItem(R.id.menu_set_as).isVisible = mMedium?.isImage() == true - menu.findItem(R.id.menu_edit).isVisible = mMedium?.isImage() == true && mUri?.scheme == "file" - menu.findItem(R.id.menu_properties).isVisible = mUri?.scheme == "file" + menu.apply { + findItem(R.id.menu_set_as).isVisible = mMedium?.isImage() == true + findItem(R.id.menu_edit).isVisible = mMedium?.isImage() == true && mUri?.scheme == "file" + findItem(R.id.menu_properties).isVisible = mUri?.scheme == "file" + } return true } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SetWallpaperActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SetWallpaperActivity.kt index 9d2fddb3c..07a493239 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SetWallpaperActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SetWallpaperActivity.kt @@ -5,10 +5,10 @@ import android.app.WallpaperManager import android.content.Intent import android.graphics.Bitmap import android.net.Uri -import android.os.Build import android.os.Bundle import android.view.Menu import android.view.MenuItem +import com.simplemobiletools.commons.extensions.isActivityDestroyed import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.gallery.R import com.theartofdev.edmodo.cropper.CropImageView @@ -61,8 +61,10 @@ class SetWallpaperActivity : SimpleActivity(), CropImageView.OnCropImageComplete override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.menu_set_wallpaper, menu) - menu.findItem(R.id.portrait_aspect_ratio).isVisible = isLandscapeRatio - menu.findItem(R.id.landscape_aspect_ratio).isVisible = !isLandscapeRatio + menu.apply { + findItem(R.id.portrait_aspect_ratio).isVisible = isLandscapeRatio + findItem(R.id.landscape_aspect_ratio).isVisible = !isLandscapeRatio + } return true } @@ -84,7 +86,7 @@ class SetWallpaperActivity : SimpleActivity(), CropImageView.OnCropImageComplete } override fun onCropImageComplete(view: CropImageView?, result: CropImageView.CropResult) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && isDestroyed) + if (isActivityDestroyed()) return if (result.error == null) { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SettingsActivity.kt index a09c3bd53..4bb90d013 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SettingsActivity.kt @@ -67,7 +67,7 @@ class SettingsActivity : SimpleActivity() { } 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_holder.setOnClickListener { settings_use_english.toggle() diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SimpleActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SimpleActivity.kt index f30d65e31..42e8828dc 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SimpleActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SimpleActivity.kt @@ -1,36 +1,5 @@ package com.simplemobiletools.gallery.activities 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() { - fun tryCopyMoveFilesTo(files: ArrayList, 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): ArrayList { - val directories = ArrayList() - 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 - } -} +open class SimpleActivity : BaseSimpleActivity() diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt index 2a8099959..1c00f66a8 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt @@ -23,6 +23,7 @@ import android.support.v4.view.ViewPager import android.util.DisplayMetrics import android.view.* import android.view.animation.DecelerateInterpolator +import com.bumptech.glide.Glide import com.simplemobiletools.commons.dialogs.PropertiesDialog import com.simplemobiletools.commons.dialogs.RenameItemDialog import com.simplemobiletools.commons.extensions.* @@ -73,6 +74,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View companion object { var screenWidth = 0 var screenHeight = 0 + var wasDecodedByGlide = false } override fun onCreate(savedInstanceState: Bundle?) { @@ -185,7 +187,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View title = mPath.getFilenameFromPath() view_pager.onGlobalLayout { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !isDestroyed) { + if (!isActivityDestroyed()) { if (mMedia.isNotEmpty()) { gotMedia(mMedia) } @@ -193,7 +195,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View } reloadViewPager() - scanPath(mPath) {} + scanPath(mPath) if (config.darkBackground) view_pager.background = ColorDrawable(Color.BLACK) @@ -226,8 +228,8 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View mOrientationEventListener = object : OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) { override fun onOrientationChanged(orientation: Int) { val currOrient = when (orientation) { - in 60..134 -> ORIENT_LANDSCAPE_RIGHT - in 225..299 -> ORIENT_LANDSCAPE_LEFT + in 75..134 -> ORIENT_LANDSCAPE_RIGHT + in 225..285 -> ORIENT_LANDSCAPE_LEFT else -> ORIENT_PORTRAIT } @@ -303,7 +305,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View private fun updatePagerItems(media: MutableList) { val pagerAdapter = MyPagerAdapter(this, supportFragmentManager, media) - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !isDestroyed) { + if (!isActivityDestroyed()) { view_pager.apply { adapter = pagerAdapter currentItem = mPos @@ -321,7 +323,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View private fun startSlideshow() { if (getMediaForSlideshow()) { view_pager.onGlobalLayout { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !isDestroyed) { + if (!isActivityDestroyed()) { hideSystemUI() mSlideshowInterval = config.slideshowInterval mSlideshowMoveBackwards = config.slideshowMoveBackwards @@ -401,7 +403,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View if (mIsSlideshowActive) { if (getCurrentMedium()!!.isImage() || getCurrentMedium()!!.isGif()) { mSlideshowHandler.postDelayed({ - if (mIsSlideshowActive && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && !isDestroyed) { + if (mIsSlideshowActive && !isActivityDestroyed()) { swipeToNextMedium() } }, mSlideshowInterval * 1000L) @@ -494,52 +496,64 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View private fun saveImageAs() { val currPath = getCurrentPath() SaveAsDialog(this, currPath, false) { - Thread({ - val selectedFile = File(it) - handleSAFDialog(selectedFile) { - toast(R.string.saving) - val tmpFile = File(filesDir, ".tmp_${it.getFilenameFromPath()}") - try { - val bitmap = BitmapFactory.decodeFile(currPath) - getFileOutputStream(tmpFile) { - if (it == null) { - toast(R.string.unknown_error_occurred) - return@getFileOutputStream - } + val selectedFile = File(it) + handleSAFDialog(selectedFile) { + Thread({ + saveImageToFile(currPath, it) + }).start() + } + } + } - val oldLastModified = getCurrentFile().lastModified() - if (currPath.isJpg()) { - saveRotation(getCurrentFile(), tmpFile) - } else { - saveFile(tmpFile, bitmap, it as FileOutputStream) - } - - if (tmpFile.length() > 0 && selectedFile.exists()) { - deleteFile(selectedFile) {} - } - copyFile(tmpFile, selectedFile) - scanFile(selectedFile) {} - toast(R.string.file_saved) - - if (config.keepLastModified) { - selectedFile.setLastModified(oldLastModified) - updateLastModified(selectedFile, oldLastModified) - } - - it.flush() - it.close() - mRotationDegrees = 0f - invalidateOptionsMenu() - } - } catch (e: OutOfMemoryError) { - toast(R.string.out_of_memory_error) - } catch (e: Exception) { - showErrorToast(e) - } finally { - deleteFile(tmpFile) {} - } + private fun saveImageToFile(oldPath: String, newPath: String) { + val newFile = File(newPath) + toast(R.string.saving) + val tmpFile = File(filesDir, ".tmp_${newPath.getFilenameFromPath()}") + try { + val bitmap = BitmapFactory.decodeFile(oldPath) + getFileOutputStream(tmpFile) { + if (it == null) { + toast(R.string.unknown_error_occurred) + return@getFileOutputStream } - }).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() { val file = File(mDirectory) if (config.deleteEmptyFolders && !file.isDownloadsFolder() && file.isDirectory && file.listFiles()?.isEmpty() == true) { - deleteFile(file, true) {} + deleteFile(file, true) } - scanPath(mDirectory) {} + scanPath(mDirectory) } private fun checkOrientation() { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/DirectoryAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/DirectoryAdapter.kt index b2f585e07..74a25b4a9 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/DirectoryAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/DirectoryAdapter.kt @@ -1,22 +1,20 @@ package com.simplemobiletools.gallery.adapters 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.view.* -import com.bignerdranch.android.multiselector.ModalMultiSelectorCallback -import com.bignerdranch.android.multiselector.MultiSelector -import com.bignerdranch.android.multiselector.SwappingHolder +import android.view.Menu +import android.view.View +import android.view.ViewGroup import com.bumptech.glide.Glide 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.PropertiesDialog import com.simplemobiletools.commons.dialogs.RenameItemDialog import com.simplemobiletools.commons.extensions.* +import com.simplemobiletools.commons.views.MyRecyclerView import com.simplemobiletools.gallery.R -import com.simplemobiletools.gallery.activities.SimpleActivity import com.simplemobiletools.gallery.dialogs.ExcludeFolderDialog import com.simplemobiletools.gallery.dialogs.PickMediumDialog import com.simplemobiletools.gallery.extensions.* @@ -27,134 +25,103 @@ import kotlinx.android.synthetic.main.directory_item_list.view.* import java.io.File import java.util.* -class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList, val listener: DirOperationsListener?, val isPickIntent: Boolean, - val itemClick: (Directory) -> Unit) : RecyclerView.Adapter() { +class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: MutableList, val listener: DirOperationsListener?, recyclerView: MyRecyclerView, + val isPickIntent: Boolean, itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, itemClick) { 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 var itemViews = SparseArray() - private val selectedPositions = HashSet() - private var textColor = config.textColor private var pinnedFolders = config.pinnedFolders private var scrollHorizontally = config.scrollHorizontally private var showMediaCount = config.showMediaCount private var animateGifs = config.animateGifs private var cropThumbnails = config.cropThumbnails - fun toggleItemSelection(select: Boolean, pos: Int) { - if (select) { - 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) + init { + selectableItemCount = dirs.count() } - private fun updateTitle(cnt: Int) { - actMode?.title = "$cnt / ${dirs.size}" - actMode?.invalidate() + override fun getActionMenuId() = R.menu.cab_directories + + override fun prepareItemSelection(view: View) { + view.dir_check?.background?.applyColorFilter(primaryColor) } - private val adapterListener = object : MyAdapterListener { - override fun toggleItemSelectionAdapter(select: Boolean, position: Int) { - toggleItemSelection(select, position) - } - - override fun getSelectedPositions(): HashSet = selectedPositions + override fun markItemSelection(select: Boolean, view: View?) { + view?.dir_check?.beVisibleIf(select) } - private val multiSelectorMode = object : ModalMultiSelectorCallback(multiSelector) { - override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { - when (item.itemId) { - 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) - else -> return false + override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder { + val layoutType = if (isListViewType) R.layout.directory_item_list else R.layout.directory_item_grid + return createViewHolder(layoutType, parent) + } + + override fun onBindViewHolder(holder: MyRecyclerViewAdapter.ViewHolder, position: Int) { + val dir = dirs[position] + val view = holder.bindView(dir, !isPickIntent) { + setupView(it, dir) + } + bindViewHolder(holder, position, view) + } + + override fun getItemCount() = dirs.size + + override fun prepareActionMode(menu: Menu) { + 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 { - super.onCreateActionMode(actionMode, menu) - actMode = actionMode - activity.menuInflater.inflate(R.menu.cab_directories, menu) - return true - } + menu.findItem(R.id.cab_hide).isVisible = unhiddenCnt > 0 + menu.findItem(R.id.cab_unhide).isVisible = hiddenCnt > 0 + } - override fun onPrepareActionMode(actionMode: ActionMode?, menu: Menu): Boolean { - menu.findItem(R.id.cab_rename).isVisible = selectedPositions.size <= 1 - menu.findItem(R.id.cab_change_cover_image).isVisible = selectedPositions.size <= 1 - - checkHideBtnVisibility(menu) - checkPinBtnVisibility(menu) - - return true - } - - override fun onDestroyActionMode(actionMode: ActionMode?) { - super.onDestroyActionMode(actionMode) - selectedPositions.forEach { - itemViews[it]?.dir_check?.beGone() + private 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++ } - selectedPositions.clear() - actMode = null } - fun checkHideBtnVisibility(menu: Menu) { - var hiddenCnt = 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 - } + menu.findItem(R.id.cab_pin).isVisible = unpinnedCnt > 0 + menu.findItem(R.id.cab_unpin).isVisible = pinnedCnt > 0 } private fun showProperties() { @@ -178,7 +145,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList newItems.put(curIndex, itemViews[i]) } itemViews = newItems - actMode?.finish() + selectableItemCount = dirs.size + finishActMode() } } @@ -337,7 +296,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList) { activity.config.albumCovers = Gson().toJson(albumCovers) - actMode?.finish() + finishActMode() listener?.refreshItems() } @@ -347,30 +306,18 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList) { dirs = newDirs + selectableItemCount = dirs.size notifyDataSetChanged() - actMode?.finish() + finishActMode() } fun updateAnimateGifs(animateGifs: Boolean) { @@ -393,117 +340,31 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList -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) + if (isListViewType) { + 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) } } } - 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 - } - interface DirOperationsListener { fun refreshItems() fun tryDeleteFolders(folders: ArrayList) - fun itemLongClicked(position: Int) - fun recheckPinnedFolders() } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/ManageFoldersAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/ManageFoldersAdapter.kt new file mode 100644 index 000000000..675490a0c --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/ManageFoldersAdapter.kt @@ -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, 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(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() + (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() + } + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MediaAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MediaAdapter.kt index 039ac332a..c1a4a2c1d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MediaAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MediaAdapter.kt @@ -2,21 +2,20 @@ package com.simplemobiletools.gallery.adapters import android.graphics.PorterDuff import android.net.Uri -import android.os.Build -import android.support.v7.view.ActionMode -import android.support.v7.widget.RecyclerView import android.util.SparseArray -import android.view.* -import com.bignerdranch.android.multiselector.ModalMultiSelectorCallback -import com.bignerdranch.android.multiselector.MultiSelector -import com.bignerdranch.android.multiselector.SwappingHolder +import android.view.Menu +import android.view.View +import android.view.ViewGroup 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.RenameItemDialog -import com.simplemobiletools.commons.extensions.beGone +import com.simplemobiletools.commons.extensions.applyColorFilter 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.activities.SimpleActivity import com.simplemobiletools.gallery.dialogs.DeleteWithRememberDialog import com.simplemobiletools.gallery.extensions.* 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.util.* -class MediaAdapter(val activity: SimpleActivity, var media: MutableList, val listener: MediaOperationsListener?, val isAGetIntent: Boolean, - val allowMultiplePicks: Boolean, val itemClick: (Medium) -> Unit) : RecyclerView.Adapter() { +class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList, val listener: MediaOperationsListener?, val isAGetIntent: Boolean, + val allowMultiplePicks: Boolean, recyclerView: MyRecyclerView, itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, itemClick) { 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 var skipConfirmationDialog = false - private var itemViews = SparseArray() - private val selectedPositions = HashSet() private var scrollHorizontally = config.scrollHorizontally private var animateGifs = config.animateGifs private var cropThumbnails = config.cropThumbnails - private var textColor = config.textColor private var displayFilenames = config.displayFileNames - fun toggleItemSelection(select: Boolean, pos: Int) { - if (select) { - 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) + init { + selectableItemCount = media.count() } - private fun updateTitle(cnt: Int) { - actMode?.title = "$cnt / ${media.size}" - actMode?.invalidate() + override fun getActionMenuId() = R.menu.cab_media + + override fun prepareItemSelection(view: View) { + view.medium_check?.background?.applyColorFilter(primaryColor) } - private val adapterListener = object : MyAdapterListener { - override fun toggleItemSelectionAdapter(select: Boolean, position: Int) { - toggleItemSelection(select, position) - } - - override fun getSelectedPositions(): HashSet = selectedPositions + override fun markItemSelection(select: Boolean, view: View?) { + view?.medium_check?.beVisibleIf(select) } - private val multiSelectorMode = object : ModalMultiSelectorCallback(multiSelector) { - override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { - when (item.itemId) { - 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() - else -> return false + 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 + return createViewHolder(layoutType, parent) + } + + override fun onBindViewHolder(holder: MyRecyclerViewAdapter.ViewHolder, position: Int) { + val medium = media[position] + val view = holder.bindView(medium, !allowMultiplePicks) { + setupView(it, medium) + } + bindViewHolder(holder, position, view) + } + + override fun getItemCount() = media.size + + override fun prepareActionMode(menu: Menu) { + 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 { - super.onCreateActionMode(actionMode, menu) - 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 - } + menu.findItem(R.id.cab_hide).isVisible = unhiddenCnt > 0 + menu.findItem(R.id.cab_unhide).isVisible = hiddenCnt > 0 } private fun confirmSelection() { @@ -159,25 +127,25 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, RenameItemDialog(activity, getCurrentFile().absolutePath) { activity.runOnUiThread { listener?.refreshItems() - actMode?.finish() + finishActMode() } } } private fun editFile() { activity.openEditor(Uri.fromFile(getCurrentFile())) - actMode?.finish() + finishActMode() } private fun toggleFileVisibility(hide: Boolean) { Thread({ getSelectedMedia().forEach { val oldFile = File(it.path) - activity.toggleFileVisibility(oldFile, hide) {} + activity.toggleFileVisibility(oldFile, hide) } activity.runOnUiThread { listener?.refreshItems() - actMode?.finish() + finishActMode() } }).start() } @@ -199,20 +167,10 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, if (!isCopyOperation) { 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() { if (skipConfirmationDialog) { deleteConfirmed() @@ -243,7 +201,7 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, val removeMedia = ArrayList(selectedPositions.size) if (media.size <= selectedPositions.first()) { - actMode?.finish() + finishActMode() return } @@ -257,7 +215,6 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, } media.removeAll(removeMedia) - selectedPositions.clear() listener?.deleteFiles(files) val newItems = SparseArray() @@ -266,7 +223,8 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, .forEachIndexed { curIndex, i -> newItems.put(curIndex, itemViews[i]) } itemViews = newItems - actMode?.finish() + selectableItemCount = media.size + finishActMode() } } @@ -276,29 +234,18 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, 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?) { 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) { media = newMedia + selectableItemCount = media.size notifyDataSetChanged() - actMode?.finish() + finishActMode() } fun updateDisplayFilenames(displayFilenames: Boolean) { @@ -321,112 +268,25 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, notifyDataSetChanged() } - fun updateTextColor(textColor: Int) { - this.textColor = textColor - notifyDataSetChanged() - } + private fun setupView(view: View, medium: Medium) { + view.apply { + 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) { - toggleItemSelection(true, pos) - } - - 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) + if (isListViewType) { + photo_name.setTextColor(textColor) + play_outline.setColorFilter(textColor, PorterDuff.Mode.SRC_IN) } } } - 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 - } - interface MediaOperationsListener { fun refreshItems() fun deleteFiles(files: ArrayList) - fun itemLongClicked(position: Int) - fun selectedPaths(paths: ArrayList) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ChangeSortingDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ChangeSortingDialog.kt index 95513a98e..0af86fd6a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ChangeSortingDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ChangeSortingDialog.kt @@ -4,15 +4,15 @@ import android.content.DialogInterface import android.support.v7.app.AlertDialog import android.view.LayoutInflater import android.view.View +import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.extensions.beVisibleIf import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.gallery.R -import com.simplemobiletools.gallery.activities.SimpleActivity import com.simplemobiletools.gallery.extensions.config 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) : DialogInterface.OnClickListener { private var currSorting = 0 diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ExcludeFolderDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ExcludeFolderDialog.kt index ea386870f..e676fe0ad 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ExcludeFolderDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ExcludeFolderDialog.kt @@ -5,15 +5,15 @@ import android.view.LayoutInflater import android.view.ViewGroup import android.widget.RadioButton import android.widget.RadioGroup +import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.extensions.beVisibleIf import com.simplemobiletools.commons.extensions.getBasePath import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.gallery.R -import com.simplemobiletools.gallery.activities.SimpleActivity import com.simplemobiletools.gallery.extensions.config import kotlinx.android.synthetic.main.dialog_exclude_folder.view.* -class ExcludeFolderDialog(val activity: SimpleActivity, val selectedPaths: List, val callback: () -> Unit) { +class ExcludeFolderDialog(val activity: BaseSimpleActivity, val selectedPaths: List, val callback: () -> Unit) { val alternativePaths = getAlternativePathsList() var radioGroup: RadioGroup? = null diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/FilterMediaDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/FilterMediaDialog.kt index f99fc98c3..ce20eae97 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/FilterMediaDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/FilterMediaDialog.kt @@ -3,16 +3,16 @@ package com.simplemobiletools.gallery.dialogs import android.support.v7.app.AlertDialog import android.view.LayoutInflater import android.view.View +import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.gallery.R -import com.simplemobiletools.gallery.activities.SimpleActivity import com.simplemobiletools.gallery.extensions.config import com.simplemobiletools.gallery.helpers.GIFS import com.simplemobiletools.gallery.helpers.IMAGES import com.simplemobiletools.gallery.helpers.VIDEOS 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) init { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ManageExtendedDetailsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ManageExtendedDetailsDialog.kt index 3d8c5e3a7..bbc70402a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ManageExtendedDetailsDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ManageExtendedDetailsDialog.kt @@ -3,6 +3,7 @@ package com.simplemobiletools.gallery.dialogs import android.support.v7.app.AlertDialog import android.view.LayoutInflater import android.view.View +import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.activities.SimpleActivity @@ -10,7 +11,7 @@ import com.simplemobiletools.gallery.extensions.config import com.simplemobiletools.gallery.helpers.* import kotlinx.android.synthetic.main.dialog_manage_extended_details.view.* -class ManageExtendedDetailsDialog(val activity: SimpleActivity, val callback: (result: Int) -> Unit) { +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) init { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickDirectoryDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickDirectoryDialog.kt index e72a3395c..937f98e07 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickDirectoryDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickDirectoryDialog.kt @@ -3,15 +3,16 @@ package com.simplemobiletools.gallery.dialogs import android.support.v7.app.AlertDialog import android.support.v7.widget.GridLayoutManager import android.view.LayoutInflater +import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.dialogs.FilePickerDialog import com.simplemobiletools.commons.extensions.beGoneIf import com.simplemobiletools.commons.extensions.beVisibleIf import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.gallery.R -import com.simplemobiletools.gallery.activities.SimpleActivity import com.simplemobiletools.gallery.adapters.DirectoryAdapter import com.simplemobiletools.gallery.asynctasks.GetDirectoriesAsynctask +import com.simplemobiletools.gallery.extensions.addTempFolderIfNeeded import com.simplemobiletools.gallery.extensions.config import com.simplemobiletools.gallery.extensions.getCachedDirectories 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 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 shownDirectories = ArrayList() 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 shownDirectories = dirs - val adapter = DirectoryAdapter(activity, dirs, null, true) { - if (it.path.trimEnd('/') == sourcePath) { + val adapter = DirectoryAdapter(activity, dirs, null, view.directories_grid, true) { + if ((it as Directory).path.trimEnd('/') == sourcePath) { activity.toast(R.string.source_and_destination_same) return@DirectoryAdapter } else { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickMediumDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickMediumDialog.kt index 3596a6907..ad579e02c 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickMediumDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickMediumDialog.kt @@ -3,11 +3,11 @@ package com.simplemobiletools.gallery.dialogs import android.support.v7.app.AlertDialog import android.support.v7.widget.GridLayoutManager import android.view.LayoutInflater +import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.extensions.beGoneIf import com.simplemobiletools.commons.extensions.beVisibleIf import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.gallery.R -import com.simplemobiletools.gallery.activities.SimpleActivity import com.simplemobiletools.gallery.adapters.MediaAdapter import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask import com.simplemobiletools.gallery.extensions.config @@ -16,7 +16,7 @@ import com.simplemobiletools.gallery.helpers.VIEW_TYPE_GRID import com.simplemobiletools.gallery.models.Medium import kotlinx.android.synthetic.main.dialog_medium_picker.view.* -class PickMediumDialog(val activity: SimpleActivity, val path: String, val callback: (path: String) -> Unit) { +class PickMediumDialog(val activity: BaseSimpleActivity, val path: String, val callback: (path: String) -> Unit) { var dialog: AlertDialog var shownMedia = ArrayList() 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 shownMedia = media - val adapter = MediaAdapter(activity, media, null, true, false) { - callback(it.path) + val adapter = MediaAdapter(activity, media, null, true, false, view.media_grid) { + callback((it as Medium).path) dialog.dismiss() } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ResizeDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ResizeDialog.kt index c82c5fdce..cc2e9432f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ResizeDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ResizeDialog.kt @@ -7,14 +7,14 @@ import android.text.TextWatcher import android.view.LayoutInflater import android.view.WindowManager import android.widget.EditText +import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.extensions.value import com.simplemobiletools.gallery.R -import com.simplemobiletools.gallery.activities.SimpleActivity 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 { val view = LayoutInflater.from(activity).inflate(R.layout.resize_image, null) val widthView = view.image_width diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SaveAsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SaveAsDialog.kt index f97e2fb99..4a401e289 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SaveAsDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SaveAsDialog.kt @@ -3,15 +3,15 @@ package com.simplemobiletools.gallery.dialogs import android.support.v7.app.AlertDialog import android.view.LayoutInflater import android.view.WindowManager +import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.dialogs.FilePickerDialog import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.gallery.R -import com.simplemobiletools.gallery.activities.SimpleActivity import kotlinx.android.synthetic.main.dialog_save_as.view.* import java.io.File -class SaveAsDialog(val activity: SimpleActivity, val path: String, val appendFilename: Boolean, val callback: (savePath: String) -> Unit) { +class SaveAsDialog(val activity: BaseSimpleActivity, val path: String, val appendFilename: Boolean, val callback: (savePath: String) -> Unit) { init { var realPath = File(path).parent.trimEnd('/') diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SlideshowDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SlideshowDialog.kt index 493e8a980..e9dc60b49 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SlideshowDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SlideshowDialog.kt @@ -4,16 +4,16 @@ import android.support.v7.app.AlertDialog import android.view.LayoutInflater import android.view.View import android.view.WindowManager +import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.extensions.hideKeyboard import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.gallery.R -import com.simplemobiletools.gallery.activities.SimpleActivity import com.simplemobiletools.gallery.extensions.config import com.simplemobiletools.gallery.helpers.SLIDESHOW_DEFAULT_INTERVAL 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 init { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/activity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/activity.kt index 200b2897b..9910aa225 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/activity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/activity.kt @@ -14,11 +14,13 @@ import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions import com.bumptech.glide.request.RequestOptions import com.google.gson.Gson import com.google.gson.reflect.TypeToken +import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.gallery.BuildConfig import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.activities.SimpleActivity +import com.simplemobiletools.gallery.dialogs.PickDirectoryDialog import com.simplemobiletools.gallery.helpers.NOMEDIA import com.simplemobiletools.gallery.models.Directory import com.simplemobiletools.gallery.models.Medium @@ -89,7 +91,7 @@ fun AppCompatActivity.hideSystemUI() { View.SYSTEM_UI_FLAG_IMMERSIVE } -fun SimpleActivity.addNoMedia(path: String, callback: () -> Unit) { +fun BaseSimpleActivity.addNoMedia(path: String, callback: () -> Unit) { val file = File(path, NOMEDIA) if (file.exists()) 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) 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 var filename = oldFile.name filename = if (hide) { @@ -133,7 +135,7 @@ fun SimpleActivity.toggleFileVisibility(oldFile: File, hide: Boolean, callback: } val newFile = File(path, filename) 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 } catch (e: Exception) { loadJpg(path, target, cropThumbnails) + } catch (e: OutOfMemoryError) { + loadJpg(path, target, cropThumbnails) } } } +fun BaseSimpleActivity.tryCopyMoveFilesTo(files: ArrayList, 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): ArrayList { + val directories = ArrayList() + 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) { val options = RequestOptions() .signature(path.getFileSignature()) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt index 345ca57e4..323731665 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt @@ -7,7 +7,6 @@ import android.graphics.Color import android.graphics.Matrix import android.graphics.drawable.ColorDrawable import android.net.Uri -import android.os.Build import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -27,6 +26,7 @@ import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.activities.PhotoActivity import com.simplemobiletools.gallery.activities.ViewPagerActivity import com.simplemobiletools.gallery.extensions.* +import com.simplemobiletools.gallery.helpers.GlideDecoder import com.simplemobiletools.gallery.helpers.GlideRotateTransformation import com.simplemobiletools.gallery.helpers.MEDIUM import com.simplemobiletools.gallery.models.Medium @@ -37,7 +37,9 @@ import java.io.File import java.io.FileOutputStream class PhotoFragment : ViewPagerFragment() { + private var DEFAULT_DOUBLE_TAP_ZOOM = 5f private var isFragmentVisible = false + private var isFullscreen = false private var wasInit = false private var storedShowExtendedDetails = false 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.gif_view.setOnClickListener { photoClicked() } loadImage() @@ -131,12 +134,6 @@ class PhotoFragment : ViewPagerFragment() { private fun photoFragmentVisibilityChanged(isVisible: Boolean) { if (isVisible) { addZoomableView() - } else { - view.subsampling_view.apply { - recycle() - beGone() - background = ColorDrawable(Color.TRANSPARENT) - } } } @@ -224,9 +221,10 @@ class PhotoFragment : ViewPagerFragment() { } 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 { - //setBitmapDecoderClass(GlideDecoder::class.java) // causing random crashes on Android 7+, at rotating + setBitmapDecoderClass(GlideDecoder::class.java) maxScale = 10f beVisible() setImage(ImageSource.uri(medium.path)) @@ -268,20 +266,28 @@ class PhotoFragment : ViewPagerFragment() { val height = bitmapOptions.outHeight val bitmapAspectRatio = height / (width).toFloat() - if (context == null) - return 2f - - return if (context!!.portrait && bitmapAspectRatio <= 1f) { + return if (context == null) { + DEFAULT_DOUBLE_TAP_ZOOM + } else if (ViewPagerActivity.screenHeight / ViewPagerActivity.screenWidth.toFloat() == bitmapAspectRatio) { + DEFAULT_DOUBLE_TAP_ZOOM + } else if (ViewPagerActivity.wasDecodedByGlide) { + 1f + } else if (context!!.portrait && bitmapAspectRatio <= 1f) { ViewPagerActivity.screenHeight / height.toFloat() + } else if (context!!.portrait && bitmapAspectRatio > 1f) { + ViewPagerActivity.screenHeight / width.toFloat() } else if (!context!!.portrait && bitmapAspectRatio >= 1f) { ViewPagerActivity.screenWidth / width.toFloat() + } else if (!context!!.portrait && bitmapAspectRatio < 1f) { + ViewPagerActivity.screenWidth / height.toFloat() } else { - 2f + DEFAULT_DOUBLE_TAP_ZOOM } } 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) } @@ -292,9 +298,8 @@ class PhotoFragment : ViewPagerFragment() { setTextColor(context.config.textColor) beVisibleIf(text.isNotEmpty()) onGlobalLayout { - if (height != 0) { - val smallMargin = resources.getDimension(R.dimen.small_margin) - y = context.usableScreenSize.y - height - if (context.navigationBarHeight == 0) smallMargin else 0f + if (height != 0 && isAdded) { + y = getExtendedDetailsY(height) } } } @@ -305,7 +310,7 @@ class PhotoFragment : ViewPagerFragment() { override fun 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) } } @@ -321,13 +326,17 @@ class PhotoFragment : ViewPagerFragment() { } override fun fullscreenToggled(isFullscreen: Boolean) { + this.isFullscreen = isFullscreen view.photo_details.apply { - if (visibility == View.VISIBLE) { - val smallMargin = resources.getDimension(R.dimen.small_margin) - val fullscreenOffset = context.navigationBarHeight.toFloat() - smallMargin - val newY = context.usableScreenSize.y - height + if (isFullscreen) fullscreenOffset else -(if (context.navigationBarHeight == 0) smallMargin else 0f) - animate().y(newY) + if (isVisible()) { + animate().y(getExtendedDetailsY(height)) } } } + + 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) + } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt index e6433e246..423ecd1ea 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt @@ -34,6 +34,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee private var mCurrTimeView: TextView? = null private var mTimerHandler: Handler? = null private var mSeekBar: SeekBar? = null + private var mTimeHolder: View? = null private var mIsPlaying = false private var mIsDragged = false @@ -60,7 +61,6 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee lateinit var mView: View lateinit var medium: Medium - lateinit var mTimeHolder: View override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { mView = inflater.inflate(R.layout.pager_video_item, container, false) @@ -287,8 +287,8 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee private fun initTimeHolder() { val res = resources val height = context!!.navigationBarHeight - val left = mTimeHolder.paddingLeft - val top = mTimeHolder.paddingTop + val left = mTimeHolder!!.paddingLeft + val top = mTimeHolder!!.paddingTop var right = res.getDimension(R.dimen.timer_padding).toInt() var bottom = 0 @@ -299,7 +299,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee right += height bottom += context!!.navigationBarHeight } - mTimeHolder.setPadding(left, top, right, bottom) + mTimeHolder!!.setPadding(left, top, right, bottom) } mCurrTimeView = mView.video_curr_time @@ -307,7 +307,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee mSeekBar!!.setOnSeekBarChangeListener(this) if (mIsFullscreen) - mTimeHolder.beInvisible() + mTimeHolder!!.beInvisible() } private fun hasNavBar(): Boolean { @@ -375,7 +375,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee AnimationUtils.loadAnimation(activity, anim).apply { duration = 150 fillAfter = true - mTimeHolder.startAnimation(this) + mTimeHolder?.startAnimation(this) } } @@ -457,9 +457,13 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee releaseMediaPlayer() mSeekBar?.progress = 0 mTimerHandler?.removeCallbacksAndMessages(null) + mSurfaceView = null + mSurfaceHolder?.removeCallback(this) + mSurfaceHolder = null } private fun releaseMediaPlayer() { + mMediaPlayer?.setSurface(null) mMediaPlayer?.release() mMediaPlayer = null } @@ -551,10 +555,8 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee setTextColor(context.config.textColor) beVisibleIf(text.isNotEmpty()) onGlobalLayout { - if (height != 0) { - val smallMargin = resources.getDimension(R.dimen.small_margin) - val timeHolderHeight = mTimeHolder.height - context.navigationBarHeight - y = context.usableScreenSize.y - height - timeHolderHeight - if (context.navigationBarHeight == 0) smallMargin else 0f + if (height != 0 && isAdded) { + y = getExtendedDetailsY(height) } } } @@ -592,13 +594,16 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee mIsFullscreen = isFullscreen checkFullscreen() mView.video_details.apply { - if (visibility == View.VISIBLE) { - val smallMargin = resources.getDimension(R.dimen.small_margin) - val timeHolderHeight = mTimeHolder.height - context.navigationBarHeight.toFloat() - val fullscreenOffset = context.navigationBarHeight.toFloat() - smallMargin - val newY = context.usableScreenSize.y - height + if (mIsFullscreen) fullscreenOffset else -(timeHolderHeight + if (context.navigationBarHeight == 0) smallMargin else 0f) - animate().y(newY) + if (isVisible()) { + animate().y(getExtendedDetailsY(height)) } } } + + 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) + } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/GlideDecoder.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/GlideDecoder.kt index 78ea3c9dc..55e12722a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/GlideDecoder.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/GlideDecoder.kt @@ -23,6 +23,7 @@ class GlideDecoder : ImageDecoder { val targetWidth = if (ViewPagerActivity.screenWidth == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenWidth val targetHeight = if (ViewPagerActivity.screenHeight == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenHeight + ViewPagerActivity.wasDecodedByGlide = true val options = RequestOptions() .signature(uri.path.getFileSignature()) .diskCacheStrategy(DiskCacheStrategy.RESOURCE) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaFetcher.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaFetcher.kt index c42db1b4e..cce57aa36 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaFetcher.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaFetcher.kt @@ -247,7 +247,6 @@ class MediaFetcher(val context: Context) { private fun isThisOrParentExcluded(path: String, excludedPaths: MutableSet, includedPaths: MutableSet) = includedPaths.none { path.startsWith(it) } && excludedPaths.any { path.startsWith(it) } - private fun getMediaInFolder(folder: String, curMedia: ArrayList, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int) { val files = File(folder).listFiles() ?: return for (file in files) { @@ -282,7 +281,7 @@ class MediaFetcher(val context: Context) { val isAlreadyAdded = curMedia.any { it.path == file.absolutePath } if (!isAlreadyAdded) { 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 } - return if (sorting and SORT_DESCENDING > 0) + return if (sorting and SORT_DESCENDING > 0) { "$sortValue DESC" - else + } else { "$sortValue ASC" + } } private fun getNoMediaFolders(): ArrayList { diff --git a/app/src/main/res/layout/activity_excluded_folders.xml b/app/src/main/res/layout/activity_excluded_folders.xml deleted file mode 100644 index 64df37244..000000000 --- a/app/src/main/res/layout/activity_excluded_folders.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - diff --git a/app/src/main/res/layout/activity_included_folders.xml b/app/src/main/res/layout/activity_included_folders.xml deleted file mode 100644 index 527cdd94a..000000000 --- a/app/src/main/res/layout/activity_included_folders.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 9432206a7..073f3fd19 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -33,7 +33,7 @@ android:text="@string/change_filters_underlined" android:visibility="gone"/> - + + + + + + + diff --git a/app/src/main/res/layout/activity_media.xml b/app/src/main/res/layout/activity_media.xml index 94422b430..95bc05417 100644 --- a/app/src/main/res/layout/activity_media.xml +++ b/app/src/main/res/layout/activity_media.xml @@ -33,7 +33,7 @@ android:text="@string/change_filters_underlined" android:visibility="gone"/> - - - + android:src="@drawable/ic_check" + android:visibility="gone"/> + android:src="@drawable/ic_pin" + android:visibility="gone"/> + android:src="@drawable/ic_check" + android:visibility="gone"/> - - + android:layout_marginTop="@dimen/medium_margin"/> diff --git a/app/src/main/res/layout/photo_video_item_grid.xml b/app/src/main/res/layout/photo_video_item_grid.xml index a8fdf5d21..4ec84403d 100644 --- a/app/src/main/res/layout/photo_video_item_grid.xml +++ b/app/src/main/res/layout/photo_video_item_grid.xml @@ -4,6 +4,8 @@ android:id="@+id/media_item_holder" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:clickable="true" + android:focusable="true" android:padding="1px"> diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index f4091292b..07b53a1c9 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,5 +1,5 @@ - - + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index f4091292b..07b53a1c9 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,5 +1,5 @@ - - + + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 0a90b0dcd..9676c7754 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -23,8 +23,8 @@ Lautstärke Helligkeit Nicht erneut fragen (in dieser Sitzung) - Lock orientation - Unlock orientation + Bildschirmausrichtung sperren + Bildschirmausrichtung entsperren Filter diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 7f9f0e294..3498ff272 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -23,8 +23,8 @@ Volume Luminosità Non chiedere nuovamente in questa sessione - Lock orientation - Unlock orientation + Blocca orientamento + Sblocca orientamento Filtra i media @@ -115,7 +115,7 @@ Anima le GIF in miniatura Luminosità max durante visualizzazione Ritaglia le miniature in quadrati - Ruota a schermo intero per + Ruota schermo per Impostazione di sistema Rotazione dispositivo Proporzioni @@ -133,7 +133,7 @@ Una galleria per visualizzare foto e video senza pubblicità. - 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. diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 1f49212f3..bbd0a82dd 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -27,12 +27,12 @@ Schermrotatie ontgrendelen - Media kiezen + Filter media Afbeeldingen Video\'s GIF-bestanden Geen bestanden gevonden met de huidige filters. - Media kiezen + Filters aanpassen 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? @@ -46,8 +46,8 @@ Verwijder alles uit de lijst van uitgesloten mappen? Dit zal de mappen zelf niet verwijderen. - Ingesloten mappen - Ingesloten mappen beheren + Toegevoegde mappen + Toegevoegde mappen beheren Map toevoegen Als er mappen zijn die wel media bevatten, maar niet niet door de galerij worden herkend, voeg deze mappen dan hier handmatig toe.\n\nHet hier toevoegen van mappen zal andere mappen niet uitsluiten. diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index c6b18239b..eb749c168 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -1,7 +1,7 @@ - Simple Gallery - Simple Gallery + Prosta Galeria + Galeria Edytuj Uruchom aplikację aparatu (ukryty) @@ -23,8 +23,8 @@ Głośność Jasność Nie pytaj więcej w tej sesji - Lock orientation - Unlock orientation + Zablokuj orientację ekranu + Odblokuj orientację ekranu Filtruj multimedia @@ -35,7 +35,7 @@ Zmień filtry - 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ć? + 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ć? Wyklucz Wykluczone foldery Zarządzaj wykluczonymi folderami @@ -49,7 +49,7 @@ Dołączone foldery Zarządzaj dołączonymi folderami Dodaj folder - Jeśli masz jakieś foldery z multimediami, ale aplikacja ich nie wykryła, możesz je tutaj dodać ręcznie. + Jeśli masz jakieś foldery z multimediami, ale aplikacja ich nie wykryła, możesz je dodać ręcznie tutaj. Zmień rozmiar @@ -131,13 +131,13 @@ - Darmowa galeria bez reklam do przeglądania obrazów i filmów. + Prosta galeria bez reklam do przeglądania obrazów i filmów. - 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. - - Niniejsza aplikacja jest tylko częścią naszego zestawu prostych aplikacji. Znajdziecie je na stronie http://www.simplemobiletools.com. + 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ą naszej kolekcji prostych narzędzi. Ta, jak i pozostałe, dostępne są na stronie http://www.simplemobiletools.com 要显示的媒体文件 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index ee1e5614a..8cb25a2bb 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,6 +7,4 @@ @color/default_dark_theme_text_color @color/default_dark_theme_background_color - - @color/color_primary diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index a8c998266..5475edd14 100644 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -2,6 +2,9 @@ + + Added new options to use english language on non-english devices, to password protect whole app and to lock screen orientation at fullscreen view + Added an option to keep last-modified field at file copy/move/rename Added an option to hide folder media count on the main screen Added an option to show customizable extended details over fullscreen media