Merge pull request #32 from SimpleMobileTools/master

гзв
This commit is contained in:
solokot 2018-07-04 19:47:35 +03:00 committed by GitHub
commit b371709fa5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
108 changed files with 2891 additions and 621 deletions

View file

@ -1,6 +1,37 @@
Changelog
==========
Version 4.3.2 *(2018-07-04)*
----------------------------
* Added Panorama photo support
* Allow customizing visible fullscreen bottom actions
* Allow forcing portrait/landscape modes at fullscreen view
* Use Exoplayer for playing videos
* Many smaller UX and stability improvements
Version 4.3.1 *(2018-06-28)*
----------------------------
* Adding some crashfixes
Version 4.3.0 *(2018-06-28)*
----------------------------
* Added a Recycle Bin
* Allow grouping media thumbnails by different criteria
* Fixed some calculation glitches around fastscroller
* Change the fullscreen Edit icon to a pencil
* Allow sorting "Show All" separately
* Many smaller stability and UX improvements
Version 4.2.1 *(2018-06-20)*
----------------------------
* Allow selecting Favorite items for easy access
* Fix sorting by Date Taken after files have been copied
* Couple other stability and UX improvements
Version 4.2.0 *(2018-06-18)*
----------------------------

View file

@ -11,8 +11,8 @@ android {
applicationId "com.simplemobiletools.gallery"
minSdkVersion 16
targetSdkVersion 27
versionCode 180
versionName "4.2.0"
versionCode 184
versionName "4.3.2"
multiDexEnabled true
setProperty("archivesBaseName", "gallery")
}
@ -47,17 +47,20 @@ ext {
}
dependencies {
implementation 'com.simplemobiletools:commons:4.2.8'
implementation 'com.simplemobiletools:commons:4.3.27'
implementation 'com.theartofdev.edmodo:android-image-cropper:2.7.0'
implementation 'com.android.support:multidex:1.0.3'
implementation 'it.sephiroth.android.exif:library:1.0.1'
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.12'
implementation 'com.github.chrisbanes:PhotoView:2.1.3'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
implementation 'com.google.android.exoplayer:exoplayer-core:2.8.2'
implementation 'com.google.vr:sdk-panowidget:1.150.0'
implementation 'org.apache.sanselan:sanselan:0.97-incubator'
kapt "android.arch.persistence.room:compiler:1.1.0"
implementation "android.arch.persistence.room:runtime:1.1.0"
annotationProcessor "android.arch.persistence.room:compiler:1.1.0"
kapt "android.arch.persistence.room:compiler:1.1.1"
implementation "android.arch.persistence.room:runtime:1.1.1"
annotationProcessor "android.arch.persistence.room:compiler:1.1.1"
//implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.9.0'
implementation 'com.github.tibbi:subsampling-scale-image-view:v3.10.0-fork'

View file

@ -1,2 +1,3 @@
-keep class com.simplemobiletools.** { *; }
-dontwarn com.simplemobiletools.**
-dontwarn org.apache.**

View file

@ -1,12 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.simplemobiletools.gallery"
android:installLocation="auto">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.SET_WALLPAPER"/>
<uses-sdk
tools:overrideLibrary="com.google.vr.widgets.common, com.google.vr.sdk.widgets.pano"/>
<application
android:name=".App"
android:allowBackup="true"
@ -112,6 +116,11 @@
android:name=".activities.PhotoVideoActivity"
android:configChanges="orientation|keyboardHidden|screenSize"/>
<activity
android:name=".activities.PanoramaActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@style/FullScreenTheme"/>
<activity
android:name=".activities.IncludedFoldersActivity"
android:label="@string/include_folders"

View file

@ -32,6 +32,7 @@ import com.simplemobiletools.gallery.dialogs.FilterMediaDialog
import com.simplemobiletools.gallery.extensions.*
import com.simplemobiletools.gallery.helpers.*
import com.simplemobiletools.gallery.interfaces.DirectoryDao
import com.simplemobiletools.gallery.interfaces.DirectoryOperationsListener
import com.simplemobiletools.gallery.models.AlbumCover
import com.simplemobiletools.gallery.models.Directory
import com.simplemobiletools.gallery.models.Medium
@ -39,7 +40,7 @@ import kotlinx.android.synthetic.main.activity_main.*
import java.io.*
import java.util.*
class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
class MainActivity : SimpleActivity(), DirectoryOperationsListener {
private val PICK_MEDIA = 2
private val PICK_WALLPAPER = 3
private val LAST_MEDIA_CHECK_PERIOD = 3000L
@ -109,6 +110,19 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
if (!config.wasOTGHandled && hasPermission(PERMISSION_WRITE_STORAGE)) {
checkOTGInclusion()
}
if (!config.wereFavoritesPinned) {
config.addPinnedFolders(hashSetOf(FAVORITES))
config.wereFavoritesPinned = true
}
if (!config.wasRecycleBinPinned) {
config.addPinnedFolders(hashSetOf(RECYCLE_BIN))
config.wasRecycleBinPinned = true
config.saveFolderGrouping(SHOW_ALL, GROUP_BY_DATE_TAKEN or GROUP_DESCENDING)
}
checkRecycleBinItems()
}
override fun onStart() {
@ -133,8 +147,9 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
}
if (mStoredScrollHorizontally != config.scrollHorizontally) {
getRecyclerAdapter()?.updateScrollHorizontally(config.viewTypeFolders != VIEW_TYPE_LIST && config.scrollHorizontally)
setupScrollDirection()
mLoadedInitialPhotos = false
directories_grid.adapter = null
getDirectories()
}
if (mStoredTextColor != config.textColor) {
@ -207,8 +222,10 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
menuInflater.inflate(R.menu.menu_main_intent, menu)
} else {
menuInflater.inflate(R.menu.menu_main, menu)
menu.findItem(R.id.increase_column_count).isVisible = config.viewTypeFolders == VIEW_TYPE_GRID && config.dirColumnCnt < MAX_COLUMN_COUNT
menu.findItem(R.id.reduce_column_count).isVisible = config.viewTypeFolders == VIEW_TYPE_GRID && config.dirColumnCnt > 1
menu.apply {
findItem(R.id.increase_column_count).isVisible = config.viewTypeFolders == VIEW_TYPE_GRID && config.dirColumnCnt < MAX_COLUMN_COUNT
findItem(R.id.reduce_column_count).isVisible = config.viewTypeFolders == VIEW_TYPE_GRID && config.dirColumnCnt > 1
}
}
menu.findItem(R.id.temporarily_show_hidden).isVisible = !config.shouldShowHidden
menu.findItem(R.id.stop_showing_hidden).isVisible = config.temporarilyShowHidden
@ -264,7 +281,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
if (newFolder.exists() && newFolder.isDirectory) {
if (newFolder.list()?.isEmpty() == true) {
toast(String.format(getString(R.string.deleting_folder), config.tempFolderPath), Toast.LENGTH_LONG)
tryDeleteFileDirItem(newFolder.toFileDirItem(applicationContext), true)
tryDeleteFileDirItem(newFolder.toFileDirItem(applicationContext), true, true)
}
}
config.tempFolderPath = ""
@ -317,10 +334,13 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
private fun showSortingDialog() {
ChangeSortingDialog(this, true, false) {
directories_grid.adapter = null
if (config.directorySorting and SORT_BY_DATE_MODIFIED > 0 || config.directorySorting and SORT_BY_DATE_TAKEN > 0) {
getDirectories()
} else {
Thread {
gotDirectories(getCurrentlyDisplayedDirs())
}.start()
}
}
}
@ -329,6 +349,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
FilterMediaDialog(this) {
mLoadedInitialPhotos = false
directories_refresh_layout.isRefreshing = true
directories_grid.adapter = null
getDirectories()
}
}
@ -336,7 +357,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
private fun showAllMedia() {
config.showAll = true
Intent(this, MediaActivity::class.java).apply {
putExtra(DIRECTORY, "/")
putExtra(DIRECTORY, "")
if (mIsThirdPartyIntent) {
handleMediaIntent(this)
@ -375,12 +396,37 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
private fun toggleTemporarilyShowHidden(show: Boolean) {
mLoadedInitialPhotos = false
config.temporarilyShowHidden = show
directories_grid.adapter = null
getDirectories()
invalidateOptionsMenu()
}
override fun deleteFolders(folders: ArrayList<File>) {
val fileDirItems = folders.map { FileDirItem(it.absolutePath, it.name, true) } as ArrayList<FileDirItem>
fileDirItems.forEach {
toast(String.format(getString(R.string.deleting_folder), it.name), Toast.LENGTH_LONG)
}
if (config.useRecycleBin) {
val pathsToDelete = ArrayList<String>()
fileDirItems.filter { it.isDirectory }.forEach {
val files = File(it.path).listFiles()
files?.filter { it.absolutePath.isImageVideoGif() }?.mapTo(pathsToDelete) { it.absolutePath }
}
movePathsInRecycleBin(pathsToDelete) {
if (it) {
deleteFilteredFolders(fileDirItems, folders)
} else {
toast(R.string.unknown_error_occurred)
}
}
} else {
deleteFilteredFolders(fileDirItems, folders)
}
}
private fun deleteFilteredFolders(fileDirItems: ArrayList<FileDirItem>, folders: ArrayList<File>) {
deleteFolders(fileDirItems) {
runOnUiThread {
refreshItems()
@ -416,6 +462,32 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
layoutManager.spanCount = config.dirColumnCnt
}
private fun measureRecyclerViewContent(directories: ArrayList<Directory>) {
directories_grid.onGlobalLayout {
if (config.scrollHorizontally) {
calculateContentWidth(directories)
} else {
calculateContentHeight(directories)
}
}
}
private fun calculateContentWidth(directories: ArrayList<Directory>) {
val layoutManager = directories_grid.layoutManager as MyGridLayoutManager
val thumbnailWidth = layoutManager.getChildAt(0)?.width ?: 0
val fullWidth = ((directories.size - 1) / layoutManager.spanCount + 1) * thumbnailWidth
directories_horizontal_fastscroller.setContentWidth(fullWidth)
directories_horizontal_fastscroller.setScrollToX(directories_grid.computeHorizontalScrollOffset())
}
private fun calculateContentHeight(directories: ArrayList<Directory>) {
val layoutManager = directories_grid.layoutManager as MyGridLayoutManager
val thumbnailHeight = layoutManager.getChildAt(0)?.height ?: 0
val fullHeight = ((directories.size - 1) / layoutManager.spanCount + 1) * thumbnailHeight
directories_vertical_fastscroller.setContentHeight(fullHeight)
directories_vertical_fastscroller.setScrollToY(directories_grid.computeVerticalScrollOffset())
}
private fun initZoomListener() {
if (config.viewTypeFolders == VIEW_TYPE_GRID) {
val layoutManager = directories_grid.layoutManager as MyGridLayoutManager
@ -451,25 +523,29 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
FilePickerDialog(this, internalStoragePath, false, config.shouldShowHidden) {
CreateNewFolderDialog(this, it) {
config.tempFolderPath = it
Thread {
gotDirectories(addTempFolderIfNeeded(getCurrentlyDisplayedDirs()))
}.start()
}
}
}
private fun increaseColumnCount() {
directories_vertical_fastscroller.measureRecyclerViewOnRedraw()
directories_horizontal_fastscroller.measureRecyclerViewOnRedraw()
config.dirColumnCnt = ++(directories_grid.layoutManager as MyGridLayoutManager).spanCount
invalidateOptionsMenu()
directories_grid.adapter?.notifyDataSetChanged()
columnCountChanged()
}
private fun reduceColumnCount() {
directories_vertical_fastscroller.measureRecyclerViewOnRedraw()
directories_horizontal_fastscroller.measureRecyclerViewOnRedraw()
config.dirColumnCnt = --(directories_grid.layoutManager as MyGridLayoutManager).spanCount
columnCountChanged()
}
private fun columnCountChanged() {
invalidateOptionsMenu()
directories_grid.adapter?.notifyDataSetChanged()
getRecyclerAdapter()?.dirs?.apply {
measureRecyclerViewContent(this)
}
}
private fun isPickImageIntent(intent: Intent) = isPickIntent(intent) && (hasImageContentData(intent) || isImageType(intent))
@ -585,6 +661,14 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
}
private fun gotDirectories(newDirs: ArrayList<Directory>) {
// if hidden item showing is disabled but all Favorite items are hidden, hide the Favorites folder
if (!config.shouldShowHidden) {
val favoritesFolder = newDirs.firstOrNull { it.areFavorites() }
if (favoritesFolder != null && favoritesFolder.tmb.getFilenameFromPath().startsWith('.')) {
newDirs.remove(favoritesFolder)
}
}
val dirs = getSortedDirectories(newDirs)
var isPlaceholderVisible = dirs.isEmpty()
@ -598,7 +682,6 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
}
// cached folders have been loaded, recheck folders one by one starting with the first displayed
Thread {
val mediaFetcher = MediaFetcher(applicationContext)
val getImagesOnly = mIsPickImageIntent || mIsGetImageContentIntent
val getVideosOnly = mIsPickVideoIntent || mIsGetVideoContentIntent
@ -639,19 +722,26 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
// update directories and media files in the local db, delete invalid items
updateDBDirectory(directory)
if (!directory.isRecycleBin()) {
mediumDao.insertAll(curMedia)
}
getCachedMedia(directory.path, getVideosOnly, getImagesOnly) {
it.forEach {
if (!curMedia.contains(it)) {
mediumDao.deleteMediumPath(it.path)
val path = (it as? Medium)?.path
if (path != null) {
mediumDao.deleteMediumPath(path)
}
}
}
}
} catch (ignored: ConcurrentModificationException) {
}
} catch (ignored: Exception) {
}
val foldersToScan = mediaFetcher.getFoldersToScan()
foldersToScan.add(FAVORITES)
foldersToScan.add(RECYCLE_BIN)
dirs.forEach {
foldersToScan.remove(it.path)
}
@ -676,8 +766,10 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
dirs.add(newDir)
showSortedDirs(dirs)
directoryDao.insert(newDir)
if (folder != RECYCLE_BIN) {
mediumDao.insertAll(newMedia)
}
}
mIsGettingDirs = false
mLoadedInitialPhotos = true
@ -685,11 +777,18 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
runOnUiThread {
directories_refresh_layout.isRefreshing = false
directories_vertical_fastscroller.measureRecyclerView()
checkPlaceholderVisibility(dirs)
}
checkInvalidDirectories(dirs, directoryDao)
}.start()
val everShownFolders = config.everShownFolders as HashSet
dirs.mapTo(everShownFolders) { it.path }
try {
config.everShownFolders = everShownFolders
} catch (e: Exception) {
config.everShownFolders = HashSet()
}
}
private fun checkPlaceholderVisibility(dirs: ArrayList<Directory>) {
@ -703,7 +802,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
sortedDirs = sortedDirs.distinctBy { it.path.getDistinctPath() } as ArrayList<Directory>
runOnUiThread {
(directories_grid.adapter as DirectoryAdapter).updateDirs(sortedDirs)
(directories_grid.adapter as? DirectoryAdapter)?.updateDirs(sortedDirs)
}
}
@ -721,7 +820,11 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
}
val mediaTypes = curMedia.getDirMediaTypes()
val dirName = checkAppendingHidden(path, hiddenString, includedFolders)
val dirName = when (path) {
FAVORITES -> getString(R.string.favorites)
RECYCLE_BIN -> getString(R.string.recycle_bin)
else -> checkAppendingHidden(path, hiddenString, includedFolders)
}
val firstItem = curMedia.first()
val lastItem = curMedia.last()
@ -733,10 +836,11 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
private fun setupAdapter(dirs: ArrayList<Directory>) {
val currAdapter = directories_grid.adapter
val directories = dirs.clone() as ArrayList<Directory>
if (currAdapter == null) {
initZoomListener()
val fastscroller = if (config.scrollHorizontally) directories_horizontal_fastscroller else directories_vertical_fastscroller
DirectoryAdapter(this, dirs, this, directories_grid, isPickIntent(intent) || isGetAnyContentIntent(intent), fastscroller) {
DirectoryAdapter(this, directories, this, directories_grid, isPickIntent(intent) || isGetAnyContentIntent(intent), fastscroller) {
val path = (it as Directory).path
if (path != config.tempFolderPath) {
itemClicked(path)
@ -746,15 +850,17 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
directories_grid.adapter = this
}
} else {
(currAdapter as DirectoryAdapter).updateDirs(dirs)
(currAdapter as DirectoryAdapter).updateDirs(directories)
}
getRecyclerAdapter()?.dirs?.apply {
measureRecyclerViewContent(this)
}
setupScrollDirection()
}
private fun setupScrollDirection() {
val allowHorizontalScroll = config.scrollHorizontally && config.viewTypeFolders == VIEW_TYPE_GRID
directories_vertical_fastscroller.isHorizontal = false
directories_vertical_fastscroller.beGoneIf(allowHorizontalScroll)
@ -776,7 +882,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
private fun checkInvalidDirectories(dirs: ArrayList<Directory>, directoryDao: DirectoryDao) {
val invalidDirs = ArrayList<Directory>()
dirs.forEach {
dirs.filter { !it.areFavorites() && !it.isRecycleBin() }.forEach {
if (!getDoesFilePathExist(it.path)) {
invalidDirs.add(it)
} else if (it.path != config.tempFolderPath) {
@ -788,6 +894,20 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
}
}
if (getFavoritePaths().isEmpty()) {
val favoritesFolder = dirs.firstOrNull { it.areFavorites() }
if (favoritesFolder != null) {
invalidDirs.add(favoritesFolder)
}
}
if (config.useRecycleBin) {
val binFolder = dirs.firstOrNull { it.path == RECYCLE_BIN }
if (binFolder != null && galleryDB.MediumDao().getDeletedMedia().isEmpty()) {
invalidDirs.add(binFolder)
}
}
if (invalidDirs.isNotEmpty()) {
dirs.removeAll(invalidDirs)
showSortedDirs(dirs)
@ -833,12 +953,28 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
}, LAST_MEDIA_CHECK_PERIOD)
}
private fun checkRecycleBinItems() {
if (config.useRecycleBin) {
Thread {
val mediumDao = galleryDB.MediumDao()
val deletedMedia = mediumDao.getDeletedMedia()
deletedMedia.forEach {
if (System.currentTimeMillis() > it.deletedTS + MONTH_MILLISECONDS) {
mediumDao.deleteMediumPath(it.path)
}
}
}.start()
}
}
override fun refreshItems() {
getDirectories()
}
override fun recheckPinnedFolders() {
Thread {
gotDirectories(movePinnedDirectoriesToFront(getCurrentlyDisplayedDirs()))
}.start()
}
override fun updateDirectories(directories: ArrayList<Directory>) {
@ -896,6 +1032,9 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
add(Release(177, R.string.release_177))
add(Release(178, R.string.release_178))
add(Release(180, R.string.release_180))
add(Release(181, R.string.release_181))
add(Release(182, R.string.release_182))
add(Release(184, R.string.release_184))
checkWhatsNew(this, BuildConfig.VERSION_CODE)
}
}

View file

@ -33,18 +33,22 @@ import com.simplemobiletools.commons.views.MyRecyclerView
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.adapters.MediaAdapter
import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask
import com.simplemobiletools.gallery.dialogs.ChangeGroupingDialog
import com.simplemobiletools.gallery.dialogs.ChangeSortingDialog
import com.simplemobiletools.gallery.dialogs.ExcludeFolderDialog
import com.simplemobiletools.gallery.dialogs.FilterMediaDialog
import com.simplemobiletools.gallery.extensions.*
import com.simplemobiletools.gallery.helpers.*
import com.simplemobiletools.gallery.interfaces.MediaOperationsListener
import com.simplemobiletools.gallery.models.Medium
import com.simplemobiletools.gallery.models.ThumbnailItem
import com.simplemobiletools.gallery.models.ThumbnailSection
import kotlinx.android.synthetic.main.activity_media.*
import java.io.File
import java.io.IOException
import java.util.*
class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
class MediaActivity : SimpleActivity(), MediaOperationsListener {
private val LAST_MEDIA_CHECK_PERIOD = 3000L
private var mPath = ""
@ -72,7 +76,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
private var mStoredPrimaryColor = 0
companion object {
var mMedia = ArrayList<Medium>()
var mMedia = ArrayList<ThumbnailItem>()
}
override fun onCreate(savedInstanceState: Bundle?) {
@ -121,8 +125,9 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
}
if (mStoredScrollHorizontally != config.scrollHorizontally) {
getMediaAdapter()?.updateScrollHorizontally(config.viewTypeFiles != VIEW_TYPE_LIST || !config.scrollHorizontally)
setupScrollDirection()
mLoadedInitialPhotos = false
media_grid.adapter = null
getMedia()
}
if (mStoredTextColor != config.textColor) {
@ -188,9 +193,15 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
val isFolderHidden = File(mPath).containsNoMedia()
menu.apply {
findItem(R.id.hide_folder).isVisible = !isFolderHidden && !mShowAll
findItem(R.id.unhide_folder).isVisible = isFolderHidden && !mShowAll
findItem(R.id.exclude_folder).isVisible = !mShowAll
findItem(R.id.group).isVisible = !config.scrollHorizontally
findItem(R.id.hide_folder).isVisible = !isFolderHidden && !mShowAll && mPath != FAVORITES && mPath != RECYCLE_BIN
findItem(R.id.unhide_folder).isVisible = isFolderHidden && !mShowAll && mPath != FAVORITES && mPath != RECYCLE_BIN
findItem(R.id.exclude_folder).isVisible = !mShowAll && mPath != FAVORITES && mPath != RECYCLE_BIN
findItem(R.id.empty_recycle_bin).isVisible = mPath == RECYCLE_BIN
findItem(R.id.empty_disable_recycle_bin).isVisible = mPath == RECYCLE_BIN
findItem(R.id.restore_all_files).isVisible = mPath == RECYCLE_BIN
findItem(R.id.folder_view).isVisible = mShowAll
findItem(R.id.open_camera).isVisible = mShowAll
@ -213,10 +224,14 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
when (item.itemId) {
R.id.sort -> showSortingDialog()
R.id.filter -> showFilterMediaDialog()
R.id.empty_recycle_bin -> emptyRecycleBin()
R.id.empty_disable_recycle_bin -> emptyAndDisableRecycleBin()
R.id.restore_all_files -> restoreAllFiles()
R.id.toggle_filename -> toggleFilenameVisibility()
R.id.open_camera -> launchCamera()
R.id.folder_view -> switchToFolderView()
R.id.change_view_type -> changeViewType()
R.id.group -> showGroupByDialog()
R.id.hide_folder -> tryHideFolder()
R.id.unhide_folder -> unhideFolder()
R.id.exclude_folder -> tryExcludeFolder()
@ -268,9 +283,13 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
return true
}
// this triggers on device rotation too, avoid doing anything
override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
if (mIsSearchOpen) {
mIsSearchOpen = false
media_refresh_layout.isEnabled = config.enablePullToRefresh
searchQueryChanged("")
}
return true
}
})
@ -278,10 +297,12 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
private fun searchQueryChanged(text: String) {
Thread {
val filtered = mMedia.filter { it.name.contains(text, true) } as ArrayList
filtered.sortBy { !it.name.startsWith(text, true) }
val filtered = mMedia.filter { it is Medium && it.name.contains(text, true) } as ArrayList
filtered.sortBy { it is Medium && !it.name.startsWith(text, true) }
val grouped = MediaFetcher(applicationContext).groupMedia(filtered as ArrayList<Medium>, mPath)
runOnUiThread {
getMediaAdapter()?.updateMedia(filtered)
getMediaAdapter()?.updateMedia(grouped)
measureRecyclerViewContent(grouped)
}
}.start()
}
@ -290,6 +311,8 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
handlePermission(PERMISSION_WRITE_STORAGE) {
if (it) {
val dirName = when {
mPath == FAVORITES -> getString(R.string.favorites)
mPath == RECYCLE_BIN -> getString(R.string.recycle_bin)
mPath == OTG_PATH -> getString(R.string.otg)
mPath.startsWith(OTG_PATH) -> mPath.trimEnd('/').substringAfterLast('/')
else -> getHumanizedFilename(mPath)
@ -316,14 +339,19 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
initZoomListener()
val fastscroller = if (config.scrollHorizontally) media_horizontal_fastscroller else media_vertical_fastscroller
MediaAdapter(this, mMedia, this, mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent, mAllowPickingMultiple, media_grid, fastscroller) {
itemClicked((it as Medium).path)
if (it is Medium) {
itemClicked(it.path)
}
}.apply {
setupZoomListener(mZoomListener)
media_grid.adapter = this
}
setupLayoutManager()
} else {
(currAdapter as MediaAdapter).updateMedia(mMedia)
}
measureRecyclerViewContent(mMedia)
setupScrollDirection()
}
@ -335,8 +363,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
media_horizontal_fastscroller.isHorizontal = true
media_horizontal_fastscroller.beVisibleIf(allowHorizontalScroll)
val sorting = config.getFileSorting(mPath)
val sorting = config.getFileSorting(if (mShowAll) SHOW_ALL else mPath)
if (allowHorizontalScroll) {
media_horizontal_fastscroller.allowBubbleDisplay = config.showInfoBubble
media_horizontal_fastscroller.setViews(media_grid, media_refresh_layout) {
@ -350,11 +377,19 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
}
}
private fun getBubbleTextItem(index: Int, sorting: Int) = getMediaAdapter()?.media?.getOrNull(index)?.getBubbleText(sorting) ?: ""
private fun getBubbleTextItem(index: Int, sorting: Int): String {
var realIndex = index
val mediaAdapter = getMediaAdapter()
if (mediaAdapter?.isASectionTitle(index) == true) {
realIndex++
}
return mediaAdapter?.getItemBubbleText(realIndex, sorting) ?: ""
}
private fun checkLastMediaChanged() {
if (isActivityDestroyed())
if (isActivityDestroyed()) {
return
}
mLastMediaHandler.removeCallbacksAndMessages(null)
mLastMediaHandler.postDelayed({
@ -375,8 +410,9 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
}
private fun showSortingDialog() {
ChangeSortingDialog(this, false, !config.showAll, mPath) {
ChangeSortingDialog(this, false, true, mPath) {
mLoadedInitialPhotos = false
media_grid.adapter = null
getMedia()
}
}
@ -385,10 +421,37 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
FilterMediaDialog(this) {
mLoadedInitialPhotos = false
media_refresh_layout.isRefreshing = true
media_grid.adapter = null
getMedia()
}
}
private fun emptyRecycleBin() {
showRecycleBinEmptyingDialog {
emptyTheRecycleBin {
finish()
}
}
}
private fun emptyAndDisableRecycleBin() {
showRecycleBinEmptyingDialog {
emptyAndDisableTheRecycleBin {
finish()
}
}
}
private fun restoreAllFiles() {
val paths = mMedia.filter { it is Medium }.map { (it as Medium).path } as ArrayList<String>
restoreRecycleBinPaths(paths) {
Thread {
galleryDB.DirectoryDao().deleteDirPath(RECYCLE_BIN)
}.start()
finish()
}
}
private fun toggleFilenameVisibility() {
config.displayFileNames = !config.displayFileNames
getMediaAdapter()?.updateDisplayFilenames(config.displayFileNames)
@ -414,6 +477,14 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
}
}
private fun showGroupByDialog() {
ChangeGroupingDialog(this, mPath) {
mLoadedInitialPhotos = false
media_grid.adapter = null
getMedia()
}
}
private fun tryHideFolder() {
if (config.wasHideFolderTooltipShown) {
hideFolder()
@ -454,7 +525,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
private fun deleteDirectoryIfEmpty() {
val fileDirItem = FileDirItem(mPath, mPath.getFilenameFromPath())
if (config.deleteEmptyFolders && !fileDirItem.isDownloadsFolder() && fileDirItem.isDirectory && fileDirItem.getProperFileCount(applicationContext, true) == 0) {
tryDeleteFileDirItem(fileDirItem, true)
tryDeleteFileDirItem(fileDirItem, true, true)
}
}
@ -473,15 +544,22 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
} else {
gotMedia(it, true)
}
startAsyncTask()
}
} else {
media_refresh_layout.isRefreshing = true
startAsyncTask()
}
mLoadedInitialPhotos = true
}
private fun startAsyncTask() {
mCurrAsyncTask?.stopFetching()
mCurrAsyncTask = GetMediaAsynctask(applicationContext, mPath, mIsGetImageIntent, mIsGetVideoIntent, mShowAll) {
Thread {
gotMedia(it)
}.start()
}
mCurrAsyncTask!!.execute()
@ -489,8 +567,10 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
private fun isDirEmpty(): Boolean {
return if (mMedia.size <= 0 && config.filterMedia > 0) {
if (mPath != FAVORITES && mPath != RECYCLE_BIN) {
deleteDirectoryIfEmpty()
deleteDBDirectory()
}
finish()
true
} else {
@ -540,6 +620,62 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
}
layoutManager.spanCount = config.mediaColumnCnt
val adapter = getMediaAdapter()
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return if (adapter?.isASectionTitle(position) == true) {
layoutManager.spanCount
} else {
1
}
}
}
}
private fun measureRecyclerViewContent(media: ArrayList<ThumbnailItem>) {
media_grid.onGlobalLayout {
if (config.scrollHorizontally) {
calculateContentWidth(media)
} else {
calculateContentHeight(media)
}
}
}
private fun calculateContentWidth(media: ArrayList<ThumbnailItem>) {
val layoutManager = media_grid.layoutManager as MyGridLayoutManager
val thumbnailWidth = layoutManager.getChildAt(0)?.width ?: 0
val fullWidth = ((media.size - 1) / layoutManager.spanCount + 1) * thumbnailWidth
media_horizontal_fastscroller.setContentWidth(fullWidth)
media_horizontal_fastscroller.setScrollToX(media_grid.computeHorizontalScrollOffset())
}
private fun calculateContentHeight(media: ArrayList<ThumbnailItem>) {
val layoutManager = media_grid.layoutManager as MyGridLayoutManager
val pathToCheck = if (mPath.isEmpty()) SHOW_ALL else mPath
val hasSections = config.getFolderGrouping(pathToCheck) and GROUP_BY_NONE == 0 && !config.scrollHorizontally
val sectionTitleHeight = if (hasSections) layoutManager.getChildAt(0)?.height ?: 0 else 0
val thumbnailHeight = if (hasSections) layoutManager.getChildAt(1)?.height ?: 0 else layoutManager.getChildAt(0)?.height
?: 0
var fullHeight = 0
var curSectionItems = 0
media.forEach {
if (it is ThumbnailSection) {
fullHeight += sectionTitleHeight
if (curSectionItems != 0) {
val rows = ((curSectionItems - 1) / layoutManager.spanCount + 1)
fullHeight += rows * thumbnailHeight
}
curSectionItems = 0
} else {
curSectionItems++
}
}
fullHeight += ((curSectionItems - 1) / layoutManager.spanCount + 1) * thumbnailHeight
media_vertical_fastscroller.setContentHeight(fullHeight)
media_vertical_fastscroller.setScrollToY(media_grid.computeVerticalScrollOffset())
}
private fun initZoomListener() {
@ -574,19 +710,19 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
}
private fun increaseColumnCount() {
media_vertical_fastscroller.measureRecyclerViewOnRedraw()
media_horizontal_fastscroller.measureRecyclerViewOnRedraw()
config.mediaColumnCnt = ++(media_grid.layoutManager as MyGridLayoutManager).spanCount
invalidateOptionsMenu()
media_grid.adapter?.notifyDataSetChanged()
columnCountChanged()
}
private fun reduceColumnCount() {
media_vertical_fastscroller.measureRecyclerViewOnRedraw()
media_horizontal_fastscroller.measureRecyclerViewOnRedraw()
config.mediaColumnCnt = --(media_grid.layoutManager as MyGridLayoutManager).spanCount
columnCountChanged()
}
private fun columnCountChanged() {
invalidateOptionsMenu()
media_grid.adapter?.notifyDataSetChanged()
measureRecyclerViewContent(mMedia)
}
private fun isSetWallpaperIntent() = intent.getBooleanExtra(SET_WALLPAPER_INTENT, false)
@ -642,22 +778,15 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
Intent(this, ViewPagerActivity::class.java).apply {
putExtra(PATH, path)
putExtra(SHOW_ALL, mShowAll)
putExtra(SHOW_FAVORITES, mPath == FAVORITES)
putExtra(SHOW_RECYCLE_BIN, mPath == RECYCLE_BIN)
startActivity(this)
}
}
}
}
private fun gotMedia(media: ArrayList<Medium>, isFromCache: Boolean = false) {
val mediaToInsert = media.clone() as ArrayList<Medium>
Thread {
mLatestMediaId = getLatestMediaId()
mLatestMediaDateId = getLatestMediaByDateId()
if (!isFromCache) {
galleryDB.MediumDao().insertAll(mediaToInsert)
}
}.start()
private fun gotMedia(media: ArrayList<ThumbnailItem>, isFromCache: Boolean = false) {
mIsGettingMedia = false
checkLastMediaChanged()
mMedia = media
@ -671,26 +800,52 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
val allowHorizontalScroll = config.scrollHorizontally && config.viewTypeFiles == VIEW_TYPE_GRID
media_vertical_fastscroller.beVisibleIf(media_grid.isVisible() && !allowHorizontalScroll)
media_horizontal_fastscroller.beVisibleIf(media_grid.isVisible() && allowHorizontalScroll)
setupAdapter()
}
mLatestMediaId = getLatestMediaId()
mLatestMediaDateId = getLatestMediaByDateId()
if (!isFromCache) {
val mediaToInsert = (mMedia.clone() as ArrayList<ThumbnailItem>).filter { it is Medium && it.deletedTS == 0L }.map { it as Medium }
galleryDB.MediumDao().insertAll(mediaToInsert)
}
}
override fun tryDeleteFiles(fileDirItems: ArrayList<FileDirItem>) {
val filtered = fileDirItems.filter { it.path.isImageVideoGif() } as ArrayList
val deletingItems = resources.getQuantityString(R.plurals.deleting_items, filtered.size, filtered.size)
toast(deletingItems)
if (config.useRecycleBin && !filtered.first().path.startsWith(filesDir.toString())) {
movePathsInRecycleBin(filtered.map { it.path } as ArrayList<String>) {
if (it) {
deleteFilteredFiles(filtered)
} else {
toast(R.string.unknown_error_occurred)
}
}
} else {
deleteFilteredFiles(filtered)
}
}
private fun deleteFilteredFiles(filtered: ArrayList<FileDirItem>) {
deleteFiles(filtered) {
if (!it) {
toast(R.string.unknown_error_occurred)
return@deleteFiles
}
mMedia.removeAll { filtered.map { it.path }.contains(it.path) }
mMedia.removeAll { filtered.map { it.path }.contains((it as? Medium)?.path) }
Thread {
val mediumDao = galleryDB.MediumDao()
val useRecycleBin = config.useRecycleBin
filtered.forEach {
if (!useRecycleBin) {
mediumDao.deleteMediumPath(it.path)
}
}
}.start()
if (mMedia.isEmpty()) {

View file

@ -0,0 +1,176 @@
package com.simplemobiletools.gallery.activities
import android.content.res.Configuration
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Color
import android.os.Bundle
import android.view.View
import android.view.Window
import android.widget.RelativeLayout
import com.google.vr.sdk.widgets.pano.VrPanoramaEventListener
import com.google.vr.sdk.widgets.pano.VrPanoramaView
import com.simplemobiletools.commons.extensions.beVisible
import com.simplemobiletools.commons.extensions.showErrorToast
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.extensions.*
import com.simplemobiletools.gallery.helpers.PATH
import kotlinx.android.synthetic.main.activity_panorama.*
open class PanoramaActivity : SimpleActivity() {
private val CARDBOARD_DISPLAY_MODE = 3
private var isFullScreen = false
private var isExploreEnabled = true
private var isRendering = false
public override fun onCreate(savedInstanceState: Bundle?) {
useDynamicTheme = false
requestWindowFeature(Window.FEATURE_NO_TITLE)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_panorama)
supportActionBar?.hide()
setupButtonMargins()
cardboard.setOnClickListener {
panorama_view.displayMode = CARDBOARD_DISPLAY_MODE
}
explore.setOnClickListener {
isExploreEnabled = !isExploreEnabled
panorama_view.setPureTouchTracking(isExploreEnabled)
explore.setImageResource(if (isExploreEnabled) R.drawable.ic_explore else R.drawable.ic_explore_off)
}
handlePermission(PERMISSION_WRITE_STORAGE) {
if (it) {
checkIntent()
} else {
toast(R.string.no_storage_permissions)
finish()
}
}
}
override fun onResume() {
super.onResume()
panorama_view.resumeRendering()
isRendering = true
if (config.blackBackground) {
updateStatusbarColor(Color.BLACK)
}
}
override fun onPause() {
super.onPause()
panorama_view.pauseRendering()
isRendering = false
}
override fun onDestroy() {
super.onDestroy()
if (isRendering) {
panorama_view.shutdown()
}
}
private fun checkIntent() {
val path = intent.getStringExtra(PATH)
if (path == null) {
toast(R.string.invalid_image_path)
finish()
return
}
intent.removeExtra(PATH)
try {
val options = VrPanoramaView.Options()
options.inputType = VrPanoramaView.Options.TYPE_MONO
Thread {
val bitmap = getBitmapToLoad(path)
runOnUiThread {
panorama_view.apply {
beVisible()
loadImageFromBitmap(bitmap, options)
setFlingingEnabled(true)
setPureTouchTracking(true)
setEventListener(object : VrPanoramaEventListener() {
override fun onClick() {
handleClick()
}
})
// add custom buttons so we can position them and toggle visibility as desired
setFullscreenButtonEnabled(false)
setInfoButtonEnabled(false)
setTransitionViewEnabled(false)
setStereoModeButtonEnabled(false)
setOnClickListener {
handleClick()
}
}
}
}.start()
} catch (e: Exception) {
showErrorToast(e)
}
window.decorView.setOnSystemUiVisibilityChangeListener { visibility ->
isFullScreen = visibility and View.SYSTEM_UI_FLAG_FULLSCREEN != 0
toggleButtonVisibility()
}
}
override fun onConfigurationChanged(newConfig: Configuration?) {
super.onConfigurationChanged(newConfig)
setupButtonMargins()
}
private fun getBitmapToLoad(path: String): Bitmap? {
val options = BitmapFactory.Options()
options.inSampleSize = 1
var bitmap: Bitmap? = null
for (i in 0..10) {
try {
bitmap = BitmapFactory.decodeFile(path, options)
break
} catch (e: OutOfMemoryError) {
options.inSampleSize *= 2
}
}
return bitmap
}
private fun setupButtonMargins() {
(cardboard.layoutParams as RelativeLayout.LayoutParams).apply {
bottomMargin = navigationBarHeight
rightMargin = navigationBarWidth
}
(explore.layoutParams as RelativeLayout.LayoutParams).bottomMargin = navigationBarHeight
}
private fun toggleButtonVisibility() {
cardboard.animate().alpha(if (isFullScreen) 0f else 1f)
cardboard.isClickable = !isFullScreen
explore.animate().alpha(if (isFullScreen) 0f else 1f)
explore.isClickable = !isFullScreen
}
private fun handleClick() {
isFullScreen = !isFullScreen
toggleButtonVisibility()
if (isFullScreen) {
hideSystemUI(false)
} else {
showSystemUI(false)
}
}
}

View file

@ -85,7 +85,7 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
}
}
showSystemUI()
showSystemUI(true)
val bundle = Bundle()
val file = File(mUri.toString())
val type = when {
@ -95,7 +95,7 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
else -> TYPE_RAWS
}
mMedium = Medium(null, getFilenameFromUri(mUri!!), mUri.toString(), mUri!!.path.getParentPath(), 0, 0, file.length(), type, false)
mMedium = Medium(null, getFilenameFromUri(mUri!!), mUri.toString(), mUri!!.path.getParentPath(), 0, 0, file.length(), type, false, 0L)
supportActionBar?.title = mMedium!!.name
bundle.putSerializable(MEDIUM, mMedium)
@ -178,24 +178,32 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
}
private fun initBottomActionButtons() {
bottom_favorite.beGone()
bottom_delete.beGone()
bottom_edit.setOnClickListener {
openEditor(mUri!!.toString())
arrayListOf(bottom_favorite, bottom_delete, bottom_rotate, bottom_properties, bottom_change_orientation, bottom_slideshow, bottom_show_on_map, bottom_toggle_file_visibility).forEach {
it.beGone()
}
val visibleBottomActions = if (config.bottomActions) config.visibleBottomActions else 0
bottom_edit.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_EDIT != 0)
bottom_edit.setOnClickListener {
if (mUri != null && bottom_actions.alpha == 1f) {
openEditor(mUri!!.toString())
}
}
bottom_share.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_SHARE != 0)
bottom_share.setOnClickListener {
if (mUri != null && bottom_actions.alpha == 1f) {
sharePath(mUri!!.toString())
}
}
}
override fun fragmentClicked() {
mIsFullScreen = !mIsFullScreen
if (mIsFullScreen) {
hideSystemUI()
hideSystemUI(true)
} else {
showSystemUI()
showSystemUI(true)
}
if (!bottom_actions.isGone()) {

View file

@ -6,16 +6,19 @@ import android.os.Bundle
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.dialogs.SecurityDialog
import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.commons.extensions.getAdjustedPrimaryColor
import com.simplemobiletools.commons.extensions.handleHiddenFolderPasswordProtection
import com.simplemobiletools.commons.extensions.updateTextColors
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.PROTECTION_FINGERPRINT
import com.simplemobiletools.commons.helpers.SHOW_ALL_TABS
import com.simplemobiletools.commons.helpers.sumByLong
import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.dialogs.ManageBottomActionsDialog
import com.simplemobiletools.gallery.dialogs.ManageExtendedDetailsDialog
import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.extensions.emptyTheRecycleBin
import com.simplemobiletools.gallery.extensions.galleryDB
import com.simplemobiletools.gallery.extensions.showRecycleBinEmptyingDialog
import com.simplemobiletools.gallery.helpers.DEFAULT_BOTTOM_ACTIONS
import com.simplemobiletools.gallery.helpers.ROTATE_BY_ASPECT_RATIO
import com.simplemobiletools.gallery.helpers.ROTATE_BY_DEVICE_ROTATION
import com.simplemobiletools.gallery.helpers.ROTATE_BY_SYSTEM_SETTING
@ -24,6 +27,7 @@ import java.util.*
class SettingsActivity : SimpleActivity() {
lateinit var res: Resources
private var mRecycleBinContentSize = 0L
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -68,6 +72,9 @@ class SettingsActivity : SimpleActivity() {
setupHideExtendedDetails()
setupManageExtendedDetails()
setupSkipDeleteConfirmation()
setupManageBottomActions()
setupUseRecycleBin()
setupEmptyRecycleBin()
updateTextColors(settings_holder)
setupSectionColors()
}
@ -75,7 +82,7 @@ class SettingsActivity : SimpleActivity() {
private fun setupSectionColors() {
val adjustedPrimaryColor = getAdjustedPrimaryColor()
arrayListOf(visibility_label, videos_label, thumbnails_label, scrolling_label, fullscreen_media_label, security_label,
file_operations_label, extended_details_label).forEach {
file_operations_label, extended_details_label, bottom_actions_label, recycle_bin_label).forEach {
it.setTextColor(adjustedPrimaryColor)
}
}
@ -287,14 +294,6 @@ class SettingsActivity : SimpleActivity() {
}
}
private fun setupBottomActions() {
settings_bottom_actions.isChecked = config.bottomActions
settings_bottom_actions_holder.setOnClickListener {
settings_bottom_actions.toggle()
config.bottomActions = settings_bottom_actions.isChecked
}
}
private fun setupShowMediaCount() {
settings_show_media_count.isChecked = config.showMediaCount
settings_show_media_count_holder.setOnClickListener {
@ -409,4 +408,57 @@ class SettingsActivity : SimpleActivity() {
ROTATE_BY_DEVICE_ROTATION -> R.string.screen_rotation_device_rotation
else -> R.string.screen_rotation_aspect_ratio
})
private fun setupBottomActions() {
settings_bottom_actions.isChecked = config.bottomActions
settings_bottom_actions_holder.setOnClickListener {
settings_bottom_actions.toggle()
config.bottomActions = settings_bottom_actions.isChecked
settings_manage_bottom_actions_holder.beVisibleIf(config.bottomActions)
}
}
private fun setupManageBottomActions() {
settings_manage_bottom_actions_holder.beVisibleIf(config.bottomActions)
settings_manage_bottom_actions_holder.setOnClickListener {
ManageBottomActionsDialog(this) {
if (config.visibleBottomActions == 0) {
settings_bottom_actions_holder.callOnClick()
config.bottomActions = false
config.visibleBottomActions = DEFAULT_BOTTOM_ACTIONS
}
}
}
}
private fun setupUseRecycleBin() {
settings_empty_recycle_bin_holder.beVisibleIf(config.useRecycleBin)
settings_use_recycle_bin.isChecked = config.useRecycleBin
settings_use_recycle_bin_holder.setOnClickListener {
settings_use_recycle_bin.toggle()
config.useRecycleBin = settings_use_recycle_bin.isChecked
settings_empty_recycle_bin_holder.beVisibleIf(config.useRecycleBin)
}
}
private fun setupEmptyRecycleBin() {
Thread {
mRecycleBinContentSize = galleryDB.MediumDao().getDeletedMedia().sumByLong { it.size }
runOnUiThread {
settings_empty_recycle_bin_size.text = mRecycleBinContentSize.formatSize()
}
}.start()
settings_empty_recycle_bin_holder.setOnClickListener {
if (mRecycleBinContentSize == 0L) {
toast(R.string.recycle_bin_empty)
} else {
showRecycleBinEmptyingDialog {
emptyTheRecycleBin()
mRecycleBinContentSize = 0L
settings_empty_recycle_bin_size.text = 0L.formatSize()
}
}
}
}
}

View file

@ -44,6 +44,7 @@ import com.simplemobiletools.gallery.fragments.VideoFragment
import com.simplemobiletools.gallery.fragments.ViewPagerFragment
import com.simplemobiletools.gallery.helpers.*
import com.simplemobiletools.gallery.models.Medium
import com.simplemobiletools.gallery.models.ThumbnailItem
import kotlinx.android.synthetic.main.activity_medium.*
import kotlinx.android.synthetic.main.bottom_actions.*
import java.io.File
@ -70,7 +71,6 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private var mIsOrientationLocked = false
private var mStoredReplaceZoomableImages = false
private var mStoredBottomActions = true
private var mMediaFiles = ArrayList<Medium>()
private var mFavoritePaths = ArrayList<String>()
@ -83,7 +83,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_medium)
mMediaFiles = MediaActivity.mMedia.clone() as ArrayList<Medium>
(MediaActivity.mMedia.clone() as ArrayList<ThumbnailItem>).filter { it is Medium }.mapTo(mMediaFiles) { it as Medium }
handlePermission(PERMISSION_WRITE_STORAGE) {
if (it) {
@ -95,7 +95,6 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
storeStateVariables()
initBottomActions()
initFavorites()
}
@ -120,10 +119,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
refreshViewPager()
}
if (mStoredBottomActions != config.bottomActions) {
initBottomActions()
}
supportActionBar?.setBackgroundDrawable(resources.getDrawable(R.drawable.actionbar_gradient_background))
if (config.maxBrightness) {
@ -197,9 +193,6 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
if (!getDoesFilePathExist(mPath)) {
Thread {
scanPathRecursively(mPath)
}.start()
finish()
return
}
@ -214,9 +207,15 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
config.isThirdPartyIntent = true
}
showSystemUI()
showSystemUI(true)
mDirectory = mPath.getParentPath()
val isShowingFavorites = intent.getBooleanExtra(SHOW_FAVORITES, false)
val isShowingRecycleBin = intent.getBooleanExtra(SHOW_RECYCLE_BIN, false)
mDirectory = when {
isShowingFavorites -> FAVORITES
isShowingRecycleBin -> RECYCLE_BIN
else -> mPath.getParentPath()
}
if (mDirectory.startsWith(OTG_PATH.trimEnd('/'))) {
mDirectory += "/"
}
@ -225,7 +224,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
view_pager.onGlobalLayout {
if (!isActivityDestroyed()) {
if (mMediaFiles.isNotEmpty()) {
gotMedia(mMediaFiles)
gotMedia(mMediaFiles as ArrayList<ThumbnailItem>)
}
}
}
@ -251,6 +250,10 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
checkSystemUI()
if (!bottom_actions.isGone()) {
bottom_actions.animate().alpha(if (mIsFullScreen) 0f else 1f).start()
arrayOf(bottom_favorite, bottom_edit, bottom_share, bottom_delete, bottom_rotate, bottom_properties, bottom_change_orientation,
bottom_slideshow, bottom_show_on_map, bottom_toggle_file_visibility, bottom_rename).forEach {
it.isClickable = !mIsFullScreen
}
}
}
}
@ -268,34 +271,38 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
private fun setupRotation() {
if (mIsOrientationLocked) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
}
} else if (config.screenRotation == ROTATE_BY_DEVICE_ROTATION) {
if (!mIsOrientationLocked) {
if (config.screenRotation == ROTATE_BY_DEVICE_ROTATION) {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR
} else if (config.screenRotation == ROTATE_BY_SYSTEM_SETTING) {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
}
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_viewpager, menu)
val currentMedium = getCurrentMedium() ?: return true
currentMedium.isFavorite = mFavoritePaths.contains(currentMedium.path)
val visibleBottomActions = if (config.bottomActions) config.visibleBottomActions else 0
menu.apply {
findItem(R.id.menu_delete).isVisible = !config.bottomActions
findItem(R.id.menu_share).isVisible = !config.bottomActions
findItem(R.id.menu_edit).isVisible = !config.bottomActions
findItem(R.id.menu_rotate).isVisible = currentMedium.isImage()
findItem(R.id.menu_show_on_map).isVisible = visibleBottomActions and BOTTOM_ACTION_SHOW_ON_MAP == 0
findItem(R.id.menu_slideshow).isVisible = visibleBottomActions and BOTTOM_ACTION_SLIDESHOW == 0
findItem(R.id.menu_properties).isVisible = visibleBottomActions and BOTTOM_ACTION_PROPERTIES == 0
findItem(R.id.menu_delete).isVisible = visibleBottomActions and BOTTOM_ACTION_DELETE == 0
findItem(R.id.menu_share).isVisible = visibleBottomActions and BOTTOM_ACTION_SHARE == 0
findItem(R.id.menu_edit).isVisible = visibleBottomActions and BOTTOM_ACTION_EDIT == 0
findItem(R.id.menu_rename).isVisible = visibleBottomActions and BOTTOM_ACTION_RENAME == 0
findItem(R.id.menu_rotate).isVisible = currentMedium.isImage() && visibleBottomActions and BOTTOM_ACTION_ROTATE == 0
findItem(R.id.menu_save_as).isVisible = mRotationDegrees != 0
findItem(R.id.menu_hide).isVisible = !currentMedium.name.startsWith('.')
findItem(R.id.menu_unhide).isVisible = currentMedium.name.startsWith('.')
findItem(R.id.menu_add_to_favorites).isVisible = !currentMedium.isFavorite && !config.bottomActions
findItem(R.id.menu_remove_from_favorites).isVisible = currentMedium.isFavorite && !config.bottomActions
findItem(R.id.menu_lock_orientation).isVisible = mRotationDegrees == 0
findItem(R.id.menu_lock_orientation).title = getString(if (mIsOrientationLocked) R.string.unlock_orientation else R.string.lock_orientation)
findItem(R.id.menu_hide).isVisible = !currentMedium.isHidden() && visibleBottomActions and BOTTOM_ACTION_TOGGLE_VISIBILITY == 0
findItem(R.id.menu_unhide).isVisible = currentMedium.isHidden() && visibleBottomActions and BOTTOM_ACTION_TOGGLE_VISIBILITY == 0
findItem(R.id.menu_add_to_favorites).isVisible = !currentMedium.isFavorite && visibleBottomActions and BOTTOM_ACTION_TOGGLE_FAVORITE == 0
findItem(R.id.menu_remove_from_favorites).isVisible = currentMedium.isFavorite && visibleBottomActions and BOTTOM_ACTION_TOGGLE_FAVORITE == 0
findItem(R.id.menu_restore_file).isVisible = currentMedium.path.startsWith(filesDir.toString())
findItem(R.id.menu_change_orientation).isVisible = mRotationDegrees == 0 && visibleBottomActions and BOTTOM_ACTION_CHANGE_ORIENTATION == 0
findItem(R.id.menu_change_orientation).icon = resources.getDrawable(getChangeOrientationIcon())
findItem(R.id.menu_rotate).setShowAsAction(
if (mRotationDegrees != 0) {
MenuItem.SHOW_AS_ACTION_ALWAYS
@ -304,8 +311,8 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
})
}
if (config.bottomActions) {
updateFavoriteIcon(currentMedium)
if (visibleBottomActions != 0) {
updateBottomActionIcons(currentMedium)
}
return true
}
@ -322,7 +329,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
R.id.menu_open_with -> openPath(getCurrentPath(), true)
R.id.menu_hide -> toggleFileVisibility(true)
R.id.menu_unhide -> toggleFileVisibility(false)
R.id.menu_share -> shareMedium(getCurrentMedium()!!)
R.id.menu_share -> shareMediumPath(getCurrentPath())
R.id.menu_delete -> checkDeleteConfirmation()
R.id.menu_rename -> renameFile()
R.id.menu_edit -> openEditor(getCurrentPath())
@ -330,10 +337,13 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
R.id.menu_show_on_map -> showOnMap()
R.id.menu_rotate_right -> rotateImage(90)
R.id.menu_rotate_left -> rotateImage(270)
R.id.menu_rotate_one_eighty -> rotateImage(180)
R.id.menu_add_to_favorites -> toggleFavorite()
R.id.menu_remove_from_favorites -> toggleFavorite()
R.id.menu_rotate_one_eighty -> rotateImage(180)
R.id.menu_lock_orientation -> toggleLockOrientation()
R.id.menu_restore_file -> restoreFile()
R.id.menu_force_portrait -> toggleOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
R.id.menu_force_landscape -> toggleOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
R.id.menu_default_orientation -> toggleOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
R.id.menu_save_as -> saveImageAs()
R.id.menu_settings -> launchSettings()
else -> return super.onOptionsItemSelected(item)
@ -344,7 +354,6 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun storeStateVariables() {
config.apply {
mStoredReplaceZoomableImages = replaceZoomableImages
mStoredBottomActions = bottomActions
}
}
@ -370,7 +379,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
if (getMediaForSlideshow()) {
view_pager.onGlobalLayout {
if (!isActivityDestroyed()) {
hideSystemUI()
hideSystemUI(true)
mSlideshowInterval = config.slideshowInterval
mSlideshowMoveBackwards = config.slideshowMoveBackwards
mIsSlideshowActive = true
@ -448,7 +457,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun stopSlideshow() {
if (mIsSlideshowActive) {
mIsSlideshowActive = false
showSystemUI()
showSystemUI(true)
mSlideshowHandler.removeCallbacksAndMessages(null)
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
@ -516,7 +525,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
}
private fun toggleFileVisibility(hide: Boolean) {
private fun toggleFileVisibility(hide: Boolean, callback: (() -> Unit)? = null) {
toggleFileVisibility(getCurrentPath(), hide) {
val newFileName = it.getFilenameFromPath()
supportActionBar?.title = newFileName
@ -527,6 +536,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
getCurrentMedia()[mPos] = this
}
invalidateOptionsMenu()
callback?.invoke()
}
}
@ -538,16 +548,22 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
supportInvalidateOptionsMenu()
}
private fun toggleLockOrientation() {
mIsOrientationLocked = !mIsOrientationLocked
if (mIsOrientationLocked) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
private fun toggleOrientation(orientation: Int) {
requestedOrientation = orientation
mIsOrientationLocked = orientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
invalidateOptionsMenu()
}
private fun getChangeOrientationIcon(): Int {
return if (mIsOrientationLocked) {
if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
R.drawable.ic_orientation_portrait
} else {
R.drawable.ic_orientation_landscape
}
} else {
setupRotation()
R.drawable.ic_orientation_auto
}
invalidateOptionsMenu()
}
private fun saveImageAs() {
@ -589,7 +605,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
if (getDoesFilePathExist(newPath)) {
tryDeleteFileDirItem(FileDirItem(newPath, newPath.getFilenameFromPath()))
tryDeleteFileDirItem(FileDirItem(newPath, newPath.getFilenameFromPath()), false, true)
}
copyFile(tmpPath, newPath)
@ -618,7 +634,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
} catch (e: Exception) {
showErrorToast(e)
} finally {
tryDeleteFileDirItem(tmpFileDirItem)
tryDeleteFileDirItem(tmpFileDirItem, false, true)
}
}
@ -761,26 +777,85 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
private fun initBottomActionButtons() {
val visibleBottomActions = if (config.bottomActions) config.visibleBottomActions else 0
bottom_favorite.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_TOGGLE_FAVORITE != 0)
bottom_favorite.setOnClickListener {
toggleFavorite()
}
bottom_edit.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_EDIT != 0)
bottom_edit.setOnClickListener {
openEditor(getCurrentPath())
}
bottom_share.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_SHARE != 0)
bottom_share.setOnClickListener {
shareMedium(getCurrentMedium()!!)
shareMediumPath(getCurrentPath())
}
bottom_delete.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_DELETE != 0)
bottom_delete.setOnClickListener {
checkDeleteConfirmation()
}
bottom_rotate.setOnClickListener {
rotateImage(90)
}
private fun updateFavoriteIcon(medium: Medium) {
val icon = if (medium.isFavorite) R.drawable.ic_star_on else R.drawable.ic_star_off
bottom_favorite.setImageResource(icon)
bottom_properties.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_PROPERTIES != 0)
bottom_properties.setOnClickListener {
showProperties()
}
bottom_change_orientation.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_CHANGE_ORIENTATION != 0)
bottom_change_orientation.setOnClickListener {
requestedOrientation = when (requestedOrientation) {
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT -> ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE -> ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
else -> ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
mIsOrientationLocked = requestedOrientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
updateBottomActionIcons(getCurrentMedium())
}
bottom_slideshow.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_SLIDESHOW != 0)
bottom_slideshow.setOnClickListener {
initSlideshow()
}
bottom_show_on_map.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_SHOW_ON_MAP != 0)
bottom_show_on_map.setOnClickListener {
showOnMap()
}
bottom_toggle_file_visibility.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_TOGGLE_VISIBILITY != 0)
bottom_toggle_file_visibility.setOnClickListener {
getCurrentMedium()?.apply {
toggleFileVisibility(!isHidden()) {
updateBottomActionIcons(getCurrentMedium())
}
}
}
bottom_rename.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_RENAME != 0)
bottom_rename.setOnClickListener {
renameFile()
}
}
private fun updateBottomActionIcons(medium: Medium?) {
if (medium == null) {
return
}
val favoriteIcon = if (medium.isFavorite) R.drawable.ic_star_on else R.drawable.ic_star_off
bottom_favorite.setImageResource(favoriteIcon)
val hideIcon = if (medium.isHidden()) R.drawable.ic_unhide else R.drawable.ic_hide
bottom_toggle_file_visibility.setImageResource(hideIcon)
bottom_rotate.beVisibleIf(config.visibleBottomActions and BOTTOM_ACTION_ROTATE != 0 && getCurrentMedium()?.isImage() == true)
bottom_change_orientation.setImageResource(getChangeOrientationIcon())
}
private fun toggleFavorite() {
@ -797,6 +872,12 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}.start()
}
private fun restoreFile() {
restoreRecycleBinPath(getCurrentPath()) {
refreshViewPager()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
if (requestCode == REQUEST_EDIT_IMAGE) {
if (resultCode == Activity.RESULT_OK && resultData != null) {
@ -813,6 +894,10 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
private fun checkDeleteConfirmation() {
if (getCurrentMedium() == null) {
return
}
if (config.tempSkipDeleteConfirmation || config.skipDeleteConfirmation) {
deleteConfirmed()
} else {
@ -821,17 +906,35 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
private fun askConfirmDelete() {
DeleteWithRememberDialog(this, getString(R.string.proceed_with_deletion)) {
val message = if (config.useRecycleBin && !getCurrentMedium()!!.getIsInRecycleBin()) R.string.are_you_sure_recycle_bin else R.string.are_you_sure_delete
DeleteWithRememberDialog(this, getString(message)) {
config.tempSkipDeleteConfirmation = it
deleteConfirmed()
}
}
private fun deleteConfirmed() {
val path = getCurrentMedia()[mPos].path
tryDeleteFileDirItem(FileDirItem(path, path.getFilenameFromPath())) {
val path = getCurrentMedia().getOrNull(mPos)?.path ?: return
if (getIsPathDirectory(path)) {
return
}
val fileDirItem = FileDirItem(path, path.getFilenameFromPath())
if (config.useRecycleBin && !getCurrentMedium()!!.getIsInRecycleBin()) {
movePathsInRecycleBin(arrayListOf(path)) {
if (it) {
tryDeleteFileDirItem(fileDirItem, false, false) {
refreshViewPager()
}
} else {
toast(R.string.unknown_error_occurred)
}
}
} else {
tryDeleteFileDirItem(fileDirItem, false, true) {
refreshViewPager()
}
}
}
private fun isDirEmpty(media: ArrayList<Medium>): Boolean {
@ -884,7 +987,8 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}.execute()
}
private fun gotMedia(media: ArrayList<Medium>) {
private fun gotMedia(thumbnailItems: ArrayList<ThumbnailItem>) {
val media = thumbnailItems.filter { it is Medium }.map { it as Medium } as ArrayList<Medium>
if (isDirEmpty(media) || media.hashCode() == mPrevHashcode) {
return
}
@ -901,6 +1005,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
updatePagerItems(mMediaFiles.toMutableList())
invalidateOptionsMenu()
checkOrientation()
initBottomActions()
}
private fun getPositionInList(items: MutableList<Medium>): Int {
@ -916,7 +1021,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun deleteDirectoryIfEmpty() {
val fileDirItem = FileDirItem(mDirectory, mDirectory.getFilenameFromPath(), getIsPathDirectory(mDirectory))
if (config.deleteEmptyFolders && !fileDirItem.isDownloadsFolder() && fileDirItem.isDirectory && fileDirItem.getProperFileCount(applicationContext, true) == 0) {
tryDeleteFileDirItem(fileDirItem, true)
tryDeleteFileDirItem(fileDirItem, true, true)
}
scanPathRecursively(mDirectory)
@ -967,10 +1072,10 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun checkSystemUI() {
if (mIsFullScreen) {
hideSystemUI()
hideSystemUI(true)
} else {
stopSlideshow()
showSystemUI()
showSystemUI(true)
}
}

View file

@ -21,6 +21,7 @@ import com.simplemobiletools.gallery.dialogs.ExcludeFolderDialog
import com.simplemobiletools.gallery.dialogs.PickMediumDialog
import com.simplemobiletools.gallery.extensions.*
import com.simplemobiletools.gallery.helpers.*
import com.simplemobiletools.gallery.interfaces.DirectoryOperationsListener
import com.simplemobiletools.gallery.models.AlbumCover
import com.simplemobiletools.gallery.models.Directory
import kotlinx.android.synthetic.main.directory_item_list.view.*
@ -28,7 +29,7 @@ import java.io.File
import java.util.*
import kotlin.collections.ArrayList
class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directory>, val listener: DirOperationsListener?, recyclerView: MyRecyclerView,
class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directory>, val listener: DirectoryOperationsListener?, recyclerView: MyRecyclerView,
val isPickIntent: Boolean, fastScroller: FastScroller? = null, itemClick: (Any) -> Unit) :
MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
@ -62,7 +63,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
override fun onBindViewHolder(holder: MyRecyclerViewAdapter.ViewHolder, position: Int) {
val dir = dirs.getOrNull(position) ?: return
val view = holder.bindView(dir, !isPickIntent) { itemView, adapterPosition ->
val view = holder.bindView(dir, true, !isPickIntent) { itemView, adapterPosition ->
setupView(itemView, dir)
}
bindViewHolder(holder, position, view)
@ -71,10 +72,14 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
override fun getItemCount() = dirs.size
override fun prepareActionMode(menu: Menu) {
val selectedPaths = getSelectedPaths()
menu.apply {
findItem(R.id.cab_rename).isVisible = isOneItemSelected()
findItem(R.id.cab_rename).isVisible = isOneItemSelected() && !selectedPaths.contains(FAVORITES) && !selectedPaths.contains(RECYCLE_BIN)
findItem(R.id.cab_change_cover_image).isVisible = isOneItemSelected()
findItem(R.id.cab_empty_recycle_bin).isVisible = isOneItemSelected() && selectedPaths.first() == RECYCLE_BIN
findItem(R.id.cab_empty_disable_recycle_bin).isVisible = isOneItemSelected() && selectedPaths.first() == RECYCLE_BIN
checkHideBtnVisibility(this)
checkPinBtnVisibility(this)
}
@ -91,6 +96,8 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
R.id.cab_pin -> pinFolders(true)
R.id.cab_unpin -> pinFolders(false)
R.id.cab_hide -> toggleFoldersVisibility(true)
R.id.cab_empty_recycle_bin -> emptyRecycleBin()
R.id.cab_empty_disable_recycle_bin -> emptyAndDisableRecycleBin()
R.id.cab_unhide -> toggleFoldersVisibility(false)
R.id.cab_exclude -> tryExcludeFolder()
R.id.cab_copy_to -> copyMoveTo(true)
@ -104,6 +111,8 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
override fun getSelectableItemCount() = dirs.size
override fun getIsItemSelectable(position: Int) = true
override fun onViewRecycled(holder: ViewHolder) {
super.onViewRecycled(holder)
if (!activity.isActivityDestroyed()) {
@ -144,11 +153,12 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
private fun showProperties() {
if (selectedPositions.size <= 1) {
val path = dirs[selectedPositions.first()].path
if (path != FAVORITES && path != RECYCLE_BIN) {
PropertiesDialog(activity, dirs[selectedPositions.first()].path, config.shouldShowHidden)
}
} else {
val paths = ArrayList<String>()
selectedPositions.forEach { paths.add(dirs[it].path) }
PropertiesDialog(activity, paths, config.shouldShowHidden)
PropertiesDialog(activity, getSelectedPaths().filter { it != FAVORITES && it != RECYCLE_BIN }.toMutableList(), config.shouldShowHidden)
}
}
@ -178,7 +188,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
}
private fun toggleFoldersVisibility(hide: Boolean) {
getSelectedPaths().forEach {
getSelectedPaths().filter { it != FAVORITES && it != RECYCLE_BIN }.forEach {
val path = it
if (hide) {
if (config.wasHideFolderTooltipShown) {
@ -204,13 +214,29 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
}
}
private fun emptyRecycleBin() {
activity.showRecycleBinEmptyingDialog {
activity.emptyTheRecycleBin {
listener?.refreshItems()
}
}
}
private fun emptyAndDisableRecycleBin() {
activity.showRecycleBinEmptyingDialog {
activity.emptyAndDisableTheRecycleBin {
listener?.refreshItems()
}
}
}
private fun updateFolderNames() {
val includedFolders = activity.config.includedFolders
val hidden = activity.getString(R.string.hidden)
dirs.forEach {
it.name = activity.checkAppendingHidden(it.path, hidden, includedFolders)
}
listener?.updateDirectories(dirs.toList() as ArrayList)
listener?.updateDirectories(dirs.toMutableList() as ArrayList)
activity.runOnUiThread {
updateDirs(dirs)
}
@ -252,7 +278,6 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
dirs = newDirs
finishActMode()
fastScroller?.measureRecyclerView()
listener?.updateDirectories(newDirs)
}
}
@ -260,13 +285,13 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
}
private fun tryExcludeFolder() {
val paths = getSelectedPaths()
val paths = getSelectedPaths().filter { it != PATH }.toSet()
if (paths.size == 1) {
ExcludeFolderDialog(activity, paths.toList()) {
ExcludeFolderDialog(activity, paths.toMutableList()) {
listener?.refreshItems()
finishActMode()
}
} else {
} else if (paths.size > 1) {
activity.config.addExcludedFolders(paths)
listener?.refreshItems()
finishActMode()
@ -293,7 +318,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
val path = dirs[it].path
if (path.startsWith(OTG_PATH)) {
paths.addAll(getOTGFilePaths(path, showHidden))
} else {
} else if (path != FAVORITES) {
File(path).listFiles()?.filter {
!activity.getIsPathDirectory(it.absolutePath) && it.isImageVideoGif() && (showHidden || !it.name.startsWith('.'))
}?.mapTo(paths) { it.absolutePath }
@ -325,7 +350,8 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
} else {
val itemsCnt = selectedPositions.size
val items = resources.getQuantityString(R.plurals.delete_items, itemsCnt, itemsCnt)
var question = String.format(resources.getString(R.string.deletion_confirmation), items)
val baseString = if (config.useRecycleBin) R.string.move_to_recycle_bin_confirmation else R.string.deletion_confirmation
var question = String.format(resources.getString(baseString), items)
val warning = resources.getQuantityString(R.plurals.delete_warning, itemsCnt, itemsCnt)
question += "\n\n$warning"
ConfirmationDialog(activity, question) {
@ -355,13 +381,21 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
activity.handleSAFDialog(SAFPath) {
selectedPositions.sortedDescending().forEach {
val directory = dirs[it]
if (directory.areFavorites() || directory.isRecycleBin()) {
if (selectedPositions.size == 1) {
finishActMode()
} else {
selectedPositions.remove(it)
toggleItemSelection(false, it)
}
} else {
folders.add(File(directory.path))
removeFolders.add(directory)
}
}
dirs.removeAll(removeFolders)
listener?.deleteFolders(folders)
removeSelectedItems()
}
}
@ -409,10 +443,9 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
fun updateDirs(newDirs: ArrayList<Directory>) {
if (newDirs.hashCode() != currentDirectoriesHash) {
currentDirectoriesHash = newDirs.hashCode()
dirs = newDirs.clone() as ArrayList<Directory>
dirs = newDirs
notifyDataSetChanged()
finishActMode()
fastScroller?.measureRecyclerView()
}
}
@ -431,11 +464,6 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
notifyDataSetChanged()
}
fun updateScrollHorizontally(scrollHorizontally: Boolean) {
this.scrollHorizontally = scrollHorizontally
notifyDataSetChanged()
}
private fun setupView(view: View, directory: Directory) {
view.apply {
dir_name.text = directory.name
@ -466,14 +494,4 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
}
}
}
interface DirOperationsListener {
fun refreshItems()
fun deleteFolders(folders: ArrayList<File>)
fun recheckPinnedFolders()
fun updateDirectories(directories: ArrayList<Directory>)
}
}

View file

@ -39,11 +39,13 @@ class ManageFoldersAdapter(activity: BaseSimpleActivity, var folders: ArrayList<
override fun getSelectableItemCount() = folders.size
override fun getIsItemSelectable(position: Int) = true
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = createViewHolder(R.layout.item_manage_folder, parent)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val folder = folders[position]
val view = holder.bindView(folder) { itemView, adapterPosition ->
val view = holder.bindView(folder, true, true) { itemView, adapterPosition ->
setupView(itemView, folder)
}
bindViewHolder(holder, position, view)

View file

@ -41,11 +41,13 @@ class ManageHiddenFoldersAdapter(activity: BaseSimpleActivity, var folders: Arra
override fun getSelectableItemCount() = folders.size
override fun getIsItemSelectable(position: Int) = true
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = createViewHolder(R.layout.item_manage_folder, parent)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val folder = folders[position]
val view = holder.bindView(folder) { itemView, adapterPosition ->
val view = holder.bindView(folder, true, true) { itemView, adapterPosition ->
setupView(itemView, folder)
}
bindViewHolder(holder, position, view)

View file

@ -19,15 +19,21 @@ import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.dialogs.DeleteWithRememberDialog
import com.simplemobiletools.gallery.extensions.*
import com.simplemobiletools.gallery.helpers.VIEW_TYPE_LIST
import com.simplemobiletools.gallery.interfaces.MediaOperationsListener
import com.simplemobiletools.gallery.models.Medium
import com.simplemobiletools.gallery.models.ThumbnailItem
import com.simplemobiletools.gallery.models.ThumbnailSection
import kotlinx.android.synthetic.main.photo_video_item_grid.view.*
import kotlinx.android.synthetic.main.thumbnail_section.view.*
class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>, val listener: MediaOperationsListener?, val isAGetIntent: Boolean,
val allowMultiplePicks: Boolean, recyclerView: MyRecyclerView, fastScroller: FastScroller? = null,
itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<ThumbnailItem>, val listener: MediaOperationsListener?, val isAGetIntent: Boolean,
val allowMultiplePicks: Boolean, recyclerView: MyRecyclerView, fastScroller: FastScroller? = null, itemClick: (Any) -> Unit) :
MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
private val INSTANT_LOAD_DURATION = 2000L
private val IMAGE_LOAD_DELAY = 100L
private val ITEM_SECTION = 0
private val ITEM_MEDIUM = 1
private val config = activity.config
private val isListViewType = config.viewTypeFiles == VIEW_TYPE_LIST
@ -58,28 +64,55 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutType = if (isListViewType) R.layout.photo_video_item_list else R.layout.photo_video_item_grid
val layoutType = if (viewType == ITEM_SECTION) {
R.layout.thumbnail_section
} else {
if (isListViewType) {
R.layout.photo_video_item_list
} else {
R.layout.photo_video_item_grid
}
}
return createViewHolder(layoutType, parent)
}
override fun onBindViewHolder(holder: MyRecyclerViewAdapter.ViewHolder, position: Int) {
val medium = media.getOrNull(position) ?: return
visibleItemPaths.add(medium.path)
val view = holder.bindView(medium, !allowMultiplePicks) { itemView, adapterPosition ->
setupView(itemView, medium)
val tmbItem = media.getOrNull(position) ?: return
if (tmbItem is Medium) {
visibleItemPaths.add(tmbItem.path)
}
val allowLongPress = !allowMultiplePicks && tmbItem is Medium
val view = holder.bindView(tmbItem, tmbItem is Medium, allowLongPress) { itemView, adapterPosition ->
if (tmbItem is Medium) {
setupThumbnail(itemView, tmbItem)
} else {
setupSection(itemView, tmbItem as ThumbnailSection)
}
}
bindViewHolder(holder, position, view)
}
override fun getItemCount() = media.size
override fun getItemViewType(position: Int): Int {
val tmbItem = media[position]
return if (tmbItem is ThumbnailSection) {
ITEM_SECTION
} else {
ITEM_MEDIUM
}
}
override fun prepareActionMode(menu: Menu) {
menu.apply {
findItem(R.id.cab_rename).isVisible = isOneItemSelected()
findItem(R.id.cab_open_with).isVisible = isOneItemSelected()
findItem(R.id.cab_confirm_selection).isVisible = isAGetIntent && allowMultiplePicks && selectedPositions.size > 0
findItem(R.id.cab_restore_recycle_bin_files).isVisible = getSelectedPaths().all { it.startsWith(activity.filesDir.toString()) }
checkHideBtnVisibility(this)
checkFavoriteBtnVisibility(this)
}
}
@ -95,6 +128,9 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
R.id.cab_edit -> editFile()
R.id.cab_hide -> toggleFileVisibility(true)
R.id.cab_unhide -> toggleFileVisibility(false)
R.id.cab_add_to_favorites -> toggleFavorites(true)
R.id.cab_remove_from_favorites -> toggleFavorites(false)
R.id.cab_restore_recycle_bin_files -> restoreFiles()
R.id.cab_share -> shareMedia()
R.id.cab_copy_to -> copyMoveTo(true)
R.id.cab_move_to -> copyMoveTo(false)
@ -105,22 +141,29 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
}
}
override fun getSelectableItemCount() = media.size
override fun getSelectableItemCount() = media.filter { it is Medium }.size
override fun getIsItemSelectable(position: Int) = !isASectionTitle(position)
override fun onViewRecycled(holder: ViewHolder) {
super.onViewRecycled(holder)
if (!activity.isActivityDestroyed()) {
val itemView = holder.itemView
visibleItemPaths.remove(itemView?.photo_name?.tag)
Glide.with(activity).clear(itemView?.medium_thumbnail!!)
val tmb = itemView?.medium_thumbnail
if (tmb != null) {
Glide.with(activity).clear(tmb)
}
}
}
fun isASectionTitle(position: Int) = media.getOrNull(position) is ThumbnailSection
private fun checkHideBtnVisibility(menu: Menu) {
var hiddenCnt = 0
var unhiddenCnt = 0
selectedPositions.mapNotNull { media.getOrNull(it) }.forEach {
if (it.name.startsWith('.')) {
getSelectedMedia().forEach {
if (it.isHidden()) {
hiddenCnt++
} else {
unhiddenCnt++
@ -131,17 +174,30 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
menu.findItem(R.id.cab_unhide).isVisible = hiddenCnt > 0
}
private fun checkFavoriteBtnVisibility(menu: Menu) {
var favoriteCnt = 0
var nonFavoriteCnt = 0
getSelectedMedia().forEach {
if (it.isFavorite) {
favoriteCnt++
} else {
nonFavoriteCnt++
}
}
menu.findItem(R.id.cab_add_to_favorites).isVisible = nonFavoriteCnt > 0
menu.findItem(R.id.cab_remove_from_favorites).isVisible = favoriteCnt > 0
}
private fun confirmSelection() {
val paths = getSelectedMedia().map { it.path } as ArrayList<String>
listener?.selectedPaths(paths)
listener?.selectedPaths(getSelectedPaths())
}
private fun showProperties() {
if (selectedPositions.size <= 1) {
PropertiesDialog(activity, media[selectedPositions.first()].path, config.shouldShowHidden)
PropertiesDialog(activity, (media[selectedPositions.first()] as Medium).path, config.shouldShowHidden)
} else {
val paths = ArrayList<String>()
selectedPositions.forEach { paths.add(media[it].path) }
val paths = getSelectedPaths()
PropertiesDialog(activity, paths, config.shouldShowHidden)
}
}
@ -177,19 +233,42 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
}.start()
}
private fun toggleFavorites(add: Boolean) {
Thread {
val mediumDao = activity.galleryDB.MediumDao()
getSelectedMedia().forEach {
it.isFavorite = add
mediumDao.updateFavorite(it.path, add)
}
activity.runOnUiThread {
listener?.refreshItems()
finishActMode()
}
}.start()
}
private fun restoreFiles() {
activity.restoreRecycleBinPaths(getSelectedPaths()) {
listener?.refreshItems()
finishActMode()
}
}
private fun shareMedia() {
if (selectedPositions.size == 1 && selectedPositions.first() != -1) {
activity.shareMedium(getSelectedMedia()[0])
activity.shareMediumPath(getSelectedMedia().first().path)
} else if (selectedPositions.size > 1) {
activity.shareMedia(getSelectedMedia())
activity.shareMediaPaths(getSelectedPaths())
}
}
private fun copyMoveTo(isCopyOperation: Boolean) {
val paths = ArrayList<String>()
selectedPositions.forEach { paths.add(media[it].path) }
val paths = getSelectedPaths()
val fileDirItems = paths.map {
FileDirItem(it, it.getFilenameFromPath())
} as ArrayList
val fileDirItems = paths.map { FileDirItem(it, it.getFilenameFromPath()) } as ArrayList
activity.tryCopyMoveFilesTo(fileDirItems, isCopyOperation) {
config.tempFolderPath = ""
activity.applicationContext.rescanFolderMedia(it)
@ -210,14 +289,16 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
private fun askConfirmDelete() {
val items = resources.getQuantityString(R.plurals.delete_items, selectedPositions.size, selectedPositions.size)
val question = String.format(resources.getString(R.string.deletion_confirmation), items)
val isRecycleBin = getSelectedPaths().first().startsWith(activity.filesDir.toString())
val baseString = if (config.useRecycleBin && !isRecycleBin) R.string.move_to_recycle_bin_confirmation else R.string.deletion_confirmation
val question = String.format(resources.getString(baseString), items)
DeleteWithRememberDialog(activity, question) {
config.tempSkipDeleteConfirmation = it
deleteFiles()
}
}
private fun getCurrentPath() = media[selectedPositions.first()].path
private fun getCurrentPath() = (media[selectedPositions.first()] as Medium).path
private fun deleteFiles() {
if (selectedPositions.isEmpty()) {
@ -232,12 +313,14 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
return
}
val SAFPath = media[selectedPositions.first()].path
val SAFPath = (media[selectedPositions.first()] as Medium).path
activity.handleSAFDialog(SAFPath) {
selectedPositions.sortedDescending().forEach {
val medium = media[it]
fileDirItems.add(FileDirItem(medium.path, medium.name))
removeMedia.add(medium)
val thumbnailItem = media[it]
if (thumbnailItem is Medium) {
fileDirItems.add(FileDirItem(thumbnailItem.path, thumbnailItem.name))
removeMedia.add(thumbnailItem)
}
}
media.removeAll(removeMedia)
@ -248,19 +331,24 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
private fun getSelectedMedia(): List<Medium> {
val selectedMedia = ArrayList<Medium>(selectedPositions.size)
selectedPositions.forEach { selectedMedia.add(media[it]) }
selectedPositions.forEach {
(media.getOrNull(it) as? Medium)?.apply {
selectedMedia.add(this)
}
}
return selectedMedia
}
fun updateMedia(newMedia: ArrayList<Medium>) {
private fun getSelectedPaths() = getSelectedMedia().map { it.path } as ArrayList<String>
fun updateMedia(newMedia: ArrayList<ThumbnailItem>) {
if (newMedia.hashCode() != currentMediaHash) {
currentMediaHash = newMedia.hashCode()
Handler().postDelayed({
media = newMedia.clone() as ArrayList<Medium>
media = newMedia
enableInstantLoad()
notifyDataSetChanged()
finishActMode()
fastScroller?.measureRecyclerView()
}, 100L)
}
}
@ -281,11 +369,6 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
notifyDataSetChanged()
}
fun updateScrollHorizontally(scrollHorizontally: Boolean) {
this.scrollHorizontally = scrollHorizontally
notifyDataSetChanged()
}
private fun enableInstantLoad() {
loadImageInstantly = true
delayHandler.postDelayed({
@ -293,27 +376,29 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
}, INSTANT_LOAD_DURATION)
}
private fun setupView(view: View, medium: Medium) {
fun getItemBubbleText(position: Int, sorting: Int) = (media[position] as? Medium)?.getBubbleText(sorting)
private fun setupThumbnail(view: View, medium: Medium) {
view.apply {
play_outline.beVisibleIf(medium.isVideo())
photo_name.beVisibleIf(displayFilenames || isListViewType)
photo_name.text = medium.name
photo_name.tag = medium.path
var thumbnailPath = medium.path
if (hasOTGConnected && thumbnailPath.startsWith(OTG_PATH)) {
thumbnailPath = thumbnailPath.getOTGPublicPath(context)
var path = medium.path
if (hasOTGConnected && path.startsWith(OTG_PATH)) {
path = path.getOTGPublicPath(context)
}
if (loadImageInstantly) {
activity.loadImage(medium.type, thumbnailPath, medium_thumbnail, scrollHorizontally, animateGifs, cropThumbnails)
activity.loadImage(medium.type, path, medium_thumbnail, scrollHorizontally, animateGifs, cropThumbnails)
} else {
medium_thumbnail.setImageDrawable(null)
medium_thumbnail.isHorizontalScrolling = scrollHorizontally
delayHandler.postDelayed({
val isVisible = visibleItemPaths.contains(medium.path)
if (isVisible) {
activity.loadImage(medium.type, thumbnailPath, medium_thumbnail, scrollHorizontally, animateGifs, cropThumbnails)
activity.loadImage(medium.type, path, medium_thumbnail, scrollHorizontally, animateGifs, cropThumbnails)
}
}, IMAGE_LOAD_DELAY)
}
@ -325,11 +410,10 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Medium>,
}
}
interface MediaOperationsListener {
fun refreshItems()
fun tryDeleteFiles(fileDirItems: ArrayList<FileDirItem>)
fun selectedPaths(paths: ArrayList<String>)
private fun setupSection(view: View, section: ThumbnailSection) {
view.apply {
thumbnail_section.text = section.title
thumbnail_section.setTextColor(textColor)
}
}
}

View file

@ -6,18 +6,21 @@ import com.simplemobiletools.commons.helpers.SORT_BY_DATE_TAKEN
import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.extensions.getFavoritePaths
import com.simplemobiletools.gallery.helpers.MediaFetcher
import com.simplemobiletools.gallery.helpers.SHOW_ALL
import com.simplemobiletools.gallery.models.Medium
import com.simplemobiletools.gallery.models.ThumbnailItem
import java.util.*
class GetMediaAsynctask(val context: Context, val mPath: String, val isPickImage: Boolean = false, val isPickVideo: Boolean = false,
val showAll: Boolean, val callback: (media: ArrayList<Medium>) -> Unit) :
AsyncTask<Void, Void, ArrayList<Medium>>() {
val showAll: Boolean, val callback: (media: ArrayList<ThumbnailItem>) -> Unit) :
AsyncTask<Void, Void, ArrayList<ThumbnailItem>>() {
private val mediaFetcher = MediaFetcher(context)
override fun doInBackground(vararg params: Void): ArrayList<Medium> {
val getProperDateTaken = context.config.getFileSorting(mPath) and SORT_BY_DATE_TAKEN != 0
override fun doInBackground(vararg params: Void): ArrayList<ThumbnailItem> {
val pathToUse = if (showAll) SHOW_ALL else mPath
val getProperDateTaken = context.config.getFileSorting(pathToUse) and SORT_BY_DATE_TAKEN != 0
val favoritePaths = context.getFavoritePaths()
return if (showAll) {
val media = if (showAll) {
val foldersToScan = mediaFetcher.getFoldersToScan()
val media = ArrayList<Medium>()
foldersToScan.forEach {
@ -25,14 +28,15 @@ class GetMediaAsynctask(val context: Context, val mPath: String, val isPickImage
media.addAll(newMedia)
}
MediaFetcher(context).sortMedia(media, context.config.getFileSorting(""))
mediaFetcher.sortMedia(media, context.config.getFileSorting(SHOW_ALL))
media
} else {
mediaFetcher.getFilesFrom(mPath, isPickImage, isPickVideo, getProperDateTaken, favoritePaths)
}
return mediaFetcher.groupMedia(media, pathToUse)
}
override fun onPostExecute(media: ArrayList<Medium>) {
override fun onPostExecute(media: ArrayList<ThumbnailItem>) {
super.onPostExecute(media)
callback(media)
}

View file

@ -9,7 +9,7 @@ import com.simplemobiletools.gallery.interfaces.MediumDao
import com.simplemobiletools.gallery.models.Directory
import com.simplemobiletools.gallery.models.Medium
@Database(entities = [(Directory::class), (Medium::class)], version = 3)
@Database(entities = [(Directory::class), (Medium::class)], version = 4)
abstract class GalleryDatabase : RoomDatabase() {
abstract fun DirectoryDao(): DirectoryDao

View file

@ -0,0 +1,86 @@
package com.simplemobiletools.gallery.dialogs
import android.content.DialogInterface
import android.support.v7.app.AlertDialog
import android.view.View
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.beVisibleIf
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.helpers.*
import kotlinx.android.synthetic.main.dialog_change_grouping.view.*
class ChangeGroupingDialog(val activity: BaseSimpleActivity, val path: String = "", val callback: () -> Unit) :
DialogInterface.OnClickListener {
private var currGrouping = 0
private var config = activity.config
private val pathToUse = if (path.isEmpty()) SHOW_ALL else path
private var view: View
init {
view = activity.layoutInflater.inflate(R.layout.dialog_change_grouping, null).apply {
grouping_dialog_use_for_this_folder.isChecked = config.hasCustomGrouping(pathToUse)
grouping_dialog_radio_folder.beVisibleIf(path.isEmpty())
}
AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, this)
.setNegativeButton(R.string.cancel, null)
.create().apply {
activity.setupDialogStuff(view, this, R.string.group_by)
}
currGrouping = config.getFolderGrouping(pathToUse)
setupGroupRadio()
setupOrderRadio()
}
private fun setupGroupRadio() {
val groupingRadio = view.grouping_dialog_radio_grouping
val groupBtn = when {
currGrouping and GROUP_BY_NONE != 0 -> groupingRadio.grouping_dialog_radio_none
currGrouping and GROUP_BY_LAST_MODIFIED != 0 -> groupingRadio.grouping_dialog_radio_last_modified
currGrouping and GROUP_BY_DATE_TAKEN != 0 -> groupingRadio.grouping_dialog_radio_date_taken
currGrouping and GROUP_BY_FILE_TYPE != 0 -> groupingRadio.grouping_dialog_radio_file_type
currGrouping and GROUP_BY_EXTENSION != 0 -> groupingRadio.grouping_dialog_radio_extension
else -> groupingRadio.grouping_dialog_radio_folder
}
groupBtn.isChecked = true
}
private fun setupOrderRadio() {
val orderRadio = view.grouping_dialog_radio_order
var orderBtn = orderRadio.grouping_dialog_radio_ascending
if (currGrouping and GROUP_DESCENDING != 0) {
orderBtn = orderRadio.grouping_dialog_radio_descending
}
orderBtn.isChecked = true
}
override fun onClick(dialog: DialogInterface, which: Int) {
val groupingRadio = view.grouping_dialog_radio_grouping
var grouping = when (groupingRadio.checkedRadioButtonId) {
R.id.grouping_dialog_radio_none -> GROUP_BY_NONE
R.id.grouping_dialog_radio_last_modified -> GROUP_BY_LAST_MODIFIED
R.id.grouping_dialog_radio_date_taken -> GROUP_BY_DATE_TAKEN
R.id.grouping_dialog_radio_file_type -> GROUP_BY_FILE_TYPE
R.id.grouping_dialog_radio_extension -> GROUP_BY_EXTENSION
else -> GROUP_BY_FOLDER
}
if (view.grouping_dialog_radio_order.checkedRadioButtonId == R.id.grouping_dialog_radio_descending) {
grouping = grouping or GROUP_DESCENDING
}
if (view.grouping_dialog_use_for_this_folder.isChecked) {
config.saveFolderGrouping(pathToUse, grouping)
} else {
config.removeFolderGrouping(pathToUse)
config.groupBy = grouping
}
callback()
}
}

View file

@ -9,6 +9,7 @@ import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.helpers.SHOW_ALL
import kotlinx.android.synthetic.main.dialog_change_sorting.view.*
class ChangeSortingDialog(val activity: BaseSimpleActivity, val isDirectorySorting: Boolean, showFolderCheckbox: Boolean,
@ -16,13 +17,14 @@ class ChangeSortingDialog(val activity: BaseSimpleActivity, val isDirectorySorti
DialogInterface.OnClickListener {
private var currSorting = 0
private var config = activity.config
private var pathToUse = if (!isDirectorySorting && path.isEmpty()) SHOW_ALL else path
private var view: View
init {
view = activity.layoutInflater.inflate(R.layout.dialog_change_sorting, null).apply {
use_for_this_folder_divider.beVisibleIf(showFolderCheckbox)
sorting_dialog_use_for_this_folder.beVisibleIf(showFolderCheckbox)
sorting_dialog_use_for_this_folder.isChecked = config.hasCustomSorting(path)
sorting_dialog_use_for_this_folder.isChecked = config.hasCustomSorting(pathToUse)
}
AlertDialog.Builder(activity)
@ -32,7 +34,7 @@ class ChangeSortingDialog(val activity: BaseSimpleActivity, val isDirectorySorti
activity.setupDialogStuff(view, this, R.string.sort_by)
}
currSorting = if (isDirectorySorting) config.directorySorting else config.getFileSorting(path)
currSorting = if (isDirectorySorting) config.directorySorting else config.getFileSorting(pathToUse)
setupSortRadio()
setupOrderRadio()
}
@ -78,9 +80,9 @@ class ChangeSortingDialog(val activity: BaseSimpleActivity, val isDirectorySorti
config.directorySorting = sorting
} else {
if (view.sorting_dialog_use_for_this_folder.isChecked) {
config.saveFileSorting(path, sorting)
config.saveFileSorting(pathToUse, sorting)
} else {
config.removeFileSorting(path)
config.removeFileSorting(pathToUse)
config.sorting = sorting
}
}

View file

@ -13,7 +13,7 @@ class DeleteWithRememberDialog(val activity: Activity, val message: String, val
init {
view.delete_remember_title.text = message
val builder = AlertDialog.Builder(activity)
.setPositiveButton(R.string.yes, { dialog, which -> dialogConfirmed() })
.setPositiveButton(R.string.yes) { dialog, which -> dialogConfirmed() }
.setNegativeButton(R.string.no, null)
dialog = builder.create().apply {

View file

@ -0,0 +1,68 @@
package com.simplemobiletools.gallery.dialogs
import android.support.v7.app.AlertDialog
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.helpers.*
import kotlinx.android.synthetic.main.dialog_manage_bottom_actions.view.*
class ManageBottomActionsDialog(val activity: BaseSimpleActivity, val callback: (result: Int) -> Unit) {
private var view = activity.layoutInflater.inflate(R.layout.dialog_manage_bottom_actions, null)
init {
val actions = activity.config.visibleBottomActions
view.apply {
manage_bottom_actions_toggle_favorite.isChecked = actions and BOTTOM_ACTION_TOGGLE_FAVORITE != 0
manage_bottom_actions_edit.isChecked = actions and BOTTOM_ACTION_EDIT != 0
manage_bottom_actions_share.isChecked = actions and BOTTOM_ACTION_SHARE != 0
manage_bottom_actions_delete.isChecked = actions and BOTTOM_ACTION_DELETE != 0
manage_bottom_actions_rotate.isChecked = actions and BOTTOM_ACTION_ROTATE != 0
manage_bottom_actions_properties.isChecked = actions and BOTTOM_ACTION_PROPERTIES != 0
manage_bottom_actions_change_orientation.isChecked = actions and BOTTOM_ACTION_CHANGE_ORIENTATION != 0
manage_bottom_actions_slideshow.isChecked = actions and BOTTOM_ACTION_PROPERTIES != 0
manage_bottom_actions_show_on_map.isChecked = actions and BOTTOM_ACTION_SHOW_ON_MAP != 0
manage_bottom_actions_toggle_visibility.isChecked = actions and BOTTOM_ACTION_TOGGLE_VISIBILITY != 0
manage_bottom_actions_rename.isChecked = actions and BOTTOM_ACTION_RENAME != 0
}
AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok) { dialog, which -> dialogConfirmed() }
.setNegativeButton(R.string.cancel, null)
.create().apply {
activity.setupDialogStuff(view, this)
}
}
private fun dialogConfirmed() {
var result = 0
view.apply {
if (manage_bottom_actions_toggle_favorite.isChecked)
result += BOTTOM_ACTION_TOGGLE_FAVORITE
if (manage_bottom_actions_edit.isChecked)
result += BOTTOM_ACTION_EDIT
if (manage_bottom_actions_share.isChecked)
result += BOTTOM_ACTION_SHARE
if (manage_bottom_actions_delete.isChecked)
result += BOTTOM_ACTION_DELETE
if (manage_bottom_actions_rotate.isChecked)
result += BOTTOM_ACTION_ROTATE
if (manage_bottom_actions_properties.isChecked)
result += BOTTOM_ACTION_PROPERTIES
if (manage_bottom_actions_change_orientation.isChecked)
result += BOTTOM_ACTION_CHANGE_ORIENTATION
if (manage_bottom_actions_slideshow.isChecked)
result += BOTTOM_ACTION_SLIDESHOW
if (manage_bottom_actions_show_on_map.isChecked)
result += BOTTOM_ACTION_SHOW_ON_MAP
if (manage_bottom_actions_toggle_visibility.isChecked)
result += BOTTOM_ACTION_TOGGLE_VISIBILITY
if (manage_bottom_actions_rename.isChecked)
result += BOTTOM_ACTION_RENAME
}
activity.config.visibleBottomActions = result
callback(result)
}
}

View file

@ -28,7 +28,7 @@ class ManageExtendedDetailsDialog(val activity: BaseSimpleActivity, val callback
}
AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, { dialog, which -> dialogConfirmed() })
.setPositiveButton(R.string.ok) { dialog, which -> dialogConfirmed() }
.setNegativeButton(R.string.cancel, null)
.create().apply {
activity.setupDialogStuff(view, this)

View file

@ -12,13 +12,15 @@ import com.simplemobiletools.gallery.adapters.MediaAdapter
import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask
import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.extensions.getCachedMedia
import com.simplemobiletools.gallery.helpers.SHOW_ALL
import com.simplemobiletools.gallery.helpers.VIEW_TYPE_GRID
import com.simplemobiletools.gallery.models.Medium
import com.simplemobiletools.gallery.models.ThumbnailItem
import kotlinx.android.synthetic.main.dialog_medium_picker.view.*
class PickMediumDialog(val activity: BaseSimpleActivity, val path: String, val callback: (path: String) -> Unit) {
var dialog: AlertDialog
var shownMedia = ArrayList<Medium>()
var shownMedia = ArrayList<ThumbnailItem>()
val view = activity.layoutInflater.inflate(R.layout.dialog_medium_picker, null)
var isGridViewType = activity.config.viewTypeFiles == VIEW_TYPE_GRID
@ -31,13 +33,13 @@ class PickMediumDialog(val activity: BaseSimpleActivity, val path: String, val c
dialog = AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.setNeutralButton(R.string.other_folder, { dialogInterface, i -> showOtherFolder() })
.setNeutralButton(R.string.other_folder) { dialogInterface, i -> showOtherFolder() }
.create().apply {
activity.setupDialogStuff(view, this, R.string.select_photo)
}
activity.getCachedMedia(path) {
val media = it.filter { !it.isVideo() } as ArrayList
val media = it.filter { it is Medium && !it.isVideo() } as ArrayList
if (media.isNotEmpty()) {
activity.runOnUiThread {
gotMedia(media)
@ -57,18 +59,20 @@ class PickMediumDialog(val activity: BaseSimpleActivity, val path: String, val c
}
}
private fun gotMedia(media: ArrayList<Medium>) {
private fun gotMedia(media: ArrayList<ThumbnailItem>) {
if (media.hashCode() == shownMedia.hashCode())
return
shownMedia = media
val adapter = MediaAdapter(activity, media, null, true, false, view.media_grid) {
callback((it as Medium).path)
val adapter = MediaAdapter(activity, shownMedia, null, true, false, view.media_grid, null) {
if (it is Medium) {
callback(it.path)
dialog.dismiss()
}
}
val scrollHorizontally = activity.config.scrollHorizontally && isGridViewType
val sorting = activity.config.getFileSorting(path)
val sorting = activity.config.getFileSorting(if (path.isEmpty()) SHOW_ALL else path)
view.apply {
media_grid.adapter = adapter
@ -81,12 +85,12 @@ class PickMediumDialog(val activity: BaseSimpleActivity, val path: String, val c
if (scrollHorizontally) {
media_horizontal_fastscroller.allowBubbleDisplay = activity.config.showInfoBubble
media_horizontal_fastscroller.setViews(media_grid) {
media_horizontal_fastscroller.updateBubbleText(media[it].getBubbleText(sorting))
media_horizontal_fastscroller.updateBubbleText((media[it] as? Medium)?.getBubbleText(sorting) ?: "")
}
} else {
media_vertical_fastscroller.allowBubbleDisplay = activity.config.showInfoBubble
media_vertical_fastscroller.setViews(media_grid) {
media_vertical_fastscroller.updateBubbleText(media[it].getBubbleText(sorting))
media_vertical_fastscroller.updateBubbleText((media[it] as? Medium)?.getBubbleText(sorting) ?: "")
}
}
}

View file

@ -6,6 +6,7 @@ import android.provider.MediaStore
import android.support.v7.app.AppCompatActivity
import android.view.View
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.commons.models.FAQItem
@ -15,8 +16,9 @@ import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
import com.simplemobiletools.gallery.dialogs.PickDirectoryDialog
import com.simplemobiletools.gallery.helpers.NOMEDIA
import com.simplemobiletools.gallery.models.Medium
import java.io.File
import java.io.InputStream
import java.io.OutputStream
import java.util.*
fun Activity.sharePath(path: String) {
@ -27,12 +29,11 @@ fun Activity.sharePaths(paths: ArrayList<String>) {
sharePathsIntent(paths, BuildConfig.APPLICATION_ID)
}
fun Activity.shareMedium(medium: Medium) {
sharePath(medium.path)
fun Activity.shareMediumPath(path: String) {
sharePath(path)
}
fun Activity.shareMedia(media: List<Medium>) {
val paths = media.map { it.path } as ArrayList
fun Activity.shareMediaPaths(paths: ArrayList<String>) {
sharePaths(paths)
}
@ -59,7 +60,7 @@ fun Activity.launchCamera() {
fun SimpleActivity.launchAbout() {
val faqItems = arrayListOf(
FAQItem(R.string.faq_3_title_commons, R.string.faq_3_text_commons),
FAQItem(R.string.faq_5_title_commons, R.string.faq_5_text_commons),
FAQItem(R.string.faq_1_title, R.string.faq_1_text),
FAQItem(R.string.faq_2_title, R.string.faq_2_text),
FAQItem(R.string.faq_3_title, R.string.faq_3_text),
@ -70,21 +71,29 @@ fun SimpleActivity.launchAbout() {
FAQItem(R.string.faq_8_title, R.string.faq_8_text),
FAQItem(R.string.faq_9_title, R.string.faq_9_text),
FAQItem(R.string.faq_10_title, R.string.faq_10_text),
FAQItem(R.string.faq_11_title, R.string.faq_11_text),
FAQItem(R.string.faq_2_title_commons, R.string.faq_2_text_commons))
startAboutActivity(R.string.app_name, LICENSE_GLIDE or LICENSE_CROPPER or LICENSE_MULTISELECT or LICENSE_RTL
or LICENSE_SUBSAMPLING or LICENSE_PATTERN or LICENSE_REPRINT or LICENSE_GIF_DRAWABLE or LICENSE_PHOTOVIEW, BuildConfig.VERSION_NAME, faqItems)
or LICENSE_SUBSAMPLING or LICENSE_PATTERN or LICENSE_REPRINT or LICENSE_GIF_DRAWABLE or LICENSE_PHOTOVIEW or LICENSE_EXOPLAYER or
LICENSE_PANORAMA_VIEW or LICENSE_SANSELAN, BuildConfig.VERSION_NAME, faqItems)
}
fun AppCompatActivity.showSystemUI() {
fun AppCompatActivity.showSystemUI(toggleActionBarVisibility: Boolean) {
if (toggleActionBarVisibility) {
supportActionBar?.show()
}
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
}
fun AppCompatActivity.hideSystemUI() {
fun AppCompatActivity.hideSystemUI(toggleActionBarVisibility: Boolean) {
if (toggleActionBarVisibility) {
supportActionBar?.hide()
}
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
@ -134,7 +143,7 @@ fun BaseSimpleActivity.removeNoMedia(path: String, callback: (() -> Unit)? = nul
return
}
tryDeleteFileDirItem(file.toFileDirItem(applicationContext)) {
tryDeleteFileDirItem(file.toFileDirItem(applicationContext), false, false) {
callback?.invoke()
}
}
@ -169,12 +178,92 @@ fun BaseSimpleActivity.tryCopyMoveFilesTo(fileDirItems: ArrayList<FileDirItem>,
}
}
fun BaseSimpleActivity.tryDeleteFileDirItem(fileDirItem: FileDirItem, allowDeleteFolder: Boolean = false, callback: ((wasSuccess: Boolean) -> Unit)? = null) {
fun BaseSimpleActivity.tryDeleteFileDirItem(fileDirItem: FileDirItem, allowDeleteFolder: Boolean = false, deleteFromDatabase: Boolean,
callback: ((wasSuccess: Boolean) -> Unit)? = null) {
deleteFile(fileDirItem, allowDeleteFolder) {
callback?.invoke(it)
if (deleteFromDatabase) {
Thread {
galleryDB.MediumDao().deleteMediumPath(fileDirItem.path)
runOnUiThread {
callback?.invoke(it)
}
}.start()
} else {
callback?.invoke(it)
}
}
}
fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, callback: ((wasSuccess: Boolean) -> Unit)?) {
Thread {
var pathsCnt = paths.size
paths.forEach {
val file = File(it)
val internalFile = File(filesDir, it)
try {
file.copyRecursively(internalFile, true)
galleryDB.MediumDao().updateDeleted(it, System.currentTimeMillis())
pathsCnt--
} catch (ignored: Exception) {
}
}
callback?.invoke(pathsCnt == 0)
}.start()
}
fun BaseSimpleActivity.restoreRecycleBinPath(path: String, callback: () -> Unit) {
restoreRecycleBinPaths(arrayListOf(path), callback)
}
fun BaseSimpleActivity.restoreRecycleBinPaths(paths: ArrayList<String>, callback: () -> Unit) {
Thread {
val mediumDao = galleryDB.MediumDao()
paths.forEach {
val source = it
val destination = it.removePrefix(filesDir.toString())
var inputStream: InputStream? = null
var out: OutputStream? = null
try {
out = getFileOutputStreamSync(destination, source.getMimeType())
inputStream = getFileInputStreamSync(source)!!
inputStream.copyTo(out!!)
mediumDao.updateDeleted(destination, 0)
} catch (e: Exception) {
showErrorToast(e)
} finally {
inputStream?.close()
out?.close()
}
}
runOnUiThread {
callback()
}
}.start()
}
fun BaseSimpleActivity.emptyTheRecycleBin(callback: (() -> Unit)? = null) {
Thread {
filesDir.deleteRecursively()
galleryDB.MediumDao().clearRecycleBin()
galleryDB.DirectoryDao().deleteRecycleBin()
toast(R.string.recycle_bin_emptied)
callback?.invoke()
}.start()
}
fun BaseSimpleActivity.emptyAndDisableTheRecycleBin(callback: () -> Unit) {
Thread {
emptyTheRecycleBin {
config.useRecycleBin = false
callback()
}
}.start()
}
fun BaseSimpleActivity.showRecycleBinEmptyingDialog(callback: () -> Unit) {
ConfirmationDialog(this, "", R.string.empty_recycle_bin_confirmation, R.string.yes, R.string.no) {
callback()
}
}

View file

@ -24,8 +24,10 @@ import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask
import com.simplemobiletools.gallery.databases.GalleryDatabase
import com.simplemobiletools.gallery.helpers.*
import com.simplemobiletools.gallery.interfaces.DirectoryDao
import com.simplemobiletools.gallery.interfaces.MediumDao
import com.simplemobiletools.gallery.models.Directory
import com.simplemobiletools.gallery.models.Medium
import com.simplemobiletools.gallery.models.ThumbnailItem
import com.simplemobiletools.gallery.views.MySquareImageView
import pl.droidsonroids.gif.GifDrawable
import java.io.File
@ -163,11 +165,15 @@ fun Context.rescanFolderMediaSync(path: String) {
Thread {
val newMedia = it
val mediumDao = galleryDB.MediumDao()
mediumDao.insertAll(newMedia)
val media = newMedia.filter { it is Medium } as ArrayList<Medium>
mediumDao.insertAll(media)
cached.forEach {
if (!newMedia.contains(it)) {
mediumDao.deleteMediumPath(it.path)
val mediumPath = (it as? Medium)?.path
if (mediumPath != null) {
mediumDao.deleteMediumPath(mediumPath)
}
}
}
}.start()
@ -315,11 +321,20 @@ fun Context.getCachedDirectories(getVideosOnly: Boolean = false, getImagesOnly:
}.start()
}
fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImagesOnly: Boolean = false, callback: (ArrayList<Medium>) -> Unit) {
fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImagesOnly: Boolean = false, callback: (ArrayList<ThumbnailItem>) -> Unit) {
Thread {
val mediaFetcher = MediaFetcher(this)
val mediumDao = galleryDB.MediumDao()
val foldersToScan = if (path == "/") MediaFetcher(this).getFoldersToScan() else arrayListOf(path)
val foldersToScan = if (path.isEmpty()) mediaFetcher.getFoldersToScan() else arrayListOf(path)
var media = ArrayList<Medium>()
if (path == FAVORITES) {
media.addAll(mediumDao.getFavorites())
}
if (path == RECYCLE_BIN) {
media.addAll(getUpdatedDeletedMedia(mediumDao))
}
val shouldShowHidden = config.shouldShowHidden
foldersToScan.forEach {
try {
@ -345,18 +360,25 @@ fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImag
}
}) as ArrayList<Medium>
MediaFetcher(this).sortMedia(media, config.getFileSorting(path))
callback(media.clone() as ArrayList<Medium>)
val pathToUse = if (path.isEmpty()) SHOW_ALL else path
mediaFetcher.sortMedia(media, config.getFileSorting(pathToUse))
val grouped = mediaFetcher.groupMedia(media, pathToUse)
callback(grouped.clone() as ArrayList<ThumbnailItem>)
val recycleBinPath = filesDir.toString()
media.filter { !getDoesFilePathExist(it.path) }.forEach {
if (it.path.startsWith(recycleBinPath)) {
mediumDao.deleteMediumPath(it.path.removePrefix(recycleBinPath))
} else {
mediumDao.deleteMediumPath(it.path)
}
}
}.start()
}
fun Context.removeInvalidDBDirectories(dirs: ArrayList<Directory>? = null, directoryDao: DirectoryDao = galleryDB.DirectoryDao()) {
val dirsToCheck = dirs ?: directoryDao.getAll()
dirsToCheck.filter { !getDoesFilePathExist(it.path) && it.path != config.tempFolderPath }.forEach {
dirsToCheck.filter { !it.areFavorites() && !it.isRecycleBin() && !getDoesFilePathExist(it.path) && it.path != config.tempFolderPath }.forEach {
directoryDao.deleteDirPath(it.path)
}
}
@ -373,6 +395,14 @@ fun Context.updateDBDirectory(directory: Directory) {
fun Context.getOTGFolderChildren(path: String) = getDocumentFile(path)?.listFiles()
fun Context.getOTGFolderChildrenNames(path: String) = getOTGFolderChildren(path)?.map { it.name }?.toList()
fun Context.getOTGFolderChildrenNames(path: String) = getOTGFolderChildren(path)?.map { it.name }?.toMutableList()
fun Context.getFavoritePaths() = galleryDB.MediumDao().getFavoritePaths() as ArrayList<String>
fun Context.getUpdatedDeletedMedia(mediumDao: MediumDao): ArrayList<Medium> {
val media = mediumDao.getDeletedMedia() as ArrayList<Medium>
media.forEach {
it.path = File(filesDir, it.path).toString()
}
return media
}

View file

@ -1,5 +1,6 @@
package com.simplemobiletools.gallery.fragments
import android.content.Intent
import android.content.res.Configuration
import android.graphics.Bitmap
import android.graphics.BitmapFactory
@ -26,16 +27,21 @@ import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.OTG_PATH
import com.simplemobiletools.commons.helpers.isLollipopPlus
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.PanoramaActivity
import com.simplemobiletools.gallery.activities.PhotoActivity
import com.simplemobiletools.gallery.activities.ViewPagerActivity
import com.simplemobiletools.gallery.extensions.*
import com.simplemobiletools.gallery.helpers.GlideRotateTransformation
import com.simplemobiletools.gallery.helpers.MEDIUM
import com.simplemobiletools.gallery.helpers.PATH
import com.simplemobiletools.gallery.helpers.ROTATE_BY_ASPECT_RATIO
import com.simplemobiletools.gallery.models.Medium
import it.sephiroth.android.library.exif2.ExifInterface
import kotlinx.android.synthetic.main.pager_photo_item.view.*
import org.apache.sanselan.common.byteSources.ByteSourceInputStream
import org.apache.sanselan.formats.jpeg.JpegImageParser
import pl.droidsonroids.gif.GifDrawable
import java.io.File
import java.io.FileOutputStream
@ -46,6 +52,7 @@ class PhotoFragment : ViewPagerFragment() {
private var isFullscreen = false
private var wasInit = false
private var useHalfResolution = false
private var isPanorama = false
private var imageOrientation = -1
private var gifDrawable: GifDrawable? = null
@ -62,6 +69,7 @@ class PhotoFragment : ViewPagerFragment() {
photo_view.setOnClickListener { photoClicked() }
instant_prev_item.setOnClickListener { listener?.goToPrevItem() }
instant_next_item.setOnClickListener { listener?.goToNextItem() }
panorama_outline.setOnClickListener { openPanorama() }
instant_prev_item.parentView = container
instant_next_item.parentView = container
@ -118,6 +126,7 @@ class PhotoFragment : ViewPagerFragment() {
loadImage()
initExtendedDetails()
wasInit = true
checkIfPanorama()
return view
}
@ -286,6 +295,13 @@ class PhotoFragment : ViewPagerFragment() {
}
}
private fun openPanorama() {
Intent(context, PanoramaActivity::class.java).apply {
putExtra(PATH, medium.path)
startActivity(this)
}
}
private fun addZoomableView() {
if (!context!!.config.replaceZoomableImages && medium.isImage() && isFragmentVisible && view.subsampling_view.isGone()) {
ViewPagerActivity.wasDecodedByGlide = false
@ -329,6 +345,18 @@ class PhotoFragment : ViewPagerFragment() {
}
}
private fun checkIfPanorama() {
isPanorama = try {
val inputStream = if (medium.path.startsWith("content:/")) context!!.contentResolver.openInputStream(Uri.parse(medium.path)) else File(medium.path).inputStream()
val imageParser = JpegImageParser().getXmpXml(ByteSourceInputStream(inputStream, medium.name), HashMap<String, Any>())
imageParser.contains("GPano:UsePanoramaViewer=\"True\"", true)
} catch (e: Exception) {
false
}
view.panorama_outline.beVisibleIf(isPanorama && isLollipopPlus())
}
private fun getImageOrientation(): Int {
val defaultOrientation = -1
var orient = defaultOrientation

View file

@ -1,21 +1,32 @@
package com.simplemobiletools.gallery.fragments
import android.annotation.TargetApi
import android.content.res.Configuration
import android.graphics.Point
import android.graphics.SurfaceTexture
import android.media.AudioManager
import android.media.MediaPlayer
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.support.annotation.RequiresApi
import android.util.DisplayMetrics
import android.view.*
import android.view.animation.AnimationUtils
import android.widget.SeekBar
import android.widget.TextView
import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
import com.google.android.exoplayer2.source.ExtractorMediaSource
import com.google.android.exoplayer2.source.TrackGroupArray
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
import com.google.android.exoplayer2.trackselection.TrackSelectionArray
import com.google.android.exoplayer2.upstream.ContentDataSource
import com.google.android.exoplayer2.upstream.DataSource
import com.google.android.exoplayer2.upstream.DataSpec
import com.google.android.exoplayer2.upstream.FileDataSource
import com.google.android.exoplayer2.video.VideoListener
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.isJellyBean1Plus
import com.simplemobiletools.gallery.BuildConfig
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.VideoActivity
import com.simplemobiletools.gallery.extensions.*
@ -24,32 +35,30 @@ import com.simplemobiletools.gallery.helpers.MediaSideScroll
import com.simplemobiletools.gallery.models.Medium
import kotlinx.android.synthetic.main.pager_video_item.view.*
import java.io.File
import java.io.IOException
class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSeekBarChangeListener {
class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, SeekBar.OnSeekBarChangeListener {
private val PROGRESS = "progress"
private val MIN_SKIP_LENGTH = 2000
private val HIDE_PAUSE_DELAY = 2000L
private val PLAY_PAUSE_VISIBLE_ALPHA = 0.8f
private var mMediaPlayer: MediaPlayer? = null
private var mSurfaceView: SurfaceView? = null
private var mSurfaceHolder: SurfaceHolder? = null
private var mTextureView: TextureView? = null
private var mCurrTimeView: TextView? = null
private var mTimerHandler: Handler? = null
private var mSeekBar: SeekBar? = null
private var mTimeHolder: View? = null
private var mView: View? = null
private var mExoPlayer: SimpleExoPlayer? = null
private var mVideoSize = Point(0, 0)
private var mTimerHandler = Handler()
private var mHidePauseHandler = Handler()
private var mIsPlaying = false
private var mIsDragged = false
private var mIsFullscreen = false
private var mIsFragmentVisible = false
private var mPlayOnPrepare = false
private var wasEncoded = false
private var wasInit = false
private var isPrepared = false
private var mWasInit = false
private var mCurrTime = 0
private var mDuration = 0
private var mEncodedPath = ""
private var mStoredShowExtendedDetails = false
private var mStoredHideExtendedDetails = false
@ -77,7 +86,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
}
mIsFullscreen = activity!!.window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == View.SYSTEM_UI_FLAG_FULLSCREEN
mView!!.video_play_outline.alpha = if (mIsFullscreen) 0f else 1f
mView!!.video_play_outline.alpha = if (mIsFullscreen) 0f else PLAY_PAUSE_VISIBLE_ALPHA
setupPlayer()
if (savedInstanceState != null) {
@ -85,7 +94,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
}
checkFullscreen()
wasInit = true
mWasInit = true
mView!!.apply {
brightnessSideScroll = video_brightness_controller
@ -102,6 +111,66 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
video_duration.setOnClickListener { skip(true) }
}
mExoPlayer = ExoPlayerFactory.newSimpleInstance(context, DefaultTrackSelector())
mExoPlayer!!.addListener(object : Player.EventListener {
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {}
override fun onSeekProcessed() {}
override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) {}
override fun onPlayerError(error: ExoPlaybackException?) {
activity?.showErrorToast(error.toString())
}
override fun onLoadingChanged(isLoading: Boolean) {}
override fun onPositionDiscontinuity(reason: Int) {}
override fun onRepeatModeChanged(repeatMode: Int) {}
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {}
override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) {}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
when (playbackState) {
Player.STATE_READY -> videoPrepared()
Player.STATE_ENDED -> videoCompleted()
}
}
})
mExoPlayer!!.addVideoListener(object : VideoListener {
override fun onVideoSizeChanged(width: Int, height: Int, unappliedRotationDegrees: Int, pixelWidthHeightRatio: Float) {
mVideoSize.x = width
mVideoSize.y = height
setVideoSize()
}
override fun onRenderedFirstFrame() {}
})
val isContentUri = medium.path.startsWith("content://")
val uri = if (isContentUri) Uri.parse(medium.path) else Uri.fromFile(File(medium.path))
val dataSpec = DataSpec(uri)
val fileDataSource = if (isContentUri) ContentDataSource(context) else FileDataSource()
try {
fileDataSource.open(dataSpec)
} catch (e: Exception) {
activity?.showErrorToast(e)
}
val factory = DataSource.Factory { fileDataSource }
val audioSource = ExtractorMediaSource(fileDataSource.uri, factory, DefaultExtractorsFactory(), null, null)
mExoPlayer!!.audioStreamType = AudioManager.STREAM_MUSIC
mExoPlayer!!.prepare(audioSource)
medium.path.getVideoResolution()?.apply {
mVideoSize.x = x
mVideoSize.y = y
setVideoSize()
}
return mView
}
@ -157,26 +226,23 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
mView!!.video_play_outline.setOnClickListener { togglePlayPause() }
mSurfaceView = mView!!.video_surface
mSurfaceHolder = mSurfaceView!!.holder
mSurfaceHolder!!.addCallback(this)
mSurfaceView!!.setOnClickListener { toggleFullscreen() }
mTextureView = mView!!.video_surface
mTextureView!!.setOnClickListener { toggleFullscreen() }
mTextureView!!.surfaceTextureListener = this
mView!!.video_holder.setOnClickListener { toggleFullscreen() }
initTimeHolder()
checkExtendedDetails()
initMediaPlayer()
}
override fun setMenuVisibility(menuVisible: Boolean) {
super.setMenuVisibility(menuVisible)
if (mIsFragmentVisible && !menuVisible) {
pauseVideo()
releaseMediaPlayer()
}
mIsFragmentVisible = menuVisible
if (menuVisible && wasInit) {
initMediaPlayer()
if (menuVisible && mWasInit) {
if (context?.config?.autoplayVideos == true) {
playVideo()
}
@ -252,20 +318,19 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
private fun setupTimeHolder() {
mSeekBar!!.max = mDuration
mView!!.video_duration.text = mDuration.getFormattedDuration()
mTimerHandler = Handler()
setupTimer()
}
private fun setupTimer() {
activity!!.runOnUiThread(object : Runnable {
override fun run() {
if (mMediaPlayer != null && !mIsDragged && mIsPlaying) {
mCurrTime = mMediaPlayer!!.currentPosition / 1000
if (mExoPlayer != null && !mIsDragged && mIsPlaying) {
mCurrTime = (mExoPlayer!!.currentPosition / 1000).toInt()
mSeekBar!!.progress = mCurrTime
mCurrTimeView!!.text = mCurrTime.getFormattedDuration()
}
mTimerHandler!!.postDelayed(this, 1000)
mTimerHandler.postDelayed(this, 1000)
}
})
}
@ -299,9 +364,8 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
if (activity == null || !isAdded)
return
initMediaPlayer()
mIsPlaying = !mIsPlaying
mHidePauseHandler.removeCallbacksAndMessages(null)
if (mIsPlaying) {
playVideo()
} else {
@ -310,102 +374,65 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
}
fun playVideo() {
if (mMediaPlayer != null && isPrepared) {
mIsPlaying = true
mMediaPlayer?.start()
} else {
mPlayOnPrepare = true
}
mView!!.video_play_outline.setImageDrawable(resources.getDrawable(R.drawable.img_pause_outline_big))
activity!!.window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
private fun pauseVideo() {
mIsPlaying = false
mMediaPlayer?.pause()
mView?.video_play_outline?.setImageDrawable(resources.getDrawable(R.drawable.img_play_outline_big))
activity!!.window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
private fun initMediaPlayer() {
if (mMediaPlayer != null || !mIsFragmentVisible) {
if (mExoPlayer == null) {
return
}
val mediumPath = if (wasEncoded) mEncodedPath else getPathToLoad(medium)
if (videoEnded()) {
setProgress(0)
}
// this workaround is needed for example if the filename contains a colon
val fileUri = if (mediumPath.startsWith("/")) context!!.getFilePublicUri(File(mediumPath), BuildConfig.APPLICATION_ID) else Uri.parse(mediumPath)
try {
mMediaPlayer = MediaPlayer().apply {
setDataSource(context, fileUri)
setDisplay(mSurfaceHolder)
setOnCompletionListener { videoCompleted() }
setOnVideoSizeChangedListener { mediaPlayer, width, height -> setVideoSize() }
setOnPreparedListener { videoPrepared(it) }
setAudioStreamType(AudioManager.STREAM_MUSIC)
prepare()
mIsPlaying = true
mExoPlayer?.playWhenReady = true
mView!!.video_play_outline.setImageDrawable(resources.getDrawable(R.drawable.img_pause_outline_big))
activity!!.window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
mHidePauseHandler.postDelayed({
mView!!.video_play_outline.animate().alpha(0f).start()
}, HIDE_PAUSE_DELAY)
}
} catch (e: IOException) {
mEncodedPath = Uri.encode(getPathToLoad(medium))
if (wasEncoded) {
releaseMediaPlayer()
} else {
wasEncoded = true
mMediaPlayer = null
initMediaPlayer()
private fun pauseVideo() {
if (mExoPlayer == null) {
return
}
} catch (e: Exception) {
releaseMediaPlayer()
mIsPlaying = false
if (!videoEnded()) {
mExoPlayer?.playWhenReady = false
}
mView?.video_play_outline?.setImageDrawable(resources.getDrawable(R.drawable.img_play_outline_big))
mView!!.video_play_outline.alpha = PLAY_PAUSE_VISIBLE_ALPHA
activity!!.window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
private fun videoEnded() = mExoPlayer!!.currentPosition >= mExoPlayer!!.duration
private fun setProgress(seconds: Int) {
mMediaPlayer!!.seekTo(seconds * 1000)
mExoPlayer!!.seekTo(seconds * 1000L)
mSeekBar!!.progress = seconds
mCurrTimeView!!.text = seconds.getFormattedDuration()
}
private fun addPreviewImage() {
mMediaPlayer!!.start()
mMediaPlayer!!.pause()
}
private fun cleanup() {
pauseVideo()
mCurrTimeView?.text = 0.getFormattedDuration()
releaseMediaPlayer()
mSeekBar?.progress = 0
mTimerHandler?.removeCallbacksAndMessages(null)
mSurfaceView = null
mSurfaceHolder?.removeCallback(this)
mSurfaceHolder = null
}
private fun releaseMediaPlayer() {
mMediaPlayer?.setSurface(null)
mMediaPlayer?.release()
mMediaPlayer = null
}
private fun videoPrepared(mediaPlayer: MediaPlayer) {
isPrepared = true
mDuration = mediaPlayer.duration / 1000
addPreviewImage()
private fun videoPrepared() {
if (mDuration == 0) {
mDuration = (mExoPlayer!!.duration / 1000).toInt()
setupTimeHolder()
setProgress(mCurrTime)
if (mIsFragmentVisible && (context!!.config.autoplayVideos || mPlayOnPrepare)) {
if (mIsFragmentVisible && (context!!.config.autoplayVideos)) {
playVideo()
}
}
}
private fun videoCompleted() {
if (!isAdded) {
if (!isAdded || mExoPlayer == null) {
return
}
mCurrTime = (mExoPlayer!!.duration / 1000).toInt()
if (listener?.videoEnded() == false && context!!.config.loopVideos) {
playVideo()
} else {
@ -415,37 +442,43 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
}
}
override fun surfaceCreated(holder: SurfaceHolder) {
mSurfaceHolder = holder
if (mIsFragmentVisible) {
initMediaPlayer()
}
private fun cleanup() {
pauseVideo()
mCurrTimeView?.text = 0.getFormattedDuration()
releaseExoPlayer()
mSeekBar?.progress = 0
mTimerHandler.removeCallbacksAndMessages(null)
mHidePauseHandler.removeCallbacksAndMessages(null)
mTextureView = null
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
if (width != 0 && height != 0 && mSurfaceView != null) {
setVideoSize()
}
private fun releaseExoPlayer() {
mExoPlayer?.stop()
mExoPlayer?.release()
mExoPlayer = null
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
releaseMediaPlayer()
override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture?, width: Int, height: Int) {
}
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
override fun onSurfaceTextureUpdated(surface: SurfaceTexture?) {
}
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture?): Boolean {
releaseExoPlayer()
return false
}
override fun onSurfaceTextureAvailable(surface: SurfaceTexture?, width: Int, height: Int) {
mExoPlayer?.setVideoSurface(Surface(mTextureView!!.surfaceTexture))
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private fun setVideoSize() {
if (mSurfaceHolder == null)
mSurfaceHolder = mSurfaceView!!.holder
if (activity == null || mSurfaceHolder == null || !mSurfaceHolder!!.surface.isValid)
if (activity == null || mTextureView == null)
return
initMediaPlayer()
if (mMediaPlayer == null) {
return
}
val videoProportion = mMediaPlayer!!.videoWidth.toFloat() / mMediaPlayer!!.videoHeight.toFloat()
val videoProportion = mVideoSize.x.toFloat() / mVideoSize.y.toFloat()
val display = activity!!.windowManager.defaultDisplay
val screenWidth: Int
val screenHeight: Int
@ -462,7 +495,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
val screenProportion = screenWidth.toFloat() / screenHeight.toFloat()
mSurfaceView!!.layoutParams.apply {
mTextureView!!.layoutParams.apply {
if (videoProportion > screenProportion) {
width = screenWidth
height = (screenWidth.toFloat() / videoProportion).toInt()
@ -470,7 +503,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
width = (videoProportion * screenHeight.toFloat()).toInt()
height = screenHeight
}
mSurfaceView!!.layoutParams = this
mTextureView!!.layoutParams = this
}
}
@ -496,15 +529,15 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
}
private fun skip(forward: Boolean) {
if (mMediaPlayer == null) {
if (mExoPlayer == null) {
return
}
val curr = mMediaPlayer!!.currentPosition
val twoPercents = Math.max(mMediaPlayer!!.duration / 50, MIN_SKIP_LENGTH)
val curr = mExoPlayer!!.currentPosition
val twoPercents = Math.max((mExoPlayer!!.duration / 50).toInt(), MIN_SKIP_LENGTH)
val newProgress = if (forward) curr + twoPercents else curr - twoPercents
val roundProgress = Math.round(newProgress / 1000f)
val limitedProgress = Math.max(Math.min(mMediaPlayer!!.duration / 1000, roundProgress), 0)
val limitedProgress = Math.max(Math.min(mExoPlayer!!.duration.toInt(), roundProgress), 0)
setProgress(limitedProgress)
if (!mIsPlaying) {
togglePlayPause()
@ -512,17 +545,16 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
}
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (mMediaPlayer != null && fromUser) {
if (mExoPlayer != null && fromUser) {
setProgress(progress)
}
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
initMediaPlayer()
if (mMediaPlayer == null)
if (mExoPlayer == null)
return
mMediaPlayer!!.pause()
mExoPlayer!!.playWhenReady = false
mIsDragged = true
}
@ -530,7 +562,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
if (!mIsPlaying) {
togglePlayPause()
} else {
mMediaPlayer?.start()
mExoPlayer!!.playWhenReady = true
}
mIsDragged = false
@ -549,7 +581,16 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
}
}
mView!!.video_play_outline.animate().alpha(if (isFullscreen) 0f else 1f).start()
mView!!.video_play_outline.animate().alpha(if (isFullscreen && mIsPlaying) 0f else PLAY_PAUSE_VISIBLE_ALPHA).start()
if (isFullscreen) {
mHidePauseHandler.removeCallbacksAndMessages(null)
} else {
mHidePauseHandler.postDelayed({
if (mExoPlayer?.currentPosition ?: 0 > 0) {
mView!!.video_play_outline.animate().alpha(0f).start()
}
}, HIDE_PAUSE_DELAY)
}
}
private fun getExtendedDetailsY(height: Int): Float {

View file

@ -36,6 +36,28 @@ class Config(context: Context) : BaseConfig(context) {
fun hasCustomSorting(path: String) = prefs.contains(SORT_FOLDER_PREFIX + path.toLowerCase())
fun saveFolderGrouping(path: String, value: Int) {
if (path.isEmpty()) {
groupBy = value
} else {
prefs.edit().putInt(GROUP_FOLDER_PREFIX + path.toLowerCase(), value).apply()
}
}
fun getFolderGrouping(path: String): Int {
var groupBy = prefs.getInt(GROUP_FOLDER_PREFIX + path.toLowerCase(), groupBy)
if (path != SHOW_ALL && groupBy and GROUP_BY_FOLDER != 0) {
groupBy -= GROUP_BY_FOLDER + 1
}
return groupBy
}
fun removeFolderGrouping(path: String) {
prefs.edit().remove(GROUP_FOLDER_PREFIX + path.toLowerCase()).apply()
}
fun hasCustomGrouping(path: String) = prefs.contains(GROUP_FOLDER_PREFIX + path.toLowerCase())
var wasHideFolderTooltipShown: Boolean
get() = prefs.getBoolean(HIDE_FOLDER_TOOLTIP_SHOWN, false)
set(wasShown) = prefs.edit().putBoolean(HIDE_FOLDER_TOOLTIP_SHOWN, wasShown).apply()
@ -239,10 +261,6 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getBoolean(ALLOW_VIDEO_GESTURES, true)
set(allowVideoGestures) = prefs.edit().putBoolean(ALLOW_VIDEO_GESTURES, allowVideoGestures).apply()
var bottomActions: Boolean
get() = prefs.getBoolean(BOTTOM_ACTIONS, true)
set(bottomActions) = prefs.edit().putBoolean(BOTTOM_ACTIONS, bottomActions).apply()
var showMediaCount: Boolean
get() = prefs.getBoolean(SHOW_MEDIA_COUNT, true)
set(showMediaCount) = prefs.edit().putBoolean(SHOW_MEDIA_COUNT, showMediaCount).apply()
@ -322,4 +340,33 @@ class Config(context: Context) : BaseConfig(context) {
var tempSkipDeleteConfirmation: Boolean
get() = prefs.getBoolean(TEMP_SKIP_DELETE_CONFIRMATION, false)
set(tempSkipDeleteConfirmation) = prefs.edit().putBoolean(TEMP_SKIP_DELETE_CONFIRMATION, tempSkipDeleteConfirmation).apply()
var wereFavoritesPinned: Boolean
get() = prefs.getBoolean(WERE_FAVORITES_PINNED, false)
set(wereFavoritesPinned) = prefs.edit().putBoolean(WERE_FAVORITES_PINNED, wereFavoritesPinned).apply()
var wasRecycleBinPinned: Boolean
get() = prefs.getBoolean(WAS_RECYCLE_BIN_PINNED, false)
set(wasRecycleBinPinned) = prefs.edit().putBoolean(WAS_RECYCLE_BIN_PINNED, wasRecycleBinPinned).apply()
var groupBy: Int
get() = prefs.getInt(GROUP_BY, GROUP_BY_NONE)
set(groupBy) = prefs.edit().putInt(GROUP_BY, groupBy).apply()
var useRecycleBin: Boolean
get() = prefs.getBoolean(USE_RECYCLE_BIN, true)
set(useRecycleBin) = prefs.edit().putBoolean(USE_RECYCLE_BIN, useRecycleBin).apply()
var bottomActions: Boolean
get() = prefs.getBoolean(BOTTOM_ACTIONS, true)
set(bottomActions) = prefs.edit().putBoolean(BOTTOM_ACTIONS, bottomActions).apply()
var visibleBottomActions: Int
get() = prefs.getInt(VISIBLE_BOTTOM_ACTIONS, DEFAULT_BOTTOM_ACTIONS)
set(visibleBottomActions) = prefs.edit().putInt(VISIBLE_BOTTOM_ACTIONS, visibleBottomActions).apply()
// if a user hides a folder, then enables temporary hidden folder displaying, make sure we show it properly
var everShownFolders: Set<String>
get() = prefs.getStringSet(EVER_SHOWN_FOLDERS, HashSet<String>())
set(everShownFolders) = prefs.edit().putStringSet(EVER_SHOWN_FOLDERS, everShownFolders).apply()
}

View file

@ -1,8 +1,11 @@
package com.simplemobiletools.gallery.helpers
import com.simplemobiletools.commons.helpers.MONTH_SECONDS
// shared preferences
const val DIRECTORY_SORT_ORDER = "directory_sort_order"
const val SORT_FOLDER_PREFIX = "sort_folder_"
const val GROUP_FOLDER_PREFIX = "group_folder_"
const val SHOW_HIDDEN_MEDIA = "show_hidden_media"
const val TEMPORARILY_SHOW_HIDDEN = "temporarily_show_hidden"
const val IS_THIRD_PARTY_INTENT = "is_third_party_intent"
@ -49,6 +52,12 @@ const val LAST_FILEPICKER_PATH = "last_filepicker_path"
const val WAS_OTG_HANDLED = "was_otg_handled"
const val TEMP_SKIP_DELETE_CONFIRMATION = "temp_skip_delete_confirmation"
const val BOTTOM_ACTIONS = "bottom_actions"
const val VISIBLE_BOTTOM_ACTIONS = "visible_bottom_actions"
const val WERE_FAVORITES_PINNED = "were_favorites_pinned"
const val WAS_RECYCLE_BIN_PINNED = "was_recycle_bin_pinned"
const val USE_RECYCLE_BIN = "use_recycle_bin"
const val GROUP_BY = "group_by"
const val EVER_SHOWN_FOLDERS = "ever_shown_folders"
// slideshow
const val SLIDESHOW_INTERVAL = "slideshow_interval"
@ -64,10 +73,14 @@ const val SLIDESHOW_SCROLL_DURATION = 500L
const val NOMEDIA = ".nomedia"
const val FAVORITES = "favorites"
const val RECYCLE_BIN = "recycle_bin"
const val SHOW_FAVORITES = "show_favorites"
const val SHOW_RECYCLE_BIN = "show_recycle_bin"
const val MAX_COLUMN_COUNT = 20
const val SHOW_TEMP_HIDDEN_DURATION = 300000L
const val CLICK_MAX_DURATION = 150
const val DRAG_THRESHOLD = 8
const val MONTH_MILLISECONDS = MONTH_SECONDS * 1000L
const val DIRECTORY = "directory"
const val MEDIUM = "medium"
@ -110,3 +123,26 @@ const val TYPE_RAWS = 8
const val LOCAITON_INTERNAL = 1
const val LOCATION_SD = 2
const val LOCATION_OTG = 3
const val GROUP_BY_NONE = 1
const val GROUP_BY_LAST_MODIFIED = 2
const val GROUP_BY_DATE_TAKEN = 4
const val GROUP_BY_FILE_TYPE = 8
const val GROUP_BY_EXTENSION = 16
const val GROUP_BY_FOLDER = 32
const val GROUP_DESCENDING = 1024
// bottom actions
const val BOTTOM_ACTION_TOGGLE_FAVORITE = 1
const val BOTTOM_ACTION_EDIT = 2
const val BOTTOM_ACTION_SHARE = 4
const val BOTTOM_ACTION_DELETE = 8
const val BOTTOM_ACTION_ROTATE = 16
const val BOTTOM_ACTION_PROPERTIES = 32
const val BOTTOM_ACTION_CHANGE_ORIENTATION = 64
const val BOTTOM_ACTION_SLIDESHOW = 128
const val BOTTOM_ACTION_SHOW_ON_MAP = 256
const val BOTTOM_ACTION_TOGGLE_VISIBILITY = 512
const val BOTTOM_ACTION_RENAME = 1024
const val DEFAULT_BOTTOM_ACTIONS = BOTTOM_ACTION_TOGGLE_FAVORITE or BOTTOM_ACTION_EDIT or BOTTOM_ACTION_SHARE or BOTTOM_ACTION_DELETE

View file

@ -4,14 +4,16 @@ import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.provider.MediaStore
import android.text.format.DateFormat
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.extensions.getDistinctPath
import com.simplemobiletools.gallery.extensions.getOTGFolderChildren
import com.simplemobiletools.gallery.extensions.shouldFolderBeVisible
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.extensions.*
import com.simplemobiletools.gallery.models.Medium
import com.simplemobiletools.gallery.models.ThumbnailItem
import com.simplemobiletools.gallery.models.ThumbnailSection
import java.io.File
import java.util.*
class MediaFetcher(val context: Context) {
var shouldStop = false
@ -112,7 +114,7 @@ class MediaFetcher(val context: Context) {
val foldersToIgnore = arrayListOf("/storage/emulated/legacy")
val config = context.config
val includedFolders = config.includedFolders
var foldersToScan = ArrayList<String>()
var foldersToScan = config.everShownFolders.toMutableList() as ArrayList
cursor.use {
if (cursor.moveToFirst()) {
@ -159,7 +161,19 @@ class MediaFetcher(val context: Context) {
private fun getMediaInFolder(folder: String, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int, getProperDateTaken: Boolean,
favoritePaths: ArrayList<String>): ArrayList<Medium> {
val media = ArrayList<Medium>()
val files = File(folder).listFiles() ?: return media
val deletedMedia = if (folder == RECYCLE_BIN) {
context.getUpdatedDeletedMedia(context.galleryDB.MediumDao())
} else {
ArrayList()
}
val files = when (folder) {
FAVORITES -> favoritePaths.map { File(it) }.toTypedArray()
RECYCLE_BIN -> deletedMedia.map { File(it.path) }.toTypedArray()
else -> File(folder).listFiles() ?: return media
}
val doExtraCheck = context.config.doExtraCheck
val showHidden = context.config.shouldShowHidden
val dateTakens = if (getProperDateTaken) getFolderDateTakens(folder) else HashMap()
@ -197,6 +211,12 @@ class MediaFetcher(val context: Context) {
if (size <= 0L || (doExtraCheck && !file.exists()))
continue
val path = file.absolutePath
if (folder == RECYCLE_BIN) {
deletedMedia.firstOrNull { it.path == path }?.apply {
media.add(this)
}
} else {
val lastModified = file.lastModified()
var dateTaken = lastModified
@ -211,11 +231,11 @@ class MediaFetcher(val context: Context) {
else -> TYPE_RAWS
}
val path = file.absolutePath
val isFavorite = favoritePaths.contains(path)
val medium = Medium(null, filename, path, folder, lastModified, dateTaken, size, type, isFavorite)
val medium = Medium(null, filename, path, file.parent, lastModified, dateTaken, size, type, isFavorite, 0L)
media.add(medium)
}
}
return media
}
@ -270,7 +290,7 @@ class MediaFetcher(val context: Context) {
val path = Uri.decode(file.uri.toString().replaceFirst("${context.config.OTGTreeUri}/document/${context.config.OTGPartition}%3A", OTG_PATH))
val isFavorite = favoritePaths.contains(path)
val medium = Medium(null, filename, path, folder, dateModified, dateTaken, size, type, isFavorite)
val medium = Medium(null, filename, path, folder, dateModified, dateTaken, size, type, isFavorite, 0L)
media.add(medium)
}
@ -323,4 +343,82 @@ class MediaFetcher(val context: Context) {
result
})
}
fun groupMedia(media: ArrayList<Medium>, path: String): ArrayList<ThumbnailItem> {
val mediumGroups = LinkedHashMap<String, ArrayList<Medium>>()
val pathToCheck = if (path.isEmpty()) SHOW_ALL else path
val currentGrouping = context.config.getFolderGrouping(pathToCheck)
if (currentGrouping and GROUP_BY_NONE != 0) {
return media as ArrayList<ThumbnailItem>
}
val thumbnailItems = ArrayList<ThumbnailItem>()
if (context.config.scrollHorizontally) {
media.mapTo(thumbnailItems) { it }
return thumbnailItems
}
media.forEach {
val key = it.getGroupingKey(currentGrouping)
if (!mediumGroups.containsKey(key)) {
mediumGroups[key] = ArrayList()
}
mediumGroups[key]!!.add(it)
}
val sortDescending = currentGrouping and GROUP_DESCENDING != 0
val sorted = mediumGroups.toSortedMap(if (sortDescending) compareByDescending { it } else compareBy { it })
mediumGroups.clear()
for ((key, value) in sorted) {
mediumGroups[key] = value
}
val today = formatDate(System.currentTimeMillis().toString())
val yesterday = formatDate((System.currentTimeMillis() - DAY_SECONDS * 1000).toString())
for ((key, value) in mediumGroups) {
val sectionKey = getFormattedKey(key, currentGrouping, today, yesterday)
thumbnailItems.add(ThumbnailSection(sectionKey))
thumbnailItems.addAll(value)
}
return thumbnailItems
}
private fun getFormattedKey(key: String, grouping: Int, today: String, yesterday: String): String {
return when {
grouping and GROUP_BY_LAST_MODIFIED != 0 || grouping and GROUP_BY_DATE_TAKEN != 0 -> getFinalDate(formatDate(key), today, yesterday)
grouping and GROUP_BY_FILE_TYPE != 0 -> getFileTypeString(key)
grouping and GROUP_BY_EXTENSION != 0 -> key.toUpperCase()
grouping and GROUP_BY_FOLDER != 0 -> context.humanizePath(key)
else -> key
}
}
private fun getFinalDate(date: String, today: String, yesterday: String): String {
return when (date) {
today -> context.getString(R.string.today)
yesterday -> context.getString(R.string.yesterday)
else -> date
}
}
private fun formatDate(timestamp: String): String {
return if (timestamp.areDigitsOnly()) {
val cal = Calendar.getInstance(Locale.ENGLISH)
cal.timeInMillis = timestamp.toLong()
return DateFormat.format("dd MMM yyyy", cal).toString()
} else {
""
}
}
private fun getFileTypeString(key: String): String {
val stringId = when (key.toInt()) {
TYPE_IMAGES -> R.string.images
TYPE_VIDEOS -> R.string.videos
TYPE_GIFS -> R.string.gifs
else -> R.string.raw_images
}
return context.getString(stringId)
}
}

View file

@ -4,6 +4,7 @@ import android.arch.persistence.room.Dao
import android.arch.persistence.room.Insert
import android.arch.persistence.room.OnConflictStrategy.REPLACE
import android.arch.persistence.room.Query
import com.simplemobiletools.gallery.helpers.RECYCLE_BIN
import com.simplemobiletools.gallery.models.Directory
@Dao
@ -17,12 +18,15 @@ interface DirectoryDao {
@Insert(onConflict = REPLACE)
fun insertAll(directories: List<Directory>)
@Query("DELETE FROM directories WHERE path = :path")
@Query("DELETE FROM directories WHERE path = :path COLLATE NOCASE")
fun deleteDirPath(path: String)
@Query("UPDATE OR REPLACE directories SET thumbnail = :thumbnail, media_count = :mediaCnt, last_modified = :lastModified, date_taken = :dateTaken, size = :size, media_types = :mediaTypes WHERE path = :path")
@Query("UPDATE OR REPLACE directories SET thumbnail = :thumbnail, media_count = :mediaCnt, last_modified = :lastModified, date_taken = :dateTaken, size = :size, media_types = :mediaTypes WHERE path = :path COLLATE NOCASE")
fun updateDirectory(path: String, thumbnail: String, mediaCnt: Int, lastModified: Long, dateTaken: Long, size: Long, mediaTypes: Int)
@Query("UPDATE directories SET thumbnail = :thumbnail, filename = :name, path = :newPath WHERE path = :oldPath")
@Query("UPDATE directories SET thumbnail = :thumbnail, filename = :name, path = :newPath WHERE path = :oldPath COLLATE NOCASE")
fun updateDirectoryAfterRename(thumbnail: String, name: String, newPath: String, oldPath: String)
@Query("DELETE FROM directories WHERE path = \'$RECYCLE_BIN\' COLLATE NOCASE")
fun deleteRecycleBin()
}

View file

@ -0,0 +1,14 @@
package com.simplemobiletools.gallery.interfaces
import com.simplemobiletools.gallery.models.Directory
import java.io.File
interface DirectoryOperationsListener {
fun refreshItems()
fun deleteFolders(folders: ArrayList<File>)
fun recheckPinnedFolders()
fun updateDirectories(directories: ArrayList<Directory>)
}

View file

@ -0,0 +1,11 @@
package com.simplemobiletools.gallery.interfaces
import com.simplemobiletools.commons.models.FileDirItem
interface MediaOperationsListener {
fun refreshItems()
fun tryDeleteFiles(fileDirItems: ArrayList<FileDirItem>)
fun selectedPaths(paths: ArrayList<String>)
}

View file

@ -8,24 +8,36 @@ import com.simplemobiletools.gallery.models.Medium
@Dao
interface MediumDao {
@Query("SELECT filename, full_path, parent_path, last_modified, date_taken, size, type, is_favorite FROM media WHERE parent_path = :path")
@Query("SELECT filename, full_path, parent_path, last_modified, date_taken, size, type, is_favorite, deleted_ts FROM media WHERE deleted_ts = 0 AND parent_path = :path COLLATE NOCASE")
fun getMediaFromPath(path: String): List<Medium>
@Query("SELECT full_path FROM media WHERE is_favorite = 1")
@Query("SELECT filename, full_path, parent_path, last_modified, date_taken, size, type, is_favorite, deleted_ts FROM media WHERE deleted_ts = 0 AND is_favorite = 1")
fun getFavorites(): List<Medium>
@Query("SELECT full_path FROM media WHERE deleted_ts = 0 AND is_favorite = 1")
fun getFavoritePaths(): List<String>
@Query("SELECT filename, full_path, parent_path, last_modified, date_taken, size, type, is_favorite, deleted_ts FROM media WHERE deleted_ts != 0")
fun getDeletedMedia(): List<Medium>
@Insert(onConflict = REPLACE)
fun insert(medium: Medium)
@Insert(onConflict = REPLACE)
fun insertAll(media: List<Medium>)
@Query("DELETE FROM media WHERE full_path = :path")
@Query("DELETE FROM media WHERE full_path = :path COLLATE NOCASE")
fun deleteMediumPath(path: String)
@Query("UPDATE OR REPLACE media SET filename = :newFilename, full_path = :newFullPath, parent_path = :newParentPath WHERE full_path = :oldPath")
@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")
@Query("UPDATE media SET is_favorite = :isFavorite WHERE full_path = :path COLLATE NOCASE")
fun updateFavorite(path: String, isFavorite: Boolean)
@Query("UPDATE media SET deleted_ts = :deletedTS WHERE full_path = :path COLLATE NOCASE")
fun updateDeleted(path: String, deletedTS: Long)
@Query("DELETE FROM media WHERE deleted_ts != 0")
fun clearRecycleBin()
}

View file

@ -10,6 +10,8 @@ import com.simplemobiletools.commons.helpers.SORT_BY_DATE_MODIFIED
import com.simplemobiletools.commons.helpers.SORT_BY_NAME
import com.simplemobiletools.commons.helpers.SORT_BY_PATH
import com.simplemobiletools.commons.helpers.SORT_BY_SIZE
import com.simplemobiletools.gallery.helpers.FAVORITES
import com.simplemobiletools.gallery.helpers.RECYCLE_BIN
import java.io.Serializable
@Entity(tableName = "directories", indices = [Index(value = "path", unique = true)])
@ -36,4 +38,8 @@ data class Directory(
sorting and SORT_BY_DATE_MODIFIED != 0 -> modified.formatDate()
else -> taken.formatDate()
}
fun areFavorites() = path == FAVORITES
fun isRecycleBin() = path == RECYCLE_BIN
}

View file

@ -6,15 +6,14 @@ import android.arch.persistence.room.Index
import android.arch.persistence.room.PrimaryKey
import com.simplemobiletools.commons.extensions.formatDate
import com.simplemobiletools.commons.extensions.formatSize
import com.simplemobiletools.commons.extensions.getFilenameExtension
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_MODIFIED
import com.simplemobiletools.commons.helpers.SORT_BY_NAME
import com.simplemobiletools.commons.helpers.SORT_BY_PATH
import com.simplemobiletools.commons.helpers.SORT_BY_SIZE
import com.simplemobiletools.gallery.helpers.TYPE_GIFS
import com.simplemobiletools.gallery.helpers.TYPE_IMAGES
import com.simplemobiletools.gallery.helpers.TYPE_RAWS
import com.simplemobiletools.gallery.helpers.TYPE_VIDEOS
import com.simplemobiletools.gallery.helpers.*
import java.io.Serializable
import java.util.*
@Entity(tableName = "media", indices = [(Index(value = "full_path", unique = true))])
data class Medium(
@ -26,10 +25,11 @@ data class Medium(
@ColumnInfo(name = "date_taken") var taken: Long,
@ColumnInfo(name = "size") val size: Long,
@ColumnInfo(name = "type") val type: Int,
@ColumnInfo(name = "is_favorite") var isFavorite: Boolean) : Serializable {
@ColumnInfo(name = "is_favorite") var isFavorite: Boolean,
@ColumnInfo(name = "deleted_ts") var deletedTS: Long) : Serializable, ThumbnailItem() {
companion object {
private const val serialVersionUID = -6553149366975455L
private const val serialVersionUID = -6553149366975655L
}
fun isGif() = type == TYPE_GIFS
@ -40,6 +40,8 @@ data class Medium(
fun isRaw() = type == TYPE_RAWS
fun isHidden() = name.startsWith('.')
fun getBubbleText(sorting: Int) = when {
sorting and SORT_BY_NAME != 0 -> name
sorting and SORT_BY_PATH != 0 -> path
@ -47,4 +49,29 @@ data class Medium(
sorting and SORT_BY_DATE_MODIFIED != 0 -> modified.formatDate()
else -> taken.formatDate()
}
fun getGroupingKey(groupBy: Int): String {
return when {
groupBy and GROUP_BY_LAST_MODIFIED != 0 -> getDayStartTS(modified)
groupBy and GROUP_BY_DATE_TAKEN != 0 -> getDayStartTS(taken)
groupBy and GROUP_BY_FILE_TYPE != 0 -> type.toString()
groupBy and GROUP_BY_EXTENSION != 0 -> name.getFilenameExtension().toLowerCase()
groupBy and GROUP_BY_FOLDER != 0 -> parentPath
else -> ""
}
}
fun getIsInRecycleBin() = deletedTS != 0L
private fun getDayStartTS(ts: Long): String {
val calendar = Calendar.getInstance(Locale.ENGLISH).apply {
timeInMillis = ts
set(Calendar.HOUR_OF_DAY, 0)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
return calendar.timeInMillis.toString()
}
}

View file

@ -0,0 +1,3 @@
package com.simplemobiletools.gallery.models
open class ThumbnailItem

View file

@ -0,0 +1,3 @@
package com.simplemobiletools.gallery.models
data class ThumbnailSection(val title: String) : ThumbnailItem()

View file

@ -19,7 +19,7 @@ class RefreshMediaReceiver : BroadcastReceiver() {
Thread {
val medium = Medium(null, path.getFilenameFromPath(), path, path.getParentPath(), System.currentTimeMillis(), System.currentTimeMillis(),
File(path).length(), getFileType(path), false)
File(path).length(), getFileType(path), false, 0L)
context.galleryDB.MediumDao().insert(medium)
}.start()
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

View file

Before

Width:  |  Height:  |  Size: 680 B

After

Width:  |  Height:  |  Size: 680 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 B

View file

Before

Width:  |  Height:  |  Size: 812 B

After

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 996 B

View file

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 845 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 979 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

Before

Width:  |  Height:  |  Size: 994 B

After

Width:  |  Height:  |  Size: 994 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 B

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/panorama_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF000000">
<com.google.vr.sdk.widgets.pano.VrPanoramaView
android:id="@+id/panorama_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
<ImageView
android:id="@+id/cardboard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:padding="@dimen/activity_margin"
android:src="@drawable/ic_cardboard"/>
<ImageView
android:id="@+id/explore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:padding="@dimen/activity_margin"
android:src="@drawable/ic_explore"/>
</RelativeLayout>

View file

@ -649,29 +649,6 @@
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_bottom_actions_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/settings_bottom_actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:text="@string/show_at_bottom"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_screen_rotation_holder"
android:layout_width="match_parent"
@ -941,5 +918,144 @@
android:text="@string/skip_delete_confirmation"/>
</RelativeLayout>
<View
android:id="@+id/bottom_actions_divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/divider_grey"
android:importantForAccessibility="no"/>
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/bottom_actions_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/bigger_margin"
android:layout_marginStart="@dimen/bigger_margin"
android:layout_marginTop="@dimen/activity_margin"
android:text="@string/bottom_actions"
android:textAllCaps="true"
android:textSize="@dimen/smaller_text_size"/>
<RelativeLayout
android:id="@+id/settings_bottom_actions_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/settings_bottom_actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:text="@string/show_at_bottom"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_manage_bottom_actions_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_manage_bottom_actions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:text="@string/manage_bottom_actions"/>
</RelativeLayout>
<View
android:id="@+id/recycle_bin_divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/divider_grey"
android:importantForAccessibility="no"/>
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/recycle_bin_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/bigger_margin"
android:layout_marginStart="@dimen/bigger_margin"
android:layout_marginTop="@dimen/activity_margin"
android:text="@string/recycle_bin"
android:textAllCaps="true"
android:textSize="@dimen/smaller_text_size"/>
<RelativeLayout
android:id="@+id/settings_use_recycle_bin_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/settings_use_recycle_bin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:text="@string/move_items_into_recycle_bin"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_empty_recycle_bin_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/bigger_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/bigger_margin">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_empty_recycle_bin_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/settings_empty_recycle_bin_size"
android:layout_toStartOf="@+id/settings_empty_recycle_bin_size"
android:paddingLeft="@dimen/medium_margin"
android:paddingRight="@dimen/medium_margin"
android:text="@string/empty_recycle_bin"/>
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_empty_recycle_bin_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginEnd="@dimen/small_margin"
android:layout_marginRight="@dimen/small_margin"
android:background="@null"
android:clickable="false"/>
</RelativeLayout>
</LinearLayout>
</ScrollView>

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/splash_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

View file

@ -49,8 +49,85 @@
android:layout_height="wrap_content"
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_delete"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintEnd_toStartOf="@+id/bottom_rotate"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_share"/>
<ImageView
android:id="@+id/bottom_rotate"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_rotate_right"
app:layout_constraintEnd_toStartOf="@+id/bottom_properties"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_delete"/>
<ImageView
android:id="@+id/bottom_properties"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_properties"
app:layout_constraintEnd_toStartOf="@+id/bottom_change_orientation"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_rotate"/>
<ImageView
android:id="@+id/bottom_change_orientation"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_orientation_auto"
app:layout_constraintEnd_toStartOf="@+id/bottom_slideshow"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_properties"/>
<ImageView
android:id="@+id/bottom_slideshow"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_slideshow"
app:layout_constraintEnd_toStartOf="@+id/bottom_show_on_map"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_change_orientation"/>
<ImageView
android:id="@+id/bottom_show_on_map"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_place"
app:layout_constraintEnd_toStartOf="@+id/bottom_toggle_file_visibility"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_slideshow"/>
<ImageView
android:id="@+id/bottom_toggle_file_visibility"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_hide"
app:layout_constraintEnd_toStartOf="@+id/bottom_rename"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_show_on_map"/>
<ImageView
android:id="@+id/bottom_rename"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_rename_new"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_toggle_file_visibility"/>
</android.support.constraint.ConstraintLayout>

View file

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/grouping_dialog_scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/grouping_dialog_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_margin"
android:paddingRight="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin">
<RadioGroup
android:id="@+id/grouping_dialog_radio_grouping"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/medium_margin">
<com.simplemobiletools.commons.views.MyCompatRadioButton
android:id="@+id/grouping_dialog_radio_none"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/medium_margin"
android:paddingTop="@dimen/medium_margin"
android:text="@string/do_not_group_files"/>
<com.simplemobiletools.commons.views.MyCompatRadioButton
android:id="@+id/grouping_dialog_radio_last_modified"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/medium_margin"
android:paddingTop="@dimen/medium_margin"
android:text="@string/by_last_modified"/>
<com.simplemobiletools.commons.views.MyCompatRadioButton
android:id="@+id/grouping_dialog_radio_date_taken"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/medium_margin"
android:paddingTop="@dimen/medium_margin"
android:text="@string/by_date_taken"/>
<com.simplemobiletools.commons.views.MyCompatRadioButton
android:id="@+id/grouping_dialog_radio_file_type"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/medium_margin"
android:paddingTop="@dimen/medium_margin"
android:text="@string/by_file_type"/>
<com.simplemobiletools.commons.views.MyCompatRadioButton
android:id="@+id/grouping_dialog_radio_extension"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/medium_margin"
android:paddingTop="@dimen/medium_margin"
android:text="@string/by_extension"/>
<com.simplemobiletools.commons.views.MyCompatRadioButton
android:id="@+id/grouping_dialog_radio_folder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/medium_margin"
android:paddingTop="@dimen/medium_margin"
android:text="@string/by_folder"/>
</RadioGroup>
<include
layout="@layout/divider"/>
<RadioGroup
android:id="@+id/grouping_dialog_radio_order"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:paddingBottom="@dimen/medium_margin">
<com.simplemobiletools.commons.views.MyCompatRadioButton
android:id="@+id/grouping_dialog_radio_ascending"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/medium_margin"
android:paddingTop="@dimen/medium_margin"
android:text="@string/ascending"/>
<com.simplemobiletools.commons.views.MyCompatRadioButton
android:id="@+id/grouping_dialog_radio_descending"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/medium_margin"
android:paddingTop="@dimen/medium_margin"
android:text="@string/descending"/>
</RadioGroup>
<include
android:id="@+id/use_for_this_folder_divider"
layout="@layout/divider"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/grouping_dialog_use_for_this_folder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/use_for_this_folder"/>
</LinearLayout>
</ScrollView>

View file

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/manage_bottom_actions_scrollview"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/manage_bottom_actions_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_margin"
android:paddingRight="@dimen/activity_margin"
android:paddingTop="@dimen/medium_margin">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_bottom_actions_toggle_favorite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/toggle_favorite"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_bottom_actions_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/edit"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_bottom_actions_share"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/share"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_bottom_actions_delete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/delete"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_bottom_actions_rotate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/rotate"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_bottom_actions_properties"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/properties"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_bottom_actions_change_orientation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/change_orientation"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_bottom_actions_slideshow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/slideshow"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_bottom_actions_show_on_map"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/show_on_map"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_bottom_actions_toggle_visibility"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/toggle_file_visibility"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_bottom_actions_rename"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/rename"/>
</LinearLayout>
</ScrollView>

View file

@ -18,6 +18,16 @@
android:layout_height="match_parent"
android:visibility="gone"/>
<ImageView
android:id="@+id/panorama_outline"
android:layout_width="@dimen/play_outline_size_big"
android:layout_height="@dimen/play_outline_size_big"
android:layout_centerInParent="true"
android:background="@android:color/transparent"
android:padding="@dimen/big_margin"
android:src="@drawable/ic_panorama"
android:visibility="gone"/>
<TextView
android:id="@+id/photo_details"
android:layout_width="wrap_content"

View file

@ -6,12 +6,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
<TextureView
android:id="@+id/video_surface"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@android:color/transparent"/>
android:layout_centerInParent="true"/>
<com.simplemobiletools.gallery.helpers.MediaSideScroll
android:id="@+id/video_volume_controller"

View file

@ -45,6 +45,7 @@
android:layout_alignParentBottom="true"
android:layout_alignRight="@+id/medium_thumbnail"
android:background="@drawable/gradient_background"
android:ellipsize="end"
android:gravity="bottom"
android:maxLines="3"
android:paddingBottom="@dimen/small_margin"

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<com.simplemobiletools.commons.views.MyTextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/thumbnail_section"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:padding="@dimen/activity_margin"
android:textSize="@dimen/bigger_text_size"/>

View file

@ -23,7 +23,7 @@
app:showAsAction="ifRoom"/>
<item
android:id="@+id/cab_rename"
android:icon="@drawable/ic_rename"
android:icon="@drawable/ic_rename_new"
android:title="@string/rename"
app:showAsAction="ifRoom"/>
<item
@ -36,6 +36,14 @@
android:icon="@drawable/ic_unhide"
android:title="@string/unhide_folder"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/cab_empty_recycle_bin"
android:title="@string/empty_recycle_bin"
app:showAsAction="never"/>
<item
android:id="@+id/cab_empty_disable_recycle_bin"
android:title="@string/empty_and_disable_recycle_bin"
app:showAsAction="never"/>
<item
android:id="@+id/cab_exclude"
android:title="@string/exclude"

View file

@ -23,7 +23,7 @@
app:showAsAction="ifRoom"/>
<item
android:id="@+id/cab_rename"
android:icon="@drawable/ic_rename"
android:icon="@drawable/ic_rename_new"
android:title="@string/rename"
app:showAsAction="ifRoom"/>
<item
@ -46,6 +46,20 @@
android:icon="@drawable/ic_select_all"
android:title="@string/select_all"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/cab_add_to_favorites"
android:icon="@drawable/ic_star_off"
android:title="@string/add_to_favorites"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/cab_remove_from_favorites"
android:icon="@drawable/ic_star_on"
android:title="@string/remove_from_favorites"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/cab_restore_recycle_bin_files"
android:title="@string/restore_selected_files"
app:showAsAction="never"/>
<item
android:id="@+id/cab_open_with"
android:title="@string/open_with"

View file

@ -22,6 +22,18 @@
android:icon="@drawable/ic_filter"
android:title="@string/filter_media"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/empty_recycle_bin"
android:title="@string/empty_recycle_bin"
app:showAsAction="never"/>
<item
android:id="@+id/empty_disable_recycle_bin"
android:title="@string/empty_and_disable_recycle_bin"
app:showAsAction="never"/>
<item
android:id="@+id/restore_all_files"
android:title="@string/restore_all_files"
app:showAsAction="never"/>
<item
android:id="@+id/folder_view"
android:title="@string/folder_view"
@ -31,6 +43,10 @@
android:icon="@drawable/ic_camera"
android:title="@string/open_camera"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/group"
android:title="@string/group_by"
app:showAsAction="never"/>
<item
android:id="@+id/change_view_type"
android:title="@string/change_view_type"

View file

@ -45,13 +45,26 @@
android:title="@string/remove_from_favorites"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_lock_orientation"
android:title="@string/lock_orientation"
android:id="@+id/menu_restore_file"
android:title="@string/restore_this_file"
app:showAsAction="never"/>
<item
android:id="@+id/menu_slideshow"
android:title="@string/slideshow"
app:showAsAction="never"/>
android:id="@+id/menu_change_orientation"
android:icon="@drawable/ic_orientation_auto"
android:title="@string/change_orientation"
app:showAsAction="ifRoom">
<menu>
<item
android:id="@+id/menu_force_portrait"
android:title="@string/force_portrait"/>
<item
android:id="@+id/menu_force_landscape"
android:title="@string/force_landscape"/>
<item
android:id="@+id/menu_default_orientation"
android:title="@string/use_default_orientation"/>
</menu>
</item>
<item
android:id="@+id/menu_copy_to"
android:title="@string/copy_to"
@ -81,16 +94,21 @@
android:icon="@drawable/ic_edit"
android:title="@string/edit"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_rename"
android:icon="@drawable/ic_rename"
android:title="@string/rename"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_properties"
android:icon="@drawable/ic_info"
android:title="@string/properties"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_slideshow"
android:icon="@drawable/ic_slideshow"
android:title="@string/slideshow"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_rename"
android:icon="@drawable/ic_rename_new"
android:title="@string/rename"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_show_on_map"
android:title="@string/show_on_map"

View file

@ -24,6 +24,10 @@
<string name="brightness">السطوع</string>
<string name="lock_orientation">غلق الاتجاه</string>
<string name="unlock_orientation">فتح الاتجاه</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">فلتر الميديا</string>
@ -158,6 +162,12 @@
<string name="thumbnails">المصغرات</string>
<string name="fullscreen_media">وسائط ملء الشاشة</string>
<string name="extended_details">تفاصيل موسعة</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">كيف يمكنني جعل الاستوديو البسيط معرض الأجهزة الافتراضي؟</string>
@ -180,6 +190,8 @@
<string name="faq_9_text">نعم ، هناك تبديل في الإعدادات يقول \"استبدل صورًا ذات زووم عميق بجودة أفضل منها\" ، يمكنك استخدام ذلك. سيؤدي ذلك إلى تحسين جودة الصور ، ولكن ستظهر بشكل واضح عند محاولة التكبير كثيرًا.</string>
<string name="faq_10_title">هل يمكنني قص الصور باستخدام هذا التطبيق؟</string>
<string name="faq_10_text">نعم ، يمكنك اقتصاص الصور في المحرر ، عن طريق سحب زوايا الصورة. يمكنك الوصول إلى المحرر إما عن طريق الضغط لفترة طويلة على صورة مصغرة وتحديد تحرير ، أو تحديد تحرير من العرض بملء الشاشة.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Brillantor</string>
<string name="lock_orientation">Bloquejar orientació</string>
<string name="unlock_orientation">Desbloquejar orientació</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Filtre d\'arxius</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Miniatures</string>
<string name="fullscreen_media">Mitjans a pantalla completa</string>
<string name="extended_details">Detalls estesos</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">Com puc fer que Simple Gallery sigui la galeria de dispositius predeterminada?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Sí, hi ha un commutador a la configuració que diu \"Substituïu imatges ampliades i de gran qualitat\", podeu fer-ho. Millora la qualitat de les imatges, però es borraran una vegada que intenteu fer zoom massa.</string>
<string name="faq_10_title">Puc retallar imatges amb aquesta aplicació?</string>
<string name="faq_10_text">Sí, pots retallar imatges a l\'editor, arrossegant les cantonades de la imatge. Pots accedir a l\'editor prement una miniatura d\'imatge i seleccionant Edita o seleccionant Edita des de la visualització de pantalla completa.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Brightness</string>
<string name="lock_orientation">Lock orientation</string>
<string name="unlock_orientation">Unlock orientation</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Filter media</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Thumbnails</string>
<string name="fullscreen_media">Fullscreen media</string>
<string name="extended_details">Extended details</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">How can I make Simple Gallery the default device gallery?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Yea, there is a toggle in Settings saying \"Replace deep zoomable images with better quality ones\", you can use that. It will improve the quality of the images, but they will get blurred once you try zooming in too much.</string>
<string name="faq_10_title">Can I crop images with this app?</string>
<string name="faq_10_text">Yes, you can crop images in the editor, by dragging the image corners. You can get to the editor either by long pressing an image thumbnail and selecting Edit, or selecting Edit from the fullscreen view.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Brightness</string>
<string name="lock_orientation">Lås orientering</string>
<string name="unlock_orientation">Lås orientering op</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Filtrer medier</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Thumbnails</string>
<string name="fullscreen_media">Fullscreen media</string>
<string name="extended_details">Flere oplysninger</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">How can I make Simple Gallery the default device gallery?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Yea, there is a toggle in Settings saying \"Replace deep zoomable images with better quality ones\", you can use that. It will improve the quality of the images, but they will get blurred once you try zooming in too much.</string>
<string name="faq_10_title">Can I crop images with this app?</string>
<string name="faq_10_text">Yes, you can crop images in the editor, by dragging the image corners. You can get to the editor either by long pressing an image thumbnail and selecting Edit, or selecting Edit from the fullscreen view.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Helligkeit</string>
<string name="lock_orientation">Bildschirmausrichtung sperren</string>
<string name="unlock_orientation">Bildschirmausrichtung entsperren</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Filter</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Thumbnails</string>
<string name="fullscreen_media">Vollbild-Medien</string>
<string name="extended_details">Erweiterte Details</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">Wie kann ich Schlichte Galerie als Standardanwendung auswählen?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Ja, es gibt einen Schalter in den Einstellungen gekennzeichnet mit \"Stark zoombare Bilder durch Bilder mit hoher Qualität ersetzen\". Dieser wird die Bildqualität verbessern, aber sie werden bei sehr hoher Zoomstufe unscharf.</string>
<string name="faq_10_title">Kann ich mit dieser App Bilder zuschneiden?</string>
<string name="faq_10_text">Ja, du kannst Bilder über das Ziehen der Bildecken im Editor zuschneiden. Du gelangst zum Editor indem du lange auf ein Vorschaubild drückst und Bearbeiten auswählst oder durch Auswählen von Bearbeiten in der Vollbildansicht.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Φωτεινότητα</string>
<string name="lock_orientation">Κλείδωμα προσανατολισμού</string>
<string name="unlock_orientation">Ξεκλείδωμα προσανατολισμού</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Φιλτράρισμα πολυμέσων</string>
@ -155,6 +159,12 @@
<string name="thumbnails">Εικονίδια</string>
<string name="fullscreen_media">Πολυμέσα πλήρους οθόνης</string>
<string name="extended_details">Περισσότερες λεπτομέρειες</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">Πώς μπορώ να κάνω το Simple Gallery προκαθορισμένη εφαρμογή συλλογής πολυμέσων;</string>
@ -177,6 +187,8 @@
Αυτό θα κάνει ορατούς μόνο τους επιλεγμένους φακέλους, καθώς η εξαίρεση και η συμπερίληψη λειτουργούν αναδρομικά και αν ενας φάκελος ανήκει και στα δύο, θα εμφανιστεί.</string>
<string name="faq_9_title">Οι εικόνες πλήρους οθόνης έχουν κάποια περίεργα σημάδια. Μπορώ κάπως να βελτιώσω την ποιότητα;</string>
<string name="faq_9_text">Ναι. Υπάρχει ένας διακόπτης στις Ρυθμίσεις με το κείμενο \"Αντικατάσταση των φωτογραφιών που απαιτούν ζούμ με άλλες καλύτερης ποιότητας\". Μπορείτε να χρησιμοποιήσετε αυτό. Θα βελτιώσει την ποιότητα των φωτογραφιών, αλλά θα θολώσουν στο μεγάλο ζουμ.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Brillo</string>
<string name="lock_orientation">Bloquear orientación</string>
<string name="unlock_orientation">Desbloquear orientación</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Filtro de medios</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Miniaturas</string>
<string name="fullscreen_media">Medios a pantalla compelta</string>
<string name="extended_details">Detalles ampliados</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">¿Cómo puedo hacer que Simple Gallery sea la galería de dispositivos predeterminada?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Sí, hay una alternancia en Configuración que dice \"Reemplazar imágenes con zoom profundo con las de mejor calidad\", puedes usar eso. Mejorará la calidad de las imágenes, pero se volverán borrosas una vez que intente ampliar demasiado.</string>
<string name="faq_10_title">¿Puedo recortar imágenes con esta aplicación?</string>
<string name="faq_10_text">Sí, puede recortar imágenes en el editor arrastrando las esquinas de la imagen. Puede acceder al editor pulsando prolongadamente una imagen en miniatura y seleccionando Editar, o seleccionando Editar en la vista de pantalla completa.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Kirkkaus</string>
<string name="lock_orientation">Lukitse näytönkierto</string>
<string name="unlock_orientation">Vapauta näytönkierto</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Suodata media</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Esikatselukuvat</string>
<string name="fullscreen_media">Täyden näytön media</string>
<string name="extended_details">Yksityiskohtaiset tiedot</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">Miten voin tehdä Simple Gallerystä oletusgalleriasovelluksen?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Yea, there is a toggle in Settings saying \"Replace deep zoomable images with better quality ones\", you can use that. It will improve the quality of the images, but they will get blurred once you try zooming in too much.</string>
<string name="faq_10_title">Can I crop images with this app?</string>
<string name="faq_10_text">Yes, you can crop images in the editor, by dragging the image corners. You can get to the editor either by long pressing an image thumbnail and selecting Edit, or selecting Edit from the fullscreen view.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Luminosité</string>
<string name="lock_orientation">Verrouiller la rotation</string>
<string name="unlock_orientation">Déverrouiller la rotation</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Filtrer les médias</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Vignettes</string>
<string name="fullscreen_media">Média plein écran</string>
<string name="extended_details">Détails supplémentaires</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">Comment faire de Simple Galerie ma galerie par défaut ?</string>
@ -177,6 +187,8 @@
<string name="faq_9_text">Oui, il existe dans « Paramètres » une option « Remplacer les images zoomables profondes par des images de meilleure qualité », mais les images seront alors floues si vous zoomez trop.</string>
<string name="faq_10_title">Puis-je recadrer des images avec cette application?</string>
<string name="faq_10_text">Oui, vous pouvez recadrer les images dans l\'éditeur en faisant glisser les coins de l\'image. Vous pouvez accéder à l\'éditeur en appuyant longuement sur une vignette d\'image et en sélectionnant Modifier, ou en sélectionnant Modifier en mode plein écran.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Brillo</string>
<string name="lock_orientation">Fixar orientación</string>
<string name="unlock_orientation">Desbloquear orientación</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Filtrar medios</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Iconas</string>
<string name="fullscreen_media">Medios a pantalla completa</string>
<string name="extended_details">Detalles ampliados</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">Cómo podo facer que Simple Gallery sexa a galería por omisión no dispositivo?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Si, hai unha opción en Axustes que di \"Substituír imaxes con un gran zoom con imaxes de mellor calidade\", pode usar eso. mellorará a calidade das imaxes, mais farase máis borrosaxa si intenta facer moito zoom.</string>
<string name="faq_10_title">Can I crop images with this app?</string>
<string name="faq_10_text">Yes, you can crop images in the editor, by dragging the image corners. You can get to the editor either by long pressing an image thumbnail and selecting Edit, or selecting Edit from the fullscreen view.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Svjetlina</string>
<string name="lock_orientation">Zaključaj rotaciju</string>
<string name="unlock_orientation">Otključaj rotaciju</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Filtriranje medija</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Sličice</string>
<string name="fullscreen_media">Mediji na cijelom zaslonu</string>
<string name="extended_details">Proširene pojedinosti</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">Kako mogu postaviti Jednostavnu galeriju kao zadanu galeriju uređaja?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Da, u "Postavkama" postoji opcija "Zamjena duboko zumiranih slika s kvalitetnijim slikama", ali slike će biti zamućene ako zumirate previše.</string>
<string name="faq_10_title">Mogu li izrezati slike pomoću ove aplikacije?</string>
<string name="faq_10_text">Da, možete obrezati slike u uređivaču povlačenjem uglova. Možete doći do uređivača dugim pritiskom na minijaturu slike i odabirom Uređivanje ili odabirom Uredi iz prikaza preko cijelog zaslona.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Brightness</string>
<string name="lock_orientation">Lock orientation</string>
<string name="unlock_orientation">Unlock orientation</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Filter media</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Thumbnails</string>
<string name="fullscreen_media">Fullscreen media</string>
<string name="extended_details">Extended details</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">How can I make Simple Gallery the default device gallery?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Yea, there is a toggle in Settings saying \"Replace deep zoomable images with better quality ones\", you can use that. It will improve the quality of the images, but they will get blurred once you try zooming in too much.</string>
<string name="faq_10_title">Can I crop images with this app?</string>
<string name="faq_10_text">Yes, you can crop images in the editor, by dragging the image corners. You can get to the editor either by long pressing an image thumbnail and selecting Edit, or selecting Edit from the fullscreen view.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -10,7 +10,7 @@
<string name="unpin_folder">Sblocca cartella</string>
<string name="pin_to_the_top">Fissa in alto</string>
<string name="show_all">Mostra tutti i contenuti</string>
<string name="all_folders">Tutti i media</string>
<string name="all_folders">Tutte le cartelle</string>
<string name="folder_view">Visualizza a cartelle</string>
<string name="other_folder">Altra cartella</string>
<string name="show_on_map">Mostra sulla mappa</string>
@ -24,13 +24,17 @@
<string name="brightness">Luminosità</string>
<string name="lock_orientation">Blocca orientamento</string>
<string name="unlock_orientation">Sblocca orientamento</string>
<string name="change_orientation">Cambia orientamento</string>
<string name="force_portrait">Forza verticale</string>
<string name="force_landscape">Forza orizzontale</string>
<string name="use_default_orientation">Usa l'orientamento predefinito</string>
<!-- Filter -->
<string name="filter_media">Filtra i media</string>
<string name="images">Immagini</string>
<string name="videos">Video</string>
<string name="gifs">GIF</string>
<string name="raw_images">RAW images</string>
<string name="raw_images">Immagini RAW</string>
<string name="no_media_with_filters">Nessun file trovato per il filtro selezionato.</string>
<string name="change_filters_underlined"><u>Cambia filtro</u></string>
@ -111,16 +115,16 @@
<string name="change_view_type">Cambia modalità visualizzazione</string>
<string name="grid">Griglia</string>
<string name="list">Elenco</string>
<string name="group_direct_subfolders">Group direct subfolders</string>
<string name="group_direct_subfolders">Raggruppa sottocartelle dirette</string>
<!-- Grouping at media thumbnails -->
<string name="group_by">Group by</string>
<string name="do_not_group_files">Do not group files</string>
<string name="by_folder">Folder</string>
<string name="by_last_modified">Last modified</string>
<string name="by_date_taken">Date taken</string>
<string name="by_file_type">File type</string>
<string name="by_extension">Extension</string>
<string name="group_by">Raggruppa per</string>
<string name="do_not_group_files">Non raggruppare i file</string>
<string name="by_folder">Cartella</string>
<string name="by_last_modified">Ultima modifica</string>
<string name="by_date_taken">Data creazione</string>
<string name="by_file_type">Tipo di file</string>
<string name="by_extension">Estensione</string>
<!-- Settings -->
<string name="autoplay_videos">Riproduci i video automaticamente</string>
@ -148,12 +152,18 @@
<string name="replace_zoomable_images">Sostituisci le immagini ingrandibili a fondo con altre di migliore qualità</string>
<string name="hide_extended_details">Nascondi i dettagli estesi quando la barra di stato è nascosta</string>
<string name="do_extra_check">Fai un controllo ulteriore per evitare di mostrare file non validi</string>
<string name="show_at_bottom">Show some action buttons at the bottom of the screen</string>
<string name="show_at_bottom">Mostra alcuni pulsanti azione in fondo allo schermo</string>
<!-- Setting sections -->
<string name="thumbnails">Miniature</string>
<string name="fullscreen_media">Media a schermo intero</string>
<string name="extended_details">Dettagli estesi</string>
<string name="bottom_actions">Azioni inferiori</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Gestisci la visibilità delle azioni</string>
<string name="toggle_favorite">Attiva / disattiva preferito</string>
<string name="toggle_file_visibility">Attiva / disattiva la visibilità dei file</string>
<!-- FAQ -->
<string name="faq_1_title">Come posso impostare Simple Gallery come galleria predefinita del dispositivo?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Sì, c\'è un\'opzione nelle impostazioni che dice \"Sostituisci le immagini ingrandibili a fondo con altre di migliore qualità\", puoi usare quella. Ciò migliorerà la qualità delle immagini, ma saranno sfuocate quando proverai a ingrandirle troppo.</string>
<string name="faq_10_title">Posso ritagliare le immagini con questa app?</string>
<string name="faq_10_text">Sì, puoi ritagliare le immagini nell\'editor, trascinando gli angoli dell\'immagine. Puoi usare l\'editor sia premendo a lungo la miniatura di un\'immagine e selezionando Modifica, o selezionando Modifica mentre la vedi a schermo intero.</string>
<string name="faq_11_title">Posso raggruppare in qualche modo le miniature dei file?</string>
<string name="faq_11_text">Certo, usa il menu \"Raggruppa per\" mentre visualizzi le miniature. Puoi raggruppare i file con diversi criteri, incluso la data di creazione. Se utilizzi la funzione \"Mostra tutti i contenuti\" puoi anche raggrupparli per cartelle.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">明るさ</string>
<string name="lock_orientation">画面の向きを固定する</string>
<string name="unlock_orientation">向きの固定を解除する</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">表示するメディアの種類</string>
@ -154,6 +158,12 @@
<string name="thumbnails">サムネイル</string>
<string name="fullscreen_media">メディアのみ</string>
<string name="extended_details">詳細も表示する</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">How can I make Simple Gallery the default device gallery?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Yea, there is a toggle in Settings saying \"Replace deep zoomable images with better quality ones\", you can use that. It will improve the quality of the images, but they will get blurred once you try zooming in too much.</string>
<string name="faq_10_title">Can I crop images with this app?</string>
<string name="faq_10_text">Yes, you can crop images in the editor, by dragging the image corners. You can get to the editor either by long pressing an image thumbnail and selecting Edit, or selecting Edit from the fullscreen view.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">밝기</string>
<string name="lock_orientation">사진회전 잠금</string>
<string name="unlock_orientation">사진회전 해제</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">미디어 필터 설정</string>
@ -154,6 +158,12 @@
<string name="thumbnails">섬네일</string>
<string name="fullscreen_media">미디어 전체화면</string>
<string name="extended_details">확장 된 세부 정보</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">How can I make Simple Gallery the default device gallery?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Yea, there is a toggle in Settings saying \"Replace deep zoomable images with better quality ones\", you can use that. It will improve the quality of the images, but they will get blurred once you try zooming in too much.</string>
<string name="faq_10_title">Can I crop images with this app?</string>
<string name="faq_10_text">Yes, you can crop images in the editor, by dragging the image corners. You can get to the editor either by long pressing an image thumbnail and selecting Edit, or selecting Edit from the fullscreen view.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="do_not_ask_again">Šiame seanse daugiau neklausti</string>
<string name="lock_orientation">Užrakinti orientaciją</string>
<string name="unlock_orientation">Atrakinti orientaciją</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Filtruoti mediją</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Miniatiūros</string>
<string name="fullscreen_media">Viso ekrano medija</string>
<string name="extended_details">Išsami informacija</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">Kaip galiu padaryti paprastą galeriją kaip numatytąją įrenginio galeriją?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Taip, "Nustatymuose" perjunkite \ "Pakeisti giliuosius, patobulintus vaizdus geresnės kokybės vaizdais \", galite tai naudoti. Tai pagerins vaizdų kokybę, tačiau kai jūs pabandysite per daug padidinti vaizdą, jie bus neryškūs.</string>
<string name="faq_10_title">Ar galiu apkarpyti vaizdus naudojant šią programėlę?</string>
<string name="faq_10_text">Taip, redaguodami vaizdus, galite juos apkarpyti, vilkdami vaizdo kampus. Galite patekti į redaktorių ilgai paspaudę vaizdo miniatiūrą ir pasirinkę "Redaguoti" arba iš viso ekrano rodinio pasirinkę "Redaguoti".</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Lysstyrke</string>
<string name="lock_orientation">Lås skjermorientering</string>
<string name="unlock_orientation">Lås opp skjermorientering</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Filtrer media</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Minibilder</string>
<string name="fullscreen_media">Mediavisning</string>
<string name="extended_details">Utvidede detaljer</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">How can I make Simple Gallery the default device gallery?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Yea, there is a toggle in Settings saying \"Replace deep zoomable images with better quality ones\", you can use that. It will improve the quality of the images, but they will get blurred once you try zooming in too much.</string>
<string name="faq_10_title">Can I crop images with this app?</string>
<string name="faq_10_text">Yes, you can crop images in the editor, by dragging the image corners. You can get to the editor either by long pressing an image thumbnail and selecting Edit, or selecting Edit from the fullscreen view.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Helderheid</string>
<string name="lock_orientation">Schermoriëntatie vergrendelen</string>
<string name="unlock_orientation">Schermoriëntatie ontgrendelen</string>
<string name="change_orientation">Schermoriëntatie wijzigen</string>
<string name="force_portrait">Portretmodus forceren</string>
<string name="force_landscape">Landschapsmodus forceren</string>
<string name="use_default_orientation">Standaardmodus gebruiken</string>
<!-- Filter -->
<string name="filter_media">Media filteren</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Miniatuurvoorbeelden</string>
<string name="fullscreen_media">Volledig scherm</string>
<string name="extended_details">Uitgebreide informatie</string>
<string name="bottom_actions">Acties onderaan het scherm</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Actieknoppen onderaan beheren</string>
<string name="toggle_favorite">Als favoriet instellen</string>
<string name="toggle_file_visibility">Bestand tonen/verbergen</string>
<!-- FAQ -->
<string name="faq_1_title">How can I make Simple Gallery the default device gallery?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Yea, there is a toggle in Settings saying \"Replace deep zoomable images with better quality ones\", you can use that. It will improve the quality of the images, but they will get blurred once you try zooming in too much.</string>
<string name="faq_10_title">Can I crop images with this app?</string>
<string name="faq_10_text">Yes, you can crop images in the editor, by dragging the image corners. You can get to the editor either by long pressing an image thumbnail and selecting Edit, or selecting Edit from the fullscreen view.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -7,7 +7,7 @@
<string name="hidden">(ukryty)</string>
<string name="excluded">(wykluczony)</string>
<string name="pin_folder">Przypnij folder</string>
<string name="unpin_folder">Wypakuj folder</string>
<string name="unpin_folder">Odepnij folder</string>
   <string name="pin_to_the_top">Przypnij na górze</string>
<string name="show_all">Pokaż wszystko</string>
<string name="all_folders">Wszystkie foldery</string>
@ -24,6 +24,10 @@
<string name="brightness">Jasność</string>
<string name="lock_orientation">Zablokuj orientację ekranu</string>
<string name="unlock_orientation">Odblokuj orientację ekranu</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Filtruj multimedia</string>
@ -154,6 +158,12 @@
   <string name="thumbnails">Miniatury</string>
   <string name="fullscreen_media">Widok pełnoekranowy</string>
   <string name="extended_details">Dodatkowe szczegóły</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
   <string name="faq_1_title">Jak mogę ustawić tą aplikację jako domyślną aplikację galerii?</string>
@ -173,9 +183,11 @@
   <string name="faq_8_title">Co jeśli chcę widzieć tylko.wybrane foldery?</string>
   <string name="faq_8_text">Przejdź do sekcji z wykluczonymi folderami w ustawieniach aplikacji, dodaj tam folder główny (\"/\"), a następnie dodaj pożądane foldery w sekcji z dołączonymi folderami.</string>
   <string name="faq_9_title">Zdjęcia w widoku pełnoekranowym mają dziwne artefakty. Jak mogę to naprawić?</string>
   <string name="faq_9_text">U ustawieniach aplikacji włącz opcję \'Zamieniaj powiększalne obrazy na te o lepszej jakości\'. Poprawi ona jakość zdjęć, jednak przy bardzo dużych powiększeniach mogą się stać one zbyt rozmazane.</string>
<string name="faq_9_text">W ustawieniach aplikacji włącz opcję \'Zamieniaj powiększalne obrazy na te o lepszej jakości\'. Poprawi ona jakość zdjęć, jednak przy bardzo dużych powiększeniach mogą się stać one zbyt rozmazane.</string>
<string name="faq_10_title">Czy mogę w tej aplikacji przycinać obrazy?</string>
<string name="faq_10_text">Tak, możesz to zrobić w edytorze, przeciągając krawędzie obrazu. Edytor otworzysz przytrzymując miniaturę obrazu i wybierając opcję \'Edytuj\', bądź wybierając tą samą opcję w menu pełnoekranowym.</string>
<string name="faq_11_title">Czy mogę jakoś grupować miniatury plików?</string>
<string name="faq_11_text">Tak. Użyj opcji \'Grupuj według\', gdy jesteś w widoku miniatur. Grupować je możesz według wielu kryteriów, włącznie z datą ich utworzenia. Ponadto, jeśli użyjesz opcji \'Pokazuj całą zawartość folderów\', możesz je także grupować według folderów.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Brilho</string>
<string name="lock_orientation">Travar orientação</string>
<string name="unlock_orientation">Destravar orientação</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Filtrar mídia</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Miniaturas</string>
<string name="fullscreen_media">Mídia em tela cheia</string>
<string name="extended_details">Detalhes extendidos</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>v
<!-- FAQ -->
<string name="faq_1_title">How can I make Simple Gallery the default device gallery?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Yea, there is a toggle in Settings saying \"Replace deep zoomable images with better quality ones\", you can use that. It will improve the quality of the images, but they will get blurred once you try zooming in too much.</string>
<string name="faq_10_title">Can I crop images with this app?</string>
<string name="faq_10_text">Yes, you can crop images in the editor, by dragging the image corners. You can get to the editor either by long pressing an image thumbnail and selecting Edit, or selecting Edit from the fullscreen view.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Brilho</string>
<string name="lock_orientation">Bloquear orientação</string>
<string name="unlock_orientation">Desbloquear orientação</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Filtrar multimédia</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Miniaturas</string>
<string name="fullscreen_media">Multimédia em ecrã completo</string>
<string name="extended_details">Detalhes extra</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">How can I make Simple Gallery the default device gallery?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Yea, there is a toggle in Settings saying \"Replace deep zoomable images with better quality ones\", you can use that. It will improve the quality of the images, but they will get blurred once you try zooming in too much.</string>
<string name="faq_10_title">Can I crop images with this app?</string>
<string name="faq_10_text">Yes, you can crop images in the editor, by dragging the image corners. You can get to the editor either by long pressing an image thumbnail and selecting Edit, or selecting Edit from the fullscreen view.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Яркость</string>
<string name="lock_orientation">Заблокировать ориентацию</string>
<string name="unlock_orientation">Разблокировать ориентацию</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Фильтр медиа</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Миниатюры</string>
<string name="fullscreen_media">Просмотр медиафайлов</string>
<string name="extended_details">Подробности</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">Как сделать Simple Gallery галереей по умолчанию?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Да, в настройках есть переключатель \"Заменять масштабируемые изображения высококачественными\", использовуйте его. Это улучшит качество изображений, но они будут размыты, если вы попытаетесь сильно увеличить масштаб отображения.</string>
<string name="faq_10_title">Можно ли обрезать изображения с помощью данного приложения?</string>
<string name="faq_10_text">Да, вы можете обрезать изображения в редакторе, перетаскивая за углы. К редактированию можно перейти, выбрав соответсвующий пункт в меню, открывающемуся длительным нажатием на миниатюру или изображение в полноэкранном режиме.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Jas</string>
<string name="lock_orientation">Uzamknúť otočenie obrazovky</string>
<string name="unlock_orientation">Odomknúť otočenie obrazovky</string>
<string name="change_orientation">Zmeniť otočenie obrazovky</string>
<string name="force_portrait">Vynútiť orientáciu na výšku</string>
<string name="force_landscape">Vynútiť orientáciu na šírku</string>
<string name="use_default_orientation">Použiť predvolenú orientáciu</string>
<!-- Filter -->
<string name="filter_media">Filter médií</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Náhľady</string>
<string name="fullscreen_media">Celoobrazovkový režim</string>
<string name="extended_details">Rozšírené vlastnosti</string>
<string name="bottom_actions">Spodné akčné tlačidlá</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Upraviť viditeľné spodné akčné tlačidlá</string>
<string name="toggle_favorite">Prepnutie obľúbenosti</string>
<string name="toggle_file_visibility">Prepnutie viditeľnosti súboru</string>
<!-- FAQ -->
<string name="faq_1_title">Ako viem spraviť Jednoduchú Galériu predvolenou galériou zariadenia?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Áno, v nastaveniach je prepínač s textom \"Nahradiť hlboko priblížiteľné obrázky s obrázkami s lepšou kvalitou\", môžete ho skúsiť. Spôsobí to vyššiu kvalitu obrázkov, po priblížení sa ale budú rozmazávať oveľa skôr.</string>
<string name="faq_10_title">Dá sa s touto aplikáciou orezať obrázky?</string>
<string name="faq_10_text">Áno, orezanie je možné v editore, potiahnutím rohov obrázkov. Do editoru sa môžete dostať buď dlhým podržaním náhľadu obrázku a zvolením menu položky Upraviť, alebo zvolením Upraviť pri celoobrazovkovom režime.</string>
<string name="faq_11_title">Viem nejakým spôsobom zoskupiť náhľady súborov?</string>
<string name="faq_11_text">Áno, použitím funkcie \"Zoskupiť podľa\" na menu obrazovky s náhľadmi. Zoskupenie je možné na základe rozličných kritérií vrátane Dátumu vytvorenia. Ak použijete funkciu \"Zobraziť obsah všetkých priečinkov\", viete ich zoskupiť aj podľa priečinkov.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

View file

@ -24,6 +24,10 @@
<string name="brightness">Ljusstyrka</string>
<string name="lock_orientation">Aktivera rotationslås</string>
<string name="unlock_orientation">Inaktivera rotationslås</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<!-- Filter -->
<string name="filter_media">Filtrera media</string>
@ -154,6 +158,12 @@
<string name="thumbnails">Miniatyrer</string>
<string name="fullscreen_media">Visning av media i helskärmsläge</string>
<string name="extended_details">Utökad information</string>
<string name="bottom_actions">Bottom actions</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<!-- FAQ -->
<string name="faq_1_title">How can I make Simple Gallery the default device gallery?</string>
@ -178,6 +188,8 @@
<string name="faq_9_text">Yea, there is a toggle in Settings saying \"Replace deep zoomable images with better quality ones\", you can use that. It will improve the quality of the images, but they will get blurred once you try zooming in too much.</string>
<string name="faq_10_title">Can I crop images with this app?</string>
<string name="faq_10_text">Yes, you can crop images in the editor, by dragging the image corners. You can get to the editor either by long pressing an image thumbnail and selecting Edit, or selecting Edit from the fullscreen view.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars -->

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