mirror of
https://github.com/FossifyOrg/Gallery.git
synced 2024-11-23 13:08:00 +01:00
commit
ef90bc8fce
45 changed files with 1200 additions and 729 deletions
31
CHANGELOG.md
31
CHANGELOG.md
|
@ -1,6 +1,37 @@
|
||||||
Changelog
|
Changelog
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
Version 3.8.2 *(2018-04-26)*
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
* Rewrote media caching and new file discovery for better performance
|
||||||
|
* Many OTG file handling improvements
|
||||||
|
|
||||||
|
Version 3.8.1 *(2018-04-24)*
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
* Rewrote media caching and new file discovery for better performance
|
||||||
|
* Some OTG file handling improvements
|
||||||
|
|
||||||
|
Version 3.8.0 *(2018-04-22)*
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
* Rewrote media caching for better performance
|
||||||
|
* Cache all media items, not just 80 per folder
|
||||||
|
* Some additional performance and stability improvements
|
||||||
|
|
||||||
|
Version 3.7.3 *(2018-04-15)*
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
* Show hidden folders when appropriate
|
||||||
|
|
||||||
|
Version 3.7.2 *(2018-04-14)*
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
* Fix Edit intent handled by other apps
|
||||||
|
* Hide folders containing ".nomedia" file, even if explicitly included
|
||||||
|
* Remove sorting by Date Taken until proper implementation
|
||||||
|
|
||||||
Version 3.7.1 *(2018-04-12)*
|
Version 3.7.1 *(2018-04-12)*
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-android-extensions'
|
apply plugin: 'kotlin-android-extensions'
|
||||||
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 27
|
compileSdkVersion 27
|
||||||
|
@ -10,8 +11,8 @@ android {
|
||||||
applicationId "com.simplemobiletools.gallery"
|
applicationId "com.simplemobiletools.gallery"
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 27
|
targetSdkVersion 27
|
||||||
versionCode 171
|
versionCode 176
|
||||||
versionName "3.7.1"
|
versionName "3.8.2"
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
setProperty("archivesBaseName", "gallery")
|
setProperty("archivesBaseName", "gallery")
|
||||||
}
|
}
|
||||||
|
@ -46,13 +47,17 @@ ext {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.simplemobiletools:commons:3.18.22'
|
implementation 'com.simplemobiletools:commons:3.19.21'
|
||||||
implementation 'com.theartofdev.edmodo:android-image-cropper:2.6.0'
|
implementation 'com.theartofdev.edmodo:android-image-cropper:2.7.0'
|
||||||
implementation 'com.android.support:multidex:1.0.3'
|
implementation 'com.android.support:multidex:1.0.3'
|
||||||
implementation 'it.sephiroth.android.exif:library:1.0.1'
|
implementation 'it.sephiroth.android.exif:library:1.0.1'
|
||||||
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.12'
|
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.12'
|
||||||
implementation 'com.github.chrisbanes:PhotoView:2.1.3'
|
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"
|
||||||
|
|
||||||
//implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.9.0'
|
//implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.9.0'
|
||||||
implementation 'com.github.tibbi:subsampling-scale-image-view:v3.10.0-fork'
|
implementation 'com.github.tibbi:subsampling-scale-image-view:v3.10.0-fork'
|
||||||
|
|
||||||
|
|
|
@ -205,14 +205,6 @@
|
||||||
android:resource="@xml/provider_paths"/>
|
android:resource="@xml/provider_paths"/>
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
<receiver
|
|
||||||
android:name=".receivers.InstallReceiver"
|
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="com.android.vending.INSTALL_REFERRER"/>
|
|
||||||
</intent-filter>
|
|
||||||
</receiver>
|
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".receivers.RefreshMediaReceiver"
|
android:name=".receivers.RefreshMediaReceiver"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
|
|
|
@ -66,7 +66,7 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
|
||||||
if (intent.extras?.containsKey(REAL_FILE_PATH) == true) {
|
if (intent.extras?.containsKey(REAL_FILE_PATH) == true) {
|
||||||
val realPath = intent.extras.getString(REAL_FILE_PATH)
|
val realPath = intent.extras.getString(REAL_FILE_PATH)
|
||||||
uri = when {
|
uri = when {
|
||||||
realPath.startsWith(OTG_PATH) -> Uri.parse(realPath)
|
realPath.startsWith(OTG_PATH) -> uri
|
||||||
realPath.startsWith("file:/") -> Uri.parse(realPath)
|
realPath.startsWith("file:/") -> Uri.parse(realPath)
|
||||||
else -> Uri.fromFile(File(realPath))
|
else -> Uri.fromFile(File(realPath))
|
||||||
}
|
}
|
||||||
|
@ -188,6 +188,15 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
|
||||||
} else if (saveUri.scheme == "content") {
|
} else if (saveUri.scheme == "content") {
|
||||||
var newPath = applicationContext.getRealPathFromURI(saveUri) ?: ""
|
var newPath = applicationContext.getRealPathFromURI(saveUri) ?: ""
|
||||||
var shouldAppendFilename = true
|
var shouldAppendFilename = true
|
||||||
|
if (newPath.isEmpty()) {
|
||||||
|
val filename = applicationContext.getFilenameFromContentUri(saveUri) ?: ""
|
||||||
|
if (filename.isNotEmpty()) {
|
||||||
|
val path = if (intent.extras?.containsKey(REAL_FILE_PATH) == true) intent.getStringExtra(REAL_FILE_PATH).getParentPath() else internalStoragePath
|
||||||
|
newPath = "$path/$filename"
|
||||||
|
shouldAppendFilename = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (newPath.isEmpty()) {
|
if (newPath.isEmpty()) {
|
||||||
newPath = "$internalStoragePath/${getCurrentFormattedDateTime()}.${saveUri.toString().getFilenameExtension()}"
|
newPath = "$internalStoragePath/${getCurrentFormattedDateTime()}.${saveUri.toString().getFilenameExtension()}"
|
||||||
shouldAppendFilename = false
|
shouldAppendFilename = false
|
||||||
|
|
|
@ -12,14 +12,12 @@ import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
|
import android.widget.Toast
|
||||||
import com.simplemobiletools.commons.dialogs.CreateNewFolderDialog
|
import com.simplemobiletools.commons.dialogs.CreateNewFolderDialog
|
||||||
import com.simplemobiletools.commons.dialogs.FilePickerDialog
|
import com.simplemobiletools.commons.dialogs.FilePickerDialog
|
||||||
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
|
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
|
||||||
import com.simplemobiletools.commons.extensions.*
|
import com.simplemobiletools.commons.extensions.*
|
||||||
import com.simplemobiletools.commons.helpers.PERMISSION_READ_STORAGE
|
import com.simplemobiletools.commons.helpers.*
|
||||||
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE
|
|
||||||
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_MODIFIED
|
|
||||||
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_TAKEN
|
|
||||||
import com.simplemobiletools.commons.models.FileDirItem
|
import com.simplemobiletools.commons.models.FileDirItem
|
||||||
import com.simplemobiletools.commons.models.RadioItem
|
import com.simplemobiletools.commons.models.RadioItem
|
||||||
import com.simplemobiletools.commons.models.Release
|
import com.simplemobiletools.commons.models.Release
|
||||||
|
@ -28,12 +26,15 @@ import com.simplemobiletools.commons.views.MyRecyclerView
|
||||||
import com.simplemobiletools.gallery.BuildConfig
|
import com.simplemobiletools.gallery.BuildConfig
|
||||||
import com.simplemobiletools.gallery.R
|
import com.simplemobiletools.gallery.R
|
||||||
import com.simplemobiletools.gallery.adapters.DirectoryAdapter
|
import com.simplemobiletools.gallery.adapters.DirectoryAdapter
|
||||||
import com.simplemobiletools.gallery.asynctasks.GetDirectoriesAsynctask
|
import com.simplemobiletools.gallery.databases.GalleryDataBase
|
||||||
import com.simplemobiletools.gallery.dialogs.ChangeSortingDialog
|
import com.simplemobiletools.gallery.dialogs.ChangeSortingDialog
|
||||||
import com.simplemobiletools.gallery.dialogs.FilterMediaDialog
|
import com.simplemobiletools.gallery.dialogs.FilterMediaDialog
|
||||||
import com.simplemobiletools.gallery.extensions.*
|
import com.simplemobiletools.gallery.extensions.*
|
||||||
import com.simplemobiletools.gallery.helpers.*
|
import com.simplemobiletools.gallery.helpers.*
|
||||||
|
import com.simplemobiletools.gallery.interfaces.DirectoryDao
|
||||||
|
import com.simplemobiletools.gallery.models.AlbumCover
|
||||||
import com.simplemobiletools.gallery.models.Directory
|
import com.simplemobiletools.gallery.models.Directory
|
||||||
|
import com.simplemobiletools.gallery.models.Medium
|
||||||
import kotlinx.android.synthetic.main.activity_main.*
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
import java.io.*
|
import java.io.*
|
||||||
|
|
||||||
|
@ -43,8 +44,6 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
private val LAST_MEDIA_CHECK_PERIOD = 3000L
|
private val LAST_MEDIA_CHECK_PERIOD = 3000L
|
||||||
private val NEW_APP_PACKAGE = "com.simplemobiletools.clock"
|
private val NEW_APP_PACKAGE = "com.simplemobiletools.clock"
|
||||||
|
|
||||||
lateinit var mDirs: ArrayList<Directory>
|
|
||||||
|
|
||||||
private var mIsPickImageIntent = false
|
private var mIsPickImageIntent = false
|
||||||
private var mIsPickVideoIntent = false
|
private var mIsPickVideoIntent = false
|
||||||
private var mIsGetImageContentIntent = false
|
private var mIsGetImageContentIntent = false
|
||||||
|
@ -60,7 +59,6 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
private var mLatestMediaDateId = 0L
|
private var mLatestMediaDateId = 0L
|
||||||
private var mLastMediaHandler = Handler()
|
private var mLastMediaHandler = Handler()
|
||||||
private var mTempShowHiddenHandler = Handler()
|
private var mTempShowHiddenHandler = Handler()
|
||||||
private var mCurrAsyncTask: GetDirectoriesAsynctask? = null
|
|
||||||
private var mZoomListener: MyRecyclerView.MyZoomListener? = null
|
private var mZoomListener: MyRecyclerView.MyZoomListener? = null
|
||||||
|
|
||||||
private var mStoredAnimateGifs = true
|
private var mStoredAnimateGifs = true
|
||||||
|
@ -88,7 +86,6 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
|
|
||||||
removeTempFolder()
|
removeTempFolder()
|
||||||
directories_refresh_layout.setOnRefreshListener { getDirectories() }
|
directories_refresh_layout.setOnRefreshListener { getDirectories() }
|
||||||
mDirs = ArrayList()
|
|
||||||
storeStateVariables()
|
storeStateVariables()
|
||||||
checkWhatsNewDialog()
|
checkWhatsNewDialog()
|
||||||
|
|
||||||
|
@ -104,6 +101,10 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
config.wasNewAppShown = true
|
config.wasNewAppShown = true
|
||||||
NewAppDialog(this, NEW_APP_PACKAGE, "Simple Clock")
|
NewAppDialog(this, NEW_APP_PACKAGE, "Simple Clock")
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
if (!config.wasOTGHandled && hasPermission(PERMISSION_WRITE_STORAGE)) {
|
||||||
|
checkOTGInclusion()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
|
@ -127,7 +128,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
getRecyclerAdapter()?.updateShowMediaCount(config.showMediaCount)
|
getRecyclerAdapter()?.updateShowMediaCount(config.showMediaCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mStoredScrollHorizontally != config.scrollHorizontally || mStoredShowInfoBubble != config.showInfoBubble) {
|
if (mStoredScrollHorizontally != config.scrollHorizontally) {
|
||||||
getRecyclerAdapter()?.updateScrollHorizontally(config.viewTypeFolders != VIEW_TYPE_LIST && config.scrollHorizontally)
|
getRecyclerAdapter()?.updateScrollHorizontally(config.viewTypeFolders != VIEW_TYPE_LIST && config.scrollHorizontally)
|
||||||
setupScrollDirection()
|
setupScrollDirection()
|
||||||
}
|
}
|
||||||
|
@ -144,6 +145,8 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
|
|
||||||
directories_horizontal_fastscroller.updateBubbleColors()
|
directories_horizontal_fastscroller.updateBubbleColors()
|
||||||
directories_vertical_fastscroller.updateBubbleColors()
|
directories_vertical_fastscroller.updateBubbleColors()
|
||||||
|
directories_horizontal_fastscroller.allowBubbleDisplay = config.showInfoBubble
|
||||||
|
directories_vertical_fastscroller.allowBubbleDisplay = config.showInfoBubble
|
||||||
directories_refresh_layout.isEnabled = config.enablePullToRefresh
|
directories_refresh_layout.isEnabled = config.enablePullToRefresh
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
directories_empty_text_label.setTextColor(config.textColor)
|
directories_empty_text_label.setTextColor(config.textColor)
|
||||||
|
@ -187,9 +190,8 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
config.temporarilyShowHidden = false
|
config.temporarilyShowHidden = false
|
||||||
mTempShowHiddenHandler.removeCallbacksAndMessages(null)
|
mTempShowHiddenHandler.removeCallbacksAndMessages(null)
|
||||||
removeTempFolder()
|
removeTempFolder()
|
||||||
|
if (!isChangingConfigurations) {
|
||||||
if (!mDirs.isEmpty()) {
|
GalleryDataBase.destroyInstance()
|
||||||
mCurrAsyncTask?.stopFetching()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,13 +246,27 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
val newFolder = File(config.tempFolderPath)
|
val newFolder = File(config.tempFolderPath)
|
||||||
if (newFolder.exists() && newFolder.isDirectory) {
|
if (newFolder.exists() && newFolder.isDirectory) {
|
||||||
if (newFolder.list()?.isEmpty() == true) {
|
if (newFolder.list()?.isEmpty() == true) {
|
||||||
deleteFile(newFolder.toFileDirItem(applicationContext), true)
|
toast(String.format(getString(R.string.deleting_folder), config.tempFolderPath), Toast.LENGTH_LONG)
|
||||||
|
tryDeleteFileDirItem(newFolder.toFileDirItem(applicationContext), true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
config.tempFolderPath = ""
|
config.tempFolderPath = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkOTGInclusion() {
|
||||||
|
Thread {
|
||||||
|
if (hasOTGConnected()) {
|
||||||
|
runOnUiThread {
|
||||||
|
handleOTGPermission {
|
||||||
|
config.addIncludedFolder(OTG_PATH)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.wasOTGHandled = true
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
private fun tryLoadGallery() {
|
private fun tryLoadGallery() {
|
||||||
handlePermission(PERMISSION_WRITE_STORAGE) {
|
handlePermission(PERMISSION_WRITE_STORAGE) {
|
||||||
if (it) {
|
if (it) {
|
||||||
|
@ -274,22 +290,17 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
mIsGettingDirs = true
|
mIsGettingDirs = true
|
||||||
val dirs = getCachedDirectories()
|
val getImagesOnly = mIsPickImageIntent || mIsGetImageContentIntent
|
||||||
if (dirs.isNotEmpty() && !mLoadedInitialPhotos) {
|
val getVideosOnly = mIsPickVideoIntent || mIsGetVideoContentIntent
|
||||||
gotDirectories(dirs, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
getCachedDirectories(getVideosOnly, getImagesOnly) {
|
||||||
if (!mLoadedInitialPhotos) {
|
if (!mLoadedInitialPhotos) {
|
||||||
|
runOnUiThread {
|
||||||
directories_refresh_layout.isRefreshing = true
|
directories_refresh_layout.isRefreshing = true
|
||||||
}
|
}
|
||||||
|
|
||||||
mLoadedInitialPhotos = true
|
|
||||||
mCurrAsyncTask?.stopFetching()
|
|
||||||
mCurrAsyncTask = GetDirectoriesAsynctask(applicationContext, mIsPickVideoIntent || mIsGetVideoContentIntent, mIsPickImageIntent || mIsGetImageContentIntent) {
|
|
||||||
mCurrAsyncTask = null
|
|
||||||
gotDirectories(addTempFolderIfNeeded(it), false)
|
|
||||||
}
|
}
|
||||||
mCurrAsyncTask!!.execute()
|
gotDirectories(addTempFolderIfNeeded(it))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showSortingDialog() {
|
private fun showSortingDialog() {
|
||||||
|
@ -297,13 +308,14 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
if (config.directorySorting and SORT_BY_DATE_MODIFIED > 0 || config.directorySorting and SORT_BY_DATE_TAKEN > 0) {
|
if (config.directorySorting and SORT_BY_DATE_MODIFIED > 0 || config.directorySorting and SORT_BY_DATE_TAKEN > 0) {
|
||||||
getDirectories()
|
getDirectories()
|
||||||
} else {
|
} else {
|
||||||
gotDirectories(mDirs, true)
|
gotDirectories(getCurrentlyDisplayedDirs())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showFilterMediaDialog() {
|
private fun showFilterMediaDialog() {
|
||||||
FilterMediaDialog(this) {
|
FilterMediaDialog(this) {
|
||||||
|
mLoadedInitialPhotos = false
|
||||||
directories_refresh_layout.isRefreshing = true
|
directories_refresh_layout.isRefreshing = true
|
||||||
getDirectories()
|
getDirectories()
|
||||||
}
|
}
|
||||||
|
@ -332,8 +344,9 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
config.viewTypeFolders = it as Int
|
config.viewTypeFolders = it as Int
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
setupLayoutManager()
|
setupLayoutManager()
|
||||||
|
val dirs = getCurrentlyDisplayedDirs()
|
||||||
directories_grid.adapter = null
|
directories_grid.adapter = null
|
||||||
setupAdapter()
|
setupAdapter(dirs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,6 +361,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleTemporarilyShowHidden(show: Boolean) {
|
private fun toggleTemporarilyShowHidden(show: Boolean) {
|
||||||
|
mLoadedInitialPhotos = false
|
||||||
config.temporarilyShowHidden = show
|
config.temporarilyShowHidden = show
|
||||||
getDirectories()
|
getDirectories()
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
|
@ -359,6 +373,13 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
refreshItems()
|
refreshItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Thread {
|
||||||
|
val directoryDao = galleryDB.DirectoryDao()
|
||||||
|
folders.filter { !it.exists() }.forEach {
|
||||||
|
directoryDao.deleteDirPath(it.absolutePath)
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,7 +439,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
FilePickerDialog(this, internalStoragePath, false, config.shouldShowHidden) {
|
FilePickerDialog(this, internalStoragePath, false, config.shouldShowHidden) {
|
||||||
CreateNewFolderDialog(this, it) {
|
CreateNewFolderDialog(this, it) {
|
||||||
config.tempFolderPath = it
|
config.tempFolderPath = it
|
||||||
gotDirectories(addTempFolderIfNeeded(mDirs), true)
|
gotDirectories(addTempFolderIfNeeded(getCurrentlyDisplayedDirs()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -550,68 +571,162 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun gotDirectories(newDirs: ArrayList<Directory>, isFromCache: Boolean) {
|
private fun gotDirectories(newDirs: ArrayList<Directory>) {
|
||||||
/*if (!isFromCache) {
|
|
||||||
Thread {
|
|
||||||
checkFolderContentChange(newDirs)
|
|
||||||
}.start()
|
|
||||||
}*/
|
|
||||||
|
|
||||||
val dirs = getSortedDirectories(newDirs)
|
val dirs = getSortedDirectories(newDirs)
|
||||||
directories_refresh_layout.isRefreshing = false
|
var isPlaceholderVisible = dirs.isEmpty()
|
||||||
mIsGettingDirs = false
|
|
||||||
|
|
||||||
directories_empty_text_label.beVisibleIf(dirs.isEmpty() && !isFromCache)
|
runOnUiThread {
|
||||||
directories_empty_text.beVisibleIf(dirs.isEmpty() && !isFromCache)
|
checkPlaceholderVisibility(dirs)
|
||||||
directories_grid.beVisibleIf(directories_empty_text_label.isGone())
|
|
||||||
|
|
||||||
val allowHorizontalScroll = config.scrollHorizontally && config.viewTypeFiles == VIEW_TYPE_GRID
|
val allowHorizontalScroll = config.scrollHorizontally && config.viewTypeFiles == VIEW_TYPE_GRID
|
||||||
directories_vertical_fastscroller.beVisibleIf(directories_grid.isVisible() && !allowHorizontalScroll)
|
directories_vertical_fastscroller.beVisibleIf(directories_grid.isVisible() && !allowHorizontalScroll)
|
||||||
directories_horizontal_fastscroller.beVisibleIf(directories_grid.isVisible() && allowHorizontalScroll)
|
directories_horizontal_fastscroller.beVisibleIf(directories_grid.isVisible() && allowHorizontalScroll)
|
||||||
|
setupAdapter(dirs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cached folders have been loaded, recheck folders one by one starting with the first displayed
|
||||||
|
Thread {
|
||||||
|
val mediaFetcher = MediaFetcher(applicationContext)
|
||||||
|
val getImagesOnly = mIsPickImageIntent || mIsGetImageContentIntent
|
||||||
|
val getVideosOnly = mIsPickVideoIntent || mIsGetVideoContentIntent
|
||||||
|
val hiddenString = getString(R.string.hidden)
|
||||||
|
val albumCovers = config.parseAlbumCovers()
|
||||||
|
val includedFolders = config.includedFolders
|
||||||
|
val isSortingAscending = config.directorySorting and SORT_DESCENDING == 0
|
||||||
|
val mediumDao = galleryDB.MediumDao()
|
||||||
|
val directoryDao = galleryDB.DirectoryDao()
|
||||||
|
|
||||||
|
for (directory in dirs) {
|
||||||
|
val curMedia = mediaFetcher.getFilesFrom(directory.path, getImagesOnly, getVideosOnly)
|
||||||
|
val newDir = if (curMedia.isEmpty()) {
|
||||||
|
directory
|
||||||
|
} else {
|
||||||
|
createDirectoryFromMedia(directory.path, curMedia, albumCovers, hiddenString, includedFolders, isSortingAscending)
|
||||||
|
}
|
||||||
|
|
||||||
|
// we are looping through the already displayed folders looking for changes, do not do anything if nothing changed
|
||||||
|
if (directory == newDir) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
directory.apply {
|
||||||
|
tmb = newDir.tmb
|
||||||
|
mediaCnt = newDir.mediaCnt
|
||||||
|
modified = newDir.modified
|
||||||
|
taken = newDir.taken
|
||||||
|
this@apply.size = newDir.size
|
||||||
|
types = newDir.types
|
||||||
|
}
|
||||||
|
|
||||||
|
showSortedDirs(dirs)
|
||||||
|
|
||||||
|
// update directories and media files in the local db, delete invalid items
|
||||||
|
updateDBDirectory(directory)
|
||||||
|
mediumDao.insertAll(curMedia)
|
||||||
|
getCachedMedia(directory.path, getVideosOnly, getImagesOnly) {
|
||||||
|
it.forEach {
|
||||||
|
if (!curMedia.contains(it)) {
|
||||||
|
mediumDao.deleteMediumPath(it.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val foldersToScan = mediaFetcher.getFoldersToScan("")
|
||||||
|
dirs.forEach {
|
||||||
|
foldersToScan.remove(it.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (folder in foldersToScan) {
|
||||||
|
val newMedia = mediaFetcher.getFilesFrom(folder, getImagesOnly, getVideosOnly)
|
||||||
|
if (newMedia.isEmpty()) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPlaceholderVisible) {
|
||||||
|
isPlaceholderVisible = false
|
||||||
|
runOnUiThread {
|
||||||
|
directories_empty_text_label.beGone()
|
||||||
|
directories_empty_text.beGone()
|
||||||
|
directories_grid.beVisible()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val newDir = createDirectoryFromMedia(folder, newMedia, albumCovers, hiddenString, includedFolders, isSortingAscending)
|
||||||
|
dirs.add(newDir)
|
||||||
|
showSortedDirs(dirs)
|
||||||
|
directoryDao.insert(newDir)
|
||||||
|
mediumDao.insertAll(newMedia)
|
||||||
|
}
|
||||||
|
|
||||||
|
mIsGettingDirs = false
|
||||||
|
mLoadedInitialPhotos = true
|
||||||
checkLastMediaChanged()
|
checkLastMediaChanged()
|
||||||
mDirs = dirs
|
|
||||||
|
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
setupAdapter()
|
directories_refresh_layout.isRefreshing = false
|
||||||
|
directories_vertical_fastscroller.measureRecyclerView()
|
||||||
|
checkPlaceholderVisibility(dirs)
|
||||||
|
}
|
||||||
|
checkInvalidDirectories(dirs, directoryDao)
|
||||||
|
}.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isFromCache) {
|
private fun checkPlaceholderVisibility(dirs: ArrayList<Directory>) {
|
||||||
storeDirectories()
|
directories_empty_text_label.beVisibleIf(dirs.isEmpty() && mLoadedInitialPhotos)
|
||||||
|
directories_empty_text.beVisibleIf(dirs.isEmpty() && mLoadedInitialPhotos)
|
||||||
|
directories_grid.beVisibleIf(directories_empty_text_label.isGone())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showSortedDirs(dirs: ArrayList<Directory>) {
|
||||||
|
var sortedDirs = getSortedDirectories(dirs).clone() as ArrayList<Directory>
|
||||||
|
sortedDirs = sortedDirs.distinctBy { it.path.toLowerCase() } as ArrayList<Directory>
|
||||||
|
|
||||||
|
runOnUiThread {
|
||||||
|
(directories_grid.adapter as DirectoryAdapter).updateDirs(sortedDirs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkFolderContentChange(newDirs: ArrayList<Directory>) {
|
private fun createDirectoryFromMedia(path: String, curMedia: ArrayList<Medium>, albumCovers: ArrayList<AlbumCover>, hiddenString: String,
|
||||||
newDirs.forEach {
|
includedFolders: MutableSet<String>, isSortingAscending: Boolean): Directory {
|
||||||
val storedShortDirValue = config.loadFolderMediaShort(it.path)
|
var thumbnail = curMedia.firstOrNull { getDoesFilePathExist(it.path) }?.path ?: ""
|
||||||
if (storedShortDirValue != it.toString()) {
|
if (thumbnail.startsWith(OTG_PATH)) {
|
||||||
config.saveFolderMediaShort(it.path, it.toString())
|
thumbnail = thumbnail.getOTGPublicPath(applicationContext)
|
||||||
if (storedShortDirValue.isNotEmpty()) {
|
|
||||||
updateStoredFolderItems(it.path)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
albumCovers.forEach {
|
||||||
|
if (it.path == path && getDoesFilePathExist(it.tmb)) {
|
||||||
|
thumbnail = it.tmb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun storeDirectories() {
|
val mediaTypes = curMedia.getDirMediaTypes()
|
||||||
if (!config.temporarilyShowHidden && config.tempFolderPath.isEmpty()) {
|
val dirName = checkAppendingHidden(path, hiddenString, includedFolders)
|
||||||
storeDirectoryItems(mDirs)
|
|
||||||
}
|
val firstItem = curMedia.first()
|
||||||
|
val lastItem = curMedia.last()
|
||||||
|
val lastModified = if (isSortingAscending) Math.min(firstItem.modified, lastItem.modified) else Math.max(firstItem.modified, lastItem.modified)
|
||||||
|
val dateTaken = if (isSortingAscending) Math.min(firstItem.taken, lastItem.taken) else Math.max(firstItem.taken, lastItem.taken)
|
||||||
|
val size = curMedia.sumByLong { it.size }
|
||||||
|
return Directory(null, path, thumbnail, dirName, curMedia.size, lastModified, dateTaken, size, getPathLocation(path), mediaTypes)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupAdapter() {
|
private fun setupAdapter(dirs: ArrayList<Directory>) {
|
||||||
val currAdapter = directories_grid.adapter
|
val currAdapter = directories_grid.adapter
|
||||||
if (currAdapter == null) {
|
if (currAdapter == null) {
|
||||||
initZoomListener()
|
initZoomListener()
|
||||||
val fastscroller = if (config.scrollHorizontally) directories_horizontal_fastscroller else directories_vertical_fastscroller
|
val fastscroller = if (config.scrollHorizontally) directories_horizontal_fastscroller else directories_vertical_fastscroller
|
||||||
DirectoryAdapter(this, mDirs, this, directories_grid, isPickIntent(intent) || isGetAnyContentIntent(intent), fastscroller) {
|
DirectoryAdapter(this, dirs, this, directories_grid, isPickIntent(intent) || isGetAnyContentIntent(intent), fastscroller) {
|
||||||
itemClicked((it as Directory).path)
|
val path = (it as Directory).path
|
||||||
|
if (path != config.tempFolderPath) {
|
||||||
|
itemClicked(path)
|
||||||
|
}
|
||||||
}.apply {
|
}.apply {
|
||||||
setupZoomListener(mZoomListener)
|
setupZoomListener(mZoomListener)
|
||||||
directories_grid.adapter = this
|
directories_grid.adapter = this
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(currAdapter as DirectoryAdapter).updateDirs(mDirs)
|
(currAdapter as DirectoryAdapter).updateDirs(dirs)
|
||||||
}
|
}
|
||||||
|
|
||||||
setupScrollDirection()
|
setupScrollDirection()
|
||||||
|
@ -639,6 +754,31 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkInvalidDirectories(dirs: ArrayList<Directory>, directoryDao: DirectoryDao) {
|
||||||
|
val invalidDirs = ArrayList<Directory>()
|
||||||
|
dirs.forEach {
|
||||||
|
if (!getDoesFilePathExist(it.path)) {
|
||||||
|
invalidDirs.add(it)
|
||||||
|
} else if (it.path != config.tempFolderPath) {
|
||||||
|
val children = if (it.path.startsWith(OTG_PATH)) getOTGFolderChildrenNames(it.path) else File(it.path).list()?.asList()
|
||||||
|
val hasMediaFile = children?.any { it.isImageVideoGif() } ?: false
|
||||||
|
if (!hasMediaFile) {
|
||||||
|
invalidDirs.add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalidDirs.isNotEmpty()) {
|
||||||
|
dirs.removeAll(invalidDirs)
|
||||||
|
showSortedDirs(dirs)
|
||||||
|
invalidDirs.forEach {
|
||||||
|
directoryDao.deleteDirPath(it.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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() ?: ""
|
||||||
|
|
||||||
private fun setupLatestMediaId() {
|
private fun setupLatestMediaId() {
|
||||||
|
@ -678,16 +818,14 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun recheckPinnedFolders() {
|
override fun recheckPinnedFolders() {
|
||||||
gotDirectories(movePinnedDirectoriesToFront(mDirs), true)
|
gotDirectories(movePinnedDirectoriesToFront(getCurrentlyDisplayedDirs()))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateDirectories(directories: ArrayList<Directory>, refreshList: Boolean) {
|
override fun updateDirectories(directories: ArrayList<Directory>) {
|
||||||
if (refreshList) {
|
Thread {
|
||||||
gotDirectories(directories, true)
|
storeDirectoryItems(directories)
|
||||||
} else {
|
removeInvalidDBDirectories()
|
||||||
mDirs = directories
|
}.start()
|
||||||
storeDirectories()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkWhatsNewDialog() {
|
private fun checkWhatsNewDialog() {
|
||||||
|
|
|
@ -42,6 +42,7 @@ import com.simplemobiletools.gallery.models.Medium
|
||||||
import kotlinx.android.synthetic.main.activity_media.*
|
import kotlinx.android.synthetic.main.activity_media.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
||||||
private val LAST_MEDIA_CHECK_PERIOD = 3000L
|
private val LAST_MEDIA_CHECK_PERIOD = 3000L
|
||||||
|
@ -94,8 +95,10 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
storeStateVariables()
|
storeStateVariables()
|
||||||
if (mShowAll)
|
|
||||||
|
if (mShowAll) {
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(false)
|
supportActionBar?.setDisplayHomeAsUpEnabled(false)
|
||||||
|
}
|
||||||
|
|
||||||
media_empty_text.setOnClickListener {
|
media_empty_text.setOnClickListener {
|
||||||
showFilterMediaDialog()
|
showFilterMediaDialog()
|
||||||
|
@ -117,7 +120,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
||||||
getMediaAdapter()?.updateCropThumbnails(config.cropThumbnails)
|
getMediaAdapter()?.updateCropThumbnails(config.cropThumbnails)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mStoredScrollHorizontally != config.scrollHorizontally || mStoredShowInfoBubble != config.showInfoBubble) {
|
if (mStoredScrollHorizontally != config.scrollHorizontally) {
|
||||||
getMediaAdapter()?.updateScrollHorizontally(config.viewTypeFiles != VIEW_TYPE_LIST || !config.scrollHorizontally)
|
getMediaAdapter()?.updateScrollHorizontally(config.viewTypeFiles != VIEW_TYPE_LIST || !config.scrollHorizontally)
|
||||||
setupScrollDirection()
|
setupScrollDirection()
|
||||||
}
|
}
|
||||||
|
@ -134,6 +137,8 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
||||||
|
|
||||||
media_horizontal_fastscroller.updateBubbleColors()
|
media_horizontal_fastscroller.updateBubbleColors()
|
||||||
media_vertical_fastscroller.updateBubbleColors()
|
media_vertical_fastscroller.updateBubbleColors()
|
||||||
|
media_horizontal_fastscroller.allowBubbleDisplay = config.showInfoBubble
|
||||||
|
media_vertical_fastscroller.allowBubbleDisplay = config.showInfoBubble
|
||||||
media_refresh_layout.isEnabled = config.enablePullToRefresh
|
media_refresh_layout.isEnabled = config.enablePullToRefresh
|
||||||
tryloadGallery()
|
tryloadGallery()
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
|
@ -257,11 +262,13 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
||||||
MenuItemCompat.setOnActionExpandListener(mSearchMenuItem, object : MenuItemCompat.OnActionExpandListener {
|
MenuItemCompat.setOnActionExpandListener(mSearchMenuItem, object : MenuItemCompat.OnActionExpandListener {
|
||||||
override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
|
override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
|
||||||
mIsSearchOpen = true
|
mIsSearchOpen = true
|
||||||
|
media_refresh_layout.isEnabled = false
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
|
override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
|
||||||
mIsSearchOpen = false
|
mIsSearchOpen = false
|
||||||
|
media_refresh_layout.isEnabled = config.enablePullToRefresh
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -272,7 +279,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
||||||
val filtered = mMedia.filter { it.name.contains(text, true) } as ArrayList
|
val filtered = mMedia.filter { it.name.contains(text, true) } as ArrayList
|
||||||
filtered.sortBy { !it.name.startsWith(text, true) }
|
filtered.sortBy { !it.name.startsWith(text, true) }
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
(media_grid.adapter as? MediaAdapter)?.updateMedia(filtered)
|
getMediaAdapter()?.updateMedia(filtered)
|
||||||
}
|
}
|
||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
|
@ -365,12 +372,14 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
||||||
|
|
||||||
private fun showSortingDialog() {
|
private fun showSortingDialog() {
|
||||||
ChangeSortingDialog(this, false, !config.showAll, mPath) {
|
ChangeSortingDialog(this, false, !config.showAll, mPath) {
|
||||||
|
mLoadedInitialPhotos = false
|
||||||
getMedia()
|
getMedia()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showFilterMediaDialog() {
|
private fun showFilterMediaDialog() {
|
||||||
FilterMediaDialog(this) {
|
FilterMediaDialog(this) {
|
||||||
|
mLoadedInitialPhotos = false
|
||||||
media_refresh_layout.isRefreshing = true
|
media_refresh_layout.isRefreshing = true
|
||||||
getMedia()
|
getMedia()
|
||||||
}
|
}
|
||||||
|
@ -378,7 +387,6 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
||||||
|
|
||||||
private fun toggleFilenameVisibility() {
|
private fun toggleFilenameVisibility() {
|
||||||
config.displayFileNames = !config.displayFileNames
|
config.displayFileNames = !config.displayFileNames
|
||||||
if (media_grid.adapter != null)
|
|
||||||
getMediaAdapter()?.updateDisplayFilenames(config.displayFileNames)
|
getMediaAdapter()?.updateDisplayFilenames(config.displayFileNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,7 +450,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
||||||
private fun deleteDirectoryIfEmpty() {
|
private fun deleteDirectoryIfEmpty() {
|
||||||
val fileDirItem = FileDirItem(mPath, mPath.getFilenameFromPath())
|
val fileDirItem = FileDirItem(mPath, mPath.getFilenameFromPath())
|
||||||
if (config.deleteEmptyFolders && !fileDirItem.isDownloadsFolder() && fileDirItem.isDirectory && fileDirItem.getProperFileCount(applicationContext, true) == 0) {
|
if (config.deleteEmptyFolders && !fileDirItem.isDownloadsFolder() && fileDirItem.isDirectory && fileDirItem.getProperFileCount(applicationContext, true) == 0) {
|
||||||
deleteFile(fileDirItem, true)
|
tryDeleteFileDirItem(fileDirItem, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,16 +460,23 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
mIsGettingMedia = true
|
mIsGettingMedia = true
|
||||||
val media = getCachedMedia(mPath)
|
if (!mLoadedInitialPhotos) {
|
||||||
if (media.isNotEmpty() && !mLoadedInitialPhotos) {
|
getCachedMedia(mPath, mIsGetVideoIntent, mIsGetImageIntent) {
|
||||||
gotMedia(media, true)
|
if (it.isEmpty()) {
|
||||||
|
runOnUiThread {
|
||||||
|
media_refresh_layout.isRefreshing = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gotMedia(it, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
media_refresh_layout.isRefreshing = true
|
media_refresh_layout.isRefreshing = true
|
||||||
}
|
}
|
||||||
|
|
||||||
mLoadedInitialPhotos = true
|
mLoadedInitialPhotos = true
|
||||||
mCurrAsyncTask?.stopFetching()
|
mCurrAsyncTask?.stopFetching()
|
||||||
mCurrAsyncTask = GetMediaAsynctask(applicationContext, mPath, mIsGetVideoIntent, mIsGetImageIntent, mShowAll) {
|
mCurrAsyncTask = GetMediaAsynctask(applicationContext, mPath, mIsGetImageIntent, mIsGetVideoIntent, mShowAll) {
|
||||||
gotMedia(it)
|
gotMedia(it)
|
||||||
}
|
}
|
||||||
mCurrAsyncTask!!.execute()
|
mCurrAsyncTask!!.execute()
|
||||||
|
@ -470,11 +485,19 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
||||||
private fun isDirEmpty(): Boolean {
|
private fun isDirEmpty(): Boolean {
|
||||||
return if (mMedia.size <= 0 && config.filterMedia > 0) {
|
return if (mMedia.size <= 0 && config.filterMedia > 0) {
|
||||||
deleteDirectoryIfEmpty()
|
deleteDirectoryIfEmpty()
|
||||||
|
deleteDBDirectory()
|
||||||
finish()
|
finish()
|
||||||
true
|
true
|
||||||
} else
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteDBDirectory() {
|
||||||
|
Thread {
|
||||||
|
galleryDB.DirectoryDao().deleteDirPath(mPath)
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
private fun tryToggleTemporarilyShowHidden() {
|
private fun tryToggleTemporarilyShowHidden() {
|
||||||
if (config.temporarilyShowHidden) {
|
if (config.temporarilyShowHidden) {
|
||||||
|
@ -487,6 +510,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleTemporarilyShowHidden(show: Boolean) {
|
private fun toggleTemporarilyShowHidden(show: Boolean) {
|
||||||
|
mLoadedInitialPhotos = false
|
||||||
config.temporarilyShowHidden = show
|
config.temporarilyShowHidden = show
|
||||||
getMedia()
|
getMedia()
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
|
@ -620,14 +644,21 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun gotMedia(media: ArrayList<Medium>, isFromCache: Boolean = false) {
|
private fun gotMedia(media: ArrayList<Medium>, isFromCache: Boolean = false) {
|
||||||
|
val mediaToInsert = media.clone() as ArrayList<Medium>
|
||||||
Thread {
|
Thread {
|
||||||
mLatestMediaId = getLatestMediaId()
|
mLatestMediaId = getLatestMediaId()
|
||||||
mLatestMediaDateId = getLatestMediaByDateId()
|
mLatestMediaDateId = getLatestMediaByDateId()
|
||||||
|
if (!isFromCache) {
|
||||||
|
galleryDB.MediumDao().insertAll(mediaToInsert)
|
||||||
|
}
|
||||||
}.start()
|
}.start()
|
||||||
|
|
||||||
mIsGettingMedia = false
|
mIsGettingMedia = false
|
||||||
media_refresh_layout.isRefreshing = false
|
checkLastMediaChanged()
|
||||||
|
mMedia = media
|
||||||
|
|
||||||
|
runOnUiThread {
|
||||||
|
media_refresh_layout.isRefreshing = false
|
||||||
media_empty_text_label.beVisibleIf(media.isEmpty() && !isFromCache)
|
media_empty_text_label.beVisibleIf(media.isEmpty() && !isFromCache)
|
||||||
media_empty_text.beVisibleIf(media.isEmpty() && !isFromCache)
|
media_empty_text.beVisibleIf(media.isEmpty() && !isFromCache)
|
||||||
media_grid.beVisibleIf(media_empty_text_label.isGone())
|
media_grid.beVisibleIf(media_empty_text_label.isGone())
|
||||||
|
@ -636,45 +667,37 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
||||||
media_vertical_fastscroller.beVisibleIf(media_grid.isVisible() && !allowHorizontalScroll)
|
media_vertical_fastscroller.beVisibleIf(media_grid.isVisible() && !allowHorizontalScroll)
|
||||||
media_horizontal_fastscroller.beVisibleIf(media_grid.isVisible() && allowHorizontalScroll)
|
media_horizontal_fastscroller.beVisibleIf(media_grid.isVisible() && allowHorizontalScroll)
|
||||||
|
|
||||||
checkLastMediaChanged()
|
|
||||||
|
|
||||||
mMedia = media
|
|
||||||
runOnUiThread {
|
|
||||||
setupAdapter()
|
setupAdapter()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isFromCache) {
|
|
||||||
storeFolder()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun storeFolder() {
|
override fun tryDeleteFiles(fileDirItems: ArrayList<FileDirItem>) {
|
||||||
if (!config.temporarilyShowHidden) {
|
|
||||||
Thread {
|
|
||||||
storeFolderItems(mPath, mMedia)
|
|
||||||
}.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun deleteFiles(fileDirItems: ArrayList<FileDirItem>) {
|
|
||||||
val filtered = fileDirItems.filter { it.path.isImageVideoGif() } as ArrayList
|
val filtered = fileDirItems.filter { it.path.isImageVideoGif() } as ArrayList
|
||||||
deleteFiles(filtered) {
|
deleteFiles(filtered) {
|
||||||
if (!it) {
|
if (!it) {
|
||||||
toast(R.string.unknown_error_occurred)
|
toast(R.string.unknown_error_occurred)
|
||||||
} else if (mMedia.isEmpty()) {
|
return@deleteFiles
|
||||||
|
}
|
||||||
|
|
||||||
|
mMedia.removeAll { filtered.map { it.path }.contains(it.path) }
|
||||||
|
|
||||||
|
Thread {
|
||||||
|
val mediumDao = galleryDB.MediumDao()
|
||||||
|
filtered.forEach {
|
||||||
|
mediumDao.deleteMediumPath(it.path)
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
|
||||||
|
if (mMedia.isEmpty()) {
|
||||||
deleteDirectoryIfEmpty()
|
deleteDirectoryIfEmpty()
|
||||||
|
deleteDBDirectory()
|
||||||
finish()
|
finish()
|
||||||
} else {
|
|
||||||
updateStoredDirectories()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun refreshItems() {
|
override fun refreshItems() {
|
||||||
getMedia()
|
getMedia()
|
||||||
Handler().postDelayed({
|
|
||||||
getMedia()
|
|
||||||
}, 1000)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun selectedPaths(paths: ArrayList<String>) {
|
override fun selectedPaths(paths: ArrayList<String>) {
|
||||||
|
|
|
@ -85,12 +85,12 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
val file = File(mUri.toString())
|
val file = File(mUri.toString())
|
||||||
val type = when {
|
val type = when {
|
||||||
file.isImageFast() -> TYPE_IMAGE
|
file.isImageFast() -> TYPE_IMAGES
|
||||||
file.isVideoFast() -> TYPE_VIDEO
|
file.isVideoFast() -> TYPE_VIDEOS
|
||||||
else -> TYPE_GIF
|
else -> TYPE_GIFS
|
||||||
}
|
}
|
||||||
|
|
||||||
mMedium = Medium(getFilenameFromUri(mUri!!), mUri.toString(), 0, 0, file.length(), type)
|
mMedium = Medium(null, getFilenameFromUri(mUri!!), mUri.toString(), mUri!!.path.getParentPath(), 0, 0, file.length(), type)
|
||||||
supportActionBar?.title = mMedium!!.name
|
supportActionBar?.title = mMedium!!.name
|
||||||
bundle.putSerializable(MEDIUM, mMedium)
|
bundle.putSerializable(MEDIUM, mMedium)
|
||||||
|
|
||||||
|
|
|
@ -203,6 +203,11 @@ class SettingsActivity : SimpleActivity() {
|
||||||
settings_scroll_horizontally_holder.setOnClickListener {
|
settings_scroll_horizontally_holder.setOnClickListener {
|
||||||
settings_scroll_horizontally.toggle()
|
settings_scroll_horizontally.toggle()
|
||||||
config.scrollHorizontally = settings_scroll_horizontally.isChecked
|
config.scrollHorizontally = settings_scroll_horizontally.isChecked
|
||||||
|
|
||||||
|
if (config.scrollHorizontally) {
|
||||||
|
config.enablePullToRefresh = false
|
||||||
|
settings_enable_pull_to_refresh.isChecked = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,10 @@ import com.simplemobiletools.gallery.fragments.ViewPagerFragment
|
||||||
import com.simplemobiletools.gallery.helpers.*
|
import com.simplemobiletools.gallery.helpers.*
|
||||||
import com.simplemobiletools.gallery.models.Medium
|
import com.simplemobiletools.gallery.models.Medium
|
||||||
import kotlinx.android.synthetic.main.activity_medium.*
|
import kotlinx.android.synthetic.main.activity_medium.*
|
||||||
import java.io.*
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, ViewPagerFragment.FragmentListener {
|
class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, ViewPagerFragment.FragmentListener {
|
||||||
|
@ -197,7 +200,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
||||||
|
|
||||||
showSystemUI()
|
showSystemUI()
|
||||||
|
|
||||||
mDirectory = mPath.getParentPath().trimEnd('/')
|
mDirectory = mPath.getParentPath()
|
||||||
if (mDirectory.startsWith(OTG_PATH.trimEnd('/'))) {
|
if (mDirectory.startsWith(OTG_PATH.trimEnd('/'))) {
|
||||||
mDirectory += "/"
|
mDirectory += "/"
|
||||||
}
|
}
|
||||||
|
@ -527,11 +530,10 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val newFile = File(newPath)
|
val tmpPath = "$filesDir/.tmp_${newPath.getFilenameFromPath()}"
|
||||||
val tmpFile = File(filesDir, ".tmp_${newPath.getFilenameFromPath()}")
|
val tmpFileDirItem = FileDirItem(tmpPath, tmpPath.getFilenameFromPath())
|
||||||
|
|
||||||
try {
|
try {
|
||||||
getFileOutputStream(tmpFile.toFileDirItem(applicationContext)) {
|
getFileOutputStream(tmpFileDirItem) {
|
||||||
if (it == null) {
|
if (it == null) {
|
||||||
toast(R.string.unknown_error_occurred)
|
toast(R.string.unknown_error_occurred)
|
||||||
return@getFileOutputStream
|
return@getFileOutputStream
|
||||||
|
@ -539,22 +541,24 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
||||||
|
|
||||||
val oldLastModified = getCurrentFile().lastModified()
|
val oldLastModified = getCurrentFile().lastModified()
|
||||||
if (oldPath.isJpg()) {
|
if (oldPath.isJpg()) {
|
||||||
copyFile(getCurrentFile(), tmpFile)
|
copyFile(getCurrentPath(), tmpPath)
|
||||||
saveExifRotation(ExifInterface(tmpFile.absolutePath), mRotationDegrees)
|
saveExifRotation(ExifInterface(tmpPath), mRotationDegrees)
|
||||||
} else {
|
} else {
|
||||||
val bitmap = BitmapFactory.decodeFile(oldPath)
|
val inputstream = getFileInputStreamSync(oldPath)
|
||||||
saveFile(tmpFile, bitmap, it as FileOutputStream)
|
val bitmap = BitmapFactory.decodeStream(inputstream)
|
||||||
|
saveFile(tmpPath, bitmap, it as FileOutputStream)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmpFile.length() > 0 && getDoesFilePathExist(newPath)) {
|
if (getDoesFilePathExist(newPath)) {
|
||||||
deleteFile(FileDirItem(newPath, newPath.getFilenameFromPath()))
|
tryDeleteFileDirItem(FileDirItem(newPath, newPath.getFilenameFromPath()))
|
||||||
}
|
}
|
||||||
copyFile(tmpFile, newFile)
|
|
||||||
|
copyFile(tmpPath, newPath)
|
||||||
scanPath(newPath)
|
scanPath(newPath)
|
||||||
toast(R.string.file_saved)
|
toast(R.string.file_saved)
|
||||||
|
|
||||||
if (config.keepLastModified) {
|
if (config.keepLastModified) {
|
||||||
newFile.setLastModified(oldLastModified)
|
File(newPath).setLastModified(oldLastModified)
|
||||||
updateLastModified(newPath, oldLastModified)
|
updateLastModified(newPath, oldLastModified)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -575,13 +579,14 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
showErrorToast(e)
|
showErrorToast(e)
|
||||||
} finally {
|
} finally {
|
||||||
deleteFile(FileDirItem(tmpFile.absolutePath, tmpFile.absolutePath.getFilenameFromPath()))
|
tryDeleteFileDirItem(tmpFileDirItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.N)
|
@TargetApi(Build.VERSION_CODES.N)
|
||||||
private fun tryRotateByExif(path: String): Boolean {
|
private fun tryRotateByExif(path: String): Boolean {
|
||||||
return if (saveImageRotation(path, mRotationDegrees)) {
|
return try {
|
||||||
|
if (saveImageRotation(path, mRotationDegrees)) {
|
||||||
mRotationDegrees = 0
|
mRotationDegrees = 0
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
toast(R.string.file_saved)
|
toast(R.string.file_saved)
|
||||||
|
@ -589,27 +594,30 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
showErrorToast(e)
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun copyFile(source: File, destination: File) {
|
private fun copyFile(source: String, destination: String) {
|
||||||
var inputStream: InputStream? = null
|
var inputStream: InputStream? = null
|
||||||
var out: OutputStream? = null
|
var out: OutputStream? = null
|
||||||
try {
|
try {
|
||||||
val fileDocument = if (isPathOnSD(destination.absolutePath)) getDocumentFile(destination.parent) else null
|
out = getFileOutputStreamSync(destination, source.getMimeType())
|
||||||
out = getFileOutputStreamSync(destination.absolutePath, source.getMimeType(), fileDocument)
|
inputStream = getFileInputStreamSync(source)
|
||||||
inputStream = FileInputStream(source)
|
inputStream?.copyTo(out!!)
|
||||||
inputStream.copyTo(out!!)
|
|
||||||
} finally {
|
} finally {
|
||||||
inputStream?.close()
|
inputStream?.close()
|
||||||
out?.close()
|
out?.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun saveFile(file: File, bitmap: Bitmap, out: FileOutputStream) {
|
private fun saveFile(path: String, bitmap: Bitmap, out: FileOutputStream) {
|
||||||
val matrix = Matrix()
|
val matrix = Matrix()
|
||||||
matrix.postRotate(mRotationDegrees.toFloat())
|
matrix.postRotate(mRotationDegrees.toFloat())
|
||||||
val bmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
|
val bmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
|
||||||
bmp.compress(file.absolutePath.getCompressionFormat(), 90, out)
|
bmp.compress(path.getCompressionFormat(), 90, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isShowHiddenFlagNeeded(): Boolean {
|
private fun isShowHiddenFlagNeeded(): Boolean {
|
||||||
|
@ -736,7 +744,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
||||||
|
|
||||||
private fun deleteConfirmed() {
|
private fun deleteConfirmed() {
|
||||||
val path = getCurrentMedia()[mPos].path
|
val path = getCurrentMedia()[mPos].path
|
||||||
deleteFile(FileDirItem(path, path.getFilenameFromPath())) {
|
tryDeleteFileDirItem(FileDirItem(path, path.getFilenameFromPath())) {
|
||||||
refreshViewPager()
|
refreshViewPager()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -752,8 +760,16 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renameFile() {
|
private fun renameFile() {
|
||||||
RenameItemDialog(this, getCurrentPath()) {
|
val oldPath = getCurrentPath()
|
||||||
getCurrentMedia()[mPos].path = it
|
RenameItemDialog(this, oldPath) {
|
||||||
|
getCurrentMedia()[mPos].apply {
|
||||||
|
path = it
|
||||||
|
name = it.getFilenameFromPath()
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread {
|
||||||
|
updateDBMediaPath(oldPath, it)
|
||||||
|
}.start()
|
||||||
updateActionbarTitle()
|
updateActionbarTitle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -814,7 +830,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
||||||
private fun deleteDirectoryIfEmpty() {
|
private fun deleteDirectoryIfEmpty() {
|
||||||
val fileDirItem = FileDirItem(mDirectory, mDirectory.getFilenameFromPath(), getIsPathDirectory(mDirectory))
|
val fileDirItem = FileDirItem(mDirectory, mDirectory.getFilenameFromPath(), getIsPathDirectory(mDirectory))
|
||||||
if (config.deleteEmptyFolders && !fileDirItem.isDownloadsFolder() && fileDirItem.isDirectory && fileDirItem.getProperFileCount(applicationContext, true) == 0) {
|
if (config.deleteEmptyFolders && !fileDirItem.isDownloadsFolder() && fileDirItem.isDirectory && fileDirItem.getProperFileCount(applicationContext, true) == 0) {
|
||||||
deleteFile(fileDirItem, true)
|
tryDeleteFileDirItem(fileDirItem, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
scanPath(mDirectory)
|
scanPath(mDirectory)
|
||||||
|
|
|
@ -12,6 +12,7 @@ import com.simplemobiletools.commons.dialogs.ConfirmationDialog
|
||||||
import com.simplemobiletools.commons.dialogs.PropertiesDialog
|
import com.simplemobiletools.commons.dialogs.PropertiesDialog
|
||||||
import com.simplemobiletools.commons.dialogs.RenameItemDialog
|
import com.simplemobiletools.commons.dialogs.RenameItemDialog
|
||||||
import com.simplemobiletools.commons.extensions.*
|
import com.simplemobiletools.commons.extensions.*
|
||||||
|
import com.simplemobiletools.commons.helpers.OTG_PATH
|
||||||
import com.simplemobiletools.commons.models.FileDirItem
|
import com.simplemobiletools.commons.models.FileDirItem
|
||||||
import com.simplemobiletools.commons.views.FastScroller
|
import com.simplemobiletools.commons.views.FastScroller
|
||||||
import com.simplemobiletools.commons.views.MyRecyclerView
|
import com.simplemobiletools.commons.views.MyRecyclerView
|
||||||
|
@ -19,10 +20,7 @@ import com.simplemobiletools.gallery.R
|
||||||
import com.simplemobiletools.gallery.dialogs.ExcludeFolderDialog
|
import com.simplemobiletools.gallery.dialogs.ExcludeFolderDialog
|
||||||
import com.simplemobiletools.gallery.dialogs.PickMediumDialog
|
import com.simplemobiletools.gallery.dialogs.PickMediumDialog
|
||||||
import com.simplemobiletools.gallery.extensions.*
|
import com.simplemobiletools.gallery.extensions.*
|
||||||
import com.simplemobiletools.gallery.helpers.TYPE_GIF
|
import com.simplemobiletools.gallery.helpers.*
|
||||||
import com.simplemobiletools.gallery.helpers.TYPE_IMAGE
|
|
||||||
import com.simplemobiletools.gallery.helpers.TYPE_VIDEO
|
|
||||||
import com.simplemobiletools.gallery.helpers.VIEW_TYPE_LIST
|
|
||||||
import com.simplemobiletools.gallery.models.AlbumCover
|
import com.simplemobiletools.gallery.models.AlbumCover
|
||||||
import com.simplemobiletools.gallery.models.Directory
|
import com.simplemobiletools.gallery.models.Directory
|
||||||
import kotlinx.android.synthetic.main.directory_item_list.view.*
|
import kotlinx.android.synthetic.main.directory_item_list.view.*
|
||||||
|
@ -155,7 +153,8 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renameDir() {
|
private fun renameDir() {
|
||||||
val sourcePath = dirs[selectedPositions.first()].path
|
val firstDir = dirs[selectedPositions.first()]
|
||||||
|
val sourcePath = firstDir.path
|
||||||
val dir = File(sourcePath)
|
val dir = File(sourcePath)
|
||||||
if (activity.isAStorageRootFolder(dir.absolutePath)) {
|
if (activity.isAStorageRootFolder(dir.absolutePath)) {
|
||||||
activity.toast(R.string.rename_folder_root)
|
activity.toast(R.string.rename_folder_root)
|
||||||
|
@ -164,17 +163,13 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
|
||||||
|
|
||||||
RenameItemDialog(activity, dir.absolutePath) {
|
RenameItemDialog(activity, dir.absolutePath) {
|
||||||
activity.runOnUiThread {
|
activity.runOnUiThread {
|
||||||
if (selectedPositions.isEmpty()) {
|
firstDir.apply {
|
||||||
return@runOnUiThread
|
|
||||||
}
|
|
||||||
|
|
||||||
dirs[selectedPositions.first()].apply {
|
|
||||||
path = it
|
path = it
|
||||||
name = it.getFilenameFromPath()
|
name = it.getFilenameFromPath()
|
||||||
tmb = File(it, tmb.getFilenameFromPath()).absolutePath
|
tmb = File(it, tmb.getFilenameFromPath()).absolutePath
|
||||||
}
|
}
|
||||||
updateDirs(dirs)
|
updateDirs(dirs)
|
||||||
listener?.updateDirectories(dirs.toList() as ArrayList, false)
|
listener?.updateDirectories(dirs.toList() as ArrayList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,7 +207,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
|
||||||
dirs.forEach {
|
dirs.forEach {
|
||||||
it.name = activity.checkAppendingHidden(it.path, hidden, includedFolders)
|
it.name = activity.checkAppendingHidden(it.path, hidden, includedFolders)
|
||||||
}
|
}
|
||||||
listener?.updateDirectories(dirs.toList() as ArrayList, false)
|
listener?.updateDirectories(dirs.toList() as ArrayList)
|
||||||
activity.runOnUiThread {
|
activity.runOnUiThread {
|
||||||
updateDirs(dirs)
|
updateDirs(dirs)
|
||||||
}
|
}
|
||||||
|
@ -249,7 +244,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
|
||||||
dirs = newDirs
|
dirs = newDirs
|
||||||
finishActMode()
|
finishActMode()
|
||||||
fastScroller?.measureRecyclerView()
|
fastScroller?.measureRecyclerView()
|
||||||
listener?.updateDirectories(newDirs, false)
|
listener?.updateDirectories(newDirs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,9 +279,16 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
|
||||||
|
|
||||||
private fun copyMoveTo(isCopyOperation: Boolean) {
|
private fun copyMoveTo(isCopyOperation: Boolean) {
|
||||||
val paths = ArrayList<String>()
|
val paths = ArrayList<String>()
|
||||||
|
val showHidden = activity.config.shouldShowHidden
|
||||||
selectedPositions.forEach {
|
selectedPositions.forEach {
|
||||||
val dir = File(dirs[it].path)
|
val path = dirs[it].path
|
||||||
paths.addAll(dir.listFiles().filter { !activity.getIsPathDirectory(it.absolutePath) && it.absolutePath.isImageVideoGif() }.map { it.absolutePath })
|
if (path.startsWith(OTG_PATH)) {
|
||||||
|
paths.addAll(getOTGFilePaths(path, showHidden))
|
||||||
|
} else {
|
||||||
|
File(path).listFiles()?.filter {
|
||||||
|
!activity.getIsPathDirectory(it.absolutePath) && it.isImageVideoGif() && (showHidden || !it.name.startsWith('.'))
|
||||||
|
}?.mapTo(paths, { it.absolutePath })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val fileDirItems = paths.map { FileDirItem(it, it.getFilenameFromPath()) } as ArrayList<FileDirItem>
|
val fileDirItems = paths.map { FileDirItem(it, it.getFilenameFromPath()) } as ArrayList<FileDirItem>
|
||||||
|
@ -297,6 +299,17 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getOTGFilePaths(path: String, showHidden: Boolean): ArrayList<String> {
|
||||||
|
val paths = ArrayList<String>()
|
||||||
|
activity.getOTGFolderChildren(path)?.forEach {
|
||||||
|
if (!it.isDirectory && it.name.isImageVideoGif() && (showHidden || !it.name.startsWith('.'))) {
|
||||||
|
val relativePath = it.uri.path.substringAfterLast("${activity.config.OTGPartition}:")
|
||||||
|
paths.add("$OTG_PATH$relativePath")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return paths
|
||||||
|
}
|
||||||
|
|
||||||
private fun askConfirmDelete() {
|
private fun askConfirmDelete() {
|
||||||
if (config.skipDeleteConfirmation) {
|
if (config.skipDeleteConfirmation) {
|
||||||
deleteFiles()
|
deleteFiles()
|
||||||
|
@ -416,14 +429,18 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
|
||||||
dir_path?.text = "${directory.path.substringBeforeLast("/")}/"
|
dir_path?.text = "${directory.path.substringBeforeLast("/")}/"
|
||||||
photo_cnt.text = directory.mediaCnt.toString()
|
photo_cnt.text = directory.mediaCnt.toString()
|
||||||
val thumbnailType = when {
|
val thumbnailType = when {
|
||||||
directory.tmb.isImageFast() -> TYPE_IMAGE
|
directory.tmb.isImageFast() -> TYPE_IMAGES
|
||||||
directory.tmb.isVideoFast() -> TYPE_VIDEO
|
directory.tmb.isVideoFast() -> TYPE_VIDEOS
|
||||||
else -> TYPE_GIF
|
else -> TYPE_GIFS
|
||||||
}
|
}
|
||||||
|
|
||||||
activity.loadImage(thumbnailType, directory.tmb, dir_thumbnail, scrollHorizontally, animateGifs, cropThumbnails)
|
activity.loadImage(thumbnailType, directory.tmb, dir_thumbnail, scrollHorizontally, animateGifs, cropThumbnails)
|
||||||
dir_pin.beVisibleIf(pinnedFolders.contains(directory.path))
|
dir_pin.beVisibleIf(pinnedFolders.contains(directory.path))
|
||||||
dir_sd_card.beVisibleIf(directory.isOnSDCard)
|
dir_location.beVisibleIf(directory.location != LOCAITON_INTERNAL)
|
||||||
|
if (dir_location.isVisible()) {
|
||||||
|
dir_location.setImageResource(if (directory.location == LOCATION_SD) R.drawable.ic_sd_card else R.drawable.ic_usb)
|
||||||
|
}
|
||||||
|
|
||||||
photo_cnt.beVisibleIf(showMediaCount)
|
photo_cnt.beVisibleIf(showMediaCount)
|
||||||
|
|
||||||
if (isListViewType) {
|
if (isListViewType) {
|
||||||
|
@ -431,7 +448,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
|
||||||
dir_path.setTextColor(textColor)
|
dir_path.setTextColor(textColor)
|
||||||
photo_cnt.setTextColor(textColor)
|
photo_cnt.setTextColor(textColor)
|
||||||
dir_pin.applyColorFilter(textColor)
|
dir_pin.applyColorFilter(textColor)
|
||||||
dir_sd_card.applyColorFilter(textColor)
|
dir_location.applyColorFilter(textColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,6 +460,6 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
|
||||||
|
|
||||||
fun recheckPinnedFolders()
|
fun recheckPinnedFolders()
|
||||||
|
|
||||||
fun updateDirectories(directories: ArrayList<Directory>, refreshList: Boolean)
|
fun updateDirectories(directories: ArrayList<Directory>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,7 +148,12 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renameFile() {
|
private fun renameFile() {
|
||||||
RenameItemDialog(activity, getCurrentPath()) {
|
val oldPath = getCurrentPath()
|
||||||
|
RenameItemDialog(activity, oldPath) {
|
||||||
|
Thread {
|
||||||
|
activity.updateDBMediaPath(oldPath, it)
|
||||||
|
}.start()
|
||||||
|
|
||||||
activity.runOnUiThread {
|
activity.runOnUiThread {
|
||||||
listener?.refreshItems()
|
listener?.refreshItems()
|
||||||
finishActMode()
|
finishActMode()
|
||||||
|
@ -158,7 +163,6 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
|
||||||
|
|
||||||
private fun editFile() {
|
private fun editFile() {
|
||||||
activity.openEditor(getCurrentPath())
|
activity.openEditor(getCurrentPath())
|
||||||
finishActMode()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleFileVisibility(hide: Boolean) {
|
private fun toggleFileVisibility(hide: Boolean) {
|
||||||
|
@ -188,7 +192,8 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
|
||||||
val fileDirItems = paths.map { FileDirItem(it, it.getFilenameFromPath()) } as ArrayList
|
val fileDirItems = paths.map { FileDirItem(it, it.getFilenameFromPath()) } as ArrayList
|
||||||
activity.tryCopyMoveFilesTo(fileDirItems, isCopyOperation) {
|
activity.tryCopyMoveFilesTo(fileDirItems, isCopyOperation) {
|
||||||
config.tempFolderPath = ""
|
config.tempFolderPath = ""
|
||||||
activity.applicationContext.updateStoredFolderItems(it)
|
activity.applicationContext.rescanFolderMedia(it)
|
||||||
|
activity.applicationContext.rescanFolderMedia(fileDirItems.first().getParentPath())
|
||||||
if (!isCopyOperation) {
|
if (!isCopyOperation) {
|
||||||
listener?.refreshItems()
|
listener?.refreshItems()
|
||||||
}
|
}
|
||||||
|
@ -236,9 +241,8 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
|
||||||
}
|
}
|
||||||
|
|
||||||
media.removeAll(removeMedia)
|
media.removeAll(removeMedia)
|
||||||
listener?.deleteFiles(fileDirItems)
|
listener?.tryDeleteFiles(fileDirItems)
|
||||||
removeSelectedItems()
|
removeSelectedItems()
|
||||||
updateStoredFolderItems()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,14 +252,6 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
|
||||||
return selectedMedia
|
return selectedMedia
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateStoredFolderItems() {
|
|
||||||
Thread {
|
|
||||||
if (media.isNotEmpty()) {
|
|
||||||
activity.applicationContext.storeFolderItems(media.first().path.getParentPath().trimEnd('/'), media as ArrayList<Medium>)
|
|
||||||
}
|
|
||||||
}.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateMedia(newMedia: ArrayList<Medium>) {
|
fun updateMedia(newMedia: ArrayList<Medium>) {
|
||||||
if (newMedia.hashCode() != currentMediaHash) {
|
if (newMedia.hashCode() != currentMediaHash) {
|
||||||
currentMediaHash = newMedia.hashCode()
|
currentMediaHash = newMedia.hashCode()
|
||||||
|
@ -331,7 +327,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
|
||||||
interface MediaOperationsListener {
|
interface MediaOperationsListener {
|
||||||
fun refreshItems()
|
fun refreshItems()
|
||||||
|
|
||||||
fun deleteFiles(fileDirItems: ArrayList<FileDirItem>)
|
fun tryDeleteFiles(fileDirItems: ArrayList<FileDirItem>)
|
||||||
|
|
||||||
fun selectedPaths(paths: ArrayList<String>)
|
fun selectedPaths(paths: ArrayList<String>)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
package com.simplemobiletools.gallery.asynctasks
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.AsyncTask
|
|
||||||
import com.simplemobiletools.commons.extensions.*
|
|
||||||
import com.simplemobiletools.commons.helpers.OTG_PATH
|
|
||||||
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE
|
|
||||||
import com.simplemobiletools.commons.helpers.SORT_DESCENDING
|
|
||||||
import com.simplemobiletools.commons.helpers.sumByLong
|
|
||||||
import com.simplemobiletools.gallery.R
|
|
||||||
import com.simplemobiletools.gallery.extensions.checkAppendingHidden
|
|
||||||
import com.simplemobiletools.gallery.extensions.config
|
|
||||||
import com.simplemobiletools.gallery.helpers.MediaFetcher
|
|
||||||
import com.simplemobiletools.gallery.models.Directory
|
|
||||||
import com.simplemobiletools.gallery.models.Medium
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class GetDirectoriesAsynctask(val context: Context, val isPickVideo: Boolean, val isPickImage: Boolean,
|
|
||||||
val callback: (dirs: ArrayList<Directory>) -> Unit) : AsyncTask<Void, Void, ArrayList<Directory>>() {
|
|
||||||
private val mediaFetcher = MediaFetcher(context)
|
|
||||||
|
|
||||||
override fun doInBackground(vararg params: Void): ArrayList<Directory> {
|
|
||||||
if (!context.hasPermission(PERMISSION_WRITE_STORAGE)) {
|
|
||||||
return ArrayList()
|
|
||||||
}
|
|
||||||
|
|
||||||
val config = context.config
|
|
||||||
val groupedMedia = mediaFetcher.getMediaByDirectories(isPickVideo, isPickImage)
|
|
||||||
val directories = ArrayList<Directory>()
|
|
||||||
val hidden = context.getString(R.string.hidden)
|
|
||||||
val albumCovers = config.parseAlbumCovers()
|
|
||||||
val hasOTG = context.hasOTGConnected() && context.config.OTGBasePath.isNotEmpty()
|
|
||||||
val includedFolders = config.includedFolders
|
|
||||||
|
|
||||||
for ((path, curMedia) in groupedMedia) {
|
|
||||||
Medium.sorting = config.getFileSorting(path)
|
|
||||||
curMedia.sort()
|
|
||||||
|
|
||||||
val firstItem = curMedia.first()
|
|
||||||
val lastItem = curMedia.last()
|
|
||||||
val parentDir = if (hasOTG && firstItem.path.startsWith(OTG_PATH)) firstItem.path.getParentPath() else File(firstItem.path).parent ?: continue
|
|
||||||
var thumbnail = curMedia.firstOrNull { context.getDoesFilePathExist(it.path) }?.path ?: ""
|
|
||||||
if (thumbnail.startsWith(OTG_PATH)) {
|
|
||||||
thumbnail = thumbnail.getOTGPublicPath(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
albumCovers.forEach {
|
|
||||||
if (it.path == parentDir && context.getDoesFilePathExist(it.tmb)) {
|
|
||||||
thumbnail = it.tmb
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val dirName = context.checkAppendingHidden(parentDir, hidden, includedFolders)
|
|
||||||
val lastModified = if (config.directorySorting and SORT_DESCENDING > 0) Math.max(firstItem.modified, lastItem.modified) else Math.min(firstItem.modified, lastItem.modified)
|
|
||||||
val dateTaken = if (config.directorySorting and SORT_DESCENDING > 0) Math.max(firstItem.taken, lastItem.taken) else Math.min(firstItem.taken, lastItem.taken)
|
|
||||||
val size = curMedia.sumByLong { it.size }
|
|
||||||
val directory = Directory(parentDir, thumbnail, dirName, curMedia.size, lastModified, dateTaken, size, context.isPathOnSD(parentDir))
|
|
||||||
directories.add(directory)
|
|
||||||
}
|
|
||||||
|
|
||||||
return directories
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPostExecute(dirs: ArrayList<Directory>) {
|
|
||||||
super.onPostExecute(dirs)
|
|
||||||
callback(dirs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun stopFetching() {
|
|
||||||
mediaFetcher.shouldStop = true
|
|
||||||
cancel(true)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,18 +7,18 @@ import com.simplemobiletools.gallery.helpers.MediaFetcher
|
||||||
import com.simplemobiletools.gallery.models.Medium
|
import com.simplemobiletools.gallery.models.Medium
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class GetMediaAsynctask(val context: Context, val mPath: String, val isPickVideo: Boolean = false, val isPickImage: Boolean = false,
|
class GetMediaAsynctask(val context: Context, val mPath: String, val isPickImage: Boolean = false, val isPickVideo: Boolean = false,
|
||||||
val showAll: Boolean, val callback: (media: ArrayList<Medium>) -> Unit) :
|
val showAll: Boolean, val callback: (media: ArrayList<Medium>) -> Unit) :
|
||||||
AsyncTask<Void, Void, ArrayList<Medium>>() {
|
AsyncTask<Void, Void, ArrayList<Medium>>() {
|
||||||
private val mediaFetcher = MediaFetcher(context)
|
private val mediaFetcher = MediaFetcher(context)
|
||||||
|
|
||||||
override fun doInBackground(vararg params: Void): ArrayList<Medium> {
|
override fun doInBackground(vararg params: Void): ArrayList<Medium> {
|
||||||
return if (showAll) {
|
return if (showAll) {
|
||||||
val mediaMap = mediaFetcher.getMediaByDirectories(isPickVideo, isPickImage)
|
val foldersToScan = mediaFetcher.getFoldersToScan("")
|
||||||
val media = ArrayList<Medium>()
|
val media = ArrayList<Medium>()
|
||||||
|
for (folder in foldersToScan) {
|
||||||
mediaMap.values.forEach {
|
val newMedia = mediaFetcher.getFilesFrom(folder, isPickImage, isPickVideo)
|
||||||
media.addAll(it)
|
media.addAll(newMedia)
|
||||||
}
|
}
|
||||||
|
|
||||||
Medium.sorting = context.config.getFileSorting("")
|
Medium.sorting = context.config.getFileSorting("")
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.simplemobiletools.gallery.databases
|
||||||
|
|
||||||
|
import android.arch.persistence.room.Database
|
||||||
|
import android.arch.persistence.room.Room
|
||||||
|
import android.arch.persistence.room.RoomDatabase
|
||||||
|
import android.content.Context
|
||||||
|
import com.simplemobiletools.gallery.interfaces.DirectoryDao
|
||||||
|
import com.simplemobiletools.gallery.interfaces.MediumDao
|
||||||
|
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 fun DirectoryDao(): DirectoryDao
|
||||||
|
|
||||||
|
abstract fun MediumDao(): MediumDao
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private var INSTANCE: GalleryDataBase? = null
|
||||||
|
|
||||||
|
fun getInstance(context: Context): GalleryDataBase {
|
||||||
|
if (INSTANCE == null) {
|
||||||
|
synchronized(GalleryDataBase::class) {
|
||||||
|
INSTANCE = Room.databaseBuilder(context.applicationContext, GalleryDataBase::class.java, "gallery.db")
|
||||||
|
.fallbackToDestructiveMigration()
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return INSTANCE!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun destroyInstance() {
|
||||||
|
INSTANCE = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,7 +44,6 @@ class ChangeSortingDialog(val activity: BaseSimpleActivity, val isDirectorySorti
|
||||||
currSorting and SORT_BY_PATH != 0 -> sortingRadio.sorting_dialog_radio_path
|
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_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_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
|
else -> sortingRadio.sorting_dialog_radio_name
|
||||||
}
|
}
|
||||||
sortBtn.isChecked = true
|
sortBtn.isChecked = true
|
||||||
|
@ -66,8 +65,7 @@ class ChangeSortingDialog(val activity: BaseSimpleActivity, val isDirectorySorti
|
||||||
R.id.sorting_dialog_radio_name -> SORT_BY_NAME
|
R.id.sorting_dialog_radio_name -> SORT_BY_NAME
|
||||||
R.id.sorting_dialog_radio_path -> SORT_BY_PATH
|
R.id.sorting_dialog_radio_path -> SORT_BY_PATH
|
||||||
R.id.sorting_dialog_radio_size -> SORT_BY_SIZE
|
R.id.sorting_dialog_radio_size -> SORT_BY_SIZE
|
||||||
R.id.sorting_dialog_radio_last_modified -> SORT_BY_DATE_MODIFIED
|
else -> SORT_BY_DATE_MODIFIED
|
||||||
else -> SORT_BY_DATE_TAKEN
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (view.sorting_dialog_radio_order.checkedRadioButtonId == R.id.sorting_dialog_radio_descending) {
|
if (view.sorting_dialog_radio_order.checkedRadioButtonId == R.id.sorting_dialog_radio_descending) {
|
||||||
|
|
|
@ -5,9 +5,9 @@ import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||||
import com.simplemobiletools.commons.extensions.setupDialogStuff
|
import com.simplemobiletools.commons.extensions.setupDialogStuff
|
||||||
import com.simplemobiletools.gallery.R
|
import com.simplemobiletools.gallery.R
|
||||||
import com.simplemobiletools.gallery.extensions.config
|
import com.simplemobiletools.gallery.extensions.config
|
||||||
import com.simplemobiletools.gallery.helpers.GIFS
|
import com.simplemobiletools.gallery.helpers.TYPE_GIFS
|
||||||
import com.simplemobiletools.gallery.helpers.IMAGES
|
import com.simplemobiletools.gallery.helpers.TYPE_IMAGES
|
||||||
import com.simplemobiletools.gallery.helpers.VIDEOS
|
import com.simplemobiletools.gallery.helpers.TYPE_VIDEOS
|
||||||
import kotlinx.android.synthetic.main.dialog_filter_media.view.*
|
import kotlinx.android.synthetic.main.dialog_filter_media.view.*
|
||||||
|
|
||||||
class FilterMediaDialog(val activity: BaseSimpleActivity, val callback: (result: Int) -> Unit) {
|
class FilterMediaDialog(val activity: BaseSimpleActivity, val callback: (result: Int) -> Unit) {
|
||||||
|
@ -16,9 +16,9 @@ class FilterMediaDialog(val activity: BaseSimpleActivity, val callback: (result:
|
||||||
init {
|
init {
|
||||||
val filterMedia = activity.config.filterMedia
|
val filterMedia = activity.config.filterMedia
|
||||||
view.apply {
|
view.apply {
|
||||||
filter_media_images.isChecked = filterMedia and IMAGES != 0
|
filter_media_images.isChecked = filterMedia and TYPE_IMAGES != 0
|
||||||
filter_media_videos.isChecked = filterMedia and VIDEOS != 0
|
filter_media_videos.isChecked = filterMedia and TYPE_VIDEOS != 0
|
||||||
filter_media_gifs.isChecked = filterMedia and GIFS != 0
|
filter_media_gifs.isChecked = filterMedia and TYPE_GIFS != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
AlertDialog.Builder(activity)
|
AlertDialog.Builder(activity)
|
||||||
|
@ -32,11 +32,11 @@ class FilterMediaDialog(val activity: BaseSimpleActivity, val callback: (result:
|
||||||
private fun dialogConfirmed() {
|
private fun dialogConfirmed() {
|
||||||
var result = 0
|
var result = 0
|
||||||
if (view.filter_media_images.isChecked)
|
if (view.filter_media_images.isChecked)
|
||||||
result += IMAGES
|
result += TYPE_IMAGES
|
||||||
if (view.filter_media_videos.isChecked)
|
if (view.filter_media_videos.isChecked)
|
||||||
result += VIDEOS
|
result += TYPE_VIDEOS
|
||||||
if (view.filter_media_gifs.isChecked)
|
if (view.filter_media_gifs.isChecked)
|
||||||
result += GIFS
|
result += TYPE_GIFS
|
||||||
|
|
||||||
activity.config.filterMedia = result
|
activity.config.filterMedia = result
|
||||||
callback(result)
|
callback(result)
|
||||||
|
|
|
@ -11,7 +11,6 @@ import com.simplemobiletools.commons.extensions.toast
|
||||||
import com.simplemobiletools.commons.views.MyGridLayoutManager
|
import com.simplemobiletools.commons.views.MyGridLayoutManager
|
||||||
import com.simplemobiletools.gallery.R
|
import com.simplemobiletools.gallery.R
|
||||||
import com.simplemobiletools.gallery.adapters.DirectoryAdapter
|
import com.simplemobiletools.gallery.adapters.DirectoryAdapter
|
||||||
import com.simplemobiletools.gallery.asynctasks.GetDirectoriesAsynctask
|
|
||||||
import com.simplemobiletools.gallery.extensions.addTempFolderIfNeeded
|
import com.simplemobiletools.gallery.extensions.addTempFolderIfNeeded
|
||||||
import com.simplemobiletools.gallery.extensions.config
|
import com.simplemobiletools.gallery.extensions.config
|
||||||
import com.simplemobiletools.gallery.extensions.getCachedDirectories
|
import com.simplemobiletools.gallery.extensions.getCachedDirectories
|
||||||
|
@ -40,14 +39,13 @@ class PickDirectoryDialog(val activity: BaseSimpleActivity, val sourcePath: Stri
|
||||||
activity.setupDialogStuff(view, this, R.string.select_destination)
|
activity.setupDialogStuff(view, this, R.string.select_destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
val dirs = activity.getCachedDirectories()
|
activity.getCachedDirectories {
|
||||||
if (dirs.isNotEmpty()) {
|
if (it.isNotEmpty()) {
|
||||||
gotDirectories(activity.addTempFolderIfNeeded(dirs))
|
activity.runOnUiThread {
|
||||||
}
|
|
||||||
|
|
||||||
GetDirectoriesAsynctask(activity, false, false) {
|
|
||||||
gotDirectories(activity.addTempFolderIfNeeded(it))
|
gotDirectories(activity.addTempFolderIfNeeded(it))
|
||||||
}.execute()
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showOtherFolder() {
|
private fun showOtherFolder() {
|
||||||
|
|
|
@ -36,12 +36,16 @@ class PickMediumDialog(val activity: BaseSimpleActivity, val path: String, val c
|
||||||
activity.setupDialogStuff(view, this, R.string.select_photo)
|
activity.setupDialogStuff(view, this, R.string.select_photo)
|
||||||
}
|
}
|
||||||
|
|
||||||
val media = activity.getCachedMedia(path).filter { !it.isVideo() } as ArrayList
|
activity.getCachedMedia(path) {
|
||||||
|
val media = it.filter { !it.isVideo() } as ArrayList
|
||||||
if (media.isNotEmpty()) {
|
if (media.isNotEmpty()) {
|
||||||
|
activity.runOnUiThread {
|
||||||
gotMedia(media)
|
gotMedia(media)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GetMediaAsynctask(activity, path, false, true, false) {
|
GetMediaAsynctask(activity, path, true, false, false) {
|
||||||
gotMedia(it)
|
gotMedia(it)
|
||||||
}.execute()
|
}.execute()
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,14 @@ import com.simplemobiletools.commons.dialogs.FilePickerDialog
|
||||||
import com.simplemobiletools.commons.extensions.*
|
import com.simplemobiletools.commons.extensions.*
|
||||||
import com.simplemobiletools.gallery.R
|
import com.simplemobiletools.gallery.R
|
||||||
import kotlinx.android.synthetic.main.dialog_save_as.view.*
|
import kotlinx.android.synthetic.main.dialog_save_as.view.*
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class SaveAsDialog(val activity: BaseSimpleActivity, val path: String, val appendFilename: Boolean, val callback: (savePath: String) -> Unit) {
|
class SaveAsDialog(val activity: BaseSimpleActivity, val path: String, val appendFilename: Boolean, val callback: (savePath: String) -> Unit) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
var realPath = path.getParentPath().trimEnd('/')
|
var realPath = path.getParentPath()
|
||||||
|
|
||||||
val view = activity.layoutInflater.inflate(R.layout.dialog_save_as, null).apply {
|
val view = activity.layoutInflater.inflate(R.layout.dialog_save_as, null).apply {
|
||||||
save_as_path.text = activity.humanizePath(realPath)
|
save_as_path.text = "${activity.humanizePath(realPath).trimEnd('/')}/"
|
||||||
|
|
||||||
val fullName = path.getFilenameFromPath()
|
val fullName = path.getFilenameFromPath()
|
||||||
val dotAt = fullName.lastIndexOf(".")
|
val dotAt = fullName.lastIndexOf(".")
|
||||||
|
@ -60,20 +59,21 @@ class SaveAsDialog(val activity: BaseSimpleActivity, val path: String, val appen
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
}
|
}
|
||||||
|
|
||||||
val newFile = File(realPath, "$filename.$extension")
|
val newFilename = "$filename.$extension"
|
||||||
if (!newFile.name.isAValidFilename()) {
|
val newPath = "${realPath.trimEnd('/')}/$newFilename"
|
||||||
|
if (!newFilename.isAValidFilename()) {
|
||||||
activity.toast(R.string.filename_invalid_characters)
|
activity.toast(R.string.filename_invalid_characters)
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newFile.exists()) {
|
if (activity.getDoesFilePathExist(newPath)) {
|
||||||
val title = String.format(activity.getString(R.string.file_already_exists_overwrite), newFile.name)
|
val title = String.format(activity.getString(R.string.file_already_exists_overwrite), newFilename)
|
||||||
ConfirmationDialog(activity, title) {
|
ConfirmationDialog(activity, title) {
|
||||||
callback(newFile.absolutePath)
|
callback(newPath)
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
callback(newFile.absolutePath)
|
callback(newPath)
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,6 @@ import android.content.Intent
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.support.v7.app.AppCompatActivity
|
import android.support.v7.app.AppCompatActivity
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import com.bumptech.glide.load.DecodeFormat
|
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
|
||||||
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.activities.BaseSimpleActivity
|
||||||
import com.simplemobiletools.commons.extensions.*
|
import com.simplemobiletools.commons.extensions.*
|
||||||
import com.simplemobiletools.commons.helpers.*
|
import com.simplemobiletools.commons.helpers.*
|
||||||
|
@ -23,13 +15,7 @@ import com.simplemobiletools.gallery.R
|
||||||
import com.simplemobiletools.gallery.activities.SimpleActivity
|
import com.simplemobiletools.gallery.activities.SimpleActivity
|
||||||
import com.simplemobiletools.gallery.dialogs.PickDirectoryDialog
|
import com.simplemobiletools.gallery.dialogs.PickDirectoryDialog
|
||||||
import com.simplemobiletools.gallery.helpers.NOMEDIA
|
import com.simplemobiletools.gallery.helpers.NOMEDIA
|
||||||
import com.simplemobiletools.gallery.helpers.TYPE_GIF
|
|
||||||
import com.simplemobiletools.gallery.helpers.TYPE_IMAGE
|
|
||||||
import com.simplemobiletools.gallery.helpers.TYPE_VIDEO
|
|
||||||
import com.simplemobiletools.gallery.models.Directory
|
|
||||||
import com.simplemobiletools.gallery.models.Medium
|
import com.simplemobiletools.gallery.models.Medium
|
||||||
import com.simplemobiletools.gallery.views.MySquareImageView
|
|
||||||
import pl.droidsonroids.gif.GifDrawable
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
@ -148,7 +134,7 @@ fun BaseSimpleActivity.removeNoMedia(path: String, callback: (() -> Unit)? = nul
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteFile(file.toFileDirItem(applicationContext)) {
|
tryDeleteFileDirItem(file.toFileDirItem(applicationContext)) {
|
||||||
callback?.invoke()
|
callback?.invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,36 +148,12 @@ fun BaseSimpleActivity.toggleFileVisibility(oldPath: String, hide: Boolean, call
|
||||||
filename.substring(1, filename.length)
|
filename.substring(1, filename.length)
|
||||||
}
|
}
|
||||||
|
|
||||||
val newPath = "$path$filename"
|
val newPath = "$path/$filename"
|
||||||
renameFile(oldPath, newPath) {
|
renameFile(oldPath, newPath) {
|
||||||
callback?.invoke(newPath)
|
callback?.invoke(newPath)
|
||||||
}
|
Thread {
|
||||||
}
|
updateDBMediaPath(oldPath, newPath)
|
||||||
|
}.start()
|
||||||
fun Activity.loadImage(type: Int, path: String, target: MySquareImageView, horizontalScroll: Boolean, animateGifs: Boolean, cropThumbnails: Boolean) {
|
|
||||||
target.isHorizontalScrolling = horizontalScroll
|
|
||||||
if (type == TYPE_IMAGE || type == TYPE_VIDEO) {
|
|
||||||
if (type == TYPE_IMAGE && path.isPng()) {
|
|
||||||
loadPng(path, target, cropThumbnails)
|
|
||||||
} else {
|
|
||||||
loadJpg(path, target, cropThumbnails)
|
|
||||||
}
|
|
||||||
} else if (type == TYPE_GIF) {
|
|
||||||
try {
|
|
||||||
val gifDrawable = GifDrawable(path)
|
|
||||||
target.setImageDrawable(gifDrawable)
|
|
||||||
if (animateGifs) {
|
|
||||||
gifDrawable.start()
|
|
||||||
} else {
|
|
||||||
gifDrawable.stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
target.scaleType = if (cropThumbnails) ImageView.ScaleType.CENTER_CROP else ImageView.ScaleType.FIT_CENTER
|
|
||||||
} catch (e: Exception) {
|
|
||||||
loadJpg(path, target, cropThumbnails)
|
|
||||||
} catch (e: OutOfMemoryError) {
|
|
||||||
loadJpg(path, target, cropThumbnails)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,49 +169,12 @@ fun BaseSimpleActivity.tryCopyMoveFilesTo(fileDirItems: ArrayList<FileDirItem>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun BaseSimpleActivity.addTempFolderIfNeeded(dirs: ArrayList<Directory>): ArrayList<Directory> {
|
fun BaseSimpleActivity.tryDeleteFileDirItem(fileDirItem: FileDirItem, allowDeleteFolder: Boolean = false, callback: ((wasSuccess: Boolean) -> Unit)? = null) {
|
||||||
val directories = ArrayList<Directory>()
|
deleteFile(fileDirItem, allowDeleteFolder) {
|
||||||
val tempFolderPath = config.tempFolderPath
|
callback?.invoke(it)
|
||||||
if (tempFolderPath.isNotEmpty()) {
|
|
||||||
val newFolder = Directory(tempFolderPath, "", tempFolderPath.getFilenameFromPath(), 0, 0, 0, 0L, isPathOnSD(tempFolderPath))
|
Thread {
|
||||||
directories.add(newFolder)
|
galleryDB.MediumDao().deleteMediumPath(fileDirItem.path)
|
||||||
|
}.start()
|
||||||
}
|
}
|
||||||
directories.addAll(dirs)
|
|
||||||
return directories
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Activity.loadPng(path: String, target: MySquareImageView, cropThumbnails: Boolean) {
|
|
||||||
val options = RequestOptions()
|
|
||||||
.signature(path.getFileSignature())
|
|
||||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
|
||||||
.format(DecodeFormat.PREFER_ARGB_8888)
|
|
||||||
|
|
||||||
val builder = Glide.with(applicationContext)
|
|
||||||
.asBitmap()
|
|
||||||
.load(path)
|
|
||||||
|
|
||||||
if (cropThumbnails) options.centerCrop() else options.fitCenter()
|
|
||||||
builder.apply(options).into(target)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Activity.loadJpg(path: String, target: MySquareImageView, cropThumbnails: Boolean) {
|
|
||||||
val options = RequestOptions()
|
|
||||||
.signature(path.getFileSignature())
|
|
||||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
|
||||||
|
|
||||||
val builder = Glide.with(applicationContext)
|
|
||||||
.load(path)
|
|
||||||
|
|
||||||
if (cropThumbnails) options.centerCrop() else options.fitCenter()
|
|
||||||
builder.apply(options).transition(DrawableTransitionOptions.withCrossFade()).into(target)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Activity.getCachedDirectories(): ArrayList<Directory> {
|
|
||||||
val token = object : TypeToken<List<Directory>>() {}.type
|
|
||||||
return Gson().fromJson<ArrayList<Directory>>(config.directories, token) ?: ArrayList(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Activity.getCachedMedia(path: String): ArrayList<Medium> {
|
|
||||||
val token = object : TypeToken<List<Medium>>() {}.type
|
|
||||||
return Gson().fromJson<ArrayList<Medium>>(config.loadFolderMedia(path), token) ?: ArrayList(1)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.simplemobiletools.gallery.extensions
|
||||||
|
|
||||||
|
import com.simplemobiletools.gallery.helpers.TYPE_GIFS
|
||||||
|
import com.simplemobiletools.gallery.helpers.TYPE_IMAGES
|
||||||
|
import com.simplemobiletools.gallery.helpers.TYPE_VIDEOS
|
||||||
|
import com.simplemobiletools.gallery.models.Medium
|
||||||
|
|
||||||
|
fun ArrayList<Medium>.getDirMediaTypes(): Int {
|
||||||
|
var types = 0
|
||||||
|
if (any { it.isImage() }) {
|
||||||
|
types += TYPE_IMAGES
|
||||||
|
}
|
||||||
|
|
||||||
|
if (any { it.isVideo() }) {
|
||||||
|
types += TYPE_VIDEOS
|
||||||
|
}
|
||||||
|
|
||||||
|
if (any { it.isGif() }) {
|
||||||
|
types += TYPE_GIFS
|
||||||
|
}
|
||||||
|
|
||||||
|
return types
|
||||||
|
}
|
|
@ -9,19 +9,24 @@ import android.media.AudioManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import com.google.gson.Gson
|
import android.widget.ImageView
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.load.DecodeFormat
|
||||||
|
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.extensions.*
|
||||||
import com.simplemobiletools.commons.helpers.OTG_PATH
|
import com.simplemobiletools.commons.helpers.OTG_PATH
|
||||||
import com.simplemobiletools.gallery.R
|
import com.simplemobiletools.gallery.R
|
||||||
import com.simplemobiletools.gallery.activities.SettingsActivity
|
import com.simplemobiletools.gallery.activities.SettingsActivity
|
||||||
import com.simplemobiletools.gallery.asynctasks.GetDirectoriesAsynctask
|
|
||||||
import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask
|
import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask
|
||||||
import com.simplemobiletools.gallery.helpers.Config
|
import com.simplemobiletools.gallery.databases.GalleryDataBase
|
||||||
import com.simplemobiletools.gallery.helpers.NOMEDIA
|
import com.simplemobiletools.gallery.helpers.*
|
||||||
import com.simplemobiletools.gallery.helpers.SAVE_DIRS_CNT
|
import com.simplemobiletools.gallery.interfaces.DirectoryDao
|
||||||
import com.simplemobiletools.gallery.helpers.SAVE_MEDIA_CNT
|
|
||||||
import com.simplemobiletools.gallery.models.Directory
|
import com.simplemobiletools.gallery.models.Directory
|
||||||
import com.simplemobiletools.gallery.models.Medium
|
import com.simplemobiletools.gallery.models.Medium
|
||||||
|
import com.simplemobiletools.gallery.views.MySquareImageView
|
||||||
|
import pl.droidsonroids.gif.GifDrawable
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
val Context.portrait get() = resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
|
val Context.portrait get() = resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||||
|
@ -65,17 +70,27 @@ fun Context.launchSettings() {
|
||||||
|
|
||||||
val Context.config: Config get() = Config.newInstance(applicationContext)
|
val Context.config: Config get() = Config.newInstance(applicationContext)
|
||||||
|
|
||||||
|
val Context.galleryDB: GalleryDataBase get() = GalleryDataBase.getInstance(applicationContext)
|
||||||
|
|
||||||
fun Context.movePinnedDirectoriesToFront(dirs: ArrayList<Directory>): ArrayList<Directory> {
|
fun Context.movePinnedDirectoriesToFront(dirs: ArrayList<Directory>): ArrayList<Directory> {
|
||||||
val foundFolders = ArrayList<Directory>()
|
val foundFolders = ArrayList<Directory>()
|
||||||
val pinnedFolders = config.pinnedFolders
|
val pinnedFolders = config.pinnedFolders
|
||||||
|
|
||||||
dirs.forEach {
|
dirs.forEach {
|
||||||
if (pinnedFolders.contains(it.path))
|
if (pinnedFolders.contains(it.path)) {
|
||||||
foundFolders.add(it)
|
foundFolders.add(it)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dirs.removeAll(foundFolders)
|
dirs.removeAll(foundFolders)
|
||||||
dirs.addAll(0, foundFolders)
|
dirs.addAll(0, foundFolders)
|
||||||
|
if (config.tempFolderPath.isNotEmpty()) {
|
||||||
|
val newFolder = dirs.firstOrNull { it.path == config.tempFolderPath }
|
||||||
|
if (newFolder != null) {
|
||||||
|
dirs.remove(newFolder)
|
||||||
|
dirs.add(0, newFolder)
|
||||||
|
}
|
||||||
|
}
|
||||||
return dirs
|
return dirs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +113,6 @@ fun Context.getNoMediaFolders(callback: (folders: ArrayList<String>) -> Unit) {
|
||||||
val sortOrder = "${MediaStore.Files.FileColumns.DATE_MODIFIED} DESC"
|
val sortOrder = "${MediaStore.Files.FileColumns.DATE_MODIFIED} DESC"
|
||||||
|
|
||||||
var cursor: Cursor? = null
|
var cursor: Cursor? = null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)
|
cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)
|
||||||
if (cursor?.moveToFirst() == true) {
|
if (cursor?.moveToFirst() == true) {
|
||||||
|
@ -118,50 +132,35 @@ fun Context.getNoMediaFolders(callback: (folders: ArrayList<String>) -> Unit) {
|
||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.isPathInMediaStore(path: String): Boolean {
|
fun Context.rescanFolderMedia(path: String) {
|
||||||
if (path.startsWith(OTG_PATH)) {
|
Thread {
|
||||||
return false
|
rescanFolderMediaSync(path)
|
||||||
|
}.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
val projection = arrayOf(MediaStore.Images.Media.DATE_MODIFIED)
|
fun Context.rescanFolderMediaSync(path: String) {
|
||||||
val uri = MediaStore.Files.getContentUri("external")
|
getCachedMedia(path) {
|
||||||
val selection = "${MediaStore.MediaColumns.DATA} = ?"
|
val cached = it
|
||||||
val selectionArgs = arrayOf(path)
|
GetMediaAsynctask(applicationContext, path, false, false, false) {
|
||||||
val cursor = contentResolver.query(uri, projection, selection, selectionArgs, null)
|
Thread {
|
||||||
|
val newMedia = it
|
||||||
|
val mediumDao = galleryDB.MediumDao()
|
||||||
|
mediumDao.insertAll(newMedia)
|
||||||
|
|
||||||
cursor?.use {
|
cached.forEach {
|
||||||
return cursor.moveToFirst()
|
if (!newMedia.contains(it)) {
|
||||||
|
mediumDao.deleteMediumPath(it.path)
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
}.start()
|
||||||
fun Context.updateStoredFolderItems(path: String) {
|
|
||||||
GetMediaAsynctask(this, path, false, false, false) {
|
|
||||||
storeFolderItems(path, it)
|
|
||||||
}.execute()
|
}.execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.storeFolderItems(path: String, items: ArrayList<Medium>) {
|
|
||||||
try {
|
|
||||||
val subList = items.subList(0, Math.min(SAVE_MEDIA_CNT, items.size))
|
|
||||||
val json = Gson().toJson(subList)
|
|
||||||
config.saveFolderMedia(path, json)
|
|
||||||
} catch (ignored: Exception) {
|
|
||||||
} catch (ignored: OutOfMemoryError) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Context.updateStoredDirectories() {
|
|
||||||
GetDirectoriesAsynctask(this, false, false) {
|
|
||||||
if (!config.temporarilyShowHidden) {
|
|
||||||
storeDirectoryItems(it)
|
|
||||||
}
|
|
||||||
}.execute()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.storeDirectoryItems(items: ArrayList<Directory>) {
|
fun Context.storeDirectoryItems(items: ArrayList<Directory>) {
|
||||||
val subList = items.subList(0, Math.min(SAVE_DIRS_CNT, items.size))
|
Thread {
|
||||||
config.directories = Gson().toJson(subList)
|
galleryDB.DirectoryDao().insertAll(items)
|
||||||
|
}.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.checkAppendingHidden(path: String, hidden: String, includedFolders: MutableSet<String>): String {
|
fun Context.checkAppendingHidden(path: String, hidden: String, includedFolders: MutableSet<String>): String {
|
||||||
|
@ -184,3 +183,150 @@ fun Context.checkAppendingHidden(path: String, hidden: String, includedFolders:
|
||||||
dirName
|
dirName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Context.loadImage(type: Int, path: String, target: MySquareImageView, horizontalScroll: Boolean, animateGifs: Boolean, cropThumbnails: Boolean) {
|
||||||
|
target.isHorizontalScrolling = horizontalScroll
|
||||||
|
if (type == TYPE_IMAGES || type == TYPE_VIDEOS) {
|
||||||
|
if (type == TYPE_IMAGES && path.isPng()) {
|
||||||
|
loadPng(path, target, cropThumbnails)
|
||||||
|
} else {
|
||||||
|
loadJpg(path, target, cropThumbnails)
|
||||||
|
}
|
||||||
|
} else if (type == TYPE_GIFS) {
|
||||||
|
try {
|
||||||
|
val gifDrawable = GifDrawable(path)
|
||||||
|
target.setImageDrawable(gifDrawable)
|
||||||
|
if (animateGifs) {
|
||||||
|
gifDrawable.start()
|
||||||
|
} else {
|
||||||
|
gifDrawable.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
target.scaleType = if (cropThumbnails) ImageView.ScaleType.CENTER_CROP else ImageView.ScaleType.FIT_CENTER
|
||||||
|
} catch (e: Exception) {
|
||||||
|
loadJpg(path, target, cropThumbnails)
|
||||||
|
} catch (e: OutOfMemoryError) {
|
||||||
|
loadJpg(path, target, cropThumbnails)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.addTempFolderIfNeeded(dirs: ArrayList<Directory>): ArrayList<Directory> {
|
||||||
|
val directories = ArrayList<Directory>()
|
||||||
|
val tempFolderPath = config.tempFolderPath
|
||||||
|
if (tempFolderPath.isNotEmpty()) {
|
||||||
|
val newFolder = Directory(null, tempFolderPath, "", tempFolderPath.getFilenameFromPath(), 0, 0, 0, 0L, getPathLocation(tempFolderPath), 0)
|
||||||
|
directories.add(newFolder)
|
||||||
|
}
|
||||||
|
directories.addAll(dirs)
|
||||||
|
return directories
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.getPathLocation(path: String): Int {
|
||||||
|
return when {
|
||||||
|
isPathOnSD(path) -> LOCATION_SD
|
||||||
|
path.startsWith(OTG_PATH) -> LOCATION_OTG
|
||||||
|
else -> LOCAITON_INTERNAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.loadPng(path: String, target: MySquareImageView, cropThumbnails: Boolean) {
|
||||||
|
val options = RequestOptions()
|
||||||
|
.signature(path.getFileSignature())
|
||||||
|
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||||
|
.format(DecodeFormat.PREFER_ARGB_8888)
|
||||||
|
|
||||||
|
val builder = Glide.with(applicationContext)
|
||||||
|
.asBitmap()
|
||||||
|
.load(path)
|
||||||
|
|
||||||
|
if (cropThumbnails) options.centerCrop() else options.fitCenter()
|
||||||
|
builder.apply(options).into(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.loadJpg(path: String, target: MySquareImageView, cropThumbnails: Boolean) {
|
||||||
|
val options = RequestOptions()
|
||||||
|
.signature(path.getFileSignature())
|
||||||
|
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||||
|
|
||||||
|
val builder = Glide.with(applicationContext)
|
||||||
|
.load(path)
|
||||||
|
|
||||||
|
if (cropThumbnails) options.centerCrop() else options.fitCenter()
|
||||||
|
builder.apply(options).transition(DrawableTransitionOptions.withCrossFade()).into(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.getCachedDirectories(getVideosOnly: Boolean = false, getImagesOnly: Boolean = false, callback: (ArrayList<Directory>) -> Unit) {
|
||||||
|
Thread {
|
||||||
|
val directoryDao = galleryDB.DirectoryDao()
|
||||||
|
val directories = directoryDao.getAll() as ArrayList<Directory>
|
||||||
|
val shouldShowHidden = config.shouldShowHidden
|
||||||
|
val excludedPaths = config.excludedFolders
|
||||||
|
val includedPaths = config.includedFolders
|
||||||
|
var filteredDirectories = directories.filter { it.path.shouldFolderBeVisible(excludedPaths, includedPaths, shouldShowHidden) } as ArrayList<Directory>
|
||||||
|
val filterMedia = config.filterMedia
|
||||||
|
|
||||||
|
filteredDirectories = (when {
|
||||||
|
getVideosOnly -> filteredDirectories.filter { it.types and TYPE_VIDEOS != 0 }
|
||||||
|
getImagesOnly -> filteredDirectories.filter { it.types and TYPE_IMAGES != 0 }
|
||||||
|
else -> filteredDirectories.filter {
|
||||||
|
(filterMedia and TYPE_IMAGES != 0 && it.types and TYPE_IMAGES != 0) ||
|
||||||
|
(filterMedia and TYPE_VIDEOS != 0 && it.types and TYPE_VIDEOS != 0) ||
|
||||||
|
(filterMedia and TYPE_GIFS != 0 && it.types and TYPE_GIFS != 0)
|
||||||
|
}
|
||||||
|
}) as ArrayList<Directory>
|
||||||
|
|
||||||
|
callback(filteredDirectories.distinctBy { it.path.toLowerCase() } as ArrayList<Directory>)
|
||||||
|
|
||||||
|
removeInvalidDBDirectories(directories, 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 shouldShowHidden = config.shouldShowHidden
|
||||||
|
var filteredMedia = media
|
||||||
|
if (!shouldShowHidden) {
|
||||||
|
filteredMedia = media.filter { !it.name.startsWith('.') } 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 {
|
||||||
|
(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)
|
||||||
|
media.filter { !getDoesFilePathExist(it.path) }.forEach {
|
||||||
|
mediumDao.deleteMediumPath(it.path)
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.removeInvalidDBDirectories(dirs: ArrayList<Directory>? = null, directoryDao: DirectoryDao = galleryDB.DirectoryDao()) {
|
||||||
|
val dirsToCheck = dirs ?: directoryDao.getAll()
|
||||||
|
dirsToCheck.filter { !getDoesFilePathExist(it.path) && it.path != config.tempFolderPath }.forEach {
|
||||||
|
directoryDao.deleteDirPath(it.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.updateDBMediaPath(oldPath: String, newPath: String) {
|
||||||
|
val newFilename = newPath.getFilenameFromPath()
|
||||||
|
val newParentPath = newPath.getParentPath()
|
||||||
|
galleryDB.MediumDao().updateMedium(oldPath, newParentPath, newFilename, newPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.updateDBDirectory(directory: Directory) {
|
||||||
|
galleryDB.DirectoryDao().updateDirectory(directory.path, directory.tmb, directory.mediaCnt, directory.modified, directory.taken, directory.size, directory.types)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.getOTGFolderChildren(path: String) = getDocumentFile(path)?.listFiles()
|
||||||
|
|
||||||
|
fun Context.getOTGFolderChildrenNames(path: String) = getOTGFolderChildren(path)?.map { it.name }?.toList()
|
||||||
|
|
|
@ -5,9 +5,30 @@ import java.io.File
|
||||||
|
|
||||||
fun String.getFileSignature(): ObjectKey {
|
fun String.getFileSignature(): ObjectKey {
|
||||||
val file = File(this)
|
val file = File(this)
|
||||||
return ObjectKey("${file.name}${file.lastModified()}")
|
return ObjectKey("${file.absolutePath}${file.lastModified()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.isThisOrParentIncluded(includedPaths: MutableSet<String>) = includedPaths.any { startsWith(it, true) }
|
fun String.isThisOrParentIncluded(includedPaths: MutableSet<String>) = includedPaths.any { startsWith(it, true) }
|
||||||
|
|
||||||
fun String.isThisOrParentExcluded(excludedPaths: MutableSet<String>) = excludedPaths.any { startsWith(it, true) }
|
fun String.isThisOrParentExcluded(excludedPaths: MutableSet<String>) = excludedPaths.any { startsWith(it, true) }
|
||||||
|
|
||||||
|
fun String.shouldFolderBeVisible(excludedPaths: MutableSet<String>, includedPaths: MutableSet<String>, showHidden: Boolean): Boolean {
|
||||||
|
val file = File(this)
|
||||||
|
return if (isEmpty()) {
|
||||||
|
false
|
||||||
|
} else if (!showHidden && file.containsNoMedia()) {
|
||||||
|
false
|
||||||
|
} else if (isThisOrParentIncluded(includedPaths)) {
|
||||||
|
true
|
||||||
|
} else if (isThisOrParentExcluded(excludedPaths)) {
|
||||||
|
false
|
||||||
|
} else if (!showHidden && file.isDirectory && file.canonicalFile == file.absoluteFile) {
|
||||||
|
var containsNoMediaOrDot = file.containsNoMedia() || contains("/.")
|
||||||
|
if (!containsNoMediaOrDot) {
|
||||||
|
containsNoMediaOrDot = file.doesThisOrParentHaveNoMedia()
|
||||||
|
}
|
||||||
|
!containsNoMediaOrDot
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -275,7 +275,7 @@ class PhotoFragment : ViewPagerFragment() {
|
||||||
} else {
|
} else {
|
||||||
val options = RequestOptions()
|
val options = RequestOptions()
|
||||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
.transform(GlideRotateTransformation(context!!, degrees))
|
.transform(GlideRotateTransformation(degrees))
|
||||||
|
|
||||||
Glide.with(this)
|
Glide.with(this)
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
|
|
|
@ -6,6 +6,7 @@ import com.google.gson.Gson
|
||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
import com.simplemobiletools.commons.helpers.BaseConfig
|
import com.simplemobiletools.commons.helpers.BaseConfig
|
||||||
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_MODIFIED
|
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.commons.helpers.SORT_DESCENDING
|
||||||
import com.simplemobiletools.gallery.R
|
import com.simplemobiletools.gallery.R
|
||||||
import com.simplemobiletools.gallery.models.AlbumCover
|
import com.simplemobiletools.gallery.models.AlbumCover
|
||||||
|
@ -17,7 +18,13 @@ class Config(context: Context) : BaseConfig(context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var directorySorting: Int
|
var directorySorting: Int
|
||||||
get() = prefs.getInt(DIRECTORY_SORT_ORDER, SORT_BY_DATE_MODIFIED or SORT_DESCENDING)
|
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
|
||||||
|
}
|
||||||
set(order) = prefs.edit().putInt(DIRECTORY_SORT_ORDER, order).apply()
|
set(order) = prefs.edit().putInt(DIRECTORY_SORT_ORDER, order).apply()
|
||||||
|
|
||||||
fun saveFileSorting(path: String, value: Int) {
|
fun saveFileSorting(path: String, value: Int) {
|
||||||
|
@ -28,7 +35,13 @@ class Config(context: Context) : BaseConfig(context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFileSorting(path: String) = prefs.getInt(SORT_FOLDER_PREFIX + path.toLowerCase(), sorting)
|
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 removeFileSorting(path: String) {
|
fun removeFileSorting(path: String) {
|
||||||
prefs.edit().remove(SORT_FOLDER_PREFIX + path.toLowerCase()).apply()
|
prefs.edit().remove(SORT_FOLDER_PREFIX + path.toLowerCase()).apply()
|
||||||
|
@ -118,18 +131,6 @@ class Config(context: Context) : BaseConfig(context) {
|
||||||
get() = prefs.getStringSet(INCLUDED_FOLDERS, HashSet<String>())
|
get() = prefs.getStringSet(INCLUDED_FOLDERS, HashSet<String>())
|
||||||
set(includedFolders) = prefs.edit().remove(INCLUDED_FOLDERS).putStringSet(INCLUDED_FOLDERS, includedFolders).apply()
|
set(includedFolders) = prefs.edit().remove(INCLUDED_FOLDERS).putStringSet(INCLUDED_FOLDERS, includedFolders).apply()
|
||||||
|
|
||||||
fun saveFolderMedia(path: String, json: String) {
|
|
||||||
prefs.edit().putString(SAVE_FOLDER_PREFIX + path, json).apply()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadFolderMedia(path: String) = prefs.getString(SAVE_FOLDER_PREFIX + path, "")
|
|
||||||
|
|
||||||
fun saveFolderMediaShort(path: String, value: String) {
|
|
||||||
prefs.edit().putString(SAVE_FOLDER_SHORT_PREFIX + path, value).apply()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadFolderMediaShort(path: String) = prefs.getString(SAVE_FOLDER_SHORT_PREFIX + path, "")
|
|
||||||
|
|
||||||
var autoplayVideos: Boolean
|
var autoplayVideos: Boolean
|
||||||
get() = prefs.getBoolean(AUTOPLAY_VIDEOS, false)
|
get() = prefs.getBoolean(AUTOPLAY_VIDEOS, false)
|
||||||
set(autoplay) = prefs.edit().putBoolean(AUTOPLAY_VIDEOS, autoplay).apply()
|
set(autoplay) = prefs.edit().putBoolean(AUTOPLAY_VIDEOS, autoplay).apply()
|
||||||
|
@ -163,7 +164,7 @@ class Config(context: Context) : BaseConfig(context) {
|
||||||
set(darkBackground) = prefs.edit().putBoolean(DARK_BACKGROUND, darkBackground).apply()
|
set(darkBackground) = prefs.edit().putBoolean(DARK_BACKGROUND, darkBackground).apply()
|
||||||
|
|
||||||
var filterMedia: Int
|
var filterMedia: Int
|
||||||
get() = prefs.getInt(FILTER_MEDIA, IMAGES or VIDEOS or GIFS)
|
get() = prefs.getInt(FILTER_MEDIA, TYPE_IMAGES or TYPE_VIDEOS or TYPE_GIFS)
|
||||||
set(filterMedia) = prefs.edit().putInt(FILTER_MEDIA, filterMedia).apply()
|
set(filterMedia) = prefs.edit().putInt(FILTER_MEDIA, filterMedia).apply()
|
||||||
|
|
||||||
var dirColumnCnt: Int
|
var dirColumnCnt: Int
|
||||||
|
@ -226,10 +227,6 @@ class Config(context: Context) : BaseConfig(context) {
|
||||||
private fun getDefaultMediaColumnCount() = context.resources.getInteger(if (scrollHorizontally) R.integer.media_columns_horizontal_scroll
|
private fun getDefaultMediaColumnCount() = context.resources.getInteger(if (scrollHorizontally) R.integer.media_columns_horizontal_scroll
|
||||||
else R.integer.media_columns_vertical_scroll)
|
else R.integer.media_columns_vertical_scroll)
|
||||||
|
|
||||||
var directories: String
|
|
||||||
get() = prefs.getString(DIRECTORIES, "")
|
|
||||||
set(directories) = prefs.edit().putString(DIRECTORIES, directories).apply()
|
|
||||||
|
|
||||||
var albumCovers: String
|
var albumCovers: String
|
||||||
get() = prefs.getString(ALBUM_COVERS, "")
|
get() = prefs.getString(ALBUM_COVERS, "")
|
||||||
set(albumCovers) = prefs.edit().putString(ALBUM_COVERS, albumCovers).apply()
|
set(albumCovers) = prefs.edit().putString(ALBUM_COVERS, albumCovers).apply()
|
||||||
|
@ -328,6 +325,10 @@ class Config(context: Context) : BaseConfig(context) {
|
||||||
set(wasNewAppShown) = prefs.edit().putBoolean(WAS_NEW_APP_SHOWN, wasNewAppShown).apply()
|
set(wasNewAppShown) = prefs.edit().putBoolean(WAS_NEW_APP_SHOWN, wasNewAppShown).apply()
|
||||||
|
|
||||||
var lastFilepickerPath: String
|
var lastFilepickerPath: String
|
||||||
get() = prefs.getString(TEMP_FOLDER_PATH, "")
|
get() = prefs.getString(LAST_FILEPICKER_PATH, "")
|
||||||
set(tempFolderPath) = prefs.edit().putString(TEMP_FOLDER_PATH, tempFolderPath).apply()
|
set(lastFilepickerPath) = prefs.edit().putString(LAST_FILEPICKER_PATH, lastFilepickerPath).apply()
|
||||||
|
|
||||||
|
var wasOTGHandled: Boolean
|
||||||
|
get() = prefs.getBoolean(WAS_OTG_HANDLED, false)
|
||||||
|
set(wasOTGHandled) = prefs.edit().putBoolean(WAS_OTG_HANDLED, wasOTGHandled).apply()
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,6 @@ const val MEDIA_LANDSCAPE_COLUMN_CNT = "media_landscape_column_cnt"
|
||||||
const val MEDIA_HORIZONTAL_COLUMN_CNT = "media_horizontal_column_cnt"
|
const val MEDIA_HORIZONTAL_COLUMN_CNT = "media_horizontal_column_cnt"
|
||||||
const val MEDIA_LANDSCAPE_HORIZONTAL_COLUMN_CNT = "media_landscape_horizontal_column_cnt"
|
const val MEDIA_LANDSCAPE_HORIZONTAL_COLUMN_CNT = "media_landscape_horizontal_column_cnt"
|
||||||
const val SHOW_ALL = "show_all" // display images and videos from all folders together
|
const val SHOW_ALL = "show_all" // display images and videos from all folders together
|
||||||
const val SAVE_FOLDER_PREFIX = "folder2_"
|
|
||||||
const val SAVE_FOLDER_SHORT_PREFIX = "folder_short_"
|
|
||||||
const val HIDE_FOLDER_TOOLTIP_SHOWN = "hide_folder_tooltip_shown"
|
const val HIDE_FOLDER_TOOLTIP_SHOWN = "hide_folder_tooltip_shown"
|
||||||
const val EXCLUDED_FOLDERS = "excluded_folders"
|
const val EXCLUDED_FOLDERS = "excluded_folders"
|
||||||
const val INCLUDED_FOLDERS = "included_folders"
|
const val INCLUDED_FOLDERS = "included_folders"
|
||||||
|
@ -49,6 +47,7 @@ const val REPLACE_ZOOMABLE_IMAGES = "replace_zoomable_images"
|
||||||
const val DO_EXTRA_CHECK = "do_extra_check"
|
const val DO_EXTRA_CHECK = "do_extra_check"
|
||||||
const val WAS_NEW_APP_SHOWN = "was_new_app_shown_clock"
|
const val WAS_NEW_APP_SHOWN = "was_new_app_shown_clock"
|
||||||
const val LAST_FILEPICKER_PATH = "last_filepicker_path"
|
const val LAST_FILEPICKER_PATH = "last_filepicker_path"
|
||||||
|
const val WAS_OTG_HANDLED = "was_otg_handled"
|
||||||
|
|
||||||
// slideshow
|
// slideshow
|
||||||
const val SLIDESHOW_INTERVAL = "slideshow_interval"
|
const val SLIDESHOW_INTERVAL = "slideshow_interval"
|
||||||
|
@ -67,8 +66,6 @@ const val MAX_COLUMN_COUNT = 20
|
||||||
const val SHOW_TEMP_HIDDEN_DURATION = 600000L
|
const val SHOW_TEMP_HIDDEN_DURATION = 600000L
|
||||||
const val CLICK_MAX_DURATION = 150
|
const val CLICK_MAX_DURATION = 150
|
||||||
const val DRAG_THRESHOLD = 8
|
const val DRAG_THRESHOLD = 8
|
||||||
const val SAVE_DIRS_CNT = 60
|
|
||||||
const val SAVE_MEDIA_CNT = 80
|
|
||||||
|
|
||||||
const val DIRECTORY = "directory"
|
const val DIRECTORY = "directory"
|
||||||
const val MEDIUM = "medium"
|
const val MEDIUM = "medium"
|
||||||
|
@ -77,7 +74,6 @@ const val GET_IMAGE_INTENT = "get_image_intent"
|
||||||
const val GET_VIDEO_INTENT = "get_video_intent"
|
const val GET_VIDEO_INTENT = "get_video_intent"
|
||||||
const val GET_ANY_INTENT = "get_any_intent"
|
const val GET_ANY_INTENT = "get_any_intent"
|
||||||
const val SET_WALLPAPER_INTENT = "set_wallpaper_intent"
|
const val SET_WALLPAPER_INTENT = "set_wallpaper_intent"
|
||||||
const val DIRECTORIES = "directories2"
|
|
||||||
const val IS_VIEW_INTENT = "is_view_intent"
|
const val IS_VIEW_INTENT = "is_view_intent"
|
||||||
const val PICKED_PATHS = "picked_paths"
|
const val PICKED_PATHS = "picked_paths"
|
||||||
|
|
||||||
|
@ -86,11 +82,6 @@ const val ROTATE_BY_SYSTEM_SETTING = 0
|
||||||
const val ROTATE_BY_DEVICE_ROTATION = 1
|
const val ROTATE_BY_DEVICE_ROTATION = 1
|
||||||
const val ROTATE_BY_ASPECT_RATIO = 2
|
const val ROTATE_BY_ASPECT_RATIO = 2
|
||||||
|
|
||||||
// filter media
|
|
||||||
const val IMAGES = 1
|
|
||||||
const val VIDEOS = 2
|
|
||||||
const val GIFS = 4
|
|
||||||
|
|
||||||
// view types
|
// view types
|
||||||
const val VIEW_TYPE_GRID = 1
|
const val VIEW_TYPE_GRID = 1
|
||||||
const val VIEW_TYPE_LIST = 2
|
const val VIEW_TYPE_LIST = 2
|
||||||
|
@ -109,6 +100,10 @@ const val EXT_ARTIST = 512
|
||||||
const val EXT_ALBUM = 1024
|
const val EXT_ALBUM = 1024
|
||||||
|
|
||||||
// media types
|
// media types
|
||||||
const val TYPE_IMAGE = 1
|
const val TYPE_IMAGES = 1
|
||||||
const val TYPE_VIDEO = 2
|
const val TYPE_VIDEOS = 2
|
||||||
const val TYPE_GIF = 3
|
const val TYPE_GIFS = 4
|
||||||
|
|
||||||
|
const val LOCAITON_INTERNAL = 1
|
||||||
|
const val LOCATION_SD = 2
|
||||||
|
const val LOCATION_OTG = 3
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
package com.simplemobiletools.gallery.helpers
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.graphics.Canvas
|
|
||||||
import android.graphics.drawable.BitmapDrawable
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.media.ExifInterface
|
|
||||||
import android.net.Uri
|
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
|
||||||
import com.bumptech.glide.request.RequestOptions
|
|
||||||
import com.bumptech.glide.request.target.Target
|
|
||||||
import com.davemorrissey.labs.subscaleview.decoder.ImageDecoder
|
|
||||||
import com.simplemobiletools.gallery.activities.ViewPagerActivity
|
|
||||||
import com.simplemobiletools.gallery.extensions.getFileSignature
|
|
||||||
|
|
||||||
class GlideDecoder : ImageDecoder {
|
|
||||||
override fun decode(context: Context, uri: Uri): Bitmap {
|
|
||||||
val exif = android.media.ExifInterface(uri.path)
|
|
||||||
val orientation = exif.getAttributeInt(android.media.ExifInterface.TAG_ORIENTATION, android.media.ExifInterface.ORIENTATION_NORMAL)
|
|
||||||
|
|
||||||
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)
|
|
||||||
.override(targetWidth, targetHeight)
|
|
||||||
|
|
||||||
val degrees = getRotationDegrees(orientation)
|
|
||||||
if (degrees != 0) {
|
|
||||||
options.transform(GlideRotateTransformation(context, getRotationDegrees(orientation)))
|
|
||||||
}
|
|
||||||
|
|
||||||
val drawable = Glide.with(context)
|
|
||||||
.load(uri)
|
|
||||||
.apply(options)
|
|
||||||
.submit()
|
|
||||||
.get()
|
|
||||||
|
|
||||||
return drawableToBitmap(drawable)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun drawableToBitmap(drawable: Drawable): Bitmap {
|
|
||||||
if (drawable is BitmapDrawable && drawable.bitmap != null) {
|
|
||||||
return drawable.bitmap
|
|
||||||
}
|
|
||||||
|
|
||||||
val bitmap = if (drawable.intrinsicWidth <= 0 || drawable.intrinsicHeight <= 0) {
|
|
||||||
Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
|
|
||||||
} else {
|
|
||||||
Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
|
|
||||||
}
|
|
||||||
|
|
||||||
val canvas = Canvas(bitmap)
|
|
||||||
drawable.setBounds(0, 0, canvas.width, canvas.height)
|
|
||||||
drawable.draw(canvas)
|
|
||||||
return bitmap
|
|
||||||
}
|
|
||||||
|
|
||||||
// rotating backwards intentionally, as SubsamplingScaleImageView will rotate it properly at displaying
|
|
||||||
private fun getRotationDegrees(orientation: Int) = when (orientation) {
|
|
||||||
ExifInterface.ORIENTATION_ROTATE_270 -> 90
|
|
||||||
ExifInterface.ORIENTATION_ROTATE_180 -> 180
|
|
||||||
ExifInterface.ORIENTATION_ROTATE_90 -> 270
|
|
||||||
else -> 0
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +1,12 @@
|
||||||
package com.simplemobiletools.gallery.helpers
|
package com.simplemobiletools.gallery.helpers
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.Matrix
|
import android.graphics.Matrix
|
||||||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
|
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
|
||||||
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
|
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
|
|
||||||
class GlideRotateTransformation(context: Context, val rotateRotationAngle: Int) : BitmapTransformation(context) {
|
class GlideRotateTransformation(val rotateRotationAngle: Int) : BitmapTransformation() {
|
||||||
override fun transform(pool: BitmapPool, bitmap: Bitmap, outWidth: Int, outHeight: Int): Bitmap {
|
override fun transform(pool: BitmapPool, bitmap: Bitmap, outWidth: Int, outHeight: Int): Bitmap {
|
||||||
if (rotateRotationAngle % 360 == 0)
|
if (rotateRotationAngle % 360 == 0)
|
||||||
return bitmap
|
return bitmap
|
||||||
|
|
|
@ -8,47 +8,50 @@ import com.simplemobiletools.commons.extensions.*
|
||||||
import com.simplemobiletools.commons.helpers.OTG_PATH
|
import com.simplemobiletools.commons.helpers.OTG_PATH
|
||||||
import com.simplemobiletools.commons.helpers.photoExtensions
|
import com.simplemobiletools.commons.helpers.photoExtensions
|
||||||
import com.simplemobiletools.commons.helpers.videoExtensions
|
import com.simplemobiletools.commons.helpers.videoExtensions
|
||||||
import com.simplemobiletools.gallery.extensions.*
|
import com.simplemobiletools.gallery.extensions.config
|
||||||
|
import com.simplemobiletools.gallery.extensions.getOTGFolderChildren
|
||||||
|
import com.simplemobiletools.gallery.extensions.shouldFolderBeVisible
|
||||||
import com.simplemobiletools.gallery.models.Medium
|
import com.simplemobiletools.gallery.models.Medium
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.LinkedHashMap
|
|
||||||
import kotlin.collections.ArrayList
|
|
||||||
import kotlin.collections.HashSet
|
|
||||||
import kotlin.collections.set
|
|
||||||
|
|
||||||
class MediaFetcher(val context: Context) {
|
class MediaFetcher(val context: Context) {
|
||||||
var shouldStop = false
|
var shouldStop = false
|
||||||
|
|
||||||
fun getMediaByDirectories(isPickVideo: Boolean, isPickImage: Boolean): HashMap<String, ArrayList<Medium>> {
|
|
||||||
val media = getFilesFrom("", isPickImage, isPickVideo)
|
|
||||||
return groupDirectories(media)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getFilesFrom(curPath: String, isPickImage: Boolean, isPickVideo: Boolean): ArrayList<Medium> {
|
fun getFilesFrom(curPath: String, isPickImage: Boolean, isPickVideo: Boolean): ArrayList<Medium> {
|
||||||
val filterMedia = context.config.filterMedia
|
val filterMedia = context.config.filterMedia
|
||||||
if (filterMedia == 0) {
|
if (filterMedia == 0) {
|
||||||
return ArrayList()
|
return ArrayList()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curPath.startsWith(OTG_PATH)) {
|
|
||||||
val curMedia = ArrayList<Medium>()
|
val curMedia = ArrayList<Medium>()
|
||||||
getMediaOnOTG(curPath, curMedia, isPickImage, isPickVideo, filterMedia)
|
if (curPath.startsWith(OTG_PATH)) {
|
||||||
return curMedia
|
val newMedia = getMediaOnOTG(curPath, isPickImage, isPickVideo, filterMedia)
|
||||||
|
curMedia.addAll(newMedia)
|
||||||
} else {
|
} else {
|
||||||
|
val newMedia = fetchFolderContent(curPath, isPickImage, isPickVideo, filterMedia)
|
||||||
|
curMedia.addAll(newMedia)
|
||||||
|
}
|
||||||
|
|
||||||
|
Medium.sorting = context.config.getFileSorting(curPath)
|
||||||
|
curMedia.sort()
|
||||||
|
return curMedia
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFoldersToScan(path: String): ArrayList<String> {
|
||||||
|
val filterMedia = context.config.filterMedia
|
||||||
val projection = arrayOf(MediaStore.Images.Media.DATA)
|
val projection = arrayOf(MediaStore.Images.Media.DATA)
|
||||||
val uri = MediaStore.Files.getContentUri("external")
|
val uri = MediaStore.Files.getContentUri("external")
|
||||||
|
|
||||||
val selection = "${getSelectionQuery(curPath, filterMedia)} ${MediaStore.Images.ImageColumns.BUCKET_ID} IS NOT NULL) GROUP BY (${MediaStore.Images.ImageColumns.BUCKET_ID}"
|
val selection = "${getSelectionQuery(path, filterMedia)} ${MediaStore.Images.ImageColumns.BUCKET_ID} IS NOT NULL) GROUP BY (${MediaStore.Images.ImageColumns.BUCKET_ID}"
|
||||||
val selectionArgs = getSelectionArgsQuery(curPath, filterMedia).toTypedArray()
|
val selectionArgs = getSelectionArgsQuery(path, filterMedia).toTypedArray()
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
val cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
val cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||||
parseCursor(context, cursor, isPickImage, isPickVideo, curPath, filterMedia)
|
parseCursor(cursor, path)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
ArrayList()
|
ArrayList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSelectionQuery(path: String, filterMedia: Int): String {
|
private fun getSelectionQuery(path: String, filterMedia: Int): String {
|
||||||
val query = StringBuilder()
|
val query = StringBuilder()
|
||||||
|
@ -57,19 +60,19 @@ class MediaFetcher(val context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
query.append("(")
|
query.append("(")
|
||||||
if (filterMedia and IMAGES != 0) {
|
if (filterMedia and TYPE_IMAGES != 0) {
|
||||||
photoExtensions.forEach {
|
photoExtensions.forEach {
|
||||||
query.append("${MediaStore.Images.Media.DATA} LIKE ? OR ")
|
query.append("${MediaStore.Images.Media.DATA} LIKE ? OR ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filterMedia and VIDEOS != 0) {
|
if (filterMedia and TYPE_VIDEOS != 0) {
|
||||||
videoExtensions.forEach {
|
videoExtensions.forEach {
|
||||||
query.append("${MediaStore.Images.Media.DATA} LIKE ? OR ")
|
query.append("${MediaStore.Images.Media.DATA} LIKE ? OR ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filterMedia and GIFS != 0) {
|
if (filterMedia and TYPE_GIFS != 0) {
|
||||||
query.append("${MediaStore.Images.Media.DATA} LIKE ?")
|
query.append("${MediaStore.Images.Media.DATA} LIKE ?")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,29 +88,29 @@ class MediaFetcher(val context: Context) {
|
||||||
args.add("$path/%/%")
|
args.add("$path/%/%")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filterMedia and IMAGES != 0) {
|
if (filterMedia and TYPE_IMAGES != 0) {
|
||||||
photoExtensions.forEach {
|
photoExtensions.forEach {
|
||||||
args.add("%$it")
|
args.add("%$it")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filterMedia and VIDEOS != 0) {
|
if (filterMedia and TYPE_VIDEOS != 0) {
|
||||||
videoExtensions.forEach {
|
videoExtensions.forEach {
|
||||||
args.add("%$it")
|
args.add("%$it")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filterMedia and GIFS != 0) {
|
if (filterMedia and TYPE_GIFS != 0) {
|
||||||
args.add("%.gif")
|
args.add("%.gif")
|
||||||
}
|
}
|
||||||
|
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseCursor(context: Context, cursor: Cursor, isPickImage: Boolean, isPickVideo: Boolean, curPath: String, filterMedia: Int): ArrayList<Medium> {
|
private fun parseCursor(cursor: Cursor, curPath: String): ArrayList<String> {
|
||||||
val config = context.config
|
val config = context.config
|
||||||
val includedFolders = config.includedFolders
|
val includedFolders = config.includedFolders
|
||||||
val foldersToScan = HashSet<String>()
|
var foldersToScan = ArrayList<String>()
|
||||||
|
|
||||||
cursor.use {
|
cursor.use {
|
||||||
if (cursor.moveToFirst()) {
|
if (cursor.moveToFirst()) {
|
||||||
|
@ -129,25 +132,27 @@ class MediaFetcher(val context: Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val curMedia = ArrayList<Medium>()
|
|
||||||
val showHidden = config.shouldShowHidden
|
val showHidden = config.shouldShowHidden
|
||||||
val excludedFolders = config.excludedFolders
|
val excludedFolders = config.excludedFolders
|
||||||
foldersToScan.filter { shouldFolderBeVisible(it, excludedFolders, includedFolders, showHidden) }.toList().forEach {
|
foldersToScan = foldersToScan.filter { it.shouldFolderBeVisible(excludedFolders, includedFolders, showHidden) } as ArrayList<String>
|
||||||
fetchFolderContent(it, curMedia, isPickImage, isPickVideo, filterMedia)
|
if (config.isThirdPartyIntent && curPath.isNotEmpty()) {
|
||||||
|
foldersToScan.add(curPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.isThirdPartyIntent && curPath.isNotEmpty() && curMedia.isEmpty()) {
|
return foldersToScan.distinctBy { it.toLowerCase() } as ArrayList<String>
|
||||||
getMediaInFolder(curPath, curMedia, isPickImage, isPickVideo, filterMedia)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Medium.sorting = config.getFileSorting(curPath)
|
private fun addFolder(curFolders: ArrayList<String>, folder: String) {
|
||||||
curMedia.sort()
|
|
||||||
|
|
||||||
return curMedia
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addFolder(curFolders: HashSet<String>, folder: String) {
|
|
||||||
curFolders.add(folder)
|
curFolders.add(folder)
|
||||||
|
if (folder.startsWith(OTG_PATH)) {
|
||||||
|
val files = context.getOTGFolderChildren(folder) ?: return
|
||||||
|
for (file in files) {
|
||||||
|
if (file.isDirectory) {
|
||||||
|
val relativePath = file.uri.path.substringAfterLast("${context.config.OTGPartition}:")
|
||||||
|
addFolder(curFolders, "$OTG_PATH$relativePath")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
val files = File(folder).listFiles() ?: return
|
val files = File(folder).listFiles() ?: return
|
||||||
for (file in files) {
|
for (file in files) {
|
||||||
if (file.isDirectory) {
|
if (file.isDirectory) {
|
||||||
|
@ -155,55 +160,19 @@ class MediaFetcher(val context: Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun fetchFolderContent(path: String, curMedia: ArrayList<Medium>, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int) {
|
private fun fetchFolderContent(path: String, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int): ArrayList<Medium> {
|
||||||
if (path.startsWith(OTG_PATH)) {
|
return if (path.startsWith(OTG_PATH)) {
|
||||||
getMediaOnOTG(path, curMedia, isPickImage, isPickVideo, filterMedia)
|
getMediaOnOTG(path, isPickImage, isPickVideo, filterMedia)
|
||||||
} else {
|
} else {
|
||||||
getMediaInFolder(path, curMedia, isPickImage, isPickVideo, filterMedia)
|
getMediaInFolder(path, isPickImage, isPickVideo, filterMedia)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun groupDirectories(media: ArrayList<Medium>): HashMap<String, ArrayList<Medium>> {
|
private fun getMediaInFolder(folder: String, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int): ArrayList<Medium> {
|
||||||
val directories = LinkedHashMap<String, ArrayList<Medium>>()
|
val media = ArrayList<Medium>()
|
||||||
val hasOTG = context.hasOTGConnected() && context.config.OTGBasePath.isNotEmpty()
|
val files = File(folder).listFiles() ?: return media
|
||||||
for (medium in media) {
|
|
||||||
if (shouldStop) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
val parentDir = (if (hasOTG && medium.path.startsWith(OTG_PATH)) medium.path.getParentPath().toLowerCase() else File(medium.path).parent?.toLowerCase())
|
|
||||||
?: continue
|
|
||||||
if (directories.containsKey(parentDir)) {
|
|
||||||
directories[parentDir]!!.add(medium)
|
|
||||||
} else {
|
|
||||||
directories[parentDir] = arrayListOf(medium)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return directories
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun shouldFolderBeVisible(path: String, excludedPaths: MutableSet<String>, includedPaths: MutableSet<String>, showHidden: Boolean): Boolean {
|
|
||||||
val file = File(path)
|
|
||||||
return if (path.isEmpty()) {
|
|
||||||
false
|
|
||||||
} else if (path.isThisOrParentIncluded(includedPaths)) {
|
|
||||||
true
|
|
||||||
} else if (path.isThisOrParentExcluded(excludedPaths)) {
|
|
||||||
false
|
|
||||||
} else if (!showHidden && file.isDirectory && file.canonicalFile == file.absoluteFile) {
|
|
||||||
var containsNoMediaOrDot = file.containsNoMedia() || path.contains("/.")
|
|
||||||
if (!containsNoMediaOrDot) {
|
|
||||||
containsNoMediaOrDot = file.doesThisOrParentHaveNoMedia()
|
|
||||||
}
|
|
||||||
!containsNoMediaOrDot
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getMediaInFolder(folder: String, curMedia: ArrayList<Medium>, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int) {
|
|
||||||
val files = File(folder).listFiles() ?: return
|
|
||||||
val doExtraCheck = context.config.doExtraCheck
|
val doExtraCheck = context.config.doExtraCheck
|
||||||
val showHidden = context.config.shouldShowHidden
|
val showHidden = context.config.shouldShowHidden
|
||||||
|
|
||||||
|
@ -220,13 +189,13 @@ class MediaFetcher(val context: Context) {
|
||||||
if (!isImage && !isVideo && !isGif)
|
if (!isImage && !isVideo && !isGif)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if (isVideo && (isPickImage || filterMedia and VIDEOS == 0))
|
if (isVideo && (isPickImage || filterMedia and TYPE_VIDEOS == 0))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if (isImage && (isPickVideo || filterMedia and IMAGES == 0))
|
if (isImage && (isPickVideo || filterMedia and TYPE_IMAGES == 0))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if (isGif && filterMedia and GIFS == 0)
|
if (isGif && filterMedia and TYPE_GIFS == 0)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if (!showHidden && filename.startsWith('.'))
|
if (!showHidden && filename.startsWith('.'))
|
||||||
|
@ -240,18 +209,20 @@ class MediaFetcher(val context: Context) {
|
||||||
val dateModified = file.lastModified()
|
val dateModified = file.lastModified()
|
||||||
|
|
||||||
val type = when {
|
val type = when {
|
||||||
isImage -> TYPE_IMAGE
|
isImage -> TYPE_IMAGES
|
||||||
isVideo -> TYPE_VIDEO
|
isVideo -> TYPE_VIDEOS
|
||||||
else -> TYPE_GIF
|
else -> TYPE_GIFS
|
||||||
}
|
}
|
||||||
|
|
||||||
val medium = Medium(filename, file.absolutePath, dateModified, dateTaken, size, type)
|
val medium = Medium(null, filename, file.absolutePath, folder, dateModified, dateTaken, size, type)
|
||||||
curMedia.add(medium)
|
media.add(medium)
|
||||||
}
|
}
|
||||||
|
return media
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMediaOnOTG(folder: String, curMedia: ArrayList<Medium>, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int) {
|
private fun getMediaOnOTG(folder: String, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int): ArrayList<Medium> {
|
||||||
val files = context.getDocumentFile(folder)?.listFiles() ?: return
|
val media = ArrayList<Medium>()
|
||||||
|
val files = context.getDocumentFile(folder)?.listFiles() ?: return media
|
||||||
val doExtraCheck = context.config.doExtraCheck
|
val doExtraCheck = context.config.doExtraCheck
|
||||||
val showHidden = context.config.shouldShowHidden
|
val showHidden = context.config.shouldShowHidden
|
||||||
|
|
||||||
|
@ -260,7 +231,7 @@ class MediaFetcher(val context: Context) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
val filename = file.name
|
val filename = file.name ?: continue
|
||||||
val isImage = filename.isImageFast()
|
val isImage = filename.isImageFast()
|
||||||
val isVideo = if (isImage) false else filename.isVideoFast()
|
val isVideo = if (isImage) false else filename.isVideoFast()
|
||||||
val isGif = if (isImage || isVideo) false else filename.isGif()
|
val isGif = if (isImage || isVideo) false else filename.isGif()
|
||||||
|
@ -268,13 +239,13 @@ class MediaFetcher(val context: Context) {
|
||||||
if (!isImage && !isVideo && !isGif)
|
if (!isImage && !isVideo && !isGif)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if (isVideo && (isPickImage || filterMedia and VIDEOS == 0))
|
if (isVideo && (isPickImage || filterMedia and TYPE_VIDEOS == 0))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if (isImage && (isPickVideo || filterMedia and IMAGES == 0))
|
if (isImage && (isPickVideo || filterMedia and TYPE_IMAGES == 0))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if (isGif && filterMedia and GIFS == 0)
|
if (isGif && filterMedia and TYPE_GIFS == 0)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if (!showHidden && filename.startsWith('.'))
|
if (!showHidden && filename.startsWith('.'))
|
||||||
|
@ -288,14 +259,16 @@ class MediaFetcher(val context: Context) {
|
||||||
val dateModified = file.lastModified()
|
val dateModified = file.lastModified()
|
||||||
|
|
||||||
val type = when {
|
val type = when {
|
||||||
isImage -> TYPE_IMAGE
|
isImage -> TYPE_IMAGES
|
||||||
isVideo -> TYPE_VIDEO
|
isVideo -> TYPE_VIDEOS
|
||||||
else -> TYPE_GIF
|
else -> TYPE_GIFS
|
||||||
}
|
}
|
||||||
|
|
||||||
val path = Uri.decode(file.uri.toString().replaceFirst("${context.config.OTGBasePath}%3A", OTG_PATH))
|
val path = Uri.decode(file.uri.toString().replaceFirst("${context.config.OTGTreeUri}/document/${context.config.OTGPartition}%3A", OTG_PATH))
|
||||||
val medium = Medium(filename, path, dateModified, dateTaken, size, type)
|
val medium = Medium(null, filename, path, folder, dateModified, dateTaken, size, type)
|
||||||
curMedia.add(medium)
|
media.add(medium)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return media
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.simplemobiletools.gallery.interfaces
|
||||||
|
|
||||||
|
import android.arch.persistence.room.Dao
|
||||||
|
import android.arch.persistence.room.Insert
|
||||||
|
import android.arch.persistence.room.OnConflictStrategy.REPLACE
|
||||||
|
import android.arch.persistence.room.Query
|
||||||
|
import com.simplemobiletools.gallery.models.Directory
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface DirectoryDao {
|
||||||
|
@Query("SELECT path, thumbnail, filename, media_count, last_modified, date_taken, size, location, media_types FROM directories")
|
||||||
|
fun getAll(): List<Directory>
|
||||||
|
|
||||||
|
@Insert(onConflict = REPLACE)
|
||||||
|
fun insert(directory: Directory)
|
||||||
|
|
||||||
|
@Insert(onConflict = REPLACE)
|
||||||
|
fun insertAll(directories: List<Directory>)
|
||||||
|
|
||||||
|
@Query("DELETE FROM directories WHERE path = :path")
|
||||||
|
fun deleteDirPath(path: String)
|
||||||
|
|
||||||
|
@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)
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.simplemobiletools.gallery.interfaces
|
||||||
|
|
||||||
|
import android.arch.persistence.room.Dao
|
||||||
|
import android.arch.persistence.room.Insert
|
||||||
|
import android.arch.persistence.room.OnConflictStrategy.REPLACE
|
||||||
|
import android.arch.persistence.room.Query
|
||||||
|
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>
|
||||||
|
|
||||||
|
@Insert(onConflict = REPLACE)
|
||||||
|
fun insert(medium: Medium)
|
||||||
|
|
||||||
|
@Insert(onConflict = REPLACE)
|
||||||
|
fun insertAll(media: List<Medium>)
|
||||||
|
|
||||||
|
@Query("DELETE FROM media WHERE full_path = :path")
|
||||||
|
fun deleteMediumPath(path: String)
|
||||||
|
|
||||||
|
@Query("UPDATE OR REPLACE media SET filename = :newFilename, full_path = :newFullPath, parent_path = :newParentPath WHERE full_path = :oldPath")
|
||||||
|
fun updateMedium(oldPath: String, newParentPath: String, newFilename: String, newFullPath: String)
|
||||||
|
}
|
|
@ -1,14 +1,29 @@
|
||||||
package com.simplemobiletools.gallery.models
|
package com.simplemobiletools.gallery.models
|
||||||
|
|
||||||
|
import android.arch.persistence.room.ColumnInfo
|
||||||
|
import android.arch.persistence.room.Entity
|
||||||
|
import android.arch.persistence.room.Index
|
||||||
|
import android.arch.persistence.room.PrimaryKey
|
||||||
import com.simplemobiletools.commons.extensions.formatDate
|
import com.simplemobiletools.commons.extensions.formatDate
|
||||||
import com.simplemobiletools.commons.extensions.formatSize
|
import com.simplemobiletools.commons.extensions.formatSize
|
||||||
import com.simplemobiletools.commons.helpers.*
|
import com.simplemobiletools.commons.helpers.*
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
data class Directory(var path: String, var tmb: String, var name: String, var mediaCnt: Int, val modified: Long, val taken: Long,
|
@Entity(tableName = "directories", indices = [Index(value = "path", unique = true)])
|
||||||
val size: Long, val isOnSDCard: Boolean) : Serializable, Comparable<Directory> {
|
data class Directory(
|
||||||
|
@PrimaryKey(autoGenerate = true) var id: Long?,
|
||||||
|
@ColumnInfo(name = "path") var path: String,
|
||||||
|
@ColumnInfo(name = "thumbnail") var tmb: String,
|
||||||
|
@ColumnInfo(name = "filename") var name: String,
|
||||||
|
@ColumnInfo(name = "media_count") var mediaCnt: Int,
|
||||||
|
@ColumnInfo(name = "last_modified") var modified: Long,
|
||||||
|
@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> {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val serialVersionUID = -6553345863555455L
|
private const val serialVersionUID = -6553345863555455L
|
||||||
var sorting: Int = 0
|
var sorting: Int = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,31 +1,42 @@
|
||||||
package com.simplemobiletools.gallery.models
|
package com.simplemobiletools.gallery.models
|
||||||
|
|
||||||
|
import android.arch.persistence.room.ColumnInfo
|
||||||
|
import android.arch.persistence.room.Entity
|
||||||
|
import android.arch.persistence.room.Index
|
||||||
|
import android.arch.persistence.room.PrimaryKey
|
||||||
import com.simplemobiletools.commons.extensions.formatDate
|
import com.simplemobiletools.commons.extensions.formatDate
|
||||||
import com.simplemobiletools.commons.extensions.formatSize
|
import com.simplemobiletools.commons.extensions.formatSize
|
||||||
import com.simplemobiletools.commons.extensions.getMimeType
|
|
||||||
import com.simplemobiletools.commons.extensions.isDng
|
import com.simplemobiletools.commons.extensions.isDng
|
||||||
import com.simplemobiletools.commons.helpers.*
|
import com.simplemobiletools.commons.helpers.*
|
||||||
import com.simplemobiletools.gallery.helpers.TYPE_GIF
|
import com.simplemobiletools.gallery.helpers.TYPE_GIFS
|
||||||
import com.simplemobiletools.gallery.helpers.TYPE_IMAGE
|
import com.simplemobiletools.gallery.helpers.TYPE_IMAGES
|
||||||
import com.simplemobiletools.gallery.helpers.TYPE_VIDEO
|
import com.simplemobiletools.gallery.helpers.TYPE_VIDEOS
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
data class Medium(var name: String, var path: String, val modified: Long, val taken: Long, val size: Long, val type: Int) : Serializable, Comparable<Medium> {
|
@Entity(tableName = "media", indices = [(Index(value = "full_path", unique = true))])
|
||||||
|
data class Medium(
|
||||||
|
@PrimaryKey(autoGenerate = true) var id: Long?,
|
||||||
|
@ColumnInfo(name = "filename") var name: String,
|
||||||
|
@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 = "size") val size: Long,
|
||||||
|
@ColumnInfo(name = "type") val type: Int) : Serializable, Comparable<Medium> {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val serialVersionUID = -6553149366975455L
|
private const val serialVersionUID = -6553149366975455L
|
||||||
var sorting: Int = 0
|
var sorting: Int = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isGif() = type == TYPE_GIF
|
fun isGif() = type == TYPE_GIFS
|
||||||
|
|
||||||
fun isImage() = type == TYPE_IMAGE
|
fun isImage() = type == TYPE_IMAGES
|
||||||
|
|
||||||
fun isVideo() = type == TYPE_VIDEO
|
fun isVideo() = type == TYPE_VIDEOS
|
||||||
|
|
||||||
fun isDng() = path.isDng()
|
fun isDng() = path.isDng()
|
||||||
|
|
||||||
fun getMimeType() = path.getMimeType()
|
|
||||||
|
|
||||||
override fun compareTo(other: Medium): Int {
|
override fun compareTo(other: Medium): Int {
|
||||||
var result: Int
|
var result: Int
|
||||||
when {
|
when {
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
package com.simplemobiletools.gallery.receivers
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.simplemobiletools.gallery.asynctasks.GetDirectoriesAsynctask
|
|
||||||
import com.simplemobiletools.gallery.extensions.config
|
|
||||||
|
|
||||||
class InstallReceiver : BroadcastReceiver() {
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
|
||||||
GetDirectoriesAsynctask(context, false, false) {
|
|
||||||
context.config.directories = Gson().toJson(it)
|
|
||||||
}.execute()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,14 +3,32 @@ package com.simplemobiletools.gallery.receivers
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import com.google.gson.Gson
|
import com.simplemobiletools.commons.extensions.getFilenameFromPath
|
||||||
import com.simplemobiletools.gallery.asynctasks.GetDirectoriesAsynctask
|
import com.simplemobiletools.commons.extensions.getParentPath
|
||||||
import com.simplemobiletools.gallery.extensions.config
|
import com.simplemobiletools.commons.extensions.isImageFast
|
||||||
|
import com.simplemobiletools.commons.extensions.isVideoFast
|
||||||
|
import com.simplemobiletools.commons.helpers.REFRESH_PATH
|
||||||
|
import com.simplemobiletools.gallery.extensions.galleryDB
|
||||||
|
import com.simplemobiletools.gallery.helpers.TYPE_GIFS
|
||||||
|
import com.simplemobiletools.gallery.helpers.TYPE_IMAGES
|
||||||
|
import com.simplemobiletools.gallery.helpers.TYPE_VIDEOS
|
||||||
|
import com.simplemobiletools.gallery.models.Medium
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
class RefreshMediaReceiver : BroadcastReceiver() {
|
class RefreshMediaReceiver : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
GetDirectoriesAsynctask(context, false, false) {
|
val path = intent.getStringExtra(REFRESH_PATH) ?: return
|
||||||
context.config.directories = Gson().toJson(it)
|
|
||||||
}.execute()
|
Thread {
|
||||||
|
val medium = Medium(null, path.getFilenameFromPath(), path, path.getParentPath(), System.currentTimeMillis(), System.currentTimeMillis(),
|
||||||
|
File(path).length(), getFileType(path))
|
||||||
|
context.galleryDB.MediumDao().insert(medium)
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getFileType(path: String) = when {
|
||||||
|
path.isImageFast() -> TYPE_IMAGES
|
||||||
|
path.isVideoFast() -> TYPE_VIDEOS
|
||||||
|
else -> TYPE_GIFS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,14 +52,6 @@
|
||||||
android:paddingTop="@dimen/medium_margin"
|
android:paddingTop="@dimen/medium_margin"
|
||||||
android:text="@string/last_modified"/>
|
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>
|
</RadioGroup>
|
||||||
|
|
||||||
<include
|
<include
|
||||||
|
|
|
@ -82,7 +82,7 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/dir_sd_card"
|
android:id="@+id/dir_location"
|
||||||
android:layout_width="@dimen/sd_card_icon_size"
|
android:layout_width="@dimen/sd_card_icon_size"
|
||||||
android:layout_height="@dimen/sd_card_icon_size"
|
android:layout_height="@dimen/sd_card_icon_size"
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
|
|
|
@ -76,7 +76,7 @@
|
||||||
android:paddingBottom="@dimen/tiny_margin">
|
android:paddingBottom="@dimen/tiny_margin">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/dir_sd_card"
|
android:id="@+id/dir_location"
|
||||||
android:layout_width="@dimen/sd_card_icon_size"
|
android:layout_width="@dimen/sd_card_icon_size"
|
||||||
android:layout_height="@dimen/sd_card_icon_size"
|
android:layout_height="@dimen/sd_card_icon_size"
|
||||||
android:paddingBottom="@dimen/small_margin"
|
android:paddingBottom="@dimen/small_margin"
|
||||||
|
|
189
app/src/main/res/values-da/strings.xml
Normal file
189
app/src/main/res/values-da/strings.xml
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">Simple Gallery</string>
|
||||||
|
<string name="app_launcher_name">Galleri</string>
|
||||||
|
<string name="edit">Rediger</string>
|
||||||
|
<string name="open_camera">Åbn kamera</string>
|
||||||
|
<string name="hidden">(skjult)</string>
|
||||||
|
<string name="excluded">(ekskluderet)</string>
|
||||||
|
<string name="pin_folder">Pin folder</string>
|
||||||
|
<string name="unpin_folder">Unpin folder</string>
|
||||||
|
<string name="pin_to_the_top">Pin to the top</string>
|
||||||
|
<string name="show_all">Vis indholdet af alle mappert</string>
|
||||||
|
<string name="all_folders">Alle mapper</string>
|
||||||
|
<string name="folder_view">Skift til mappevisning</string>
|
||||||
|
<string name="other_folder">Anden mappe</string>
|
||||||
|
<string name="show_on_map">Vis på kort</string>
|
||||||
|
<string name="unknown_location">Ukendt placering</string>
|
||||||
|
<string name="increase_column_count">Flere kolonner</string>
|
||||||
|
<string name="reduce_column_count">Færre kolonner</string>
|
||||||
|
<string name="change_cover_image">Change cover image</string>
|
||||||
|
<string name="select_photo">Select photo</string>
|
||||||
|
<string name="use_default">Use default</string>
|
||||||
|
<string name="volume">Volume</string>
|
||||||
|
<string name="brightness">Brightness</string>
|
||||||
|
<string name="lock_orientation">Lås orientering</string>
|
||||||
|
<string name="unlock_orientation">Lås orientering op</string>
|
||||||
|
|
||||||
|
<!-- Filter -->
|
||||||
|
<string name="filter_media">Filtrer medier</string>
|
||||||
|
<string name="images">Billeder</string>
|
||||||
|
<string name="videos">Videoer</string>
|
||||||
|
<string name="gifs">GIF\'er</string>
|
||||||
|
<string name="no_media_with_filters">Der blev ikke fundet nogen filer med det valgte filter.</string>
|
||||||
|
<string name="change_filters_underlined"><u>Skift filter</u></string>
|
||||||
|
|
||||||
|
<!-- Hide / Exclude -->
|
||||||
|
<string name="hide_folder_description">Denne funktion skjuler mappen og dens eventueller undermapper ved at oprette en \'.nomedia\'-fil i den. Du kan se dem ved at klikke på \'Vis skjulte\' i indstillingerne. Fortsæt?</string>
|
||||||
|
<string name="exclude">Ekskluder</string>
|
||||||
|
<string name="excluded_folders">Ekskluderede mapper</string>
|
||||||
|
<string name="manage_excluded_folders">Administrer ekskluderede mapper</string>
|
||||||
|
<string name="exclude_folder_description">Dette vil kun ekskludere de valgte mapper (og deres undermapper) fra Simple Gallery. Du kan administrere ekskluderede mapper i indstillingerne.</string>
|
||||||
|
<string name="exclude_folder_parent">Ekskluder en overliggende mappe i stedet?</string>
|
||||||
|
<string name="excluded_activity_placeholder">Ekskludering af mapper vil skjule dem og eventuelle undermapper for Simple Gallery, de vil stadig være synlige for andre apps.\n\nHvis du også vil skjule dem for andre apps, skal du bruge funktionen Skjul.</string>
|
||||||
|
<string name="remove_all">Fjern alle</string>
|
||||||
|
<string name="remove_all_description">Fjern alle fra listen med ekskluderede mapper? Det vil ikke slette mapperne.</string>
|
||||||
|
<string name="hidden_folders">Skjulte mapper</string>
|
||||||
|
<string name="manage_hidden_folders">Administrer skjulte mapper</string>
|
||||||
|
<string name="hidden_folders_placeholder">Det ser ikke ud til at du har nogen skjulte mapper med en \".nomedia\"-fil.</string>
|
||||||
|
|
||||||
|
<!-- Include folders -->
|
||||||
|
<string name="include_folders">Inkluderede mapper</string>
|
||||||
|
<string name="manage_included_folders">Administrer inkluderede mapper</string>
|
||||||
|
<string name="add_folder">Tilføj mappe</string>
|
||||||
|
<string name="included_activity_placeholder">Hvis du har mapper med mediefiler som appen ikke har fundet, kan du manuelt tilføje dem her.\n\nDet vil ikke ekskludere andre mapper.</string>
|
||||||
|
|
||||||
|
<!-- Resizing -->
|
||||||
|
<string name="resize">Skaler</string>
|
||||||
|
<string name="resize_and_save">Resize selection and save</string>
|
||||||
|
<string name="width">Width</string>
|
||||||
|
<string name="height">Height</string>
|
||||||
|
<string name="keep_aspect_ratio">Keep aspect ratio</string>
|
||||||
|
<string name="invalid_values">Please enter a valid resolution</string>
|
||||||
|
|
||||||
|
<!-- Editor -->
|
||||||
|
<string name="editor">Editor</string>
|
||||||
|
<string name="save">Gem</string>
|
||||||
|
<string name="rotate">Roter</string>
|
||||||
|
<string name="path">Sti</string>
|
||||||
|
<string name="invalid_image_path">Ugyldig sti til billede</string>
|
||||||
|
<string name="image_editing_failed">Redigering af billede mislykkedes</string>
|
||||||
|
<string name="edit_image_with">Rediger billede med:</string>
|
||||||
|
<string name="no_editor_found">Der blev ikke fundet en editor til billedbehandling</string>
|
||||||
|
<string name="unknown_file_location">Ukendt filplacering</string>
|
||||||
|
<string name="error_saving_file">Kunne ikke overskrive kildefilen</string>
|
||||||
|
<string name="rotate_left">Roter mod venstre</string>
|
||||||
|
<string name="rotate_right">Roter mod højre</string>
|
||||||
|
<string name="rotate_one_eighty">Roter 180º</string>
|
||||||
|
<string name="flip">Spejlvend</string>
|
||||||
|
<string name="flip_horizontally">Spejlvend vandret</string>
|
||||||
|
<string name="flip_vertically">Spejlvend lodret</string>
|
||||||
|
<string name="edit_with">Rediger med</string>
|
||||||
|
|
||||||
|
<!-- Set wallpaper -->
|
||||||
|
<string name="simple_wallpaper">Simple Wallpaper</string>
|
||||||
|
<string name="set_as_wallpaper">Sæt som baggrundsbillede</string>
|
||||||
|
<string name="set_as_wallpaper_failed">Det mislykkedes at sætte billedet som baggrund</string>
|
||||||
|
<string name="set_as_wallpaper_with">Sæt som baggrundsbillede med:</string>
|
||||||
|
<string name="setting_wallpaper">Sætter baggrundsbillede…</string>
|
||||||
|
<string name="wallpaper_set_successfully">Sat som baggrundsbillede</string>
|
||||||
|
<string name="portrait_aspect_ratio">Stående billedformat</string>
|
||||||
|
<string name="landscape_aspect_ratio">Liggende billedformat</string>
|
||||||
|
<string name="home_screen">Hjemmeskærm</string>
|
||||||
|
<string name="lock_screen">Låseskærm</string>
|
||||||
|
<string name="home_and_lock_screen">Hjemme- og låseskærm</string>
|
||||||
|
|
||||||
|
<!-- Slideshow -->
|
||||||
|
<string name="slideshow">Slideshow</string>
|
||||||
|
<string name="interval">Frekvens (sekunder):</string>
|
||||||
|
<string name="include_photos">Inkluder billeder</string>
|
||||||
|
<string name="include_videos">Inkluder videoer</string>
|
||||||
|
<string name="include_gifs">Inkluder GIF\'er</string>
|
||||||
|
<string name="random_order">Tilfældig rækkefølge</string>
|
||||||
|
<string name="use_fade">Use fade animations</string>
|
||||||
|
<string name="move_backwards">Kør baglæns</string>
|
||||||
|
<string name="loop_slideshow">Loop slideshow</string>
|
||||||
|
<string name="slideshow_ended">Slideshowet endte</string>
|
||||||
|
<string name="no_media_for_slideshow">Der blev ikke funket nogen mediefiler til slideshowet</string>
|
||||||
|
|
||||||
|
<!-- View types -->
|
||||||
|
<string name="change_view_type">Skift visning</string>
|
||||||
|
<string name="grid">Gitter</string>
|
||||||
|
<string name="list">Liste</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="autoplay_videos">Afspil automatisk videoer</string>
|
||||||
|
<string name="toggle_filename">Toggle filename visibility</string>
|
||||||
|
<string name="loop_videos">Kør videoer i sløjfe</string>
|
||||||
|
<string name="animate_gifs">Animér GIF\'er i miniaturer</string>
|
||||||
|
<string name="max_brightness">Maksimal lysstyrke ved fuldskærmsvisning af medier</string>
|
||||||
|
<string name="crop_thumbnails">Beskær miniaturer til kvadrater</string>
|
||||||
|
<string name="screen_rotation_by">Roter fuldskærmsmedier efter</string>
|
||||||
|
<string name="screen_rotation_system_setting">Systemindstilling</string>
|
||||||
|
<string name="screen_rotation_device_rotation">Enhedens orientering</string>
|
||||||
|
<string name="screen_rotation_aspect_ratio">Billedformat</string>
|
||||||
|
<string name="black_background_at_fullscreen">Sort baggrund og statuslinje ved medievisning i fuldskærm</string>
|
||||||
|
<string name="scroll_thumbnails_horizontally">Scroll miniaturer vandret</string>
|
||||||
|
<string name="hide_system_ui_at_fullscreen">Skjul automatisk systemets brugerflade ved fuldskærmsvisning af medier</string>
|
||||||
|
<string name="delete_empty_folders">Slet tomme mapper efter sletning af deres indhold</string>
|
||||||
|
<string name="allow_photo_gestures">Tillad kontrol af lysstyrke på billeder med lodrette bevægelser</string>
|
||||||
|
<string name="allow_video_gestures">Tillad kontrol af videolyd og lysstyrke med lodrette bevægelser</string>
|
||||||
|
<string name="show_media_count">Vis antal filer i hver mappe i oversigten</string>
|
||||||
|
<string name="replace_share_with_rotate">Erstat Del med Roter i fuldskærmsmenuen</string>
|
||||||
|
<string name="show_extended_details">Vis udvidede oplysninger over medier i fuldskærm</string>
|
||||||
|
<string name="manage_extended_details">Manage extended details</string>
|
||||||
|
<string name="one_finger_zoom">Tillad zoom med en finger når medier er i fuldskærm</string>
|
||||||
|
<string name="allow_instant_change">Tillad skift af medie ved klik på skærmens sider</string>
|
||||||
|
<string name="replace_zoomable_images">RErstat stærkt zoombare billeder med nogle i bedre kvalitet</string>
|
||||||
|
<string name="hide_extended_details">Skjul udvidede oplysninger når statuslinjen er skjult</string>
|
||||||
|
<string name="do_extra_check">Tjek en ekstra gang for at undgå visning af ugyldige filer</string>
|
||||||
|
|
||||||
|
<!-- Setting sections -->
|
||||||
|
<string name="thumbnails">Thumbnails</string>
|
||||||
|
<string name="fullscreen_media">Fullscreen media</string>
|
||||||
|
<string name="extended_details">Extended details</string>
|
||||||
|
|
||||||
|
<!-- FAQ -->
|
||||||
|
<string name="faq_1_title">How can I make Simple Gallery the default device gallery?</string>
|
||||||
|
<string name="faq_1_text">First you have to find the currently default gallery in the Apps section of your device settings, look for a button that says something like \"Open by default\", click on it, then select \"Clear defaults\".
|
||||||
|
The next time you will try opening an image or video you should see an app picker, where you can select Simple Gallery and make it the default app.</string>
|
||||||
|
<string name="faq_2_title">I locked the app with a password, but I forgot it. What can I do?</string>
|
||||||
|
<string name="faq_2_text">You can solve it in 2 ways. You can either reinstall the app, or find the app in your device settings and select \"Clear data\". It will reset all your settings, it will not remove any media files.</string>
|
||||||
|
<string name="faq_3_title">How can I make an album always appear at the top?</string>
|
||||||
|
<string name="faq_3_text">You can long press the desired album and select the Pin icon at the actionmenu, that will pin it to the top. You can pin multiple folders too, pinned items will be sorted by the default sorting method.</string>
|
||||||
|
<string name="faq_4_title">How can I fast-forward videos?</string>
|
||||||
|
<string name="faq_4_text">You can click on the current or max duration texts near the seekbar, that will move the video either backward, or forward.</string>
|
||||||
|
<string name="faq_5_title">What is the difference between hiding and excluding a folder?</string>
|
||||||
|
<string name="faq_5_text">Exclude prevents displaying the folder only in Simple Gallery, while Hide works system-wise and it hides the folder from other galleries too. It works by creating an empty \".nomedia\" file in the given folder, which you can then remove with any file manager too.</string>
|
||||||
|
<string name="faq_6_title">Why do folders with music cover art or stickers show up?</string>
|
||||||
|
<string name="faq_6_text">It can happen that you will see some unusual albums show up. You can easily exclude them by long pressing them and selecting Exclude. In the next dialog you can then select the parent folder, chances are it will prevent the other related albums showing up too.</string>
|
||||||
|
<string name="faq_7_title">A folder with images isn\'t showing up, what can I do?</string>
|
||||||
|
<string name="faq_7_text">That can have multiple reasons, but solving it is easy. Just go in Settings -> Manage Included Folders, select Plus and navigate to the required folder.</string>
|
||||||
|
<string name="faq_8_title">What if I want just a few particular folders visible?</string>
|
||||||
|
<string name="faq_8_text">Adding a folder at the Included Folders doesn\'t automatically exclude anything. What you can do is go in Settings -> Manage Excluded Folders, exclude the root folder \"/\", then add the desired folders at Settings -> Manage Included Folders.
|
||||||
|
That will make only the selected folders visible, as both excluding and including are recursive and if a folder is both excluded and included, it will show up.</string>
|
||||||
|
<string name="faq_9_title">Fullscreen images have weird artifacts, can I somehow improve the quality?</string>
|
||||||
|
<string name="faq_9_text">Yea, there is a toggle in Settings saying \"Replace deep zoomable images with better quality ones\", you can use that. It will improve the quality of the images, but they will get blurred once you try zooming in too much.</string>
|
||||||
|
<string name="faq_10_title">Can I crop images with this app?</string>
|
||||||
|
<string name="faq_10_text">Yes, you can crop images in the editor, by dragging the image corners. You can get to the editor either by long pressing an image thumbnail and selecting Edit, or selecting Edit from the fullscreen view.</string>
|
||||||
|
|
||||||
|
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||||
|
<!-- Short description has to have less than 80 chars -->
|
||||||
|
<string name="app_short_description">A gallery for viewing photos and videos without ads.</string>
|
||||||
|
<string name="app_long_description">
|
||||||
|
A simple tool usable for viewing photos and videos. Items can be sorted by date, size, name both ascending or descending, photos can be zoomed in. Media files are shown in multiple columns depending on the size of the display, you can change the column count by pinch gestures. They can be renamed, shared, deleted, copied, moved. Images can also be cropped, rotated, flipped or set as Wallpaper directly from the app.
|
||||||
|
|
||||||
|
The Gallery is also offered for third party usage for previewing images / videos, adding attachments at email clients etc. It\'s perfect for everyday usage.
|
||||||
|
|
||||||
|
The fingerprint permission is needed for locking either hidden item visibility, or the whole app.
|
||||||
|
|
||||||
|
Contains no ads or unnecessary permissions. It is fully opensource, provides customizable colors.
|
||||||
|
|
||||||
|
This app is just one piece of a bigger series of apps. You can find the rest of them at https://www.simplemobiletools.com
|
||||||
|
</string>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Haven't found some strings? There's more at
|
||||||
|
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||||
|
-->
|
||||||
|
</resources>
|
|
@ -5,7 +5,7 @@
|
||||||
<string name="edit">Modifica</string>
|
<string name="edit">Modifica</string>
|
||||||
<string name="open_camera">Apri fotocamera</string>
|
<string name="open_camera">Apri fotocamera</string>
|
||||||
<string name="hidden">(nascosta)</string>
|
<string name="hidden">(nascosta)</string>
|
||||||
<string name="excluded">(excluded)</string>
|
<string name="excluded">(esclusa)</string>
|
||||||
<string name="pin_folder">Blocca cartella</string>
|
<string name="pin_folder">Blocca cartella</string>
|
||||||
<string name="unpin_folder">Sblocca cartella</string>
|
<string name="unpin_folder">Sblocca cartella</string>
|
||||||
<string name="pin_to_the_top">Fissa in alto</string>
|
<string name="pin_to_the_top">Fissa in alto</string>
|
||||||
|
@ -165,7 +165,7 @@
|
||||||
<string name="faq_9_title">Le immagini a schermo intero hanno strani artefatti, posso migliorarne la qualità in qualche modo?</string>
|
<string name="faq_9_title">Le immagini a schermo intero hanno strani artefatti, posso migliorarne la qualità in qualche modo?</string>
|
||||||
<string name="faq_9_text">Sì, c\'è un\'opzione nelle impostazioni che dice \"Sostituisci le immagini ingrandibili a fondo con altre di migliore qualità\", puoi usare quella. Ciò migliorerà la qualità delle immagini, ma saranno sfuocate quando proverai a ingrandirle troppo.</string>
|
<string name="faq_9_text">Sì, c\'è un\'opzione nelle impostazioni che dice \"Sostituisci le immagini ingrandibili a fondo con altre di migliore qualità\", puoi usare quella. Ciò migliorerà la qualità delle immagini, ma saranno sfuocate quando proverai a ingrandirle troppo.</string>
|
||||||
<string name="faq_10_title">Posso ritagliare le immagini con questa app?</string>
|
<string name="faq_10_title">Posso ritagliare le immagini con questa app?</string>
|
||||||
<string name="faq_10_text">Sì, puoi ritagliare le immagini nell\'editor, trascinando gli angoli dell\'immagine. Puoi usare l\'editor sia premendo a lungo la miniatura di un'immagine e selezionando Modifica, o selezionando Modifica mentre la vedi a schermo intero.</string>
|
<string name="faq_10_text">Sì, puoi ritagliare le immagini nell\'editor, trascinando gli angoli dell\'immagine. Puoi usare l\'editor sia premendo a lungo la miniatura di un\'immagine e selezionando Modifica, o selezionando Modifica mentre la vedi a schermo intero.</string>
|
||||||
|
|
||||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||||
<!-- Short description has to have less than 80 chars -->
|
<!-- Short description has to have less than 80 chars -->
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<string name="edit">Rediger</string>
|
<string name="edit">Rediger</string>
|
||||||
<string name="open_camera">Åpne kamera</string>
|
<string name="open_camera">Åpne kamera</string>
|
||||||
<string name="hidden">(skjult)</string>
|
<string name="hidden">(skjult)</string>
|
||||||
<string name="excluded">(excluded)</string>
|
<string name="excluded">(ekskludert)</string>
|
||||||
<string name="pin_folder">Fest mappe</string>
|
<string name="pin_folder">Fest mappe</string>
|
||||||
<string name="unpin_folder">Løsne mappe</string>
|
<string name="unpin_folder">Løsne mappe</string>
|
||||||
<string name="pin_to_the_top">Fest til toppen</string>
|
<string name="pin_to_the_top">Fest til toppen</string>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<string name="edit">Editar</string>
|
<string name="edit">Editar</string>
|
||||||
<string name="open_camera">Abrir câmara</string>
|
<string name="open_camera">Abrir câmara</string>
|
||||||
<string name="hidden">(oculta)</string>
|
<string name="hidden">(oculta)</string>
|
||||||
<string name="excluded">(excluded)</string>
|
<string name="excluded">(excluída)</string>
|
||||||
<string name="pin_folder">Fixar pasta</string>
|
<string name="pin_folder">Fixar pasta</string>
|
||||||
<string name="unpin_folder">Desafixar pasta</string>
|
<string name="unpin_folder">Desafixar pasta</string>
|
||||||
<string name="pin_to_the_top">Fixar no topo</string>
|
<string name="pin_to_the_top">Fixar no topo</string>
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
<string name="app_name">Simple Gallery</string>
|
<string name="app_name">Simple Gallery</string>
|
||||||
<string name="app_launcher_name">Galleri</string>
|
<string name="app_launcher_name">Galleri</string>
|
||||||
<string name="edit">Redigera</string>
|
<string name="edit">Redigera</string>
|
||||||
<string name="open_camera">Starta kameran</string>
|
<string name="open_camera">Öppna kameran</string>
|
||||||
<string name="hidden">(dold)</string>
|
<string name="hidden">(dold)</string>
|
||||||
<string name="excluded">(excluded)</string>
|
<string name="excluded">(utesluten)</string>
|
||||||
<string name="pin_folder">Fäst mapp</string>
|
<string name="pin_folder">Fäst mapp</string>
|
||||||
<string name="unpin_folder">Lossa mapp</string>
|
<string name="unpin_folder">Lossa mapp</string>
|
||||||
<string name="pin_to_the_top">Fäst högst upp</string>
|
<string name="pin_to_the_top">Fäst högst upp</string>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.2.31'
|
ext.kotlin_version = '1.2.40'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
|
@ -9,7 +9,7 @@ buildscript {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.1.0'
|
classpath 'com.android.tools.build:gradle:3.1.2'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
|
Loading…
Reference in a new issue