commit
1fee52d849
68 changed files with 269 additions and 126 deletions
|
@ -1,6 +1,12 @@
|
|||
Changelog
|
||||
==========
|
||||
|
||||
Version 6.10.4 *(2019-11-05)*
|
||||
----------------------------
|
||||
|
||||
* Improved USB device handling
|
||||
* Some smaller stability and translation improvements
|
||||
|
||||
Version 6.10.3 *(2019-10-27)*
|
||||
----------------------------
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ android {
|
|||
applicationId "com.simplemobiletools.gallery.pro"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 28
|
||||
versionCode 270
|
||||
versionName "6.10.3"
|
||||
versionCode 271
|
||||
versionName "6.10.4"
|
||||
multiDexEnabled true
|
||||
setProperty("archivesBaseName", "gallery")
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
|
@ -62,12 +62,12 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.simplemobiletools:commons:5.18.14'
|
||||
implementation 'com.simplemobiletools:commons:5.19.2'
|
||||
implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.0'
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
implementation 'it.sephiroth.android.exif:library:1.0.1'
|
||||
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.18'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta3'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta2'
|
||||
implementation 'com.google.android.exoplayer:exoplayer-core:2.9.6'
|
||||
implementation 'com.google.vr:sdk-panowidget:1.180.0'
|
||||
implementation 'com.google.vr:sdk-videowidget:1.180.0'
|
||||
|
|
|
@ -389,10 +389,10 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
private fun removeTempFolder() {
|
||||
if (config.tempFolderPath.isNotEmpty()) {
|
||||
val newFolder = File(config.tempFolderPath)
|
||||
if (newFolder.exists() && newFolder.isDirectory) {
|
||||
if (getDoesFilePathExist(newFolder.absolutePath) && newFolder.isDirectory) {
|
||||
if (newFolder.list()?.isEmpty() == true && newFolder.getProperSize(true) == 0L && newFolder.getFileCount(true) == 0) {
|
||||
toast(String.format(getString(R.string.deleting_folder), config.tempFolderPath), Toast.LENGTH_LONG)
|
||||
tryDeleteFileDirItem(newFolder.toFileDirItem(), true, true)
|
||||
tryDeleteFileDirItem(newFolder.toFileDirItem(applicationContext), true, true)
|
||||
}
|
||||
}
|
||||
config.tempFolderPath = ""
|
||||
|
@ -408,16 +408,6 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
config.OTGPath = otgPath
|
||||
config.addIncludedFolder(otgPath)
|
||||
}
|
||||
|
||||
// OTG handling has been changed again in SDK version 28, the old method no longer works
|
||||
/*if (config.OTGPath.isEmpty()) {
|
||||
runOnUiThread {
|
||||
ConfirmationDialog(this, getString(R.string.usb_detected), positive = R.string.ok, negative = 0) {
|
||||
config.wasOTGHandled = true
|
||||
showOTGPermissionDialog()
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -428,8 +418,9 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
"/storage/emulated/0/Android/data/com.facebook.orca/files/stickers"
|
||||
)
|
||||
|
||||
val OTGPath = config.OTGPath
|
||||
spamFolders.forEach {
|
||||
if (File(it).exists()) {
|
||||
if (getDoesFilePathExist(it, OTGPath)) {
|
||||
config.addExcludedFolder(it)
|
||||
}
|
||||
}
|
||||
|
@ -570,7 +561,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
(it.isGif() && filter and TYPE_GIFS != 0) ||
|
||||
(it.isRawFast() && filter and TYPE_RAWS != 0) ||
|
||||
(it.isSvg() && filter and TYPE_SVGS != 0))
|
||||
}?.mapTo(itemsToDelete) { it.toFileDirItem() }
|
||||
}?.mapTo(itemsToDelete) { it.toFileDirItem(applicationContext) }
|
||||
}
|
||||
|
||||
if (config.useRecycleBin) {
|
||||
|
@ -590,13 +581,14 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
}
|
||||
|
||||
private fun deleteFilteredFileDirItems(fileDirItems: ArrayList<FileDirItem>, folders: ArrayList<File>) {
|
||||
val OTGPath = config.OTGPath
|
||||
deleteFiles(fileDirItems) {
|
||||
runOnUiThread {
|
||||
refreshItems()
|
||||
}
|
||||
|
||||
ensureBackgroundThread {
|
||||
folders.filter { !it.exists() }.forEach {
|
||||
folders.filter { !getDoesFilePathExist(it.absolutePath, OTGPath) }.forEach {
|
||||
mDirectoryDao.deleteDirPath(it.absolutePath)
|
||||
}
|
||||
}
|
||||
|
@ -1115,13 +1107,14 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
|
||||
private fun checkInvalidDirectories(dirs: ArrayList<Directory>) {
|
||||
val invalidDirs = ArrayList<Directory>()
|
||||
val OTGPath = config.OTGPath
|
||||
dirs.filter { !it.areFavorites() && !it.isRecycleBin() }.forEach {
|
||||
if (!File(it.path).exists()) {
|
||||
if (!getDoesFilePathExist(it.path, OTGPath)) {
|
||||
invalidDirs.add(it)
|
||||
} else if (it.path != config.tempFolderPath) {
|
||||
val children = File(it.path).listFiles()?.asList()
|
||||
val children = if (isPathOnOTG(it.path)) getOTGFolderChildrenNames(it.path) else File(it.path).list()?.asList()
|
||||
val hasMediaFile = children?.any {
|
||||
it?.isMediaFile() == true || (it.isDirectory && it.name.startsWith("img_", true))
|
||||
it?.isMediaFile() == true || (File(it).isDirectory && it?.startsWith("img_", true) == true)
|
||||
} ?: false
|
||||
|
||||
if (!hasMediaFile) {
|
||||
|
@ -1151,6 +1144,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
dirs.removeAll(invalidDirs)
|
||||
setupAdapter(dirs)
|
||||
invalidDirs.forEach {
|
||||
toast("invalid ${it.path}", Toast.LENGTH_LONG)
|
||||
try {
|
||||
mDirectoryDao.deleteDirPath(it.path)
|
||||
} catch (ignored: Exception) {
|
||||
|
@ -1243,9 +1237,10 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
}
|
||||
|
||||
oftenRepeatedPaths.removeAll(substringToRemove)
|
||||
val OTGPath = config.OTGPath
|
||||
oftenRepeatedPaths.forEach {
|
||||
val file = File("$internalPath/$it")
|
||||
if (file.exists()) {
|
||||
if (getDoesFilePathExist(file.absolutePath, OTGPath)) {
|
||||
config.addExcludedFolder(file.absolutePath)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -569,7 +569,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
|
|||
|
||||
private fun deleteDirectoryIfEmpty() {
|
||||
val fileDirItem = FileDirItem(mPath, mPath.getFilenameFromPath(), true)
|
||||
if (config.deleteEmptyFolders && !fileDirItem.isDownloadsFolder() && fileDirItem.isDirectory && fileDirItem.getProperFileCount(true) == 0) {
|
||||
if (config.deleteEmptyFolders && !fileDirItem.isDownloadsFolder() && fileDirItem.isDirectory && fileDirItem.getProperFileCount(this, true) == 0) {
|
||||
tryDeleteFileDirItem(fileDirItem, true, true)
|
||||
}
|
||||
}
|
||||
|
@ -606,7 +606,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
|
|||
val newMedia = it
|
||||
try {
|
||||
gotMedia(newMedia, false)
|
||||
oldMedia.filter { !newMedia.contains(it) }.mapNotNull { it as? Medium }.filter { !File(it.path).exists() }.forEach {
|
||||
oldMedia.filter { !newMedia.contains(it) }.mapNotNull { it as? Medium }.filter { !getDoesFilePathExist(it.path) }.forEach {
|
||||
mMediumDao.deleteMediumPath(it.path)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
@ -891,7 +891,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
|
|||
}
|
||||
|
||||
override fun tryDeleteFiles(fileDirItems: ArrayList<FileDirItem>) {
|
||||
val filtered = fileDirItems.filter { File(it.path).isFile && it.path.isMediaFile() } as ArrayList
|
||||
val filtered = fileDirItems.filter { !getIsPathDirectory(it.path) && it.path.isMediaFile() } as ArrayList
|
||||
if (filtered.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
|
|||
val uri = mUri.toString()
|
||||
if (uri.startsWith("content:/") && uri.contains("/storage/")) {
|
||||
val guessedPath = uri.substring(uri.indexOf("/storage/"))
|
||||
if (File(guessedPath).exists()) {
|
||||
if (getDoesFilePathExist(guessedPath)) {
|
||||
val extras = intent.extras ?: Bundle()
|
||||
extras.apply {
|
||||
putString(REAL_FILE_PATH, guessedPath)
|
||||
|
@ -93,7 +93,7 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
|
|||
|
||||
if (intent.extras?.containsKey(REAL_FILE_PATH) == true) {
|
||||
val realPath = intent.extras!!.getString(REAL_FILE_PATH)
|
||||
if (realPath != null && File(realPath).exists()) {
|
||||
if (realPath != null && getDoesFilePathExist(realPath)) {
|
||||
if (realPath.getFilenameFromPath().contains('.') || filename.contains('.')) {
|
||||
if (isFileTypeVisible(realPath)) {
|
||||
bottom_actions.beGone()
|
||||
|
@ -125,7 +125,7 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
|
|||
return
|
||||
} else {
|
||||
val path = applicationContext.getRealPathFromURI(mUri!!) ?: ""
|
||||
if (path != mUri.toString() && path.isNotEmpty() && mUri!!.authority != "mms" && filename.contains('.') && File(path).exists()) {
|
||||
if (path != mUri.toString() && path.isNotEmpty() && mUri!!.authority != "mms" && filename.contains('.') && getDoesFilePathExist(path)) {
|
||||
if (isFileTypeVisible(path)) {
|
||||
bottom_actions.beGone()
|
||||
handleLockedFolderOpening(path.getParentPath()) { success ->
|
||||
|
|
|
@ -278,7 +278,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
|||
return
|
||||
}
|
||||
|
||||
if (!File(mPath).exists() && getPortraitPath() == "") {
|
||||
if (!getDoesFilePathExist(mPath) && getPortraitPath() == "") {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
@ -945,7 +945,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
|||
|
||||
private fun deleteConfirmed() {
|
||||
val path = getCurrentMedia().getOrNull(mPos)?.path ?: return
|
||||
if (File(path).isDirectory || !path.isMediaFile()) {
|
||||
if (getIsPathDirectory(path) || !path.isMediaFile()) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1066,7 +1066,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
|||
|
||||
private fun deleteDirectoryIfEmpty() {
|
||||
val fileDirItem = FileDirItem(mDirectory, mDirectory.getFilenameFromPath(), File(mDirectory).isDirectory)
|
||||
if (config.deleteEmptyFolders && !fileDirItem.isDownloadsFolder() && fileDirItem.isDirectory && fileDirItem.getProperFileCount(true) == 0) {
|
||||
if (config.deleteEmptyFolders && !fileDirItem.isDownloadsFolder() && fileDirItem.isDirectory && fileDirItem.getProperFileCount(this, true) == 0) {
|
||||
tryDeleteFileDirItem(fileDirItem, true, true)
|
||||
scanPathRecursively(mDirectory)
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
|
|||
private var loadImageInstantly = false
|
||||
private var delayHandler = Handler(Looper.getMainLooper())
|
||||
private var currentMediaHash = media.hashCode()
|
||||
private val hasOTGConnected = activity.hasOTGConnected()
|
||||
|
||||
private var scrollHorizontally = config.scrollHorizontally
|
||||
private var animateGifs = config.animateGifs
|
||||
|
@ -492,7 +493,11 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
|
|||
medium_check?.background?.applyColorFilter(primaryColor)
|
||||
}
|
||||
|
||||
val path = medium.path
|
||||
var path = medium.path
|
||||
if (hasOTGConnected && context.isPathOnOTG(path)) {
|
||||
path = path.getOTGPublicPath(context)
|
||||
}
|
||||
|
||||
if (loadImageInstantly) {
|
||||
activity.loadImage(medium.type, path, medium_thumbnail, scrollHorizontally, animateGifs, cropThumbnails, rotatedImagePaths)
|
||||
} else {
|
||||
|
|
|
@ -7,7 +7,6 @@ import com.simplemobiletools.commons.dialogs.FilePickerDialog
|
|||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.gallery.pro.R
|
||||
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) {
|
||||
|
||||
|
@ -67,7 +66,7 @@ class SaveAsDialog(val activity: BaseSimpleActivity, val path: String, val appen
|
|||
return@setOnClickListener
|
||||
}
|
||||
|
||||
if (File(newPath).exists()) {
|
||||
if (activity.getDoesFilePathExist(newPath)) {
|
||||
val title = String.format(activity.getString(R.string.file_already_exists_overwrite), newFilename)
|
||||
ConfirmationDialog(activity, title) {
|
||||
callback(newPath)
|
||||
|
|
|
@ -131,7 +131,7 @@ fun AppCompatActivity.hideSystemUI(toggleActionBarVisibility: Boolean) {
|
|||
|
||||
fun BaseSimpleActivity.addNoMedia(path: String, callback: () -> Unit) {
|
||||
val file = File(path, NOMEDIA)
|
||||
if (file.exists()) {
|
||||
if (getDoesFilePathExist(file.absolutePath)) {
|
||||
callback()
|
||||
return
|
||||
}
|
||||
|
@ -164,12 +164,12 @@ fun BaseSimpleActivity.addNoMedia(path: String, callback: () -> Unit) {
|
|||
|
||||
fun BaseSimpleActivity.removeNoMedia(path: String, callback: (() -> Unit)? = null) {
|
||||
val file = File(path, NOMEDIA)
|
||||
if (!file.exists()) {
|
||||
if (!getDoesFilePathExist(file.absolutePath)) {
|
||||
callback?.invoke()
|
||||
return
|
||||
}
|
||||
|
||||
tryDeleteFileDirItem(file.toFileDirItem(), false, false) {
|
||||
tryDeleteFileDirItem(file.toFileDirItem(applicationContext), false, false) {
|
||||
callback?.invoke()
|
||||
}
|
||||
}
|
||||
|
@ -228,13 +228,47 @@ fun BaseSimpleActivity.tryDeleteFileDirItem(fileDirItem: FileDirItem, allowDelet
|
|||
fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, mediumDao: MediumDao = galleryDB.MediumDao(), callback: ((wasSuccess: Boolean) -> Unit)?) {
|
||||
ensureBackgroundThread {
|
||||
var pathsCnt = paths.size
|
||||
paths.forEach {
|
||||
val file = File(it)
|
||||
val internalFile = File(recycleBinPath, it)
|
||||
val OTGPath = config.OTGPath
|
||||
|
||||
for (source in paths) {
|
||||
if (OTGPath.isNotEmpty() && source.startsWith(OTGPath)) {
|
||||
var inputStream: InputStream? = null
|
||||
var out: OutputStream? = null
|
||||
try {
|
||||
val destination = "$recycleBinPath/$source"
|
||||
val fileDocument = getSomeDocumentFile(source)
|
||||
inputStream = applicationContext.contentResolver.openInputStream(fileDocument?.uri)
|
||||
out = getFileOutputStreamSync(destination, source.getMimeType())
|
||||
|
||||
var copiedSize = 0L
|
||||
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
|
||||
var bytes = inputStream.read(buffer)
|
||||
while (bytes >= 0) {
|
||||
out!!.write(buffer, 0, bytes)
|
||||
copiedSize += bytes
|
||||
bytes = inputStream.read(buffer)
|
||||
}
|
||||
|
||||
out?.flush()
|
||||
|
||||
if (fileDocument?.getItemSize(true) == copiedSize && getDoesFilePathExist(destination)) {
|
||||
mediumDao.updateDeleted("$RECYCLE_BIN$source", System.currentTimeMillis(), source)
|
||||
pathsCnt--
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
showErrorToast(e)
|
||||
return@ensureBackgroundThread
|
||||
} finally {
|
||||
inputStream?.close()
|
||||
out?.close()
|
||||
}
|
||||
} else {
|
||||
val file = File(source)
|
||||
val internalFile = File(recycleBinPath, source)
|
||||
val lastModified = file.lastModified()
|
||||
try {
|
||||
if (file.copyRecursively(internalFile, true)) {
|
||||
mediumDao.updateDeleted("$RECYCLE_BIN$it", System.currentTimeMillis(), it)
|
||||
mediumDao.updateDeleted("$RECYCLE_BIN$source", System.currentTimeMillis(), source)
|
||||
pathsCnt--
|
||||
|
||||
if (config.keepLastModified) {
|
||||
|
@ -243,7 +277,8 @@ fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, mediumDao
|
|||
}
|
||||
} catch (e: Exception) {
|
||||
showErrorToast(e)
|
||||
return@forEach
|
||||
return@ensureBackgroundThread
|
||||
}
|
||||
}
|
||||
}
|
||||
callback?.invoke(pathsCnt == 0)
|
||||
|
@ -271,8 +306,19 @@ fun BaseSimpleActivity.restoreRecycleBinPaths(paths: ArrayList<String>, mediumDa
|
|||
try {
|
||||
out = getFileOutputStreamSync(destination, source.getMimeType())
|
||||
inputStream = getFileInputStreamSync(source)
|
||||
inputStream.copyTo(out!!)
|
||||
if (File(source).length() == File(destination).length()) {
|
||||
|
||||
var copiedSize = 0L
|
||||
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
|
||||
var bytes = inputStream!!.read(buffer)
|
||||
while (bytes >= 0) {
|
||||
out!!.write(buffer, 0, bytes)
|
||||
copiedSize += bytes
|
||||
bytes = inputStream.read(buffer)
|
||||
}
|
||||
|
||||
out?.flush()
|
||||
|
||||
if (File(source).length() == copiedSize) {
|
||||
mediumDao.updateDeleted(destination.removePrefix(recycleBinPath), 0, "$RECYCLE_BIN$destination")
|
||||
}
|
||||
newPaths.add(destination)
|
||||
|
@ -519,7 +565,9 @@ fun BaseSimpleActivity.copyFile(source: String, destination: String) {
|
|||
try {
|
||||
out = getFileOutputStreamSync(destination, source.getMimeType())
|
||||
inputStream = getFileInputStreamSync(source)
|
||||
inputStream.copyTo(out!!)
|
||||
inputStream!!.copyTo(out!!)
|
||||
} catch (e: Exception) {
|
||||
showErrorToast(e)
|
||||
} finally {
|
||||
inputStream?.close()
|
||||
out?.close()
|
||||
|
|
|
@ -366,6 +366,7 @@ fun Context.getNoMediaFolders(callback: (folders: ArrayList<String>) -> Unit) {
|
|||
val selection = "${MediaStore.Files.FileColumns.MEDIA_TYPE} = ? AND ${MediaStore.Files.FileColumns.TITLE} LIKE ?"
|
||||
val selectionArgs = arrayOf(MediaStore.Files.FileColumns.MEDIA_TYPE_NONE.toString(), "%$NOMEDIA%")
|
||||
val sortOrder = "${MediaStore.Files.FileColumns.DATE_MODIFIED} DESC"
|
||||
val OTGPath = config.OTGPath
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
|
@ -374,7 +375,7 @@ fun Context.getNoMediaFolders(callback: (folders: ArrayList<String>) -> Unit) {
|
|||
do {
|
||||
val path = cursor.getStringValue(MediaStore.Files.FileColumns.DATA) ?: continue
|
||||
val noMediaFile = File(path)
|
||||
if (noMediaFile.exists() && noMediaFile.name == NOMEDIA) {
|
||||
if (getDoesFilePathExist(noMediaFile.absolutePath, OTGPath) && noMediaFile.name == NOMEDIA) {
|
||||
folders.add("${noMediaFile.parent}/")
|
||||
}
|
||||
} while (cursor.moveToNext())
|
||||
|
@ -661,9 +662,10 @@ fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImag
|
|||
mediaFetcher.sortMedia(media, config.getFileSorting(pathToUse))
|
||||
val grouped = mediaFetcher.groupMedia(media, pathToUse)
|
||||
callback(grouped.clone() as ArrayList<ThumbnailItem>)
|
||||
val OTGPath = config.OTGPath
|
||||
|
||||
val mediaToDelete = ArrayList<Medium>()
|
||||
media.filter { !File(it.path).exists() }.forEach {
|
||||
media.filter { !getDoesFilePathExist(it.path, OTGPath) }.forEach {
|
||||
if (it.path.startsWith(recycleBinPath)) {
|
||||
deleteDBPath(mediumDao, it.path)
|
||||
} else {
|
||||
|
@ -682,7 +684,8 @@ fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImag
|
|||
|
||||
fun Context.removeInvalidDBDirectories(dirs: ArrayList<Directory>? = null, directoryDao: DirectoryDao = galleryDB.DirectoryDao()) {
|
||||
val dirsToCheck = dirs ?: directoryDao.getAll()
|
||||
dirsToCheck.filter { !it.areFavorites() && !it.isRecycleBin() && !File(it.path).exists() && it.path != config.tempFolderPath }.forEach {
|
||||
val OTGPath = config.OTGPath
|
||||
dirsToCheck.filter { !it.areFavorites() && !it.isRecycleBin() && !getDoesFilePathExist(it.path, OTGPath) && it.path != config.tempFolderPath }.forEach {
|
||||
try {
|
||||
directoryDao.deleteDirPath(it.path)
|
||||
} catch (ignored: Exception) {
|
||||
|
@ -706,6 +709,10 @@ fun Context.updateDBDirectory(directory: Directory, directoryDao: DirectoryDao)
|
|||
}
|
||||
}
|
||||
|
||||
fun Context.getOTGFolderChildren(path: String) = getDocumentFile(path)?.listFiles()
|
||||
|
||||
fun Context.getOTGFolderChildrenNames(path: String) = getOTGFolderChildren(path)?.map { it.name }?.toMutableList()
|
||||
|
||||
fun Context.getFavoritePaths(): ArrayList<String> {
|
||||
return try {
|
||||
galleryDB.MediumDao().getFavoritePaths() as ArrayList<String>
|
||||
|
@ -805,7 +812,7 @@ fun Context.parseFileChannel(path: String, fc: FileChannel, level: Int, start: L
|
|||
|
||||
fun Context.addPathToDB(path: String) {
|
||||
ensureBackgroundThread {
|
||||
if (!File(path).exists()) {
|
||||
if (!getDoesFilePathExist(path)) {
|
||||
return@ensureBackgroundThread
|
||||
}
|
||||
|
||||
|
@ -833,13 +840,18 @@ fun Context.addPathToDB(path: String) {
|
|||
|
||||
fun Context.createDirectoryFromMedia(path: String, curMedia: ArrayList<Medium>, albumCovers: ArrayList<AlbumCover>, hiddenString: String,
|
||||
includedFolders: MutableSet<String>, isSortingAscending: Boolean, getProperFileSize: Boolean): Directory {
|
||||
var thumbnail = curMedia.firstOrNull { File(it.path).exists() }?.path ?: ""
|
||||
val OTGPath = config.OTGPath
|
||||
var thumbnail = curMedia.firstOrNull { getDoesFilePathExist(it.path, OTGPath) }?.path ?: ""
|
||||
albumCovers.forEach {
|
||||
if (it.path == path && File(it.tmb).exists()) {
|
||||
if (it.path == path && getDoesFilePathExist(it.tmb, OTGPath)) {
|
||||
thumbnail = it.tmb
|
||||
}
|
||||
}
|
||||
|
||||
if (config.OTGPath.isNotEmpty() && thumbnail.startsWith(config.OTGPath)) {
|
||||
thumbnail = thumbnail.getOTGPublicPath(applicationContext)
|
||||
}
|
||||
|
||||
val defaultMedium = Medium(0, "", "", "", 0L, 0L, 0L, 0, 0, false, 0L)
|
||||
val firstItem = curMedia.firstOrNull() ?: defaultMedium
|
||||
val lastItem = curMedia.lastOrNull() ?: defaultMedium
|
||||
|
|
|
@ -357,11 +357,11 @@ class PhotoFragment : ViewPagerFragment() {
|
|||
|
||||
private fun loadGif() {
|
||||
try {
|
||||
val path = mMedium.path
|
||||
val source = if (path.startsWith("content://") || path.startsWith("file://")) {
|
||||
InputSource.UriSource(context!!.contentResolver, Uri.parse(path))
|
||||
val pathToLoad = getPathToLoad(mMedium)
|
||||
val source = if (pathToLoad.startsWith("content://") || pathToLoad.startsWith("file://")) {
|
||||
InputSource.UriSource(context!!.contentResolver, Uri.parse(pathToLoad))
|
||||
} else {
|
||||
InputSource.FileSource(path)
|
||||
InputSource.FileSource(pathToLoad)
|
||||
}
|
||||
|
||||
mView.apply {
|
||||
|
@ -444,7 +444,7 @@ class PhotoFragment : ViewPagerFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Exception) {}
|
||||
override fun onError(e: Exception?) {}
|
||||
})
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
|
@ -559,7 +559,7 @@ class PhotoFragment : ViewPagerFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun getFilePathToShow() = if (mMedium.isPortrait()) mCurrentPortraitPhotoPath else mMedium.path
|
||||
private fun getFilePathToShow() = if (mMedium.isPortrait()) mCurrentPortraitPhotoPath else getPathToLoad(mMedium)
|
||||
|
||||
private fun openPanorama() {
|
||||
Intent(context, PanoramaPhotoActivity::class.java).apply {
|
||||
|
|
|
@ -35,7 +35,7 @@ abstract class ViewPagerFragment : Fragment() {
|
|||
|
||||
fun getMediumExtendedDetails(medium: Medium): String {
|
||||
val file = File(medium.path)
|
||||
if (!file.exists()) {
|
||||
if (context?.getDoesFilePathExist(file.absolutePath) == false) {
|
||||
return ""
|
||||
}
|
||||
|
||||
|
@ -81,6 +81,8 @@ abstract class ViewPagerFragment : Fragment() {
|
|||
return details.toString().trim()
|
||||
}
|
||||
|
||||
fun getPathToLoad(medium: Medium) = if (context!!.isPathOnOTG(medium.path)) medium.path.getOTGPublicPath(context!!) else medium.path
|
||||
|
||||
private fun getFileLastModified(file: File): String {
|
||||
val projection = arrayOf(MediaStore.Images.Media.DATE_MODIFIED)
|
||||
val uri = MediaStore.Files.getContentUri("external")
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.simplemobiletools.gallery.pro.helpers
|
|||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.os.Environment
|
||||
import android.provider.BaseColumns
|
||||
import android.provider.MediaStore
|
||||
|
@ -27,8 +28,15 @@ class MediaFetcher(val context: Context) {
|
|||
}
|
||||
|
||||
val curMedia = ArrayList<Medium>()
|
||||
if (context.isPathOnOTG(curPath)) {
|
||||
if (context.hasOTGConnected()) {
|
||||
val newMedia = getMediaOnOTG(curPath, isPickImage, isPickVideo, filterMedia, favoritePaths, getVideoDurations)
|
||||
curMedia.addAll(newMedia)
|
||||
}
|
||||
} else {
|
||||
val newMedia = getMediaInFolder(curPath, isPickImage, isPickVideo, filterMedia, getProperDateTaken, getProperFileSize, favoritePaths, getVideoDurations)
|
||||
curMedia.addAll(newMedia)
|
||||
}
|
||||
|
||||
if (sortMedia) {
|
||||
sortMedia(curMedia, context.config.getFileSorting(curPath))
|
||||
|
@ -39,12 +47,13 @@ class MediaFetcher(val context: Context) {
|
|||
|
||||
fun getFoldersToScan(): ArrayList<String> {
|
||||
return try {
|
||||
val OTGPath = context.config.OTGPath
|
||||
val folders = getLatestFileFolders()
|
||||
folders.addAll(arrayListOf(
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString(),
|
||||
"${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)}/Camera",
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString()
|
||||
).filter { File(it).exists() })
|
||||
).filter { context.getDoesFilePathExist(it, OTGPath) })
|
||||
|
||||
val filterMedia = context.config.filterMedia
|
||||
val uri = MediaStore.Files.getContentUri("external")
|
||||
|
@ -167,7 +176,8 @@ class MediaFetcher(val context: Context) {
|
|||
val foldersToIgnore = arrayListOf("/storage/emulated/legacy")
|
||||
val config = context.config
|
||||
val includedFolders = config.includedFolders
|
||||
var foldersToScan = config.everShownFolders.filter { it == FAVORITES || it == RECYCLE_BIN || File(it).exists() }.toMutableList() as ArrayList
|
||||
val OTGPath = config.OTGPath
|
||||
var foldersToScan = config.everShownFolders.filter { it == FAVORITES || it == RECYCLE_BIN || context.getDoesFilePathExist(it, OTGPath) }.toMutableList() as ArrayList
|
||||
|
||||
cursor.use {
|
||||
if (cursor.moveToFirst()) {
|
||||
|
@ -327,6 +337,72 @@ class MediaFetcher(val context: Context) {
|
|||
return media
|
||||
}
|
||||
|
||||
private fun getMediaOnOTG(folder: String, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int, favoritePaths: ArrayList<String>,
|
||||
getVideoDurations: Boolean): ArrayList<Medium> {
|
||||
val media = ArrayList<Medium>()
|
||||
val files = context.getDocumentFile(folder)?.listFiles() ?: return media
|
||||
val checkFileExistence = context.config.fileLoadingPriority == PRIORITY_VALIDITY
|
||||
val showHidden = context.config.shouldShowHidden
|
||||
val OTGPath = context.config.OTGPath
|
||||
|
||||
for (file in files) {
|
||||
if (shouldStop) {
|
||||
break
|
||||
}
|
||||
|
||||
val filename = file.name ?: continue
|
||||
val isImage = filename.isImageFast()
|
||||
val isVideo = if (isImage) false else filename.isVideoFast()
|
||||
val isGif = if (isImage || isVideo) false else filename.isGif()
|
||||
val isRaw = if (isImage || isVideo || isGif) false else filename.isRawFast()
|
||||
val isSvg = if (isImage || isVideo || isGif || isRaw) false else filename.isSvg()
|
||||
|
||||
if (!isImage && !isVideo && !isGif && !isRaw && !isSvg)
|
||||
continue
|
||||
|
||||
if (isVideo && (isPickImage || filterMedia and TYPE_VIDEOS == 0))
|
||||
continue
|
||||
|
||||
if (isImage && (isPickVideo || filterMedia and TYPE_IMAGES == 0))
|
||||
continue
|
||||
|
||||
if (isGif && filterMedia and TYPE_GIFS == 0)
|
||||
continue
|
||||
|
||||
if (isRaw && filterMedia and TYPE_RAWS == 0)
|
||||
continue
|
||||
|
||||
if (isSvg && filterMedia and TYPE_SVGS == 0)
|
||||
continue
|
||||
|
||||
if (!showHidden && filename.startsWith('.'))
|
||||
continue
|
||||
|
||||
val size = file.length()
|
||||
if (size <= 0L || (checkFileExistence && !context.getDoesFilePathExist(file.uri.toString(), OTGPath)))
|
||||
continue
|
||||
|
||||
val dateTaken = file.lastModified()
|
||||
val dateModified = file.lastModified()
|
||||
|
||||
val type = when {
|
||||
isVideo -> TYPE_VIDEOS
|
||||
isGif -> TYPE_GIFS
|
||||
isRaw -> TYPE_RAWS
|
||||
isSvg -> TYPE_SVGS
|
||||
else -> TYPE_IMAGES
|
||||
}
|
||||
|
||||
val path = Uri.decode(file.uri.toString().replaceFirst("${context.config.OTGTreeUri}/document/${context.config.OTGPartition}%3A", "${context.config.OTGPath}/"))
|
||||
val videoDuration = if (getVideoDurations) path.getVideoDuration() else 0
|
||||
val isFavorite = favoritePaths.contains(path)
|
||||
val medium = Medium(null, filename, path, folder, dateModified, dateTaken, size, type, videoDuration, isFavorite, 0L)
|
||||
media.add(medium)
|
||||
}
|
||||
|
||||
return media
|
||||
}
|
||||
|
||||
private fun getFolderDateTakens(folder: String): HashMap<String, Long> {
|
||||
val projection = arrayOf(
|
||||
MediaStore.Images.Media.DISPLAY_NAME,
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it. -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Navegueu pels vostres records sense interrupcions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Jednoduchá Galerie Pro: Organizér a editor fotografií</string>
|
||||
<string name="app_title">Jednoduchá Galerie Pro - Organizér a editor fotografií</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Billedhåndtering</string>
|
||||
<string name="app_title">Simple Gallery Pro - Billedhåndtering</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -234,7 +234,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Schlichte Galerie Pro: Foto Manager & Editor</string>
|
||||
<string name="app_title">Schlichte Galerie Pro - Foto Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">ΑΠΛΗ ΣΥΛΛΟΓΗ Pro: Διαχείριση & Επεξεργασία</string>
|
||||
<string name="app_title">ΑΠΛΗ ΣΥΛΛΟΓΗ Pro - Διαχείριση & Επεξεργασία</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Ξεφυλλίστε τις αναμνήσεις σας χωρίς διακοπές.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Explore sus recuerdos sin interrupciones.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -233,7 +233,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -236,7 +236,7 @@ Ezzel csak a kiválasztott mappák láthatók, mivel a kizárás és a befoglal
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Pengelola & Penyunting Foto</string>
|
||||
<string name="app_title">Simple Gallery Pro - Pengelola & Penyunting Foto</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Pengelola & Penyunting Foto</string>
|
||||
<string name="app_title">Simple Gallery Pro - Pengelola & Penyunting Foto</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Semplice Galleria Pro: gestore di foto & editor</string>
|
||||
<string name="app_title">Semplice Galleria Pro - gestore di foto & editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -233,7 +233,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -234,7 +234,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Galeria Pro: Gerenciador de Imagens</string>
|
||||
<string name="app_title">Simple Galeria Pro - Gerenciador de Imagens</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Editor e gestor de fotos</string>
|
||||
<string name="app_title">Simple Gallery Pro - Editor e gestor de fotos</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Галерея Pro: управление изображениями</string>
|
||||
<string name="app_title">Галерея Pro - управление изображениями</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Просматривайте свои воспоминания без перерывов.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Jednoduchá galéria Pro: Foto organizér a editor</string>
|
||||
<string name="app_title">Jednoduchá galéria Pro - Foto organizér a editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Prehliadajte svoje spomienky bez prerušenia.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Pregledovalnik fotografij</string>
|
||||
<string name="app_title">Simple Gallery Pro - Pregledovalnik fotografij</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Basit Galeri Pro: Fotoğraf Yönetici & Düzenleyici</string>
|
||||
<string name="app_title">Basit Galeri Pro - Fotoğraf Yönetici & Düzenleyici</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: фотоменеджер і редактор</string>
|
||||
<string name="app_title">Simple Gallery Pro - фотоменеджер і редактор</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -233,7 +233,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">简约图库 Pro: 图片管理 & 编辑</string>
|
||||
<string name="app_title">简约图库 Pro - 图片管理 & 编辑</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">簡易相簿 Pro: 相片管理&編輯器</string>
|
||||
<string name="app_title">簡易相簿 Pro - 相片管理&編輯器</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">簡易相簿 Pro: 相片管理&編輯器</string>
|
||||
<string name="app_title">簡易相簿 Pro - 相片管理&編輯器</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">毫無阻礙地瀏覽您的回憶。</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- App title has to have less than 50 characters. If you cannot squeeze it, just remove a part of it -->
|
||||
<string name="app_title">Simple Gallery Pro: Photo Manager & Editor</string>
|
||||
<string name="app_title">Simple Gallery Pro - Photo Manager & Editor</string>
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Browse your memories without any interruptions.</string>
|
||||
<string name="app_long_description">
|
||||
|
|
|
@ -9,7 +9,7 @@ buildscript {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.1'
|
||||
classpath 'com.android.tools.build:gradle:3.5.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
|
|
@ -1 +1 @@
|
|||
Simple Gallery Pro: Photo Manager & Editor
|
||||
Simple Gallery Pro - Photo Manager & Editor
|
||||
|
|
|
@ -1 +1 @@
|
|||
Jednoduchá Galerie Pro: Organizér a editor fotografií
|
||||
Jednoduchá Galerie Pro - Organizér a editor fotografií
|
||||
|
|
|
@ -1 +1 @@
|
|||
Simple Gallery Pro: Billedhåndtering
|
||||
Simple Gallery Pro - Billedhåndtering
|
||||
|
|
|
@ -1 +1 @@
|
|||
Schlichte Galerie Pro: Foto Manager & Editor
|
||||
Schlichte Galerie Pro - Foto Manager & Editor
|
||||
|
|
|
@ -1 +1 @@
|
|||
ΑΠΛΗ ΣΥΛΛΟΓΗ Pro: Διαχείριση & Επεξεργασία
|
||||
ΑΠΛΗ ΣΥΛΛΟΓΗ Pro - Διαχείριση & Επεξεργασία
|
||||
|
|
|
@ -1 +1 @@
|
|||
Simple Gallery Pro: Photo Manager & Editor
|
||||
Simple Gallery Pro - Photo Manager & Editor
|
||||
|
|
|
@ -1 +1 @@
|
|||
Simple Gallery Pro: Pengelola & Penyunting Foto
|
||||
Simple Gallery Pro - Pengelola & Penyunting Foto
|
||||
|
|
|
@ -1 +1 @@
|
|||
Simple Gallery Pro: Pengelola & Penyunting Foto
|
||||
Simple Gallery Pro - Pengelola & Penyunting Foto
|
||||
|
|
|
@ -1 +1 @@
|
|||
Semplice Galleria Pro: gestore di foto & editor
|
||||
Semplice Galleria Pro - gestore di foto & editor
|
||||
|
|
|
@ -1 +1 @@
|
|||
Simple Gallery Pro: Photo Manager & Editor
|
||||
Simple Gallery Pro - Photo Manager & Editor
|
||||
|
|
|
@ -1 +1 @@
|
|||
Simple Galeria Pro: Gerenciador de Imagens
|
||||
Simple Galeria Pro - Gerenciador de Imagens
|
||||
|
|
|
@ -1 +1 @@
|
|||
Simple Gallery Pro: Editor e gestor de fotos
|
||||
Simple Gallery Pro - Editor e gestor de fotos
|
||||
|
|
|
@ -1 +1 @@
|
|||
Галерея: управление изображениями
|
||||
Галерея Pro - управление изображениями
|
||||
|
|
|
@ -1 +1 @@
|
|||
Jednoduchá galéria Pro: Foto organizér a editor
|
||||
Jednoduchá galéria Pro - Foto organizér a editor
|
||||
|
|
|
@ -1 +1 @@
|
|||
Simple Gallery Pro: Photo Manager & Editor
|
||||
Simple Gallery Pro - Photo Manager & Editor
|
||||
|
|
|
@ -1 +1 @@
|
|||
Basit Galeri Pro: Fotoğraf Yönetici & Düzenleyici
|
||||
Basit Galeri Pro - Fotoğraf Yönetici & Düzenleyici
|
||||
|
|
|
@ -1 +1 @@
|
|||
Simple Gallery Pro: фотоменеджер і редактор
|
||||
Simple Gallery Pro - фотоменеджер і редактор
|
||||
|
|
|
@ -1 +1 @@
|
|||
简约图库 Pro: 图片管理 & 编辑
|
||||
简约图库 Pro - 图片管理 & 编辑
|
||||
|
|
|
@ -1 +1 @@
|
|||
簡易相簿 Pro: 相片管理&編輯器
|
||||
簡易相簿 Pro - 相片管理&編輯器
|
||||
|
|
|
@ -1 +1 @@
|
|||
簡易相簿 Pro: 相片管理&編輯器
|
||||
簡易相簿 Pro - 相片管理&編輯器
|
||||
|
|
Loading…
Reference in a new issue