diff --git a/CHANGELOG.md b/CHANGELOG.md index a76981def..c4d6db2ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,18 @@ Changelog ========== +Version 6.12.0 *(2020-01-28)* +---------------------------- + + * Properly handle sorting by date taken after using "Fix Date Taken values" on the wrong files + * Fixed some issues at copying files, when the source was on an SD card + * Change the way Favorite items are stored, to avoid accidental removal + * Improved video looping (by ForgottenUmbrella) + * Recognize a new type of panoramic photos + * Properly remember last video playback position if the video is paused on exit + * Properly color the top status bar icons at using light primary colors + * Other UX and translation improvements + Version 6.11.8 *(2020-01-19)* ---------------------------- diff --git a/app/build.gradle b/app/build.gradle index 9b9269853..759a1442b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,8 +17,8 @@ android { applicationId "com.simplemobiletools.gallery.pro" minSdkVersion 21 targetSdkVersion 28 - versionCode 288 - versionName "6.11.8" + versionCode 289 + versionName "6.12.0" multiDexEnabled true setProperty("archivesBaseName", "gallery") vectorDrawables.useSupportLibrary = true @@ -69,7 +69,7 @@ android { } dependencies { - implementation 'com.simplemobiletools:commons:5.21.25' + implementation 'com.simplemobiletools:commons:5.21.28' 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' diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MainActivity.kt index 1af9c13d0..7cad1ca04 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MainActivity.kt @@ -36,9 +36,7 @@ import com.simplemobiletools.gallery.pro.dialogs.ChangeViewTypeDialog import com.simplemobiletools.gallery.pro.dialogs.FilterMediaDialog import com.simplemobiletools.gallery.pro.extensions.* import com.simplemobiletools.gallery.pro.helpers.* -import com.simplemobiletools.gallery.pro.interfaces.DirectoryDao import com.simplemobiletools.gallery.pro.interfaces.DirectoryOperationsListener -import com.simplemobiletools.gallery.pro.interfaces.MediumDao import com.simplemobiletools.gallery.pro.jobs.NewPhotoFetcher import com.simplemobiletools.gallery.pro.models.Directory import com.simplemobiletools.gallery.pro.models.Medium @@ -85,17 +83,11 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { private var mStoredTextColor = 0 private var mStoredPrimaryColor = 0 - private lateinit var mMediumDao: MediumDao - private lateinit var mDirectoryDao: DirectoryDao - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) appLaunched(BuildConfig.APPLICATION_ID) - mMediumDao = galleryDB.MediumDao() - mDirectoryDao = galleryDB.DirectoryDao() - if (savedInstanceState == null) { config.temporarilyShowHidden = false config.tempSkipDeleteConfirmation = false @@ -464,7 +456,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { val getImagesOnly = mIsPickImageIntent || mIsGetImageContentIntent val getVideosOnly = mIsPickVideoIntent || mIsGetVideoContentIntent - getCachedDirectories(getVideosOnly, getImagesOnly, mDirectoryDao) { + getCachedDirectories(getVideosOnly, getImagesOnly) { gotDirectories(addTempFolderIfNeeded(it)) } } @@ -569,7 +561,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { val pathsToDelete = ArrayList() itemsToDelete.mapTo(pathsToDelete) { it.path } - movePathsInRecycleBin(pathsToDelete, mMediumDao) { + movePathsInRecycleBin(pathsToDelete) { if (it) { deleteFilteredFileDirItems(itemsToDelete, folders) } else { @@ -590,7 +582,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { ensureBackgroundThread { folders.filter { !getDoesFilePathExist(it.absolutePath, OTGPath) }.forEach { - mDirectoryDao.deleteDirPath(it.absolutePath) + directoryDao.deleteDirPath(it.absolutePath) } if (config.deleteEmptyFolders) { @@ -936,16 +928,16 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { setupAdapter(dirs) // update directories and media files in the local db, delete invalid items - updateDBDirectory(directory, mDirectoryDao) + updateDBDirectory(directory) if (!directory.isRecycleBin()) { - mMediumDao.insertAll(curMedia) + mediaDB.insertAll(curMedia) } - getCachedMedia(directory.path, getVideosOnly, getImagesOnly, mMediumDao) { + getCachedMedia(directory.path, getVideosOnly, getImagesOnly) { it.forEach { if (!curMedia.contains(it)) { val path = (it as? Medium)?.path if (path != null) { - deleteDBPath(mMediumDao, path) + deleteDBPath(path) } } } @@ -955,7 +947,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { if (dirPathsToRemove.isNotEmpty()) { val dirsToRemove = dirs.filter { dirPathsToRemove.contains(it.path) } dirsToRemove.forEach { - mDirectoryDao.deleteDirPath(it.path) + directoryDao.deleteDirPath(it.path) } dirs.removeAll(dirsToRemove) setupAdapter(dirs) @@ -999,9 +991,9 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { dirs.add(newDir) setupAdapter(dirs) try { - mDirectoryDao.insert(newDir) + directoryDao.insert(newDir) if (folder != RECYCLE_BIN) { - mMediumDao.insertAll(newMedia) + mediaDB.insertAll(newMedia) } } catch (ignored: Exception) { } @@ -1156,7 +1148,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { if (config.useRecycleBin) { try { val binFolder = dirs.firstOrNull { it.path == RECYCLE_BIN } - if (binFolder != null && mMediumDao.getDeletedMedia().isEmpty()) { + if (binFolder != null && mediaDB.getDeletedMedia().isEmpty()) { invalidDirs.add(binFolder) } } catch (ignored: Exception) { @@ -1168,7 +1160,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { setupAdapter(dirs) invalidDirs.forEach { try { - mDirectoryDao.deleteDirPath(it.path) + directoryDao.deleteDirPath(it.path) } catch (ignored: Exception) { } } @@ -1218,7 +1210,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { Handler().postDelayed({ ensureBackgroundThread { try { - mMediumDao.deleteOldRecycleBinItems(System.currentTimeMillis() - MONTH_MILLISECONDS) + mediaDB.deleteOldRecycleBinItems(System.currentTimeMillis() - MONTH_MILLISECONDS) } catch (e: Exception) { } } @@ -1283,7 +1275,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { override fun updateDirectories(directories: ArrayList) { ensureBackgroundThread { - storeDirectoryItems(directories, mDirectoryDao) + storeDirectoryItems(directories) removeInvalidDBDirectories() } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MediaActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MediaActivity.kt index 6aa7d5fcd..7f05afad3 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MediaActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MediaActivity.kt @@ -39,9 +39,7 @@ import com.simplemobiletools.gallery.pro.databases.GalleryDatabase import com.simplemobiletools.gallery.pro.dialogs.* import com.simplemobiletools.gallery.pro.extensions.* import com.simplemobiletools.gallery.pro.helpers.* -import com.simplemobiletools.gallery.pro.interfaces.DirectoryDao import com.simplemobiletools.gallery.pro.interfaces.MediaOperationsListener -import com.simplemobiletools.gallery.pro.interfaces.MediumDao import com.simplemobiletools.gallery.pro.models.Medium import com.simplemobiletools.gallery.pro.models.ThumbnailItem import com.simplemobiletools.gallery.pro.models.ThumbnailSection @@ -78,9 +76,6 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener { private var mStoredTextColor = 0 private var mStoredPrimaryColor = 0 - private lateinit var mMediumDao: MediumDao - private lateinit var mDirectoryDao: DirectoryDao - companion object { var mMedia = ArrayList() } @@ -89,9 +84,6 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener { super.onCreate(savedInstanceState) setContentView(R.layout.activity_media) - mMediumDao = galleryDB.MediumDao() - mDirectoryDao = galleryDB.DirectoryDao() - intent.apply { mIsGetImageIntent = getBooleanExtra(GET_IMAGE_INTENT, false) mIsGetVideoIntent = getBooleanExtra(GET_VIDEO_INTENT, false) @@ -495,9 +487,9 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener { private fun restoreAllFiles() { val paths = mMedia.filter { it is Medium }.map { (it as Medium).path } as ArrayList - restoreRecycleBinPaths(paths, mMediumDao) { + restoreRecycleBinPaths(paths) { ensureBackgroundThread { - mDirectoryDao.deleteDirPath(RECYCLE_BIN) + directoryDao.deleteDirPath(RECYCLE_BIN) } finish() } @@ -584,7 +576,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener { if (mLoadedInitialPhotos) { startAsyncTask() } else { - getCachedMedia(mPath, mIsGetVideoIntent, mIsGetImageIntent, mMediumDao) { + getCachedMedia(mPath, mIsGetVideoIntent, mIsGetImageIntent) { if (it.isEmpty()) { runOnUiThread { media_refresh_layout.isRefreshing = true @@ -608,7 +600,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener { try { gotMedia(newMedia, false) oldMedia.filter { !newMedia.contains(it) }.mapNotNull { it as? Medium }.filter { !getDoesFilePathExist(it.path) }.forEach { - mMediumDao.deleteMediumPath(it.path) + mediaDB.deleteMediumPath(it.path) } } catch (e: Exception) { } @@ -627,7 +619,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener { if (mPath == FAVORITES) { ensureBackgroundThread { - mDirectoryDao.deleteDirPath(FAVORITES) + directoryDao.deleteDirPath(FAVORITES) } } @@ -641,7 +633,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener { private fun deleteDBDirectory() { ensureBackgroundThread { try { - mDirectoryDao.deleteDirPath(mPath) + directoryDao.deleteDirPath(mPath) } catch (ignored: Exception) { } } @@ -897,7 +889,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener { if (!isFromCache) { val mediaToInsert = (mMedia).filter { it is Medium && it.deletedTS == 0L }.map { it as Medium } try { - mMediumDao.insertAll(mediaToInsert) + mediaDB.insertAll(mediaToInsert) } catch (e: Exception) { } } @@ -913,7 +905,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener { val movingItems = resources.getQuantityString(R.plurals.moving_items_into_bin, filtered.size, filtered.size) toast(movingItems) - movePathsInRecycleBin(filtered.map { it.path } as ArrayList, mMediumDao) { + movePathsInRecycleBin(filtered.map { it.path } as ArrayList) { if (it) { deleteFilteredFiles(filtered) } else { @@ -940,7 +932,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener { val useRecycleBin = config.useRecycleBin filtered.forEach { if (it.path.startsWith(recycleBinPath) || !useRecycleBin) { - deleteDBPath(mMediumDao, it.path) + deleteDBPath(it.path) } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/SearchActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/SearchActivity.kt index 0febbfd0b..2ef59a3bc 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/SearchActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/SearchActivity.kt @@ -315,7 +315,7 @@ class SearchActivity : SimpleActivity(), MediaOperationsListener { val movingItems = resources.getQuantityString(R.plurals.moving_items_into_bin, filtered.size, filtered.size) toast(movingItems) - movePathsInRecycleBin(filtered.map { it.path } as ArrayList, galleryDB.MediumDao()) { + movePathsInRecycleBin(filtered.map { it.path } as ArrayList) { if (it) { deleteFilteredFiles(filtered) } else { @@ -342,7 +342,7 @@ class SearchActivity : SimpleActivity(), MediaOperationsListener { val useRecycleBin = config.useRecycleBin filtered.forEach { if (it.path.startsWith(recycleBinPath) || !useRecycleBin) { - deleteDBPath(galleryDB.MediumDao(), it.path) + deleteDBPath(it.path) } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/SettingsActivity.kt index 0be79e7fe..50133ccf5 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/SettingsActivity.kt @@ -13,10 +13,7 @@ import com.simplemobiletools.commons.models.RadioItem import com.simplemobiletools.gallery.pro.R import com.simplemobiletools.gallery.pro.dialogs.ManageBottomActionsDialog import com.simplemobiletools.gallery.pro.dialogs.ManageExtendedDetailsDialog -import com.simplemobiletools.gallery.pro.extensions.config -import com.simplemobiletools.gallery.pro.extensions.emptyTheRecycleBin -import com.simplemobiletools.gallery.pro.extensions.galleryDB -import com.simplemobiletools.gallery.pro.extensions.showRecycleBinEmptyingDialog +import com.simplemobiletools.gallery.pro.extensions.* import com.simplemobiletools.gallery.pro.helpers.* import com.simplemobiletools.gallery.pro.models.AlbumCover import kotlinx.android.synthetic.main.activity_settings.* @@ -593,7 +590,7 @@ class SettingsActivity : SimpleActivity() { private fun setupEmptyRecycleBin() { ensureBackgroundThread { try { - mRecycleBinContentSize = galleryDB.MediumDao().getDeletedMedia().sumByLong { it.size } + mRecycleBinContentSize = mediaDB.getDeletedMedia().sumByLong { it.size } } catch (ignored: Exception) { } runOnUiThread { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/SplashActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/SplashActivity.kt index 20c9c9387..9d0c0cc79 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/SplashActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/SplashActivity.kt @@ -2,9 +2,42 @@ package com.simplemobiletools.gallery.pro.activities import android.content.Intent import com.simplemobiletools.commons.activities.BaseSplashActivity +import com.simplemobiletools.commons.helpers.ensureBackgroundThread +import com.simplemobiletools.gallery.pro.extensions.config +import com.simplemobiletools.gallery.pro.extensions.favoritesDB +import com.simplemobiletools.gallery.pro.extensions.getFavoriteFromPath +import com.simplemobiletools.gallery.pro.extensions.mediaDB +import com.simplemobiletools.gallery.pro.models.Favorite class SplashActivity : BaseSplashActivity() { override fun initActivity() { + + // check if previously selected favorite items have been properly migrated into the new Favorites table + if (config.wereFavoritesMigrated) { + launchActivity() + } else { + if (config.appRunCount == 0) { + config.wereFavoritesMigrated = true + launchActivity() + } else { + config.wereFavoritesMigrated = true + ensureBackgroundThread { + val favorites = ArrayList() + val favoritePaths = mediaDB.getFavorites().map { it.path }.toMutableList() as ArrayList + favoritePaths.forEach { + favorites.add(getFavoriteFromPath(it)) + } + favoritesDB.insertAll(favorites) + + runOnUiThread { + launchActivity() + } + } + } + } + } + + private fun launchActivity() { startActivity(Intent(this, MainActivity::class.java)) finish() } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/VideoPlayerActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/VideoPlayerActivity.kt index bed9bc018..27839af11 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/VideoPlayerActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/VideoPlayerActivity.kt @@ -214,6 +214,9 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen mExoPlayer = ExoPlayerFactory.newSimpleInstance(applicationContext).apply { seekParameters = SeekParameters.CLOSEST_SYNC audioStreamType = C.STREAM_TYPE_MUSIC + if (config.loopVideos) { + repeatMode = Player.REPEAT_MODE_ONE + } prepare(audioSource) } initExoPlayerListeners() @@ -231,7 +234,13 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen override fun onLoadingChanged(isLoading: Boolean) {} - override fun onPositionDiscontinuity(reason: Int) {} + override fun onPositionDiscontinuity(reason: Int) { + // Reset progress views when video loops. + if (reason == Player.DISCONTINUITY_REASON_PERIOD_TRANSITION) { + video_seekbar.progress = 0 + video_curr_time.text = 0.getFormattedDuration() + } + } override fun onRepeatModeChanged(repeatMode: Int) {} @@ -338,13 +347,9 @@ open class VideoPlayerActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListen clearLastVideoSavedProgress() mCurrTime = (mExoPlayer!!.duration / 1000).toInt() - if (config.loopVideos) { - resumeVideo() - } else { - video_seekbar.progress = video_seekbar.max - video_curr_time.text = mDuration.getFormattedDuration() - pauseVideo() - } + video_seekbar.progress = video_seekbar.max + video_curr_time.text = mDuration.getFormattedDuration() + pauseVideo() } private fun didVideoEnd(): Boolean { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/ViewPagerActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/ViewPagerActivity.kt index 0dc77ed6c..089d3da5d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/ViewPagerActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/ViewPagerActivity.kt @@ -364,8 +364,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View if (intent.action == "com.android.camera.action.REVIEW") { ensureBackgroundThread { - val mediumDao = galleryDB.MediumDao() - if (mediumDao.getMediaFromPath(mPath).isEmpty()) { + if (mediaDB.getMediaFromPath(mPath).isEmpty()) { val type = when { mPath.isVideoFast() -> TYPE_VIDEOS mPath.isGif() -> TYPE_GIFS @@ -375,11 +374,11 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View else -> TYPE_IMAGES } - val isFavorite = mediumDao.isFavorite(mPath) + val isFavorite = favoritesDB.isFavorite(mPath) val duration = if (type == TYPE_VIDEOS) mPath.getVideoDuration() else 0 val ts = System.currentTimeMillis() val medium = Medium(null, mPath.getFilenameFromPath(), mPath, mPath.getParentPath(), ts, ts, File(mPath).length(), type, duration, isFavorite, 0) - mediumDao.insert(medium) + mediaDB.insert(medium) } } } @@ -864,7 +863,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View val medium = getCurrentMedium() ?: return medium.isFavorite = !medium.isFavorite ensureBackgroundThread { - galleryDB.MediumDao().updateFavorite(medium.path, medium.isFavorite) + updateFavorite(medium.path, medium.isFavorite) if (medium.isFavorite) { mFavoritePaths.add(medium.path) } else { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/WidgetConfigureActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/WidgetConfigureActivity.kt index d2e1696bb..3f0c66912 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/WidgetConfigureActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/WidgetConfigureActivity.kt @@ -163,7 +163,7 @@ class WidgetConfigureActivity : SimpleActivity() { } ensureBackgroundThread { - val path = directoryDB.getDirectoryThumbnail(folderPath) + val path = directoryDao.getDirectoryThumbnail(folderPath) if (path != null) { runOnUiThread { loadJpg(path, config_image, config.cropThumbnails) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/adapters/DirectoryAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/adapters/DirectoryAdapter.kt index abc71941e..ec683644d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/adapters/DirectoryAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/adapters/DirectoryAdapter.kt @@ -198,7 +198,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList, mediumDao: MediumDao = galleryDB.MediumDao(), callback: ((wasSuccess: Boolean) -> Unit)?) { +fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList, callback: ((wasSuccess: Boolean) -> Unit)?) { ensureBackgroundThread { var pathsCnt = paths.size val OTGPath = config.OTGPath @@ -261,7 +261,7 @@ fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList, mediumDao out?.flush() if (fileDocument?.getItemSize(true) == copiedSize && getDoesFilePathExist(destination)) { - mediumDao.updateDeleted("$RECYCLE_BIN$source", System.currentTimeMillis(), source) + mediaDB.updateDeleted("$RECYCLE_BIN$source", System.currentTimeMillis(), source) pathsCnt-- } } catch (e: Exception) { @@ -277,7 +277,7 @@ fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList, mediumDao val lastModified = file.lastModified() try { if (file.copyRecursively(internalFile, true)) { - mediumDao.updateDeleted("$RECYCLE_BIN$source", System.currentTimeMillis(), source) + mediaDB.updateDeleted("$RECYCLE_BIN$source", System.currentTimeMillis(), source) pathsCnt-- if (config.keepLastModified) { @@ -295,10 +295,10 @@ fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList, mediumDao } fun BaseSimpleActivity.restoreRecycleBinPath(path: String, callback: () -> Unit) { - restoreRecycleBinPaths(arrayListOf(path), galleryDB.MediumDao(), callback) + restoreRecycleBinPaths(arrayListOf(path), callback) } -fun BaseSimpleActivity.restoreRecycleBinPaths(paths: ArrayList, mediumDao: MediumDao = galleryDB.MediumDao(), callback: () -> Unit) { +fun BaseSimpleActivity.restoreRecycleBinPaths(paths: ArrayList, callback: () -> Unit) { ensureBackgroundThread { val newPaths = ArrayList() for (source in paths) { @@ -328,7 +328,7 @@ fun BaseSimpleActivity.restoreRecycleBinPaths(paths: ArrayList, mediumDa out?.flush() if (File(source).length() == copiedSize) { - mediumDao.updateDeleted(destination.removePrefix(recycleBinPath), 0, "$RECYCLE_BIN$destination") + mediaDB.updateDeleted(destination.removePrefix(recycleBinPath), 0, "$RECYCLE_BIN$destination") } newPaths.add(destination) @@ -357,8 +357,8 @@ fun BaseSimpleActivity.emptyTheRecycleBin(callback: (() -> Unit)? = null) { ensureBackgroundThread { try { recycleBin.deleteRecursively() - galleryDB.MediumDao().clearRecycleBin() - galleryDB.DirectoryDao().deleteRecycleBin() + mediaDB.clearRecycleBin() + directoryDao.deleteRecycleBin() toast(R.string.recycle_bin_emptied) callback?.invoke() } catch (e: Exception) { @@ -413,9 +413,10 @@ fun Activity.fixDateTaken(paths: ArrayList, showToasts: Boolean, hasResc try { var didUpdateFile = false val operations = ArrayList() - val mediumDao = galleryDB.MediumDao() ensureBackgroundThread { + val dateTakens = ArrayList() + for (path in paths) { val dateTime = ExifInterface(path).getAttribute(ExifInterface.TAG_DATETIME_ORIGINAL) ?: ExifInterface(path).getAttribute(ExifInterface.TAG_DATETIME) ?: continue @@ -442,9 +443,11 @@ fun Activity.fixDateTaken(paths: ArrayList, showToasts: Boolean, hasResc operations.clear() } - mediumDao.updateFavoriteDateTaken(path, timestamp) + mediaDB.updateFavoriteDateTaken(path, timestamp) didUpdateFile = true + val dateTaken = DateTaken(null, path, path.getFilenameFromPath(), path.getParentPath(), timestamp, (System.currentTimeMillis() / 1000).toInt()) + dateTakens.add(dateTaken) if (!hasRescanned && getFileDateTaken(path) == 0L) { pathsToRescan.add(path) } @@ -456,6 +459,10 @@ fun Activity.fixDateTaken(paths: ArrayList, showToasts: Boolean, hasResc } if (hasRescanned || pathsToRescan.isEmpty()) { + if (dateTakens.isNotEmpty()) { + dateTakensDB.insertAll(dateTakens) + } + runOnUiThread { if (showToasts) { toast(if (didUpdateFile) R.string.dates_fixed_successfully else R.string.unknown_error_occurred) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/Context.kt index 552b47339..a3d542674 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/Context.kt @@ -25,13 +25,8 @@ import com.simplemobiletools.gallery.pro.activities.SettingsActivity import com.simplemobiletools.gallery.pro.asynctasks.GetMediaAsynctask import com.simplemobiletools.gallery.pro.databases.GalleryDatabase import com.simplemobiletools.gallery.pro.helpers.* -import com.simplemobiletools.gallery.pro.interfaces.DirectoryDao -import com.simplemobiletools.gallery.pro.interfaces.MediumDao -import com.simplemobiletools.gallery.pro.interfaces.WidgetsDao -import com.simplemobiletools.gallery.pro.models.AlbumCover -import com.simplemobiletools.gallery.pro.models.Directory -import com.simplemobiletools.gallery.pro.models.Medium -import com.simplemobiletools.gallery.pro.models.ThumbnailItem +import com.simplemobiletools.gallery.pro.interfaces.* +import com.simplemobiletools.gallery.pro.models.* import com.simplemobiletools.gallery.pro.svg.SvgSoftwareLayerSetter import com.simplemobiletools.gallery.pro.views.MySquareImageView import pl.droidsonroids.gif.GifDrawable @@ -113,11 +108,15 @@ fun Context.launchSettings() { val Context.config: Config get() = Config.newInstance(applicationContext) -val Context.galleryDB: GalleryDatabase get() = GalleryDatabase.getInstance(applicationContext) - val Context.widgetsDB: WidgetsDao get() = GalleryDatabase.getInstance(applicationContext).WidgetsDao() -val Context.directoryDB: DirectoryDao get() = GalleryDatabase.getInstance(applicationContext).DirectoryDao() +val Context.mediaDB: MediumDao get() = GalleryDatabase.getInstance(applicationContext).MediumDao() + +val Context.directoryDao: DirectoryDao get() = GalleryDatabase.getInstance(applicationContext).DirectoryDao() + +val Context.favoritesDB: FavoritesDao get() = GalleryDatabase.getInstance(applicationContext).FavoritesDao() + +val Context.dateTakensDB: DateTakensDao get() = GalleryDatabase.getInstance(applicationContext).DateTakensDao() val Context.recycleBin: File get() = filesDir @@ -400,16 +399,15 @@ fun Context.rescanFolderMediaSync(path: String) { GetMediaAsynctask(applicationContext, path, false, false, false) { ensureBackgroundThread { val newMedia = it - val mediumDao = galleryDB.MediumDao() val media = newMedia.filter { it is Medium } as ArrayList try { - mediumDao.insertAll(media) + mediaDB.insertAll(media) cached.forEach { if (!newMedia.contains(it)) { val mediumPath = (it as? Medium)?.path if (mediumPath != null) { - deleteDBPath(mediumDao, mediumPath) + deleteDBPath(mediumPath) } } } @@ -420,7 +418,7 @@ fun Context.rescanFolderMediaSync(path: String) { } } -fun Context.storeDirectoryItems(items: ArrayList, directoryDao: DirectoryDao) { +fun Context.storeDirectoryItems(items: ArrayList) { ensureBackgroundThread { directoryDao.insertAll(items) } @@ -559,7 +557,7 @@ fun Context.loadSVG(path: String, target: MySquareImageView, cropThumbnails: Boo .into(target) } -fun Context.getCachedDirectories(getVideosOnly: Boolean = false, getImagesOnly: Boolean = false, directoryDao: DirectoryDao = galleryDB.DirectoryDao(), forceShowHidden: Boolean = false, callback: (ArrayList) -> Unit) { +fun Context.getCachedDirectories(getVideosOnly: Boolean = false, getImagesOnly: Boolean = false, forceShowHidden: Boolean = false, callback: (ArrayList) -> Unit) { ensureBackgroundThread { val directories = try { directoryDao.getAll() as ArrayList @@ -602,22 +600,21 @@ fun Context.getCachedDirectories(getVideosOnly: Boolean = false, getImagesOnly: val clone = filteredDirectories.clone() as ArrayList callback(clone.distinctBy { it.path.getDistinctPath() } as ArrayList) - removeInvalidDBDirectories(filteredDirectories, directoryDao) + removeInvalidDBDirectories(filteredDirectories) } } -fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImagesOnly: Boolean = false, mediumDao: MediumDao = galleryDB.MediumDao(), - callback: (ArrayList) -> Unit) { +fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImagesOnly: Boolean = false, callback: (ArrayList) -> Unit) { ensureBackgroundThread { val mediaFetcher = MediaFetcher(this) val foldersToScan = if (path.isEmpty()) mediaFetcher.getFoldersToScan() else arrayListOf(path) var media = ArrayList() if (path == FAVORITES) { - media.addAll(mediumDao.getFavorites()) + media.addAll(mediaDB.getFavorites()) } if (path == RECYCLE_BIN) { - media.addAll(getUpdatedDeletedMedia(mediumDao)) + media.addAll(getUpdatedDeletedMedia()) } if (config.filterMedia and TYPE_PORTRAITS != 0) { @@ -634,7 +631,7 @@ fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImag val shouldShowHidden = config.shouldShowHidden foldersToScan.filter { path.isNotEmpty() || !config.isFolderProtected(it) }.forEach { try { - val currMedia = mediumDao.getMediaFromPath(it) + val currMedia = mediaDB.getMediaFromPath(it) media.addAll(currMedia) } catch (ignored: Exception) { } @@ -667,7 +664,7 @@ fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImag val mediaToDelete = ArrayList() media.filter { !getDoesFilePathExist(it.path, OTGPath) }.forEach { if (it.path.startsWith(recycleBinPath)) { - deleteDBPath(mediumDao, it.path) + deleteDBPath(it.path) } else { mediaToDelete.add(it) } @@ -675,14 +672,18 @@ fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImag try { if (mediaToDelete.isNotEmpty()) { - mediumDao.deleteMedia(*mediaToDelete.toTypedArray()) + mediaDB.deleteMedia(*mediaToDelete.toTypedArray()) + + mediaToDelete.filter { it.isFavorite }.forEach { + favoritesDB.deleteFavoritePath(it.path) + } } } catch (ignored: Exception) { } } } -fun Context.removeInvalidDBDirectories(dirs: ArrayList? = null, directoryDao: DirectoryDao = galleryDB.DirectoryDao()) { +fun Context.removeInvalidDBDirectories(dirs: ArrayList? = null) { val dirsToCheck = dirs ?: directoryDao.getAll() val OTGPath = config.OTGPath dirsToCheck.filter { !it.areFavorites() && !it.isRecycleBin() && !getDoesFilePathExist(it.path, OTGPath) && it.path != config.tempFolderPath }.forEach { @@ -697,12 +698,13 @@ fun Context.updateDBMediaPath(oldPath: String, newPath: String) { val newFilename = newPath.getFilenameFromPath() val newParentPath = newPath.getParentPath() try { - galleryDB.MediumDao().updateMedium(oldPath, newParentPath, newFilename, newPath) + mediaDB.updateMedium(newFilename, newPath, newParentPath, oldPath) + favoritesDB.updateFavorite(newFilename, newPath, newParentPath, oldPath) } catch (ignored: Exception) { } } -fun Context.updateDBDirectory(directory: Directory, directoryDao: DirectoryDao) { +fun Context.updateDBDirectory(directory: Directory) { try { directoryDao.updateDirectory(directory.path, directory.tmb, directory.mediaCnt, directory.modified, directory.taken, directory.size, directory.types) } catch (ignored: Exception) { @@ -715,16 +717,26 @@ fun Context.getOTGFolderChildrenNames(path: String) = getOTGFolderChildren(path) fun Context.getFavoritePaths(): ArrayList { return try { - galleryDB.MediumDao().getFavoritePaths() as ArrayList + favoritesDB.getValidFavoritePaths() as ArrayList } catch (e: Exception) { ArrayList() } } +fun Context.getFavoriteFromPath(path: String) = Favorite(null, path, path.getFilenameFromPath(), path.getParentPath()) + +fun Context.updateFavorite(path: String, isFavorite: Boolean) { + if (isFavorite) { + favoritesDB.insert(getFavoriteFromPath(path)) + } else { + favoritesDB.deleteFavoritePath(path) + } +} + // remove the "recycle_bin" from the file path prefix, replace it with real bin path /data/user... -fun Context.getUpdatedDeletedMedia(mediumDao: MediumDao): ArrayList { +fun Context.getUpdatedDeletedMedia(): ArrayList { val media = try { - mediumDao.getDeletedMedia() as ArrayList + mediaDB.getDeletedMedia() as ArrayList } catch (ignored: Exception) { ArrayList() } @@ -735,9 +747,14 @@ fun Context.getUpdatedDeletedMedia(mediumDao: MediumDao): ArrayList { return media } -fun Context.deleteDBPath(mediumDao: MediumDao, path: String) { +fun Context.deleteDBPath(path: String) { + deleteMediumWithPath(path.replaceFirst(recycleBinPath, RECYCLE_BIN)) +} + +fun Context.deleteMediumWithPath(path: String) { try { - mediumDao.deleteMediumPath(path.replaceFirst(recycleBinPath, RECYCLE_BIN)) + mediaDB.deleteMediumPath(path) + favoritesDB.deleteFavoritePath(path) } catch (ignored: Exception) { } } @@ -826,13 +843,12 @@ fun Context.addPathToDB(path: String) { } try { - val mediumDao = galleryDB.MediumDao() - val isFavorite = mediumDao.isFavorite(path) + val isFavorite = favoritesDB.isFavorite(path) val videoDuration = if (type == TYPE_VIDEOS) path.getVideoDuration() else 0 val medium = Medium(null, path.getFilenameFromPath(), path, path.getParentPath(), System.currentTimeMillis(), System.currentTimeMillis(), File(path).length(), type, videoDuration, isFavorite, 0L) - mediumDao.insert(medium) + mediaDB.insert(medium) } catch (ignored: Exception) { } } @@ -876,7 +892,7 @@ fun Context.updateDirectoryPath(path: String) { val favoritePaths = getFavoritePaths() val curMedia = mediaFetcher.getFilesFrom(path, getImagesOnly, getVideosOnly, getProperDateTaken, getProperFileSize, favoritePaths, false) val directory = createDirectoryFromMedia(path, curMedia, albumCovers, hiddenString, includedFolders, isSortingAscending, getProperFileSize) - updateDBDirectory(directory, galleryDB.DirectoryDao()) + updateDBDirectory(directory) } fun Context.getFileDateTaken(path: String): Long { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/PhotoFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/PhotoFragment.kt index f5cf3f93e..d7555a5b4 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/PhotoFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/PhotoFragment.kt @@ -657,7 +657,9 @@ class PhotoFragment : ViewPagerFragment() { mIsPanorama = try { val inputStream = if (mMedium.path.startsWith("content:/")) context!!.contentResolver.openInputStream(Uri.parse(mMedium.path)) else File(mMedium.path).inputStream() val imageParser = JpegImageParser().getXmpXml(ByteSourceInputStream(inputStream, mMedium.name), HashMap()) - imageParser.contains("GPano:UsePanoramaViewer=\"True\"", true) || imageParser.contains("True", true) + imageParser.contains("GPano:UsePanoramaViewer=\"True\"", true) || + imageParser.contains("True", true) || + imageParser.contains("GPano:FullPanoWidthPixels=") } catch (e: Exception) { false } catch (e: OutOfMemoryError) { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/VideoFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/VideoFragment.kt index 96879d3c1..bc7a69b56 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/VideoFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/fragments/VideoFragment.kt @@ -273,8 +273,12 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S } private fun saveVideoProgress() { - if (!videoEnded() && mExoPlayer != null) { - mConfig.saveLastVideoPosition(mMedium.path, mExoPlayer!!.currentPosition.toInt() / 1000) + if (!videoEnded()) { + if (mExoPlayer != null) { + mConfig.saveLastVideoPosition(mMedium.path, mExoPlayer!!.currentPosition.toInt() / 1000) + } else { + mConfig.saveLastVideoPosition(mMedium.path, mPositionAtPause.toInt() / 1000) + } } } @@ -313,6 +317,9 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S mExoPlayer = ExoPlayerFactory.newSimpleInstance(context) mExoPlayer!!.seekParameters = SeekParameters.CLOSEST_SYNC + if (mConfig.loopVideos) { + mExoPlayer?.repeatMode = Player.REPEAT_MODE_ONE + } val isContentUri = mMedium.path.startsWith("content://") val uri = if (isContentUri) Uri.parse(mMedium.path) else Uri.fromFile(File(mMedium.path)) @@ -346,7 +353,13 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S override fun onLoadingChanged(isLoading: Boolean) {} - override fun onPositionDiscontinuity(reason: Int) {} + override fun onPositionDiscontinuity(reason: Int) { + // Reset progress views when video loops. + if (reason == Player.DISCONTINUITY_REASON_PERIOD_TRANSITION) { + mSeekBar.progress = 0 + mCurrTimeView.text = 0.getFormattedDuration() + } + } override fun onRepeatModeChanged(repeatMode: Int) {} @@ -668,13 +681,9 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S } mCurrTime = (mExoPlayer!!.duration / 1000).toInt() - if (listener?.videoEnded() == false && mConfig.loopVideos) { - playVideo() - } else { - mSeekBar.progress = mSeekBar.max - mCurrTimeView.text = mDuration.getFormattedDuration() - pauseVideo() - } + mSeekBar.progress = mSeekBar.max + mCurrTimeView.text = mDuration.getFormattedDuration() + pauseVideo() } private fun cleanup() { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Config.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Config.kt index 4f8bce7c8..6769ec72d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Config.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Config.kt @@ -494,4 +494,8 @@ class Config(context: Context) : BaseConfig(context) { var editorBrushSize: Float get() = prefs.getFloat(EDITOR_BRUSH_SIZE, 0.05f) set(editorBrushSize) = prefs.edit().putFloat(EDITOR_BRUSH_SIZE, editorBrushSize).apply() + + var wereFavoritesMigrated: Boolean + get() = prefs.getBoolean(WERE_FAVORITES_MIGRATED, false) + set(wereFavoritesMigrated) = prefs.edit().putBoolean(WERE_FAVORITES_MIGRATED, wereFavoritesMigrated).apply() } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Constants.kt index 50ca3f376..9b549de78 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Constants.kt @@ -80,6 +80,7 @@ const val SHOW_THUMBNAIL_FILE_TYPES = "show_thumbnail_file_types" const val EDITOR_BRUSH_COLOR = "editor_brush_color" const val EDITOR_BRUSH_HARDNESS = "editor_brush_hardness" const val EDITOR_BRUSH_SIZE = "editor_brush_size" +const val WERE_FAVORITES_MIGRATED = "were_favorites_migrated" // slideshow const val SLIDESHOW_INTERVAL = "slideshow_interval" diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/MediaFetcher.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/MediaFetcher.kt index 8b625e5e5..8f060f922 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/MediaFetcher.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/MediaFetcher.kt @@ -216,7 +216,7 @@ class MediaFetcher(val context: Context) { val media = ArrayList() val isRecycleBin = folder == RECYCLE_BIN val deletedMedia = if (isRecycleBin) { - context.getUpdatedDeletedMedia(context.galleryDB.MediumDao()) + context.getUpdatedDeletedMedia() } else { ArrayList() } @@ -226,7 +226,7 @@ class MediaFetcher(val context: Context) { val checkFileExistence = config.fileLoadingPriority == PRIORITY_VALIDITY val showHidden = config.shouldShowHidden val showPortraits = filterMedia and TYPE_PORTRAITS != 0 - val dateTakens = if (getProperDateTaken && folder != FAVORITES && !isRecycleBin) getFolderDateTakens(folder) else HashMap() + val dateTakens = if (getProperDateTaken && !isRecycleBin) getFolderDateTakens(folder) else HashMap() val files = when (folder) { FAVORITES -> favoritePaths.filter { showHidden || !it.contains("/.") }.map { File(it) }.toMutableList() as ArrayList @@ -302,7 +302,7 @@ class MediaFetcher(val context: Context) { val videoDuration = if (getVideoDurations && isVideo) path.getVideoDuration() else 0 if (getProperDateTaken) { - dateTaken = dateTakens.remove(filename) ?: lastModified + dateTaken = dateTakens.remove(path) ?: lastModified } val type = when { @@ -390,32 +390,44 @@ class MediaFetcher(val context: Context) { } private fun getFolderDateTakens(folder: String): HashMap { - val projection = arrayOf( - MediaStore.Images.Media.DISPLAY_NAME, - MediaStore.Images.Media.DATE_TAKEN - ) - - val uri = MediaStore.Files.getContentUri("external") - val selection = "${MediaStore.Images.Media.DATA} LIKE ? AND ${MediaStore.Images.Media.DATA} NOT LIKE ?" - val selectionArgs = arrayOf("$folder/%", "$folder/%/%") - val dateTakens = HashMap() - val cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null) - cursor?.use { - if (cursor.moveToFirst()) { - do { - try { - val dateTaken = cursor.getLongValue(MediaStore.Images.Media.DATE_TAKEN) - if (dateTaken != 0L) { - val path = cursor.getStringValue(MediaStore.Images.Media.DISPLAY_NAME) - dateTakens[path] = dateTaken + if (folder != FAVORITES) { + val projection = arrayOf( + MediaStore.Images.Media.DISPLAY_NAME, + MediaStore.Images.Media.DATE_TAKEN + ) + + val uri = MediaStore.Files.getContentUri("external") + val selection = "${MediaStore.Images.Media.DATA} LIKE ? AND ${MediaStore.Images.Media.DATA} NOT LIKE ?" + val selectionArgs = arrayOf("$folder/%", "$folder/%/%") + + val cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null) + cursor?.use { + if (cursor.moveToFirst()) { + do { + try { + val dateTaken = cursor.getLongValue(MediaStore.Images.Media.DATE_TAKEN) + if (dateTaken != 0L) { + val name = cursor.getStringValue(MediaStore.Images.Media.DISPLAY_NAME) + dateTakens["$folder/$name"] = dateTaken + } + } catch (e: Exception) { } - } catch (e: Exception) { - } - } while (cursor.moveToNext()) + } while (cursor.moveToNext()) + } } } + val dateTakenValues = if (folder == FAVORITES) { + context.dateTakensDB.getAllDateTakens() + } else { + context.dateTakensDB.getDateTakensFromPath(folder) + } + + dateTakenValues.forEach { + dateTakens[it.fullPath] = it.taken + } + return dateTakens } @@ -456,7 +468,6 @@ class MediaFetcher(val context: Context) { } fun groupMedia(media: ArrayList, path: String): ArrayList { - val mediumGroups = LinkedHashMap>() val pathToCheck = if (path.isEmpty()) SHOW_ALL else path val currentGrouping = context.config.getFolderGrouping(pathToCheck) if (currentGrouping and GROUP_BY_NONE != 0) { @@ -469,6 +480,7 @@ class MediaFetcher(val context: Context) { return thumbnailItems } + val mediumGroups = LinkedHashMap>() media.forEach { val key = it.getGroupingKey(currentGrouping) if (!mediumGroups.containsKey(key)) { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/MyWidgetProvider.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/MyWidgetProvider.kt index 199d90952..f2e1b3d02 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/MyWidgetProvider.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/MyWidgetProvider.kt @@ -18,7 +18,7 @@ import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.gallery.pro.R import com.simplemobiletools.gallery.pro.activities.MediaActivity import com.simplemobiletools.gallery.pro.extensions.config -import com.simplemobiletools.gallery.pro.extensions.directoryDB +import com.simplemobiletools.gallery.pro.extensions.directoryDao import com.simplemobiletools.gallery.pro.extensions.getFolderNameFromPath import com.simplemobiletools.gallery.pro.extensions.widgetsDB import com.simplemobiletools.gallery.pro.models.Widget @@ -45,7 +45,7 @@ class MyWidgetProvider : AppWidgetProvider() { setText(R.id.widget_folder_name, context.getFolderNameFromPath(it.folderPath)) } - val path = context.directoryDB.getDirectoryThumbnail(it.folderPath) ?: return@forEach + val path = context.directoryDao.getDirectoryThumbnail(it.folderPath) ?: return@forEach val options = RequestOptions() .signature(path.getFileSignature()) .diskCacheStrategy(DiskCacheStrategy.RESOURCE) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/interfaces/DateTakensDAO.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/interfaces/DateTakensDAO.kt deleted file mode 100644 index 107801537..000000000 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/interfaces/DateTakensDAO.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.simplemobiletools.gallery.pro.interfaces - -import androidx.room.Dao - -@Dao -interface DateTakensDAO { - -} diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/interfaces/DateTakensDao.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/interfaces/DateTakensDao.kt new file mode 100644 index 000000000..6f8b609a8 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/interfaces/DateTakensDao.kt @@ -0,0 +1,19 @@ +package com.simplemobiletools.gallery.pro.interfaces + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.simplemobiletools.gallery.pro.models.DateTaken + +@Dao +interface DateTakensDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertAll(dateTakens: List) + + @Query("SELECT full_path, filename, parent_path, date_taken, last_fixed FROM date_takens WHERE parent_path = :path COLLATE NOCASE") + fun getDateTakensFromPath(path: String): List + + @Query("SELECT full_path, filename, parent_path, date_taken, last_fixed FROM date_takens") + fun getAllDateTakens(): List +} diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/interfaces/FavoritesDAO.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/interfaces/FavoritesDAO.kt deleted file mode 100644 index 1d80c3e80..000000000 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/interfaces/FavoritesDAO.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.simplemobiletools.gallery.pro.interfaces - -import androidx.room.Dao - -@Dao -interface FavoritesDAO { - -} diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/interfaces/FavoritesDao.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/interfaces/FavoritesDao.kt new file mode 100644 index 000000000..39a4c4530 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/interfaces/FavoritesDao.kt @@ -0,0 +1,31 @@ +package com.simplemobiletools.gallery.pro.interfaces + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.simplemobiletools.gallery.pro.models.Favorite + +@Dao +interface FavoritesDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insert(favorite: Favorite) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertAll(favorites: List) + + @Query("SELECT favorites.full_path FROM favorites INNER JOIN media ON favorites.full_path = media.full_path WHERE media.deleted_ts = 0") + fun getValidFavoritePaths(): List + + @Query("SELECT id FROM favorites WHERE full_path = :path COLLATE NOCASE") + fun isFavorite(path: String): Boolean + + @Query("UPDATE OR REPLACE favorites SET filename = :newFilename, full_path = :newFullPath, parent_path = :newParentPath WHERE full_path = :oldPath COLLATE NOCASE") + fun updateFavorite(newFilename: String, newFullPath: String, newParentPath: String, oldPath: String) + + @Query("DELETE FROM favorites WHERE full_path = :path COLLATE NOCASE") + fun deleteFavoritePath(path: String) + + @Query("DELETE FROM favorites") + fun clearFavorites() +} diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/interfaces/MediumDao.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/interfaces/MediumDao.kt index 490bd62f4..4affa1995 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/interfaces/MediumDao.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/interfaces/MediumDao.kt @@ -15,15 +15,9 @@ interface MediumDao { @Query("SELECT filename, full_path, parent_path, last_modified, date_taken, size, type, video_duration, is_favorite, deleted_ts FROM media WHERE deleted_ts = 0 AND is_favorite = 1") fun getFavorites(): List - @Query("SELECT full_path FROM media WHERE deleted_ts = 0 AND is_favorite = 1") - fun getFavoritePaths(): List - @Query("SELECT filename, full_path, parent_path, last_modified, date_taken, size, type, video_duration, is_favorite, deleted_ts FROM media WHERE deleted_ts != 0") fun getDeletedMedia(): List - @Query("SELECT is_favorite FROM media WHERE full_path = :path COLLATE NOCASE") - fun isFavorite(path: String): Boolean - @Insert(onConflict = REPLACE) fun insert(medium: Medium) @@ -40,10 +34,7 @@ interface MediumDao { fun deleteOldRecycleBinItems(timestmap: Long) @Query("UPDATE OR REPLACE media SET filename = :newFilename, full_path = :newFullPath, parent_path = :newParentPath WHERE full_path = :oldPath COLLATE NOCASE") - fun updateMedium(oldPath: String, newParentPath: String, newFilename: String, newFullPath: String) - - @Query("UPDATE media SET is_favorite = :isFavorite WHERE full_path = :path COLLATE NOCASE") - fun updateFavorite(path: String, isFavorite: Boolean) + fun updateMedium(newFilename: String, newFullPath: String, newParentPath: String, oldPath: String) @Query("UPDATE OR REPLACE media SET full_path = :newPath, deleted_ts = :deletedTS WHERE full_path = :oldPath COLLATE NOCASE") fun updateDeleted(newPath: String, deletedTS: Long, oldPath: String) @@ -51,9 +42,9 @@ interface MediumDao { @Query("UPDATE media SET date_taken = :dateTaken WHERE full_path = :path COLLATE NOCASE") fun updateFavoriteDateTaken(path: String, dateTaken: Long) - @Query("DELETE FROM media WHERE deleted_ts != 0") - fun clearRecycleBin() - @Query("UPDATE media SET is_favorite = 0") fun clearFavorites() + + @Query("DELETE FROM media WHERE deleted_ts != 0") + fun clearRecycleBin() } diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 2e17b6791..9ed63b894 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -32,7 +32,7 @@ Opravuji… Datumy byly úspěšně opraveny Sdílet verzi se změněnou velikostí - Zdravím,\n\nzdá se, že jse přešli ze staré bezplatné aplikace. Starou aplikaci, která má nahoře v nastavení tlačítko \'Stáhnout Pro verzi\', můžete již odinstalovat.\n\nZtratíte tím pouze soubory v odpadkovém koši, označení oblíbených souborů a také budete muset znovu nastavit položky v nastavení aplikace.\n\nDěkuji! + Zdravím,\n\nzdá se, že jste přešli ze staré bezplatné aplikace. Starou aplikaci, která má nahoře v nastavení tlačítko \'Stáhnout Pro verzi\', můžete již odinstalovat.\n\nZtratíte tím pouze soubory v odpadkovém koši, označení oblíbených souborů a také budete muset znovu nastavit položky v nastavení aplikace.\n\nDěkuji! Přepnout na vyhledávání souborů ve všech viditelných složkách @@ -43,7 +43,7 @@ RAW obrázky SVGčka Portréty - Se zvolenými filtry nebyly nalezeny žádné médiální soubory. + Se zvolenými filtry nebyly nalezeny žádné mediální soubory. Změnit filtry @@ -53,7 +53,7 @@ Spravovat vyloučené složky Tato funkce vyloučí výběr včetně podsložek jen z Jednoduché galerie. V nastavení můžete spravovat vyloučené složky. Chcete vyloučit nadřazenou složku? - Vyloučené složky budou spolu s podsložkami vyloučeny jen z Jednoduché Galerie, ostatní aplikace je nadále uvidí.\n\nPokud je chcete skrýt i před ostatními aplikacemi, použijte funkci Skrýt. + Vyloučené složky budou spolu s podsložkami vyloučeny jen z Jednoduché galerie, ostatní aplikace je nadále uvidí.\n\nPokud je chcete skrýt i před ostatními aplikacemi, použijte funkci Skrýt. Odstranit všechny Odstranit všechny složky ze seznamu vyloučených? Tato operace neodstraní obsah složek. Skryté složky @@ -111,7 +111,7 @@ Prezentace - Interval (vteřin): + Interval (sekund): Zahrnout fotografie Zahrnout videa Zahrnout GIFy @@ -169,10 +169,10 @@ Povolit ovládání jasu vertikálními tahy Povolit ovládání hlasitosti a jasu videí vertikálními tahy Zobrazit počet médií ve složce na hlavní obrazovce - Zobrazit rozšířené vlastnosti přes celoobrazovkové média + Zobrazit rozšířené vlastnosti přes celoobrazovková média Spravovat rozšířené vlastnosti Povolit přibližování jedním prstem v celoobrazovkovém režimu - Povolit okamžité přepínání médií ťuknutím na okraj obrazovky + Povolit okamžité přepínání médií klepnutím na okraj obrazovky Povolit hluboké přibližování obrázků Skrýt rozšířené vlastnosti pokud je skrytá stavová lišta Zobrazit některá akční tlačítka ve spodní části obrazovky @@ -198,7 +198,7 @@ Spodní akční tlačítka - Upravit viditelné spodní akční tlačítka + Upravit viditelná spodní akční tlačítka Přepnutí oblíbenosti Přepnutí viditelnosti souboru @@ -284,17 +284,17 @@ Pipetovatelná barva - Jak nastavím Jednoduchou Galerii jako výchozí galerii? + Jak nastavím Jednoduchou galerii jako výchozí galerii? Nejdříve musíte najít v nastavení zařízení, v sekci Aplikace, současnou výchozí galerii, zvolit tlačítko s textem ve smyslu \"Nastavení výchozího otevírání\" a následně \"Vymazat výchozí nastavení\". - Pokud poté zkusíte otevřít obrázek nebo video, zobrazí se seznam aplikací, kde můžete zvolit Jednoduchou Galerii a nastavit ji jako výchozí. + Pokud poté zkusíte otevřít obrázek nebo video, zobrazí se seznam aplikací, kde můžete zvolit Jednoduchou galerii a nastavit ji jako výchozí. Uzamknul jsem aplikaci heslem, ale zapomněl jsem ho. Co můžu udělat? - Můžete to vyriešǐť 2 způsoby. Můžete aplikaci buď přeinstalovat nebo ji najít v nastavení zařízení a zvolit \"Vymazat data\". Vymažou se pouze nastavení aplikace, nikoliv soubory. + Můžete to vyriešit 2 způsoby. Můžete aplikaci buď přeinstalovat nebo ji najít v nastavení zařízení a zvolit \"Vymazat data\". Vymažou se pouze nastavení aplikace, nikoliv soubory. Jak mohu dosáhnout, aby bylo dané album stále zobrazeno jako první? - Můžete označit danou složku dlouhým podržením a zvolit tlačítko s obrázkem připínáčku, to ji připne na vrch. Můžete připnout i více složek, budou seřazeny podle zvoleného řazení. + Můžete označit danou složku dlouhým podržením a zvolit tlačítko s obrázkem připínáčku, to ji připne nahoru. Můžete připnout i více složek, budou seřazeny podle zvoleného řazení. Jak mohu video posunout vpřed? - Můžete toho dosáhnout buď tažením prstu vodorovně přes okno přehrávače nebo ťuknutím na text aktuální či celkové délky videa, které najdete po bocích indikátoru aktuální pozice. To posune video buď zpět nebo vpřed. + Můžete toho dosáhnout buď tažením prstu vodorovně přes okno přehrávače nebo klepnutím na text aktuální či celkové délky videa, který najdete po bocích indikátoru aktuální pozice. To posune video buď zpět nebo vpřed. Jaký je rozdíl mezi Skrytím a Vyloučením složky? - Zatímco vyloučení zamezí zobrazení složky pouze vrámci Jednoduché Galerie, skrytí ji ukryje vrámci celého systému, tedy to ovlivní i ostatní galerie. Skrytí funguje pomocí vytvoření prázdného souboru \".nomedia\" v daném adresáři, který můžete vymazat i libovolným správcem souborů. + Zatímco vyloučení zamezí zobrazení složky pouze vrámci Jednoduché galerie, skrytí ji ukryje v celém systému, tedy to ovlivní i ostatní galerie. Skrytí funguje pomocí vytvoření prázdného souboru \".nomedia\" v daném adresáři, který můžete vymazat i libovolným správcem souborů. Proč se mi zobrazují složky s obaly hudebních alb, nebo nálepkami? Může se stát, že se vám zobrazí také neobvyklé složky. Můžete je ale jednoduše skrýt jejich vybráním pomocí dlouhého podržení a zvolením Vyloučit. Pokud na následujícím dialogu zvolíte vyloučení nadřazené složky, pravděpodobně budou vyloučeny i ostatní podobné složky. Složka s fotografiemi se mi nezobrazuje nebo ve složce nevidím všechny soubory. Co s tím? @@ -317,13 +317,13 @@ - Jednoduchá Galerie Pro - Organizér a editor fotografií + Jednoduchá galerie Pro - Organizér fotografií - Browse your memories without any interruptions with this photo and video gallery + Prohlížejte svoje vzpomínky bez prerušení s touto foto a video galerií. - Jednoduchá Galerie Pro je vysoce přizpůsobitelná offline galerie. Organizujte a upravujte své fotografie, obnovujte smazané fotografie s funkcí odpadkového koše, chraňte je a skrývejte. Prohlížejte množství různých foto a video formátů včetně RAW, SVG a mnoho dalších. + Jednoduchá galerie Pro je vysoce přizpůsobitelná offline galerie. Organizujte a upravujte své fotografie, obnovujte smazané fotografie s funkcí odpadkového koše, chraňte je a skrývejte. Prohlížejte množství různých foto a video formátů včetně RAW, SVG a mnoho dalších. - Aplikace neobsahuje žádné reklamy ani nepotřebná oprávnění. Tím, že ani nevyžaduje připojení k internetu je vaše soukromí maximálně chráněno. + Aplikace neobsahuje žádné reklamy ani nepotřebná oprávnění. Tím, že ani nevyžaduje připojení k internetu, je vaše soukromí maximálně chráněno. ------------------------------------------------- JEDNODUCHÁ GALERIE PRO – FUNKCE @@ -337,7 +337,7 @@ • Otevírejte mnoho rozličných formátů fotografií a videí (RAW, SVG, GIF, panorama, atd) • Množství intuitivních gest pro jednoduchou úpravu a organizaci souborů • Mnoho různých způsobů filtrování, seskupování a řazení souborů - • Změňte si vzhled Jednoduché galerie pro + • Změňte si vzhled Jednoduché galerie Pro • Dostupná ve 32 jazycích • Označte si oblíbené soubory pro rychlý přístup • Chraňte své fotografie a videa pomocí pinu, vzoru nebo otiskem prstu @@ -350,16 +350,16 @@ … a mnoho dalších! EDITOR OBRÁZKŮ - Jednoduchá Galerie Pro umožňuje snadnou úpravu obrázků. Ořezávejte, překlápějte, otáčejte či měňte jejich velikost. Pokud se cítíte kreativně, můžete také aplikovat filtry nebo do obrázku kreslit! + Jednoduchá galerie Pro umožňuje snadnou úpravu obrázků. Ořezávejte, překlápějte, otáčejte či měňte jejich velikost. Pokud se cítíte kreativně, můžete také aplikovat filtry nebo do obrázku kreslit! PODPORA MNOHA TYPŮ SOUBORŮ - Na rozdíl od některých galerií podporuje Jednoduchá Galerie Pro velké množství různých druhů souborů včetně JPEG, PNG, MP4, MKV, RAW, SVG, panoramatických fotografií a videí. + Na rozdíl od některých galerií podporuje Jednoduchá galerie Pro velké množství různých druhů souborů včetně JPEG, PNG, MP4, MKV, RAW, SVG, panoramatických fotografií a videí. Vysoce upravitelný správce galerie - Od vzhledu až po funkční tlačítka na spodní liště, Jednoduchá Galerie Pro je plně nastavitelná a bude fungovat přesně jak si budete přát. Žádná jiná galerie nenabízí takovou flexibilitu! A díky otevřenému kódu je naše aplikace dostupná ve 32 jazycích! + Od vzhledu až po funkční tlačítka na spodní liště, Jednoduchá galerie Pro je plně nastavitelná a bude fungovat přesně jak si budete přát. Žádná jiná galerie nenabízí takovou flexibilitu! A díky otevřenému kódu je naše aplikace dostupná ve 32 jazycích! OBNOVTE SMAZANÉ FOTOGRAFIE A VIDEA - Smazali jste nechtěně důležitou fotografii nebo video? Žádný strach! Jednoduchá Galerie Pro pro podobné případy nabízí funkci odpadkového koše, odkud smazané fotografie a videa snadno obnovíte. + Smazali jste nechtěně důležitou fotografii nebo video? Žádný strach! Jednoduchá galerie Pro pro podobné případy nabízí funkci odpadkového koše, odkud smazané fotografie a videa snadno obnovíte. CHRAŇTE A SKRÝVEJTE SVÉ FOTOGRAFIE A VIDEA Použitím pinu, vzoru nebo otisku prstu snadno své fotografie, videa či celá alba ochráníte nebo skryjete. Můžete ochránit i spuštění samotné aplikace, nebo některé její funkce. Například můžete zabránit náhodnému smazání souboru bez potvrzení otiskem prstu. diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index e5ab52d0e..f64c4896c 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -203,85 +203,85 @@ Alternar visibilidad de archivo - Custom - Reset - Square - Transform - Filter - None - Adjust - Shadows - Exposure - Highlights - Brightness - Contrast - Saturation - Clarity - Gamma - Blacks - Whites - Temperature - Sharpness - Reset - Focus - None + Personalizado + Reiniciar + Cuadrado + Recortar + Filtros + Ninguno + Ajustes + Sombras + Exposición + Luces + Brillo + Contraste + Saturación + Claridad + Colores + Negros + Blancos + Temperatura + Nitidez + Reiniciar + Enfoque + Ninguno Radial - Linear - Mirrored - Gaussian - Text - Text Options - Text Color - Font - Add - Edit - Straighten - Font + Lineal + Reflejado + Gaussiano + Texto + Opciones de texto + Color de texto + Fuente + Añadir + Editar + Enderezar + Fuente Color - BG Color - Alignment - To Front - Delete - Your text - Brush + Color de fondo + Alineación + Traer al frente + Eliminar + Tu texto + Pincel Color - Size - Hardness - To Front - Delete - Brush Color + Tamaño + Dureza + Traer al frente + Eliminar + Color del pincel Editor - Close Editor? - Do you really want to discard the image? - Yes + ¿Cerrar editor? + ¿Realmente quieres descartar la imagen? + No - Cancel - Accept - Save - Exporting image… - Exporting image %s. - Flip H - Flip V - Undo - Redo - Color Picker - Transparent - White - Gray - Black - Light blue - Blue - Purple - Orchid - Pink - Red - Orange - Gold - Yellow - Olive - Green - Aquamarin - Pipettable color + Cancelar + Aceptar + Guardar + Exportando imagen… + Exportando imagen %s. + Girar Hor + Girar Vert + Deshacer + Rehacer + Cuentagotas + Transparente + Blanco + Gris + Negro + Azul claro + Azul + Púrpura + Orquídea + Rosa + Rojo + Naranja + Dorado + Amarillo + Oliva + Verde + Aguamarina + Color pipetable ¿Cómo puedo hacer que Simple Gallery sea la galería de dispositivos predeterminada? diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 7b34fa90f..f35577c8c 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -32,8 +32,8 @@ 修正中… 撮影日が正常に修正されました リサイズした画像を共有 - Hey,\n\nseems like you upgraded from the old free app. You can now uninstall the old version, which has an \'Upgrade to Pro\' button at the top of the app settings.\n\nYou will only have the Recycle bin items deleted, favorite items unmarked and you will also have to reset your app settings.\n\nThanks! - Switch to file search across all visible folders + あなたは無料版からアップグレードしたと思われます。\"Upgrade to Pro\"というボタンが設定の上部にある無料版はアンインストールすることができます。\n\nごみ箱の中身は削除され、お気に入りもアプリの設定もリセットされることになります。\n\nありがとう! + 表示されているすべてのフォルダで検索 に切り替え 表示する形式 @@ -42,7 +42,7 @@ GIF RAW SVG - Portraits + ポートレイト 条件に該当するメディアがありません。 絞り込み条件を変更 @@ -82,7 +82,7 @@ パス 無効な画像パス 画像の編集に失敗しました - File edited successfully + ファイルの編集に成功しました 画像を編集: 画像エディターが見つかりません ファイルの場所が不明です @@ -180,11 +180,11 @@ 画像のズームを深くする 可能な限り高品質で画像を表示 ごみ箱をメイン画面の最後に表示 - Allow closing the fullscreen view with a down gesture - Allow 1:1 zooming in with two double taps + フルスクリーン表示を下にスワイプするジェスチャーで閉じる + ダブルタップして 1:1 ズームする Always open videos on a separate screen with new horizontal gestures Show a notch if available - Allow rotating images with gestures + ジェスチャーで画像を回転する File loading priority Speed Compromise @@ -203,69 +203,69 @@ 表示/非表示の切替 - Custom - Reset - Square - Transform - Filter - None - Adjust - Shadows - Exposure - Highlights - Brightness - Contrast - Saturation - Clarity - Gamma - Blacks - Whites - Temperature - Sharpness - Reset - Focus - None - Radial - Linear - Mirrored - Gaussian - Text - Text Options - Text Color - Font - Add - Edit - Straighten - Font - Color - BG Color - Alignment - To Front - Delete - Your text - Brush - Color - Size - Hardness - To Front - Delete - Brush Color - Editor - Close Editor? - Do you really want to discard the image? - Yes - No - Cancel - Accept - Save - Exporting image… - Exporting image %s. - Flip H - Flip V - Undo - Redo - Color Picker - Transparent + カスタム + リセット + 正方形 + 変形 + フィルター + なし + 調整 + シャドウ + 露出 + ハイライト + 明るさ + コントラスト + 彩度 + 明瞭度 + ガンマ + 黒レベル + 白レベル + 色温度 + シャープネス + リセット + ぼかし + なし + 円形 + 直線 + ミラー + ガウス + テキスト + テキスト オプション + 文字色 + フォント + 追加 + 編集 + まっすぐにする + フォント + + 背景色 + 配置 + 前面に + 削除 + テキストを入力 + ブラシ + + 太さ + 硬度 + 前面に + 削除 + ブラシの色 + エディター + エディターを閉じますか? + 画像を破棄して閉じますか? + はい + いいえ + キャンセル + 了解 + 保存 + 画像を保存中…… + 画像を保存中 %s. + 水平方向に反転 + 垂直方向に反転 + 元に戻す + やり直し + カラーピッカー + 透明 White Gray Black @@ -366,6 +366,9 @@ Check out the full suite of Simple Tools here: https://www.simplemobiletools.com + + Standalone website of Simple Gallery Pro: + https://www.simplemobiletools.com/gallery Facebook: https://www.facebook.com/simplemobiletools diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index bb700f47a..f04d9abc6 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -317,9 +317,9 @@ - Basit Galeri Pro - Fotoğraf Yönetici & Düzenleyici + Basit Galeri Pro - Fotoğraf Yönetici, Düzenleyici - Browse your memories without any interruptions with this photo and video gallery + Bu fotoğraf ve video galerisinde kesintisiz olarak anılarınıza göz atın Basit Galeri Pro, özelleştirilebilir bir çevrimdışı galeridir. Fotoğraflarınızı düzenleyin ve organize edin, geri dönüşüm kutusuyla silinen dosyaları kurtarın, dosyaları koruyun ve gizleyin ve RAW, SVG ve çok daha fazlası dahil olmak üzere çok çeşitli fotoğraf ve video formatlarını görüntüleyin. diff --git a/fastlane/metadata/android/cs/full_description.txt b/fastlane/metadata/android/cs/full_description.txt index 70cb84ae8..621e34bd7 100644 --- a/fastlane/metadata/android/cs/full_description.txt +++ b/fastlane/metadata/android/cs/full_description.txt @@ -1,6 +1,6 @@ -Jednoduchá Galerie Pro je vysoce přizpůsobitelná offline galerie. Organizujte a upravujte své fotografie, obnovujte smazané fotografie s funkcí odpadkového koše, chraňte je a skrývejte. Prohlížejte množství různých foto a video formátů včetně RAW, SVG a mnoho dalších. +Jednoduchá galerie Pro je vysoce přizpůsobitelná offline galerie. Organizujte a upravujte své fotografie, obnovujte smazané fotografie s funkcí odpadkového koše, chraňte je a skrývejte. Prohlížejte množství různých foto a video formátů včetně RAW, SVG a mnoho dalších. -Aplikace neobsahuje žádné reklamy ani nepotřebná oprávnění. Tím, že ani nevyžaduje připojení k internetu je vaše soukromí maximálně chráněno. +Aplikace neobsahuje žádné reklamy ani nepotřebná oprávnění. Tím, že ani nevyžaduje připojení k internetu, je vaše soukromí maximálně chráněno. ------------------------------------------------- JEDNODUCHÁ GALERIE PRO – FUNKCE @@ -14,7 +14,7 @@ Aplikace neobsahuje žádné reklamy ani nepotřebná oprávnění. Tím, že an • Otevírejte mnoho rozličných formátů fotografií a videí (RAW, SVG, GIF, panorama, atd) • Množství intuitivních gest pro jednoduchou úpravu a organizaci souborů • Mnoho různých způsobů filtrování, seskupování a řazení souborů -• Změňte si vzhled Jednoduché galerie pro +• Změňte si vzhled Jednoduché galerie Pro • Dostupná ve 32 jazycích • Označte si oblíbené soubory pro rychlý přístup • Chraňte své fotografie a videa pomocí pinu, vzoru nebo otiskem prstu @@ -27,16 +27,16 @@ Aplikace neobsahuje žádné reklamy ani nepotřebná oprávnění. Tím, že an … a mnoho dalších! EDITOR OBRÁZKŮ -Jednoduchá Galerie Pro umožňuje snadnou úpravu obrázků. Ořezávejte, překlápějte, otáčejte či měňte jejich velikost. Pokud se cítíte kreativně, můžete také aplikovat filtry nebo do obrázku kreslit! +Jednoduchá galerie Pro umožňuje snadnou úpravu obrázků. Ořezávejte, překlápějte, otáčejte či měňte jejich velikost. Pokud se cítíte kreativně, můžete také aplikovat filtry nebo do obrázku kreslit! PODPORA MNOHA TYPŮ SOUBORŮ -Na rozdíl od některých galerií podporuje Jednoduchá Galerie Pro velké množství různých druhů souborů včetně JPEG, PNG, MP4, MKV, RAW, SVG, panoramatických fotografií a videí. +Na rozdíl od některých galerií podporuje Jednoduchá galerie Pro velké množství různých druhů souborů včetně JPEG, PNG, MP4, MKV, RAW, SVG, panoramatických fotografií a videí. Vysoce upravitelný správce galerie -Od vzhledu až po funkční tlačítka na spodní liště, Jednoduchá Galerie Pro je plně nastavitelná a bude fungovat přesně jak si budete přát. Žádná jiná galerie nenabízí takovou flexibilitu! A díky otevřenému kódu je naše aplikace dostupná ve 32 jazycích! +Od vzhledu až po funkční tlačítka na spodní liště, Jednoduchá galerie Pro je plně nastavitelná a bude fungovat přesně jak si budete přát. Žádná jiná galerie nenabízí takovou flexibilitu! A díky otevřenému kódu je naše aplikace dostupná ve 32 jazycích! OBNOVTE SMAZANÉ FOTOGRAFIE A VIDEA -Smazali jste nechtěně důležitou fotografii nebo video? Žádný strach! Jednoduchá Galerie Pro pro podobné případy nabízí funkci odpadkového koše, odkud smazané fotografie a videa snadno obnovíte. +Smazali jste nechtěně důležitou fotografii nebo video? Žádný strach! Jednoduchá galerie Pro pro podobné případy nabízí funkci odpadkového koše, odkud smazané fotografie a videa snadno obnovíte. CHRAŇTE A SKRÝVEJTE SVÉ FOTOGRAFIE A VIDEA Použitím pinu, vzoru nebo otisku prstu snadno své fotografie, videa či celá alba ochráníte nebo skryjete. Můžete ochránit i spuštění samotné aplikace, nebo některé její funkce. Například můžete zabránit náhodnému smazání souboru bez potvrzení otiskem prstu. diff --git a/fastlane/metadata/android/cs/short_description.txt b/fastlane/metadata/android/cs/short_description.txt index 838a83301..07d253324 100644 --- a/fastlane/metadata/android/cs/short_description.txt +++ b/fastlane/metadata/android/cs/short_description.txt @@ -1 +1 @@ -Prohlížejte své vzpomínky bez přerušení. +Prohlížejte svoje vzpomínky bez prerušení s touto foto a video galerií. diff --git a/fastlane/metadata/android/cs/title.txt b/fastlane/metadata/android/cs/title.txt index 085c5b107..c4d4949ec 100644 --- a/fastlane/metadata/android/cs/title.txt +++ b/fastlane/metadata/android/cs/title.txt @@ -1 +1 @@ -Jednoduchá Galerie Pro - Organizér a editor fotografií +Jednoduchá Galerie Pro - Organizér fotografií diff --git a/fastlane/metadata/android/en-US/changelogs/289.txt b/fastlane/metadata/android/en-US/changelogs/289.txt new file mode 100644 index 000000000..6c4167f4f --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/289.txt @@ -0,0 +1,8 @@ + * Properly handle sorting by date taken after using "Fix Date Taken values" on the wrong files + * Fixed some issues at copying files, when the source was on an SD card + * Change the way Favorite items are stored, to avoid accidental removal + * Improved video looping (by ForgottenUmbrella) + * Recognize a new type of panoramic photos + * Properly remember last video playback position if the video is paused on exit + * Properly color the top status bar icons at using light primary colors + * Other UX and translation improvements diff --git a/fastlane/metadata/android/tr/short_description.txt b/fastlane/metadata/android/tr/short_description.txt index 690c2cc5a..66c5ba9e8 100644 --- a/fastlane/metadata/android/tr/short_description.txt +++ b/fastlane/metadata/android/tr/short_description.txt @@ -1 +1 @@ -Reklamsız çevrimdışı galeri. Fotoğraf & videolarınızı yönetin ve düzenleyin +Bu fotoğraf ve video galerisinde kesintisiz olarak anılarınıza göz atın diff --git a/fastlane/metadata/android/tr/title.txt b/fastlane/metadata/android/tr/title.txt index 7110dfc6f..5a8fd5a45 100644 --- a/fastlane/metadata/android/tr/title.txt +++ b/fastlane/metadata/android/tr/title.txt @@ -1 +1 @@ -Basit Galeri Pro - Fotoğraf Yönetici & Düzenleyici +Basit Galeri Pro - Fotoğraf Yönetici, Düzenleyici