Merge pull request #30 from SimpleMobileTools/master

upd
This commit is contained in:
solokot 2018-05-27 11:55:43 +03:00 committed by GitHub
commit 5492f003a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
181 changed files with 936 additions and 259 deletions

View file

@ -1,6 +1,29 @@
Changelog
==========
Version 4.1.1 *(2018-05-26)*
----------------------------
* Always set folder thumbnail based on folder content sorting
* Make sure hidden folders have the "(hidden)" appended
Version 4.1.0 *(2018-05-25)*
----------------------------
* Added sorting by Date Taken
* Fixed file renaming on Android Oreo
* Fixed some scrollbar glitches
* Fixed broken "Use english language" in some cases
* Make sure only the proper files are shown at "Show all folders content"
* Many other smaller UX, stability improvements and bugfixes
Version 4.0.0 *(2018-05-13)*
----------------------------
* Allow customizing the app launcher color
* Remove the top spinning circle at initial launch
* Many other bugfixes and UX/stability improvements
Version 3.8.2 *(2018-04-26)*
----------------------------

View file

@ -11,8 +11,8 @@ android {
applicationId "com.simplemobiletools.gallery"
minSdkVersion 16
targetSdkVersion 27
versionCode 176
versionName "3.8.2"
versionCode 179
versionName "4.1.1"
multiDexEnabled true
setProperty("archivesBaseName", "gallery")
}
@ -47,16 +47,16 @@ ext {
}
dependencies {
implementation 'com.simplemobiletools:commons:3.19.21'
implementation 'com.simplemobiletools:commons:4.1.4'
implementation 'com.theartofdev.edmodo:android-image-cropper:2.7.0'
implementation 'com.android.support:multidex:1.0.3'
implementation 'it.sephiroth.android.exif:library:1.0.1'
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.12'
implementation 'com.github.chrisbanes:PhotoView:2.1.3'
kapt "android.arch.persistence.room:compiler:1.0.0"
implementation "android.arch.persistence.room:runtime:1.0.0"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
kapt "android.arch.persistence.room:compiler:1.1.0"
implementation "android.arch.persistence.room:runtime:1.1.0"
annotationProcessor "android.arch.persistence.room:compiler:1.1.0"
//implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.9.0'
implementation 'com.github.tibbi:subsampling-scale-image-view:v3.10.0-fork'

View file

@ -20,8 +20,6 @@
android:name=".activities.SplashActivity"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
@ -212,5 +210,252 @@
<action android:name="com.simplemobiletools.REFRESH_MEDIA"/>
</intent-filter>
</receiver>
<!-- Do not append ".Orange" to the default alias "name", it would remove the old homescreen launcher of users at upgrade -->
<activity-alias
android:name=".activities.SplashActivity"
android:enabled="true"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Red"
android:enabled="false"
android:icon="@mipmap/ic_launcher_red"
android:roundIcon="@mipmap/ic_launcher_red"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Pink"
android:enabled="false"
android:icon="@mipmap/ic_launcher_pink"
android:roundIcon="@mipmap/ic_launcher_pink"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Purple"
android:enabled="false"
android:icon="@mipmap/ic_launcher_purple"
android:roundIcon="@mipmap/ic_launcher_purple"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Deep_purple"
android:enabled="false"
android:icon="@mipmap/ic_launcher_deep_purple"
android:roundIcon="@mipmap/ic_launcher_deep_purple"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Indigo"
android:enabled="false"
android:icon="@mipmap/ic_launcher_indigo"
android:roundIcon="@mipmap/ic_launcher_indigo"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Blue"
android:enabled="false"
android:icon="@mipmap/ic_launcher_blue"
android:roundIcon="@mipmap/ic_launcher_blue"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Light_blue"
android:enabled="false"
android:icon="@mipmap/ic_launcher_light_blue"
android:roundIcon="@mipmap/ic_launcher_light_blue"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Cyan"
android:enabled="false"
android:icon="@mipmap/ic_launcher_cyan"
android:roundIcon="@mipmap/ic_launcher_cyan"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Teal"
android:enabled="false"
android:icon="@mipmap/ic_launcher_teal"
android:roundIcon="@mipmap/ic_launcher_teal"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Green"
android:enabled="false"
android:icon="@mipmap/ic_launcher_green"
android:roundIcon="@mipmap/ic_launcher_green"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Light_green"
android:enabled="false"
android:icon="@mipmap/ic_launcher_light_green"
android:roundIcon="@mipmap/ic_launcher_light_green"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Lime"
android:enabled="false"
android:icon="@mipmap/ic_launcher_lime"
android:roundIcon="@mipmap/ic_launcher_lime"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Yellow"
android:enabled="false"
android:icon="@mipmap/ic_launcher_yellow"
android:roundIcon="@mipmap/ic_launcher_yellow"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Amber"
android:enabled="false"
android:icon="@mipmap/ic_launcher_amber"
android:roundIcon="@mipmap/ic_launcher_amber"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Deep_orange"
android:enabled="false"
android:icon="@mipmap/ic_launcher_deep_orange"
android:roundIcon="@mipmap/ic_launcher_deep_orange"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Brown"
android:enabled="false"
android:icon="@mipmap/ic_launcher_brown"
android:roundIcon="@mipmap/ic_launcher_brown"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Blue_grey"
android:enabled="false"
android:icon="@mipmap/ic_launcher_blue_grey"
android:roundIcon="@mipmap/ic_launcher_blue_grey"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Grey_black"
android:enabled="false"
android:icon="@mipmap/ic_launcher_grey_black"
android:roundIcon="@mipmap/ic_launcher_grey_black"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
</application>
</manifest>

View file

@ -176,6 +176,7 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
}
Intent().apply {
data = saveUri
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
setResult(RESULT_OK, this)
}
@ -260,7 +261,7 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
}
private fun scanFinalPath(path: String) {
scanPath(path) {
scanPathRecursively(path) {
setResult(Activity.RESULT_OK, intent)
toast(R.string.file_saved)
finish()

View file

@ -5,7 +5,7 @@ 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.extensions.scanPathRecursively
import com.simplemobiletools.commons.interfaces.RefreshRecyclerViewListener
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.adapters.ManageFoldersAdapter
@ -55,7 +55,7 @@ class IncludedFoldersActivity : SimpleActivity(), RefreshRecyclerViewListener {
config.addIncludedFolder(it)
updateFolders()
Thread {
scanPath(it)
scanPathRecursively(it)
}.start()
}
}

View file

@ -26,7 +26,7 @@ import com.simplemobiletools.commons.views.MyRecyclerView
import com.simplemobiletools.gallery.BuildConfig
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.adapters.DirectoryAdapter
import com.simplemobiletools.gallery.databases.GalleryDataBase
import com.simplemobiletools.gallery.databases.GalleryDatabase
import com.simplemobiletools.gallery.dialogs.ChangeSortingDialog
import com.simplemobiletools.gallery.dialogs.FilterMediaDialog
import com.simplemobiletools.gallery.extensions.*
@ -72,7 +72,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
appLaunched()
appLaunched(BuildConfig.APPLICATION_ID)
mIsPickImageIntent = isPickImageIntent(intent)
mIsPickVideoIntent = isPickVideoIntent(intent)
@ -188,10 +188,11 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
override fun onDestroy() {
super.onDestroy()
config.temporarilyShowHidden = false
config.tempSkipDeleteConfirmation = false
mTempShowHiddenHandler.removeCallbacksAndMessages(null)
removeTempFolder()
if (!isChangingConfigurations) {
GalleryDataBase.destroyInstance()
GalleryDatabase.destroyInstance()
}
}
@ -294,11 +295,6 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
val getVideosOnly = mIsPickVideoIntent || mIsGetVideoContentIntent
getCachedDirectories(getVideosOnly, getImagesOnly) {
if (!mLoadedInitialPhotos) {
runOnUiThread {
directories_refresh_layout.isRefreshing = true
}
}
gotDirectories(addTempFolderIfNeeded(it))
}
}
@ -542,7 +538,8 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
}
private fun fillIntentPath(resultData: Intent, resultIntent: Intent) {
val path = resultData.data.path
val data = resultData.data
val path = if (data.toString().startsWith("/")) data.toString() else data.path
val uri = getFilePublicUri(File(path), BuildConfig.APPLICATION_ID)
val type = path.getMimeType()
resultIntent.setDataAndTypeAndNormalize(uri, type)
@ -595,9 +592,10 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
val isSortingAscending = config.directorySorting and SORT_DESCENDING == 0
val mediumDao = galleryDB.MediumDao()
val directoryDao = galleryDB.DirectoryDao()
val getProperDateTaken = config.directorySorting and SORT_BY_DATE_TAKEN != 0
for (directory in dirs) {
val curMedia = mediaFetcher.getFilesFrom(directory.path, getImagesOnly, getVideosOnly)
val curMedia = mediaFetcher.getFilesFrom(directory.path, getImagesOnly, getVideosOnly, getProperDateTaken)
val newDir = if (curMedia.isEmpty()) {
directory
} else {
@ -611,6 +609,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
directory.apply {
tmb = newDir.tmb
name = newDir.name
mediaCnt = newDir.mediaCnt
modified = newDir.modified
taken = newDir.taken
@ -632,13 +631,14 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
}
}
val foldersToScan = mediaFetcher.getFoldersToScan("")
val foldersToScan = mediaFetcher.getFoldersToScan()
dirs.forEach {
foldersToScan.remove(it.path)
}
// check the remaining folders which were not cached at all yet
for (folder in foldersToScan) {
val newMedia = mediaFetcher.getFilesFrom(folder, getImagesOnly, getVideosOnly)
val newMedia = mediaFetcher.getFilesFrom(folder, getImagesOnly, getVideosOnly, getProperDateTaken)
if (newMedia.isEmpty()) {
continue
}
@ -779,7 +779,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
private fun getCurrentlyDisplayedDirs() = getRecyclerAdapter()?.dirs ?: ArrayList()
private fun getBubbleTextItem(index: Int) = getRecyclerAdapter()?.dirs?.getOrNull(index)?.getBubbleText() ?: ""
private fun getBubbleTextItem(index: Int) = getRecyclerAdapter()?.dirs?.getOrNull(index)?.getBubbleText(config.directorySorting) ?: ""
private fun setupLatestMediaId() {
Thread {
@ -873,6 +873,8 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
add(Release(158, R.string.release_158))
add(Release(159, R.string.release_159))
add(Release(163, R.string.release_163))
add(Release(177, R.string.release_177))
add(Release(178, R.string.release_178))
checkWhatsNew(this, BuildConfig.VERSION_CODE)
}
}

View file

@ -175,6 +175,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
super.onDestroy()
if (config.showAll) {
config.temporarilyShowHidden = false
config.tempSkipDeleteConfirmation = false
}
mTempShowHiddenHandler.removeCallbacksAndMessages(null)
@ -333,20 +334,22 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
media_horizontal_fastscroller.isHorizontal = true
media_horizontal_fastscroller.beVisibleIf(allowHorizontalScroll)
val sorting = config.getFileSorting(mPath)
if (allowHorizontalScroll) {
media_horizontal_fastscroller.allowBubbleDisplay = config.showInfoBubble
media_horizontal_fastscroller.setViews(media_grid, media_refresh_layout) {
media_horizontal_fastscroller.updateBubbleText(getBubbleTextItem(it))
media_horizontal_fastscroller.updateBubbleText(getBubbleTextItem(it, sorting))
}
} else {
media_vertical_fastscroller.allowBubbleDisplay = config.showInfoBubble
media_vertical_fastscroller.setViews(media_grid, media_refresh_layout) {
media_vertical_fastscroller.updateBubbleText(getBubbleTextItem(it))
media_vertical_fastscroller.updateBubbleText(getBubbleTextItem(it, sorting))
}
}
}
private fun getBubbleTextItem(index: Int) = getMediaAdapter()?.media?.getOrNull(index)?.getBubbleText() ?: ""
private fun getBubbleTextItem(index: Int, sorting: Int) = getMediaAdapter()?.media?.getOrNull(index)?.getBubbleText(sorting) ?: ""
private fun checkLastMediaChanged() {
if (isActivityDestroyed())
@ -479,6 +482,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
mCurrAsyncTask = GetMediaAsynctask(applicationContext, mPath, mIsGetImageIntent, mIsGetVideoIntent, mShowAll) {
gotMedia(it)
}
mCurrAsyncTask!!.execute()
}

View file

@ -67,14 +67,14 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
mIsFromGallery = intent.getBooleanExtra(IS_FROM_GALLERY, false)
if (mUri!!.scheme == "file") {
scanPath(mUri!!.path)
scanPathRecursively(mUri!!.path)
sendViewPagerIntent(mUri!!.path)
finish()
return
} else {
val path = applicationContext.getRealPathFromURI(mUri!!) ?: ""
if (path != mUri.toString() && path.isNotEmpty() && mUri!!.authority != "mms") {
scanPath(mUri!!.path)
scanPathRecursively(mUri!!.path)
sendViewPagerIntent(path)
finish()
return

View file

@ -1,5 +1,30 @@
package com.simplemobiletools.gallery.activities
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.gallery.R
open class SimpleActivity : BaseSimpleActivity()
open class SimpleActivity : BaseSimpleActivity() {
override fun getAppIconIDs() = arrayListOf(
R.mipmap.ic_launcher_red,
R.mipmap.ic_launcher_pink,
R.mipmap.ic_launcher_purple,
R.mipmap.ic_launcher_deep_purple,
R.mipmap.ic_launcher_indigo,
R.mipmap.ic_launcher_blue,
R.mipmap.ic_launcher_light_blue,
R.mipmap.ic_launcher_cyan,
R.mipmap.ic_launcher_teal,
R.mipmap.ic_launcher_green,
R.mipmap.ic_launcher_light_green,
R.mipmap.ic_launcher_lime,
R.mipmap.ic_launcher_yellow,
R.mipmap.ic_launcher_amber,
R.mipmap.ic_launcher,
R.mipmap.ic_launcher_deep_orange,
R.mipmap.ic_launcher_brown,
R.mipmap.ic_launcher_blue_grey,
R.mipmap.ic_launcher_grey_black
)
override fun getAppLauncherName() = getString(R.string.app_launcher_name)
}

View file

@ -58,7 +58,6 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private var mPos = -1
private var mShowAll = false
private var mIsSlideshowActive = false
private var mSkipConfirmationDialog = false
private var mRotationDegrees = 0
private var mPrevHashcode = 0
@ -182,7 +181,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
if (!getDoesFilePathExist(mPath)) {
Thread {
scanPath(mPath)
scanPathRecursively(mPath)
}.start()
finish()
return
@ -554,7 +553,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
copyFile(tmpPath, newPath)
scanPath(newPath)
scanPathRecursively(newPath)
toast(R.string.file_saved)
if (config.keepLastModified) {
@ -728,7 +727,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
private fun checkDeleteConfirmation() {
if (mSkipConfirmationDialog || config.skipDeleteConfirmation) {
if (config.tempSkipDeleteConfirmation || config.skipDeleteConfirmation) {
deleteConfirmed()
} else {
askConfirmDelete()
@ -737,7 +736,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun askConfirmDelete() {
DeleteWithRememberDialog(this, getString(R.string.proceed_with_deletion)) {
mSkipConfirmationDialog = it
config.tempSkipDeleteConfirmation = it
deleteConfirmed()
}
}
@ -833,7 +832,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
tryDeleteFileDirItem(fileDirItem, true)
}
scanPath(mDirectory)
scanPathRecursively(mDirectory)
}
private fun checkOrientation() {

View file

@ -61,8 +61,8 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
}
override fun onBindViewHolder(holder: MyRecyclerViewAdapter.ViewHolder, position: Int) {
val dir = dirs[position]
val view = holder.bindView(dir, !isPickIntent) { itemView, layoutPosition ->
val dir = dirs.getOrNull(position) ?: return
val view = holder.bindView(dir, !isPickIntent) { itemView, adapterPosition ->
setupView(itemView, dir)
}
bindViewHolder(holder, position, view)
@ -169,7 +169,10 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
tmb = File(it, tmb.getFilenameFromPath()).absolutePath
}
updateDirs(dirs)
listener?.updateDirectories(dirs.toList() as ArrayList)
Thread {
activity.galleryDB.DirectoryDao().updateDirectoryAfterRename(firstDir.tmb, firstDir.name, firstDir.path, sourcePath)
listener?.refreshItems()
}.start()
}
}
}
@ -400,6 +403,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
dirs = newDirs.clone() as ArrayList<Directory>
notifyDataSetChanged()
finishActMode()
fastScroller?.measureRecyclerView()
}
}

View file

@ -43,7 +43,7 @@ class ManageFoldersAdapter(activity: BaseSimpleActivity, var folders: ArrayList<
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val folder = folders[position]
val view = holder.bindView(folder) { itemView, layoutPosition ->
val view = holder.bindView(folder) { itemView, adapterPosition ->
setupView(itemView, folder)
}
bindViewHolder(holder, position, view)

View file

@ -45,7 +45,7 @@ class ManageHiddenFoldersAdapter(activity: BaseSimpleActivity, var folders: Arra
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val folder = folders[position]
val view = holder.bindView(folder) { itemView, layoutPosition ->
val view = holder.bindView(folder) { itemView, adapterPosition ->
setupView(itemView, folder)
}
bindViewHolder(holder, position, view)

View file

@ -31,7 +31,6 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
private val config = activity.config
private val isListViewType = config.viewTypeFiles == VIEW_TYPE_LIST
private var skipConfirmationDialog = false
private var visibleItemPaths = ArrayList<String>()
private var loadImageInstantly = false
private var delayHandler = Handler(Looper.getMainLooper())
@ -64,9 +63,9 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
}
override fun onBindViewHolder(holder: MyRecyclerViewAdapter.ViewHolder, position: Int) {
val medium = media[position]
val medium = media.getOrNull(position) ?: return
visibleItemPaths.add(medium.path)
val view = holder.bindView(medium, !allowMultiplePicks) { itemView, layoutPosition ->
val view = holder.bindView(medium, !allowMultiplePicks) { itemView, adapterPosition ->
setupView(itemView, medium)
}
bindViewHolder(holder, position, view)
@ -152,12 +151,13 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
RenameItemDialog(activity, oldPath) {
Thread {
activity.updateDBMediaPath(oldPath, it)
}.start()
activity.runOnUiThread {
enableInstantLoad()
listener?.refreshItems()
finishActMode()
}
}.start()
}
}
@ -201,7 +201,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
}
private fun checkDeleteConfirmation() {
if (skipConfirmationDialog || config.skipDeleteConfirmation) {
if (config.tempSkipDeleteConfirmation || config.skipDeleteConfirmation) {
deleteFiles()
} else {
askConfirmDelete()
@ -212,7 +212,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
val items = resources.getQuantityString(R.plurals.delete_items, selectedPositions.size, selectedPositions.size)
val question = String.format(resources.getString(R.string.deletion_confirmation), items)
DeleteWithRememberDialog(activity, question) {
skipConfirmationDialog = it
config.tempSkipDeleteConfirmation = it
deleteFiles()
}
}
@ -260,6 +260,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
enableInstantLoad()
notifyDataSetChanged()
finishActMode()
fastScroller?.measureRecyclerView()
}, 100L)
}
}

View file

@ -57,7 +57,7 @@ class MyPagerAdapter(val activity: ViewPagerActivity, fm: FragmentManager, val m
// try fixing TransactionTooLargeException crash on Android Nougat, tip from https://stackoverflow.com/a/43193425/1967672
override fun saveState(): Parcelable? {
val bundle = super.saveState() as Bundle?
bundle!!.putParcelableArray("states", null)
bundle?.putParcelableArray("states", null)
return bundle
}
}

View file

@ -2,6 +2,8 @@ package com.simplemobiletools.gallery.asynctasks
import android.content.Context
import android.os.AsyncTask
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_TAKEN
import com.simplemobiletools.commons.models.FileDirItem.Companion.sorting
import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.helpers.MediaFetcher
import com.simplemobiletools.gallery.models.Medium
@ -13,19 +15,19 @@ class GetMediaAsynctask(val context: Context, val mPath: String, val isPickImage
private val mediaFetcher = MediaFetcher(context)
override fun doInBackground(vararg params: Void): ArrayList<Medium> {
val getProperDateTaken = sorting and SORT_BY_DATE_TAKEN != 0
return if (showAll) {
val foldersToScan = mediaFetcher.getFoldersToScan("")
val foldersToScan = mediaFetcher.getFoldersToScan()
val media = ArrayList<Medium>()
for (folder in foldersToScan) {
val newMedia = mediaFetcher.getFilesFrom(folder, isPickImage, isPickVideo)
foldersToScan.forEach {
val newMedia = mediaFetcher.getFilesFrom(it, isPickImage, isPickVideo, getProperDateTaken)
media.addAll(newMedia)
}
Medium.sorting = context.config.getFileSorting("")
media.sort()
MediaFetcher(context).sortMedia(media, context.config.getFileSorting(""))
media
} else {
mediaFetcher.getFilesFrom(mPath, isPickImage, isPickVideo)
mediaFetcher.getFilesFrom(mPath, isPickImage, isPickVideo, getProperDateTaken)
}
}

View file

@ -10,28 +10,30 @@ import com.simplemobiletools.gallery.models.Directory
import com.simplemobiletools.gallery.models.Medium
@Database(entities = [(Directory::class), (Medium::class)], version = 2)
abstract class GalleryDataBase : RoomDatabase() {
abstract class GalleryDatabase : RoomDatabase() {
abstract fun DirectoryDao(): DirectoryDao
abstract fun MediumDao(): MediumDao
companion object {
private var INSTANCE: GalleryDataBase? = null
private var db: GalleryDatabase? = null
fun getInstance(context: Context): GalleryDataBase {
if (INSTANCE == null) {
synchronized(GalleryDataBase::class) {
INSTANCE = Room.databaseBuilder(context.applicationContext, GalleryDataBase::class.java, "gallery.db")
fun getInstance(context: Context): GalleryDatabase {
if (db == null) {
synchronized(GalleryDatabase::class) {
if (db == null) {
db = Room.databaseBuilder(context.applicationContext, GalleryDatabase::class.java, "gallery.db")
.fallbackToDestructiveMigration()
.build()
}
}
return INSTANCE!!
}
return db!!
}
fun destroyInstance() {
INSTANCE = null
db = null
}
}
}

View file

@ -44,6 +44,7 @@ class ChangeSortingDialog(val activity: BaseSimpleActivity, val isDirectorySorti
currSorting and SORT_BY_PATH != 0 -> sortingRadio.sorting_dialog_radio_path
currSorting and SORT_BY_SIZE != 0 -> sortingRadio.sorting_dialog_radio_size
currSorting and SORT_BY_DATE_MODIFIED != 0 -> sortingRadio.sorting_dialog_radio_last_modified
currSorting and SORT_BY_DATE_TAKEN != 0 -> sortingRadio.sorting_dialog_radio_date_taken
else -> sortingRadio.sorting_dialog_radio_name
}
sortBtn.isChecked = true
@ -65,7 +66,8 @@ class ChangeSortingDialog(val activity: BaseSimpleActivity, val isDirectorySorti
R.id.sorting_dialog_radio_name -> SORT_BY_NAME
R.id.sorting_dialog_radio_path -> SORT_BY_PATH
R.id.sorting_dialog_radio_size -> SORT_BY_SIZE
else -> SORT_BY_DATE_MODIFIED
R.id.sorting_dialog_radio_last_modified -> SORT_BY_DATE_MODIFIED
else -> SORT_BY_DATE_TAKEN
}
if (view.sorting_dialog_radio_order.checkedRadioButtonId == R.id.sorting_dialog_radio_descending) {

View file

@ -72,6 +72,7 @@ class PickDirectoryDialog(val activity: BaseSimpleActivity, val sourcePath: Stri
}
val scrollHorizontally = activity.config.scrollHorizontally && isGridViewType
val sorting = activity.config.directorySorting
view.apply {
directories_grid.adapter = adapter
@ -84,12 +85,12 @@ class PickDirectoryDialog(val activity: BaseSimpleActivity, val sourcePath: Stri
if (scrollHorizontally) {
directories_horizontal_fastscroller.allowBubbleDisplay = activity.config.showInfoBubble
directories_horizontal_fastscroller.setViews(directories_grid) {
directories_horizontal_fastscroller.updateBubbleText(dirs[it].getBubbleText())
directories_horizontal_fastscroller.updateBubbleText(dirs[it].getBubbleText(sorting))
}
} else {
directories_vertical_fastscroller.allowBubbleDisplay = activity.config.showInfoBubble
directories_vertical_fastscroller.setViews(directories_grid) {
directories_vertical_fastscroller.updateBubbleText(dirs[it].getBubbleText())
directories_vertical_fastscroller.updateBubbleText(dirs[it].getBubbleText(sorting))
}
}
}

View file

@ -68,6 +68,7 @@ class PickMediumDialog(val activity: BaseSimpleActivity, val path: String, val c
}
val scrollHorizontally = activity.config.scrollHorizontally && isGridViewType
val sorting = activity.config.getFileSorting(path)
view.apply {
media_grid.adapter = adapter
@ -80,12 +81,12 @@ class PickMediumDialog(val activity: BaseSimpleActivity, val path: String, val c
if (scrollHorizontally) {
media_horizontal_fastscroller.allowBubbleDisplay = activity.config.showInfoBubble
media_horizontal_fastscroller.setViews(media_grid) {
media_horizontal_fastscroller.updateBubbleText(media[it].getBubbleText())
media_horizontal_fastscroller.updateBubbleText(media[it].getBubbleText(sorting))
}
} else {
media_vertical_fastscroller.allowBubbleDisplay = activity.config.showInfoBubble
media_vertical_fastscroller.setViews(media_grid) {
media_vertical_fastscroller.updateBubbleText(media[it].getBubbleText())
media_vertical_fastscroller.updateBubbleText(media[it].getBubbleText(sorting))
}
}
}

View file

@ -106,7 +106,7 @@ fun BaseSimpleActivity.addNoMedia(path: String, callback: () -> Unit) {
val fileDocument = getDocumentFile(path)
if (fileDocument?.exists() == true && fileDocument.isDirectory) {
fileDocument.createFile("", NOMEDIA)
applicationContext.scanFile(file) {
applicationContext.scanFileRecursively(file) {
callback()
}
} else {
@ -117,7 +117,7 @@ fun BaseSimpleActivity.addNoMedia(path: String, callback: () -> Unit) {
} else {
try {
file.createNewFile()
applicationContext.scanFile(file) {
applicationContext.scanFileRecursively(file) {
callback()
}
} catch (e: Exception) {

View file

@ -16,11 +16,11 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.request.RequestOptions
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.OTG_PATH
import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SettingsActivity
import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask
import com.simplemobiletools.gallery.databases.GalleryDataBase
import com.simplemobiletools.gallery.databases.GalleryDatabase
import com.simplemobiletools.gallery.helpers.*
import com.simplemobiletools.gallery.interfaces.DirectoryDao
import com.simplemobiletools.gallery.models.Directory
@ -70,7 +70,7 @@ fun Context.launchSettings() {
val Context.config: Config get() = Config.newInstance(applicationContext)
val Context.galleryDB: GalleryDataBase get() = GalleryDataBase.getInstance(applicationContext)
val Context.galleryDB: GalleryDatabase get() = GalleryDatabase.getInstance(applicationContext)
fun Context.movePinnedDirectoriesToFront(dirs: ArrayList<Directory>): ArrayList<Directory> {
val foundFolders = ArrayList<Directory>()
@ -96,9 +96,26 @@ fun Context.movePinnedDirectoriesToFront(dirs: ArrayList<Directory>): ArrayList<
@Suppress("UNCHECKED_CAST")
fun Context.getSortedDirectories(source: ArrayList<Directory>): ArrayList<Directory> {
Directory.sorting = config.directorySorting
val sorting = config.directorySorting
val dirs = source.clone() as ArrayList<Directory>
dirs.sort()
dirs.sortWith(Comparator { o1, o2 ->
o1 as Directory
o2 as Directory
var result = when {
sorting and SORT_BY_NAME != 0 -> AlphanumericComparator().compare(o1.name.toLowerCase(), o2.name.toLowerCase())
sorting and SORT_BY_PATH != 0 -> AlphanumericComparator().compare(o1.path.toLowerCase(), o2.path.toLowerCase())
sorting and SORT_BY_SIZE != 0 -> o1.size.compareTo(o2.size)
sorting and SORT_BY_DATE_MODIFIED != 0 -> o1.modified.compareTo(o2.modified)
else -> o1.taken.compareTo(o2.taken)
}
if (sorting and SORT_DESCENDING != 0) {
result *= -1
}
result
})
return movePinnedDirectoriesToFront(dirs)
}
@ -276,34 +293,51 @@ fun Context.getCachedDirectories(getVideosOnly: Boolean = false, getImagesOnly:
}
}) as ArrayList<Directory>
callback(filteredDirectories.distinctBy { it.path.getDistinctPath() } as ArrayList<Directory>)
val hiddenString = resources.getString(R.string.hidden)
filteredDirectories.forEach {
it.name = if (File(it.path).doesThisOrParentHaveNoMedia() && !it.path.isThisOrParentIncluded(includedPaths)) {
"${it.name.removeSuffix(hiddenString).trim()} $hiddenString"
} else {
it.name
}
}
removeInvalidDBDirectories(directories, directoryDao)
val clone = filteredDirectories.clone() as ArrayList<Directory>
callback(clone.distinctBy { it.path.getDistinctPath() } as ArrayList<Directory>)
removeInvalidDBDirectories(filteredDirectories, directoryDao)
}.start()
}
fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImagesOnly: Boolean = false, callback: (ArrayList<Medium>) -> Unit) {
Thread {
val mediumDao = galleryDB.MediumDao()
val media = (if (path == "/") mediumDao.getAll() else mediumDao.getMediaFromPath(path)) as ArrayList<Medium>
val foldersToScan = if (path == "/") MediaFetcher(this).getFoldersToScan() else arrayListOf(path)
var media = ArrayList<Medium>()
val shouldShowHidden = config.shouldShowHidden
var filteredMedia = media
foldersToScan.forEach {
val currMedia = mediumDao.getMediaFromPath(it)
media.addAll(currMedia)
}
if (!shouldShowHidden) {
filteredMedia = media.filter { !it.name.startsWith('.') } as ArrayList<Medium>
media = media.filter { !it.path.contains("/.") } as ArrayList<Medium>
}
val filterMedia = config.filterMedia
filteredMedia = (when {
getVideosOnly -> filteredMedia.filter { it.type == TYPE_VIDEOS }
getImagesOnly -> filteredMedia.filter { it.type == TYPE_IMAGES }
else -> filteredMedia.filter {
media = (when {
getVideosOnly -> media.filter { it.type == TYPE_VIDEOS }
getImagesOnly -> media.filter { it.type == TYPE_IMAGES }
else -> media.filter {
(filterMedia and TYPE_IMAGES != 0 && it.type == TYPE_IMAGES) ||
(filterMedia and TYPE_VIDEOS != 0 && it.type == TYPE_VIDEOS) ||
(filterMedia and TYPE_GIFS != 0 && it.type == TYPE_GIFS)
}
}) as ArrayList<Medium>
callback(filteredMedia)
MediaFetcher(this).sortMedia(media, config.getFileSorting(path))
callback(media.clone() as ArrayList<Medium>)
media.filter { !getDoesFilePathExist(it.path) }.forEach {
mediumDao.deleteMediumPath(it.path)
}

View file

@ -6,7 +6,6 @@ import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.simplemobiletools.commons.helpers.BaseConfig
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_MODIFIED
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_TAKEN
import com.simplemobiletools.commons.helpers.SORT_DESCENDING
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.models.AlbumCover
@ -18,13 +17,7 @@ class Config(context: Context) : BaseConfig(context) {
}
var directorySorting: Int
get(): Int {
var sort = prefs.getInt(DIRECTORY_SORT_ORDER, SORT_BY_DATE_MODIFIED or SORT_DESCENDING)
if (sort and SORT_BY_DATE_TAKEN != 0) {
sort = sort - SORT_BY_DATE_TAKEN + SORT_BY_DATE_MODIFIED
}
return sort
}
get(): Int = prefs.getInt(DIRECTORY_SORT_ORDER, SORT_BY_DATE_MODIFIED or SORT_DESCENDING)
set(order) = prefs.edit().putInt(DIRECTORY_SORT_ORDER, order).apply()
fun saveFileSorting(path: String, value: Int) {
@ -35,13 +28,7 @@ class Config(context: Context) : BaseConfig(context) {
}
}
fun getFileSorting(path: String): Int {
var sort = prefs.getInt(SORT_FOLDER_PREFIX + path.toLowerCase(), sorting)
if (sort and SORT_BY_DATE_TAKEN != 0) {
sort = sort - SORT_BY_DATE_TAKEN + SORT_BY_DATE_MODIFIED
}
return sort
}
fun getFileSorting(path: String) = prefs.getInt(SORT_FOLDER_PREFIX + path.toLowerCase(), sorting)
fun removeFileSorting(path: String) {
prefs.edit().remove(SORT_FOLDER_PREFIX + path.toLowerCase()).apply()
@ -331,4 +318,8 @@ class Config(context: Context) : BaseConfig(context) {
var wasOTGHandled: Boolean
get() = prefs.getBoolean(WAS_OTG_HANDLED, false)
set(wasOTGHandled) = prefs.edit().putBoolean(WAS_OTG_HANDLED, wasOTGHandled).apply()
var tempSkipDeleteConfirmation: Boolean
get() = prefs.getBoolean(TEMP_SKIP_DELETE_CONFIRMATION, false)
set(tempSkipDeleteConfirmation) = prefs.edit().putBoolean(TEMP_SKIP_DELETE_CONFIRMATION, tempSkipDeleteConfirmation).apply()
}

View file

@ -48,6 +48,7 @@ const val DO_EXTRA_CHECK = "do_extra_check"
const val WAS_NEW_APP_SHOWN = "was_new_app_shown_clock"
const val LAST_FILEPICKER_PATH = "last_filepicker_path"
const val WAS_OTG_HANDLED = "was_otg_handled"
const val TEMP_SKIP_DELETE_CONFIRMATION = "temp_skip_delete_confirmation"
// slideshow
const val SLIDESHOW_INTERVAL = "slideshow_interval"

View file

@ -5,9 +5,7 @@ import android.database.Cursor
import android.net.Uri
import android.provider.MediaStore
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.OTG_PATH
import com.simplemobiletools.commons.helpers.photoExtensions
import com.simplemobiletools.commons.helpers.videoExtensions
import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.extensions.getDistinctPath
import com.simplemobiletools.gallery.extensions.getOTGFolderChildren
@ -18,7 +16,7 @@ import java.io.File
class MediaFetcher(val context: Context) {
var shouldStop = false
fun getFilesFrom(curPath: String, isPickImage: Boolean, isPickVideo: Boolean): ArrayList<Medium> {
fun getFilesFrom(curPath: String, isPickImage: Boolean, isPickVideo: Boolean, getProperDateTaken: Boolean): ArrayList<Medium> {
val filterMedia = context.config.filterMedia
if (filterMedia == 0) {
return ArrayList()
@ -29,37 +27,32 @@ class MediaFetcher(val context: Context) {
val newMedia = getMediaOnOTG(curPath, isPickImage, isPickVideo, filterMedia)
curMedia.addAll(newMedia)
} else {
val newMedia = fetchFolderContent(curPath, isPickImage, isPickVideo, filterMedia)
val newMedia = getMediaInFolder(curPath, isPickImage, isPickVideo, filterMedia, getProperDateTaken)
curMedia.addAll(newMedia)
}
Medium.sorting = context.config.getFileSorting(curPath)
curMedia.sort()
sortMedia(curMedia, context.config.getFileSorting(curPath))
return curMedia
}
fun getFoldersToScan(path: String): ArrayList<String> {
fun getFoldersToScan(): ArrayList<String> {
val filterMedia = context.config.filterMedia
val projection = arrayOf(MediaStore.Images.Media.DATA)
val uri = MediaStore.Files.getContentUri("external")
val selection = "${getSelectionQuery(path, filterMedia)} ${MediaStore.Images.ImageColumns.BUCKET_ID} IS NOT NULL) GROUP BY (${MediaStore.Images.ImageColumns.BUCKET_ID}"
val selectionArgs = getSelectionArgsQuery(path, filterMedia).toTypedArray()
val selection = "${getSelectionQuery(filterMedia)} ${MediaStore.Images.ImageColumns.BUCKET_ID} IS NOT NULL) GROUP BY (${MediaStore.Images.ImageColumns.BUCKET_ID}"
val selectionArgs = getSelectionArgsQuery(filterMedia).toTypedArray()
return try {
val cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
parseCursor(cursor, path)
parseCursor(cursor)
} catch (e: Exception) {
ArrayList()
}
}
private fun getSelectionQuery(path: String, filterMedia: Int): String {
private fun getSelectionQuery(filterMedia: Int): String {
val query = StringBuilder()
if (path.isNotEmpty()) {
query.append("${MediaStore.Images.Media.DATA} LIKE ? AND ${MediaStore.Images.Media.DATA} NOT LIKE ? AND ")
}
query.append("(")
if (filterMedia and TYPE_IMAGES != 0) {
photoExtensions.forEach {
@ -82,13 +75,8 @@ class MediaFetcher(val context: Context) {
return selectionQuery
}
private fun getSelectionArgsQuery(path: String, filterMedia: Int): ArrayList<String> {
private fun getSelectionArgsQuery(filterMedia: Int): ArrayList<String> {
val args = ArrayList<String>()
if (path.isNotEmpty()) {
args.add("$path/%")
args.add("$path/%/%")
}
if (filterMedia and TYPE_IMAGES != 0) {
photoExtensions.forEach {
args.add("%$it")
@ -108,7 +96,7 @@ class MediaFetcher(val context: Context) {
return args
}
private fun parseCursor(cursor: Cursor, curPath: String): ArrayList<String> {
private fun parseCursor(cursor: Cursor): ArrayList<String> {
val config = context.config
val includedFolders = config.includedFolders
var foldersToScan = ArrayList<String>()
@ -126,20 +114,12 @@ class MediaFetcher(val context: Context) {
}
includedFolders.forEach {
if (curPath.isEmpty()) {
addFolder(foldersToScan, it)
} else if (curPath == it) {
foldersToScan.add(it)
}
}
val showHidden = config.shouldShowHidden
val excludedFolders = config.excludedFolders
foldersToScan = foldersToScan.filter { it.shouldFolderBeVisible(excludedFolders, includedFolders, showHidden) } as ArrayList<String>
if (config.isThirdPartyIntent && curPath.isNotEmpty()) {
foldersToScan.add(curPath)
}
return foldersToScan.distinctBy { it.getDistinctPath() } as ArrayList<String>
}
@ -163,19 +143,12 @@ class MediaFetcher(val context: Context) {
}
}
private fun fetchFolderContent(path: String, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int): ArrayList<Medium> {
return if (path.startsWith(OTG_PATH)) {
getMediaOnOTG(path, isPickImage, isPickVideo, filterMedia)
} else {
getMediaInFolder(path, isPickImage, isPickVideo, filterMedia)
}
}
private fun getMediaInFolder(folder: String, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int): ArrayList<Medium> {
private fun getMediaInFolder(folder: String, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int, getProperDateTaken: Boolean): ArrayList<Medium> {
val media = ArrayList<Medium>()
val files = File(folder).listFiles() ?: return media
val doExtraCheck = context.config.doExtraCheck
val showHidden = context.config.shouldShowHidden
val dateTakens = if (getProperDateTaken) getFolderDateTakens(folder) else HashMap()
for (file in files) {
if (shouldStop) {
@ -206,8 +179,12 @@ class MediaFetcher(val context: Context) {
if (size <= 0L || (doExtraCheck && !file.exists()))
continue
val dateTaken = file.lastModified()
val dateModified = file.lastModified()
val lastModified = file.lastModified()
var dateTaken = lastModified
if (getProperDateTaken) {
dateTaken = dateTakens.remove(filename) ?: lastModified
}
val type = when {
isImage -> TYPE_IMAGES
@ -215,7 +192,7 @@ class MediaFetcher(val context: Context) {
else -> TYPE_GIFS
}
val medium = Medium(null, filename, file.absolutePath, folder, dateModified, dateTaken, size, type)
val medium = Medium(null, filename, file.absolutePath, folder, lastModified, dateTaken, size, type)
media.add(medium)
}
return media
@ -272,4 +249,51 @@ class MediaFetcher(val context: Context) {
return media
}
private fun getFolderDateTakens(folder: String): HashMap<String, Long> {
val projection = arrayOf(
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATE_TAKEN
)
val uri = MediaStore.Files.getContentUri("external")
val selection = "${MediaStore.Images.Media.DATA} LIKE ? AND ${MediaStore.Images.Media.DATA} NOT LIKE ?"
val selectionArgs = arrayOf("$folder/%", "$folder/%/%")
val dateTakens = HashMap<String, Long>()
val cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
cursor.use {
if (cursor.moveToFirst()) {
do {
try {
val path = cursor.getStringValue(MediaStore.Images.Media.DISPLAY_NAME)
val dateTaken = cursor.getLongValue(MediaStore.Images.Media.DATE_TAKEN)
dateTakens[path] = dateTaken
} catch (e: Exception) {
}
} while (cursor.moveToNext())
}
}
return dateTakens
}
fun sortMedia(media: ArrayList<Medium>, sorting: Int) {
media.sortWith(Comparator { o1, o2 ->
o1 as Medium
o2 as Medium
var result = when {
sorting and SORT_BY_NAME != 0 -> AlphanumericComparator().compare(o1.name.toLowerCase(), o2.name.toLowerCase())
sorting and SORT_BY_PATH != 0 -> AlphanumericComparator().compare(o1.path.toLowerCase(), o2.path.toLowerCase())
sorting and SORT_BY_SIZE != 0 -> o1.size.compareTo(o2.size)
sorting and SORT_BY_DATE_MODIFIED != 0 -> o1.modified.compareTo(o2.modified)
else -> o1.taken.compareTo(o2.taken)
}
if (sorting and SORT_DESCENDING != 0) {
result *= -1
}
result
})
}
}

View file

@ -22,4 +22,7 @@ interface DirectoryDao {
@Query("UPDATE OR REPLACE directories SET thumbnail = :thumbnail, media_count = :mediaCnt, last_modified = :lastModified, date_taken = :dateTaken, size = :size, media_types = :mediaTypes WHERE path = :path")
fun updateDirectory(path: String, thumbnail: String, mediaCnt: Int, lastModified: Long, dateTaken: Long, size: Long, mediaTypes: Int)
@Query("UPDATE directories SET thumbnail = :thumbnail, filename = :name, path = :newPath WHERE path = :oldPath")
fun updateDirectoryAfterRename(thumbnail: String, name: String, newPath: String, oldPath: String)
}

View file

@ -8,9 +8,6 @@ import com.simplemobiletools.gallery.models.Medium
@Dao
interface MediumDao {
@Query("SELECT * FROM media")
fun getAll(): List<Medium>
@Query("SELECT filename, full_path, parent_path, last_modified, date_taken, size, type FROM media WHERE parent_path = :path")
fun getMediaFromPath(path: String): List<Medium>

View file

@ -6,7 +6,10 @@ import android.arch.persistence.room.Index
import android.arch.persistence.room.PrimaryKey
import com.simplemobiletools.commons.extensions.formatDate
import com.simplemobiletools.commons.extensions.formatSize
import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_MODIFIED
import com.simplemobiletools.commons.helpers.SORT_BY_NAME
import com.simplemobiletools.commons.helpers.SORT_BY_PATH
import com.simplemobiletools.commons.helpers.SORT_BY_SIZE
import java.io.Serializable
@Entity(tableName = "directories", indices = [Index(value = "path", unique = true)])
@ -20,42 +23,13 @@ data class Directory(
@ColumnInfo(name = "date_taken") var taken: Long,
@ColumnInfo(name = "size") var size: Long,
@ColumnInfo(name = "location") val location: Int,
@ColumnInfo(name = "media_types") var types: Int) : Serializable, Comparable<Directory> {
@ColumnInfo(name = "media_types") var types: Int) : Serializable {
companion object {
private const val serialVersionUID = -6553345863555455L
var sorting: Int = 0
}
override fun compareTo(other: Directory): Int {
var result: Int
when {
sorting and SORT_BY_NAME != 0 -> result = AlphanumericComparator().compare(name.toLowerCase(), other.name.toLowerCase())
sorting and SORT_BY_PATH != 0 -> result = AlphanumericComparator().compare(path.toLowerCase(), other.path.toLowerCase())
sorting and SORT_BY_SIZE != 0 -> result = when {
size == other.size -> 0
size > other.size -> 1
else -> -1
}
sorting and SORT_BY_DATE_MODIFIED != 0 -> result = when {
modified == other.modified -> 0
modified > other.modified -> 1
else -> -1
}
else -> result = when {
taken == other.taken -> 0
taken > other.taken -> 1
else -> -1
}
}
if (sorting and SORT_DESCENDING != 0) {
result *= -1
}
return result
}
fun getBubbleText() = when {
fun getBubbleText(sorting: Int) = when {
sorting and SORT_BY_NAME != 0 -> name
sorting and SORT_BY_PATH != 0 -> path
sorting and SORT_BY_SIZE != 0 -> size.formatSize()

View file

@ -7,7 +7,10 @@ import android.arch.persistence.room.PrimaryKey
import com.simplemobiletools.commons.extensions.formatDate
import com.simplemobiletools.commons.extensions.formatSize
import com.simplemobiletools.commons.extensions.isDng
import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_MODIFIED
import com.simplemobiletools.commons.helpers.SORT_BY_NAME
import com.simplemobiletools.commons.helpers.SORT_BY_PATH
import com.simplemobiletools.commons.helpers.SORT_BY_SIZE
import com.simplemobiletools.gallery.helpers.TYPE_GIFS
import com.simplemobiletools.gallery.helpers.TYPE_IMAGES
import com.simplemobiletools.gallery.helpers.TYPE_VIDEOS
@ -20,13 +23,12 @@ data class Medium(
@ColumnInfo(name = "full_path") var path: String,
@ColumnInfo(name = "parent_path") var parentPath: String,
@ColumnInfo(name = "last_modified") val modified: Long,
@ColumnInfo(name = "date_taken") val taken: Long,
@ColumnInfo(name = "date_taken") var taken: Long,
@ColumnInfo(name = "size") val size: Long,
@ColumnInfo(name = "type") val type: Int) : Serializable, Comparable<Medium> {
@ColumnInfo(name = "type") val type: Int) : Serializable {
companion object {
private const val serialVersionUID = -6553149366975455L
var sorting: Int = 0
}
fun isGif() = type == TYPE_GIFS
@ -37,35 +39,7 @@ data class Medium(
fun isDng() = path.isDng()
override fun compareTo(other: Medium): Int {
var result: Int
when {
sorting and SORT_BY_NAME != 0 -> result = AlphanumericComparator().compare(name.toLowerCase(), other.name.toLowerCase())
sorting and SORT_BY_PATH != 0 -> result = AlphanumericComparator().compare(path.toLowerCase(), other.path.toLowerCase())
sorting and SORT_BY_SIZE != 0 -> result = when {
size == other.size -> 0
size > other.size -> 1
else -> -1
}
sorting and SORT_BY_DATE_MODIFIED != 0 -> result = when {
modified == other.modified -> 0
modified > other.modified -> 1
else -> -1
}
else -> result = when {
taken == other.taken -> 0
taken > other.taken -> 1
else -> -1
}
}
if (sorting and SORT_DESCENDING != 0) {
result *= -1
}
return result
}
fun getBubbleText() = when {
fun getBubbleText(sorting: Int) = when {
sorting and SORT_BY_NAME != 0 -> name
sorting and SORT_BY_PATH != 0 -> path
sorting and SORT_BY_SIZE != 0 -> size.formatSize()

View file

@ -1,13 +0,0 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillColor="#FFFFFF"
android:pathData="M63.58,40.16m-5.73,0a5.73,5.73 0,1 1,11.47 0a5.73,5.73 0,1 1,-11.47 0"/>
<path
android:fillColor="#FFFFFF"
android:pathData="M47.37,46.64l-17.45,25.43l45.46,0l-9.89,-16.21l-5.9,8.39z"/>
</vector>

View file

@ -52,6 +52,14 @@
android:paddingTop="@dimen/medium_margin"
android:text="@string/last_modified"/>
<com.simplemobiletools.commons.views.MyCompatRadioButton
android:id="@+id/sorting_dialog_radio_date_taken"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/medium_margin"
android:paddingTop="@dimen/medium_margin"
android:text="@string/date_taken"/>
</RadioGroup>
<include

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Some files were not shown because too many files have changed in this diff Show more