diff --git a/.gitignore b/.gitignore index 7051e766d..dc267ae29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ *.iml .gradle /local.properties -/gradle.properties /.idea/ .DS_Store /build diff --git a/CHANGELOG.md b/CHANGELOG.md index 2331262d1..d65d24356 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,37 @@ Changelog ========== +Version 5.1.0 *(2018-10-23)* +---------------------------- + + * Added support for panorama videos + * Added an extra check to avoid trying deleting files without write permission + * Added an initial implementation of renaming multiple items at once + * Added some performance improvements at item de/selection + * Allow enabling hidden item visibility at the copy/move destination picker + * Allow closing fullscreen view with swipe down gestures (can be disabled in settings) + * Fixed a glitch with Favorite items getting unselected every day + * Fixed exposure time displayed at long exposure photos + * Fixed fullscreen images being sometimes totally zoomed in after device rotation + * Fixed slideshow direction + * Made loading initial fullscreen view quicker and fullscreen toggling more reliable + * Not sure what else, nobody reads this anyway + +Version 5.0.1 *(2018-10-17)* +---------------------------- + + * Adding some crashfixes + +Version 5.0.0 *(2018-10-17)* +---------------------------- + + * Increased the minimal required Android OS version to 5 (Lollipop) + * Rewrote file selection for more robustness + * Added a new option for showing the Recycle Bin as the last folder + * Added Search for searching folders by names + * Replaced the G+ button with Reddit + * Couple smaller glitch fixes and improvements + Version 4.6.5 *(2018-10-02)* ---------------------------- diff --git a/app/build.gradle b/app/build.gradle index 1141d8232..cfa9e8587 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,10 +9,10 @@ android { defaultConfig { applicationId "com.simplemobiletools.gallery" - minSdkVersion 16 + minSdkVersion 21 targetSdkVersion 28 - versionCode 201 - versionName "4.6.5" + versionCode 204 + versionName "5.1.0" multiDexEnabled true setProperty("archivesBaseName", "gallery") } @@ -40,17 +40,23 @@ android { checkReleaseBuilds false abortOnError false } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } dependencies { - implementation 'com.simplemobiletools:commons:4.9.1' + implementation 'com.simplemobiletools:commons:5.2.0' implementation 'com.theartofdev.edmodo:android-image-cropper:2.7.0' implementation 'androidx.multidex:multidex:2.0.0' implementation 'it.sephiroth.android.exif:library:1.0.1' implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.15' implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2' - implementation 'com.google.android.exoplayer:exoplayer-core:2.8.4' + implementation 'com.google.android.exoplayer:exoplayer-core:2.9.0' implementation 'com.google.vr:sdk-panowidget:1.170.0' + implementation 'com.google.vr:sdk-videowidget:1.170.0' implementation 'org.apache.sanselan:sanselan:0.97-incubator' implementation 'info.androidhive:imagefilters:1.0.7' implementation 'com.squareup.picasso:picasso:2.71828' @@ -65,7 +71,7 @@ dependencies { implementation 'com.github.tibbi:subsampling-scale-image-view:v3.10.1-fork' // implementation 'com.github.chrisbanes:PhotoView:2.1.4' - implementation 'com.github.tibbi:PhotoView:2.1.4-fork' + implementation 'com.github.tibbi:PhotoView:2.2.1-fork' } Properties props = new Properties() diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 85395342a..86ed4b512 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -32,6 +32,14 @@ android:name=".activities.MainActivity" android:resizeableActivity="true"> + + + + + + @@ -115,7 +123,12 @@ android:configChanges="orientation|keyboardHidden|screenSize"/> + + diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ExcludedFoldersActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ExcludedFoldersActivity.kt index d59f0b7f4..4d3a1883a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ExcludedFoldersActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ExcludedFoldersActivity.kt @@ -20,7 +20,7 @@ class ExcludedFoldersActivity : SimpleActivity(), RefreshRecyclerViewListener { private fun updateFolders() { val folders = ArrayList() - config.excludedFolders.mapTo(folders, { it }) + config.excludedFolders.mapTo(folders) { it } manage_folders_placeholder.apply { text = getString(R.string.excluded_activity_placeholder) beVisibleIf(folders.isEmpty()) @@ -49,7 +49,7 @@ class ExcludedFoldersActivity : SimpleActivity(), RefreshRecyclerViewListener { } private fun addFolder() { - FilePickerDialog(this, config.lastFilepickerPath, false, config.shouldShowHidden) { + FilePickerDialog(this, config.lastFilepickerPath, false, config.shouldShowHidden, false, true) { config.lastFilepickerPath = it config.addExcludedFolder(it) updateFolders() diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/HiddenFoldersActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/HiddenFoldersActivity.kt index 598e153be..c46135c98 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/HiddenFoldersActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/HiddenFoldersActivity.kt @@ -53,7 +53,7 @@ class HiddenFoldersActivity : SimpleActivity(), RefreshRecyclerViewListener { } private fun addFolder() { - FilePickerDialog(this, config.lastFilepickerPath, false, config.shouldShowHidden) { + FilePickerDialog(this, config.lastFilepickerPath, false, config.shouldShowHidden, false, true) { config.lastFilepickerPath = it Thread { addNoMedia(it) { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/IncludedFoldersActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/IncludedFoldersActivity.kt index ede3ab8d8..4a4d1339e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/IncludedFoldersActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/IncludedFoldersActivity.kt @@ -21,7 +21,7 @@ class IncludedFoldersActivity : SimpleActivity(), RefreshRecyclerViewListener { private fun updateFolders() { val folders = ArrayList() - config.includedFolders.mapTo(folders, { it }) + config.includedFolders.mapTo(folders) { it } manage_folders_placeholder.apply { text = getString(R.string.included_activity_placeholder) beVisibleIf(folders.isEmpty()) @@ -50,7 +50,7 @@ class IncludedFoldersActivity : SimpleActivity(), RefreshRecyclerViewListener { } private fun addFolder() { - FilePickerDialog(this, config.lastFilepickerPath, false, config.shouldShowHidden) { + FilePickerDialog(this, config.lastFilepickerPath, false, config.shouldShowHidden, false, true) { config.lastFilepickerPath = it config.addIncludedFolder(it) updateFolders() diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MainActivity.kt index 4590512cb..de25bfda5 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MainActivity.kt @@ -1,7 +1,9 @@ package com.simplemobiletools.gallery.activities import android.app.Activity +import android.app.SearchManager import android.content.ClipData +import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle @@ -12,7 +14,8 @@ import android.view.MenuItem import android.view.ViewGroup import android.widget.FrameLayout import android.widget.Toast -import androidx.recyclerview.widget.GridLayoutManager +import androidx.appcompat.widget.SearchView +import androidx.core.view.MenuItemCompat import androidx.recyclerview.widget.RecyclerView import com.simplemobiletools.commons.dialogs.CreateNewFolderDialog import com.simplemobiletools.commons.dialogs.FilePickerDialog @@ -61,11 +64,14 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { private var mIsPasswordProtectionPending = false private var mWasProtectionHandled = false private var mShouldStopFetching = false + private var mIsSearchOpen = false private var mLatestMediaId = 0L private var mLatestMediaDateId = 0L private var mLastMediaHandler = Handler() private var mTempShowHiddenHandler = Handler() private var mZoomListener: MyRecyclerView.MyZoomListener? = null + private var mSearchMenuItem: MenuItem? = null + private var mDirs = ArrayList() private var mStoredAnimateGifs = true private var mStoredCropThumbnails = true @@ -214,6 +220,8 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { override fun onStop() { super.onStop() + mSearchMenuItem?.collapseActionView() + if (config.temporarilyShowHidden || config.tempSkipDeleteConfirmation) { mTempShowHiddenHandler.postDelayed({ config.temporarilyShowHidden = false @@ -243,10 +251,13 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { 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 + setupSearch(this) } } + menu.findItem(R.id.temporarily_show_hidden).isVisible = !config.shouldShowHidden menu.findItem(R.id.stop_showing_hidden).isVisible = config.temporarilyShowHidden + return true } @@ -293,6 +304,55 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { } } + private fun setupSearch(menu: Menu) { + val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager + mSearchMenuItem = menu.findItem(R.id.search) + (mSearchMenuItem?.actionView as? SearchView)?.apply { + setSearchableInfo(searchManager.getSearchableInfo(componentName)) + isSubmitButtonEnabled = false + setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String) = false + + override fun onQueryTextChange(newText: String): Boolean { + if (mIsSearchOpen) { + searchQueryChanged(newText) + } + return true + } + }) + } + + MenuItemCompat.setOnActionExpandListener(mSearchMenuItem, object : MenuItemCompat.OnActionExpandListener { + override fun onMenuItemActionExpand(item: MenuItem?): Boolean { + mIsSearchOpen = true + directories_refresh_layout.isEnabled = false + return true + } + + // this triggers on device rotation too, avoid doing anything + override fun onMenuItemActionCollapse(item: MenuItem?): Boolean { + if (mIsSearchOpen) { + mIsSearchOpen = false + directories_refresh_layout.isEnabled = config.enablePullToRefresh + searchQueryChanged("") + } + return true + } + }) + } + + private fun searchQueryChanged(text: String) { + Thread { + val filtered = getUniqueSortedDirs(mDirs).filter { it.name.contains(text, true) } as ArrayList + filtered.sortBy { !it.name.startsWith(text, true) } + + runOnUiThread { + getRecyclerAdapter()?.updateDirs(filtered) + measureRecyclerViewContent(filtered) + } + }.start() + } + private fun removeTempFolder() { if (config.tempFolderPath.isNotEmpty()) { val newFolder = File(config.tempFolderPath) @@ -544,7 +604,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { } private fun createNewFolder() { - FilePickerDialog(this, internalStoragePath, false, config.shouldShowHidden) { + FilePickerDialog(this, internalStoragePath, false, config.shouldShowHidden, false, true) { CreateNewFolderDialog(this, it) { config.tempFolderPath = it Thread { @@ -688,6 +748,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { // if hidden item showing is disabled but all Favorite items are hidden, hide the Favorites folder mIsGettingDirs = false mShouldStopFetching = false + if (!config.shouldShowHidden) { val favoritesFolder = newDirs.firstOrNull { it.areFavorites() } if (favoritesFolder != null && favoritesFolder.tmb.getFilenameFromPath().startsWith('.')) { @@ -714,9 +775,11 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { val hiddenString = getString(R.string.hidden) val albumCovers = config.parseAlbumCovers() val includedFolders = config.includedFolders + val tempFolderPath = config.tempFolderPath val isSortingAscending = config.directorySorting and SORT_DESCENDING == 0 val getProperDateTaken = config.directorySorting and SORT_BY_DATE_TAKEN != 0 val favoritePaths = getFavoritePaths() + val dirPathsToRemove = ArrayList() try { for (directory in dirs) { @@ -726,6 +789,9 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { val curMedia = mediaFetcher.getFilesFrom(directory.path, getImagesOnly, getVideosOnly, getProperDateTaken, favoritePaths) val newDir = if (curMedia.isEmpty()) { + if (directory.path != tempFolderPath) { + dirPathsToRemove.add(directory.path) + } directory } else { createDirectoryFromMedia(directory.path, curMedia, albumCovers, hiddenString, includedFolders, isSortingAscending) @@ -767,9 +833,18 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { } catch (ignored: Exception) { } + if (dirPathsToRemove.isNotEmpty()) { + val dirsToRemove = dirs.filter { dirPathsToRemove.contains(it.path) } + dirsToRemove.forEach { + mDirectoryDao.deleteDirPath(it.path) + } + dirs.removeAll(dirsToRemove) + showSortedDirs(dirs) + } + val foldersToScan = mediaFetcher.getFoldersToScan() foldersToScan.add(FAVORITES) - if (config.showRecycleBinAtFolders) { + if (config.useRecycleBin && config.showRecycleBinAtFolders) { foldersToScan.add(RECYCLE_BIN) } else { foldersToScan.remove(RECYCLE_BIN) @@ -825,6 +900,11 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { } catch (e: Exception) { config.everShownFolders = HashSet() } + mDirs = dirs.clone() as ArrayList + + if (config.appRunCount < 5 && mDirs.size > 100) { + excludeSpamFolders() + } } private fun checkPlaceholderVisibility(dirs: ArrayList) { @@ -834,14 +914,17 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { } private fun showSortedDirs(dirs: ArrayList) { - var sortedDirs = getSortedDirectories(dirs) - sortedDirs = sortedDirs.distinctBy { it.path.getDistinctPath() } as ArrayList - + val updatedDirs = getUniqueSortedDirs(dirs) runOnUiThread { - (directories_grid.adapter as? DirectoryAdapter)?.updateDirs(sortedDirs) + (directories_grid.adapter as? DirectoryAdapter)?.updateDirs(updatedDirs) } } + private fun getUniqueSortedDirs(dirs: ArrayList): ArrayList { + val sortedDirs = dirs.distinctBy { it.path.getDistinctPath() } as ArrayList + return getSortedDirectories(sortedDirs) + } + private fun createDirectoryFromMedia(path: String, curMedia: ArrayList, albumCovers: ArrayList, hiddenString: String, includedFolders: MutableSet, isSortingAscending: Boolean): Directory { var thumbnail = curMedia.firstOrNull { getDoesFilePathExist(it.path) }?.path ?: "" @@ -885,7 +968,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { directories_grid.adapter = this } } else { - (currAdapter as DirectoryAdapter).updateDirs(dirs) + showSortedDirs(dirs) } getRecyclerAdapter()?.dirs?.apply { @@ -966,7 +1049,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { } private fun checkLastMediaChanged() { - if (isActivityDestroyed()) { + if (isDestroyed) { return } @@ -993,12 +1076,88 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { config.lastBinCheck = System.currentTimeMillis() Handler().postDelayed({ Thread { - mMediumDao.deleteOldRecycleBinItems(System.currentTimeMillis() - MONTH_MILLISECONDS) + try { + mMediumDao.deleteOldRecycleBinItems(System.currentTimeMillis() - MONTH_MILLISECONDS) + } catch (e: Exception) { + } }.start() }, 3000L) } } + // exclude probably unwanted folders, for example facebook stickers are split between hundreds of separate folders like + // /storage/emulated/0/Android/data/com.facebook.orca/files/stickers/175139712676531/209575122566323 + // /storage/emulated/0/Android/data/com.facebook.orca/files/stickers/497837993632037/499671223448714 + private fun excludeSpamFolders() { + Thread { + try { + val internalPath = config.internalStoragePath + val sdPath = config.sdCardPath + val pathParts = ArrayList>() + mDirs.asSequence().map { it.path.removePrefix(internalPath).removePrefix(sdPath) }.sorted().toList().forEach { + val parts = it.split("/").asSequence().filter { it.isNotEmpty() }.toMutableList() as ArrayList + if (parts.size > 3) { + pathParts.add(parts) + } + } + + val keys = getLongestCommonStrings(pathParts) + pathParts.clear() + keys.forEach { it -> + val parts = it.split("/").asSequence().filter { it.isNotEmpty() }.toMutableList() as ArrayList + pathParts.add(parts) + } + + getLongestCommonStrings(pathParts).forEach { + var file = File("$internalPath/$it") + if (file.exists()) { + config.addExcludedFolder(file.absolutePath) + } else { + file = File("$sdPath/$it") + if (file.exists()) { + config.addExcludedFolder(file.absolutePath) + } + } + } + } catch (e: Exception) { + } + }.start() + } + + private fun getLongestCommonStrings(pathParts: ArrayList>): ArrayList { + val commonStrings = ArrayList() + return try { + val cnt = pathParts.size + for (i in 0..cnt) { + var longestCommonString = "" + for (j in i..cnt) { + var currentCommonString = "" + if (i != j) { + val originalParts = pathParts.getOrNull(i) + val otherParts = pathParts.getOrNull(j) + if (originalParts != null && otherParts != null) { + originalParts.forEachIndexed { index, string -> + if (string == otherParts.getOrNull(index)) { + currentCommonString += "$string/" + if (currentCommonString.length > longestCommonString.length) { + longestCommonString = currentCommonString.trimEnd('/') + } + } + } + } + } + } + + if (longestCommonString.isNotEmpty()) { + commonStrings.add(longestCommonString) + } + } + commonStrings.groupingBy { it }.eachCount().filter { it.value > 5 && it.key.length > 10 }.map { it.key }.toMutableList() as ArrayList + } catch (e: Exception) { + ArrayList() + } + } + override fun refreshItems() { getDirectories() } @@ -1068,6 +1227,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { add(Release(182, R.string.release_182)) add(Release(184, R.string.release_184)) add(Release(201, R.string.release_201)) + add(Release(202, R.string.release_202)) checkWhatsNew(this, BuildConfig.VERSION_CODE) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt index 1dd2514b6..0d37b2013 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt @@ -398,7 +398,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener { } private fun checkLastMediaChanged() { - if (isActivityDestroyed()) { + if (isDestroyed) { return } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PanoramaActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PanoramaPhotoActivity.kt similarity index 85% rename from app/src/main/kotlin/com/simplemobiletools/gallery/activities/PanoramaActivity.kt rename to app/src/main/kotlin/com/simplemobiletools/gallery/activities/PanoramaPhotoActivity.kt index e1131e92f..a1dfb2664 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PanoramaActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PanoramaPhotoActivity.kt @@ -1,11 +1,9 @@ package com.simplemobiletools.gallery.activities -import android.annotation.TargetApi import android.content.res.Configuration import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.Color -import android.os.Build import android.os.Bundle import android.view.View import android.view.Window @@ -14,20 +12,20 @@ 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.onGlobalLayout import com.simplemobiletools.commons.extensions.showErrorToast import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE -import com.simplemobiletools.commons.helpers.isLollipopPlus import com.simplemobiletools.commons.helpers.isPiePlus import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.extensions.* import com.simplemobiletools.gallery.helpers.PATH -import kotlinx.android.synthetic.main.activity_panorama.* +import kotlinx.android.synthetic.main.activity_panorama_photo.* -open class PanoramaActivity : SimpleActivity() { +open class PanoramaPhotoActivity : SimpleActivity() { private val CARDBOARD_DISPLAY_MODE = 3 - private var isFullScreen = false + private var isFullscreen = false private var isExploreEnabled = true private var isRendering = false @@ -35,7 +33,7 @@ open class PanoramaActivity : SimpleActivity() { useDynamicTheme = false requestWindowFeature(Window.FEATURE_NO_TITLE) super.onCreate(savedInstanceState) - setContentView(R.layout.activity_panorama) + setContentView(R.layout.activity_panorama_photo) supportActionBar?.hide() if (isPiePlus()) { @@ -65,7 +63,6 @@ open class PanoramaActivity : SimpleActivity() { } } - @TargetApi(Build.VERSION_CODES.LOLLIPOP) override fun onResume() { super.onResume() panorama_view.resumeRendering() @@ -74,9 +71,7 @@ open class PanoramaActivity : SimpleActivity() { updateStatusbarColor(Color.BLACK) } - if (isLollipopPlus()) { - window.statusBarColor = resources.getColor(R.color.circle_black_background) - } + window.statusBarColor = resources.getColor(R.color.circle_black_background) } override fun onPause() { @@ -113,11 +108,6 @@ open class PanoramaActivity : SimpleActivity() { 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) @@ -128,6 +118,12 @@ open class PanoramaActivity : SimpleActivity() { setOnClickListener { handleClick() } + + setEventListener(object : VrPanoramaEventListener() { + override fun onClick() { + handleClick() + } + }) } } }.start() @@ -136,7 +132,7 @@ open class PanoramaActivity : SimpleActivity() { } window.decorView.setOnSystemUiVisibilityChangeListener { visibility -> - isFullScreen = visibility and View.SYSTEM_UI_FLAG_FULLSCREEN != 0 + isFullscreen = visibility and View.SYSTEM_UI_FLAG_FULLSCREEN != 0 toggleButtonVisibility() } } @@ -164,26 +160,30 @@ open class PanoramaActivity : SimpleActivity() { } private fun setupButtonMargins() { + val navBarHeight = navigationBarHeight (cardboard.layoutParams as RelativeLayout.LayoutParams).apply { - bottomMargin = navigationBarHeight + bottomMargin = navBarHeight rightMargin = navigationBarWidth } (explore.layoutParams as RelativeLayout.LayoutParams).bottomMargin = navigationBarHeight + + cardboard.onGlobalLayout { + panorama_gradient_background.layoutParams.height = navBarHeight + cardboard.height + } } 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 + arrayOf(cardboard, explore, panorama_gradient_background).forEach { + it.animate().alpha(if (isFullscreen) 0f else 1f) + it.isClickable = !isFullscreen + } } private fun handleClick() { - isFullScreen = !isFullScreen + isFullscreen = !isFullscreen toggleButtonVisibility() - if (isFullScreen) { + if (isFullscreen) { hideSystemUI(false) } else { showSystemUI(false) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PanoramaVideoActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PanoramaVideoActivity.kt new file mode 100644 index 000000000..3e65534ff --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PanoramaVideoActivity.kt @@ -0,0 +1,343 @@ +package com.simplemobiletools.gallery.activities + +import android.content.res.Configuration +import android.graphics.Color +import android.net.Uri +import android.os.Bundle +import android.os.Handler +import android.view.View +import android.view.Window +import android.view.WindowManager +import android.view.animation.AnimationUtils +import android.widget.RelativeLayout +import android.widget.SeekBar +import com.google.vr.sdk.widgets.video.VrVideoEventListener +import com.google.vr.sdk.widgets.video.VrVideoView +import com.simplemobiletools.commons.extensions.getFormattedDuration +import com.simplemobiletools.commons.extensions.onGlobalLayout +import com.simplemobiletools.commons.extensions.showErrorToast +import com.simplemobiletools.commons.extensions.toast +import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE +import com.simplemobiletools.commons.helpers.isPiePlus +import com.simplemobiletools.gallery.R +import com.simplemobiletools.gallery.extensions.* +import com.simplemobiletools.gallery.helpers.HIDE_PLAY_PAUSE_DELAY +import com.simplemobiletools.gallery.helpers.MIN_SKIP_LENGTH +import com.simplemobiletools.gallery.helpers.PATH +import com.simplemobiletools.gallery.helpers.PLAY_PAUSE_VISIBLE_ALPHA +import kotlinx.android.synthetic.main.activity_panorama_video.* +import kotlinx.android.synthetic.main.bottom_video_time_holder.* +import java.io.File + +open class PanoramaVideoActivity : SimpleActivity(), SeekBar.OnSeekBarChangeListener { + private val CARDBOARD_DISPLAY_MODE = 3 + + private var mIsFullscreen = false + private var mIsExploreEnabled = true + private var mIsRendering = false + private var mIsPlaying = false + private var mIsDragged = false + private var mPlayOnReady = false + private var mDuration = 0 + private var mCurrTime = 0 + + private var mHidePlayPauseHandler = Handler() + private var mTimerHandler = Handler() + + public override fun onCreate(savedInstanceState: Bundle?) { + useDynamicTheme = false + requestWindowFeature(Window.FEATURE_NO_TITLE) + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_panorama_video) + supportActionBar?.hide() + + if (isPiePlus()) { + window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) + } + + setupButtons() + + cardboard.setOnClickListener { + vr_video_view.displayMode = CARDBOARD_DISPLAY_MODE + } + + explore.setOnClickListener { + mIsExploreEnabled = !mIsExploreEnabled + vr_video_view.setPureTouchTracking(mIsExploreEnabled) + explore.setImageResource(if (mIsExploreEnabled) 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() + vr_video_view.resumeRendering() + mIsRendering = true + if (config.blackBackground) { + updateStatusbarColor(Color.BLACK) + } + + window.statusBarColor = resources.getColor(R.color.circle_black_background) + } + + override fun onPause() { + super.onPause() + vr_video_view.pauseRendering() + mIsRendering = false + } + + override fun onDestroy() { + super.onDestroy() + if (mIsRendering) { + vr_video_view.shutdown() + } + + if (!isChangingConfigurations) { + mHidePlayPauseHandler.removeCallbacksAndMessages(null) + mTimerHandler.removeCallbacksAndMessages(null) + } + } + + private fun checkIntent() { + val path = intent.getStringExtra(PATH) + if (path == null) { + toast(R.string.invalid_image_path) + finish() + return + } + + intent.removeExtra(PATH) + + video_curr_time.setOnClickListener { skip(false) } + video_duration.setOnClickListener { skip(true) } + + try { + val options = VrVideoView.Options() + options.inputType = VrVideoView.Options.TYPE_MONO + + vr_video_view.apply { + loadVideo(Uri.fromFile(File(path)), options) + pauseVideo() + + setFlingingEnabled(true) + setPureTouchTracking(true) + + // add custom buttons so we can position them and toggle visibility as desired + setFullscreenButtonEnabled(false) + setInfoButtonEnabled(false) + setTransitionViewEnabled(false) + setStereoModeButtonEnabled(false) + + setOnClickListener { + handleClick() + } + + setEventListener(object : VrVideoEventListener() { + override fun onClick() { + handleClick() + } + + override fun onLoadSuccess() { + if (mDuration == 0) { + setupDuration(duration) + setupTimer() + } + + if (mPlayOnReady) { + mPlayOnReady = false + playVideo() + } + } + + override fun onCompletion() { + videoCompleted() + } + }) + } + + video_play_outline.setOnClickListener { + togglePlayPause() + } + } catch (e: Exception) { + showErrorToast(e) + } + + window.decorView.setOnSystemUiVisibilityChangeListener { visibility -> + mIsFullscreen = visibility and View.SYSTEM_UI_FLAG_FULLSCREEN != 0 + toggleButtonVisibility() + } + } + + override fun onConfigurationChanged(newConfig: Configuration?) { + super.onConfigurationChanged(newConfig) + setupButtons() + } + + private fun setupDuration(duration: Long) { + mDuration = (duration / 1000).toInt() + video_seekbar.max = mDuration + video_duration.text = mDuration.getFormattedDuration() + setVideoProgress(0) + } + + private fun setupTimer() { + runOnUiThread(object : Runnable { + override fun run() { + if (mIsPlaying && !mIsDragged) { + mCurrTime = (vr_video_view!!.currentPosition / 1000).toInt() + video_seekbar.progress = mCurrTime + video_curr_time.text = mCurrTime.getFormattedDuration() + } + + mTimerHandler.postDelayed(this, 1000) + } + }) + } + + private fun togglePlayPause() { + mIsPlaying = !mIsPlaying + video_play_outline.alpha = PLAY_PAUSE_VISIBLE_ALPHA + mHidePlayPauseHandler.removeCallbacksAndMessages(null) + if (mIsPlaying) { + playVideo() + } else { + pauseVideo() + } + schedulePlayPauseFadeOut() + } + + private fun playVideo() { + video_play_outline.setImageResource(R.drawable.ic_pause) + if (mCurrTime == mDuration) { + setVideoProgress(0) + mPlayOnReady = true + return + } + + vr_video_view.playVideo() + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + } + + private fun pauseVideo() { + vr_video_view.pauseVideo() + video_play_outline.setImageResource(R.drawable.ic_play) + window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + } + + private fun setVideoProgress(seconds: Int) { + vr_video_view.seekTo(seconds * 1000L) + video_seekbar.progress = seconds + mCurrTime = seconds + video_curr_time.text = seconds.getFormattedDuration() + } + + private fun videoCompleted() { + mIsPlaying = false + mCurrTime = (vr_video_view.duration / 1000).toInt() + video_seekbar.progress = video_seekbar.max + video_curr_time.text = mDuration.getFormattedDuration() + pauseVideo() + video_play_outline.alpha = PLAY_PAUSE_VISIBLE_ALPHA + } + + private fun schedulePlayPauseFadeOut() { + mHidePlayPauseHandler.removeCallbacksAndMessages(null) + mHidePlayPauseHandler.postDelayed({ + video_play_outline.animate().alpha(0f).start() + }, HIDE_PLAY_PAUSE_DELAY) + } + + private fun setupButtons() { + val navBarHeight = navigationBarHeight + video_time_holder.apply { + (layoutParams as RelativeLayout.LayoutParams).bottomMargin = navBarHeight + setPadding(paddingLeft, paddingTop, navigationBarWidth, paddingBottom) + } + + video_time_holder.onGlobalLayout { + (explore.layoutParams as RelativeLayout.LayoutParams).bottomMargin = navBarHeight + video_time_holder.height + + (cardboard.layoutParams as RelativeLayout.LayoutParams).apply { + bottomMargin = navBarHeight + video_time_holder.height + rightMargin = navigationBarWidth + } + vr_view_gradient_background.layoutParams.height = navBarHeight + video_time_holder.height + explore.height + explore.requestLayout() + } + } + + private fun toggleButtonVisibility() { + val newAlpha = if (mIsFullscreen) 0f else 1f + arrayOf(cardboard, explore, vr_view_gradient_background).forEach { + it.animate().alpha(newAlpha) + it.isClickable = !mIsFullscreen + } + + var anim = android.R.anim.fade_in + if (mIsFullscreen) { + anim = android.R.anim.fade_out + video_seekbar.setOnSeekBarChangeListener(null) + } else { + video_seekbar.setOnSeekBarChangeListener(this) + } + + AnimationUtils.loadAnimation(this, anim).apply { + duration = 150 + fillAfter = true + video_time_holder.startAnimation(this) + } + } + + private fun handleClick() { + mIsFullscreen = !mIsFullscreen + toggleButtonVisibility() + if (mIsFullscreen) { + hideSystemUI(false) + } else { + showSystemUI(false) + } + } + + private fun skip(forward: Boolean) { + if (forward && mCurrTime == mDuration) { + return + } + + val curr = vr_video_view.currentPosition + val twoPercents = Math.max((vr_video_view.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(vr_video_view.duration.toInt(), roundProgress), 0) + setVideoProgress(limitedProgress) + if (!mIsPlaying) { + togglePlayPause() + } + } + + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + if (fromUser) { + setVideoProgress(progress) + } + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) { + vr_video_view.pauseVideo() + mIsDragged = true + } + + override fun onStopTrackingTouch(seekBar: SeekBar?) { + mIsPlaying = true + playVideo() + mIsDragged = false + schedulePlayPauseFadeOut() + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SetWallpaperActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SetWallpaperActivity.kt index 5f02df853..8fd8dcfb5 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SetWallpaperActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SetWallpaperActivity.kt @@ -10,7 +10,6 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import com.simplemobiletools.commons.dialogs.RadioGroupDialog -import com.simplemobiletools.commons.extensions.isActivityDestroyed import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.helpers.isNougatPlus import com.simplemobiletools.commons.models.RadioItem @@ -113,7 +112,7 @@ class SetWallpaperActivity : SimpleActivity(), CropImageView.OnCropImageComplete @SuppressLint("NewApi") override fun onCropImageComplete(view: CropImageView?, result: CropImageView.CropResult) { - if (isActivityDestroyed()) + if (isDestroyed) return if (result.error == null) { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SettingsActivity.kt index d6086baaf..f58789dd1 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SettingsActivity.kt @@ -18,10 +18,7 @@ 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 +import com.simplemobiletools.gallery.helpers.* import kotlinx.android.synthetic.main.activity_settings.* import java.util.* @@ -61,6 +58,7 @@ class SettingsActivity : SimpleActivity() { setupDeleteEmptyFolders() setupAllowPhotoGestures() setupAllowVideoGestures() + setupAllowDownGesture() setupBottomActions() setupShowMediaCount() setupKeepLastModified() @@ -77,6 +75,7 @@ class SettingsActivity : SimpleActivity() { setupManageBottomActions() setupUseRecycleBin() setupShowRecycleBin() + setupShowRecycleBinLast() setupEmptyRecycleBin() updateTextColors(settings_holder) setupSectionColors() @@ -304,6 +303,14 @@ class SettingsActivity : SimpleActivity() { } } + private fun setupAllowDownGesture() { + settings_allow_down_gesture.isChecked = config.allowDownGesture + settings_allow_down_gesture_holder.setOnClickListener { + settings_allow_down_gesture.toggle() + config.allowDownGesture = settings_allow_down_gesture.isChecked + } + } + private fun setupShowMediaCount() { settings_show_media_count.isChecked = config.showMediaCount settings_show_media_count_holder.setOnClickListener { @@ -459,11 +466,14 @@ class SettingsActivity : SimpleActivity() { private fun setupUseRecycleBin() { settings_empty_recycle_bin_holder.beVisibleIf(config.useRecycleBin) settings_show_recycle_bin_holder.beVisibleIf(config.useRecycleBin) + settings_show_recycle_bin_last_holder.beVisibleIf(config.useRecycleBin && config.showRecycleBinAtFolders) 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) + settings_show_recycle_bin_holder.beVisibleIf(config.useRecycleBin) + settings_show_recycle_bin_last_holder.beVisibleIf(config.useRecycleBin && config.showRecycleBinAtFolders) } } @@ -472,6 +482,18 @@ class SettingsActivity : SimpleActivity() { settings_show_recycle_bin_holder.setOnClickListener { settings_show_recycle_bin.toggle() config.showRecycleBinAtFolders = settings_show_recycle_bin.isChecked + settings_show_recycle_bin_last_holder.beVisibleIf(config.useRecycleBin && config.showRecycleBinAtFolders) + } + } + + private fun setupShowRecycleBinLast() { + settings_show_recycle_bin_last.isChecked = config.showRecycleBinLast + settings_show_recycle_bin_last_holder.setOnClickListener { + settings_show_recycle_bin_last.toggle() + config.showRecycleBinLast = settings_show_recycle_bin_last.isChecked + if (config.showRecycleBinLast) { + config.removePinnedFolders(setOf(RECYCLE_BIN)) + } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt index 9a318db83..444097363 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt @@ -2,7 +2,6 @@ package com.simplemobiletools.gallery.activities import android.animation.Animator import android.animation.ValueAnimator -import android.annotation.SuppressLint import android.annotation.TargetApi import android.app.Activity import android.content.Intent @@ -20,13 +19,13 @@ import android.os.Build import android.os.Bundle import android.os.Handler import android.provider.MediaStore -import androidx.viewpager.widget.ViewPager import android.util.DisplayMetrics import android.view.Menu import android.view.MenuItem import android.view.View import android.view.WindowManager import android.view.animation.DecelerateInterpolator +import androidx.viewpager.widget.ViewPager import com.bumptech.glide.Glide import com.simplemobiletools.commons.dialogs.PropertiesDialog import com.simplemobiletools.commons.dialogs.RenameItemDialog @@ -103,7 +102,6 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View initFavorites() } - @TargetApi(Build.VERSION_CODES.LOLLIPOP) override fun onResume() { super.onResume() if (!hasPermission(PERMISSION_WRITE_STORAGE)) { @@ -112,9 +110,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View } if (config.bottomActions) { - if (isLollipopPlus()) { - window.navigationBarColor = Color.TRANSPARENT - } + window.navigationBarColor = Color.TRANSPARENT } else { setTranslucentNavigation() } @@ -135,9 +131,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View } supportActionBar?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) - if (isLollipopPlus()) { - window.statusBarColor = Color.TRANSPARENT - } + window.statusBarColor = Color.TRANSPARENT } override fun onPause() { @@ -225,7 +219,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View supportActionBar?.title = mPath.getFilenameFromPath() view_pager.onGlobalLayout { - if (!isActivityDestroyed()) { + if (!isDestroyed) { if (mMediaFiles.isNotEmpty()) { gotMedia(mMediaFiles as ArrayList) } @@ -365,7 +359,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View private fun updatePagerItems(media: MutableList) { val pagerAdapter = MyPagerAdapter(this, supportFragmentManager, media) - if (!isActivityDestroyed()) { + if (!isDestroyed) { view_pager.apply { adapter = pagerAdapter currentItem = mPos @@ -384,7 +378,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View private fun startSlideshow() { if (getMediaForSlideshow()) { view_pager.onGlobalLayout { - if (!isActivityDestroyed()) { + if (!isDestroyed) { hideSystemUI(true) mSlideshowInterval = config.slideshowInterval mSlideshowMoveBackwards = config.slideshowMoveBackwards @@ -434,7 +428,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View val dragOffset = dragPosition - oldDragPosition oldDragPosition = dragPosition try { - view_pager.fakeDragBy(dragOffset * (if (forward) 1f else -1f)) + view_pager.fakeDragBy(dragOffset * (if (forward) -1f else 1f)) } catch (e: Exception) { stopSlideshow() } @@ -450,9 +444,9 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View private fun slideshowEnded(forward: Boolean) { if (config.loopSlideshow) { if (forward) { - view_pager.setCurrentItem(0, false) - } else { view_pager.setCurrentItem(view_pager.adapter!!.count - 1, false) + } else { + view_pager.setCurrentItem(0, false) } } else { stopSlideshow() @@ -474,7 +468,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View if (mIsSlideshowActive) { if (getCurrentMedium()!!.isImage() || getCurrentMedium()!!.isGIF()) { mSlideshowHandler.postDelayed({ - if (mIsSlideshowActive && !isActivityDestroyed()) { + if (mIsSlideshowActive && !isDestroyed) { swipeToNextMedium() } }, mSlideshowInterval * 1000L) @@ -980,18 +974,11 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View initBottomActionsLayout() } - @SuppressLint("NewApi") private fun measureScreen() { val metrics = DisplayMetrics() - if (isJellyBean1Plus()) { - windowManager.defaultDisplay.getRealMetrics(metrics) - screenWidth = metrics.widthPixels - screenHeight = metrics.heightPixels - } else { - windowManager.defaultDisplay.getMetrics(metrics) - screenWidth = metrics.widthPixels - screenHeight = metrics.heightPixels - } + windowManager.defaultDisplay.getRealMetrics(metrics) + screenWidth = metrics.widthPixels + screenHeight = metrics.heightPixels } private fun refreshViewPager() { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/DirectoryAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/DirectoryAdapter.kt index 12b095d18..b40908788 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/DirectoryAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/DirectoryAdapter.kt @@ -1,6 +1,5 @@ package com.simplemobiletools.gallery.adapters -import android.util.SparseArray import android.view.Menu import android.view.View import android.view.ViewGroup @@ -11,6 +10,7 @@ import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.dialogs.PropertiesDialog import com.simplemobiletools.commons.dialogs.RenameItemDialog +import com.simplemobiletools.commons.dialogs.RenameItemsDialog import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.OTG_PATH import com.simplemobiletools.commons.models.FileDirItem @@ -26,8 +26,6 @@ import com.simplemobiletools.gallery.models.AlbumCover import com.simplemobiletools.gallery.models.Directory import kotlinx.android.synthetic.main.directory_item_list.view.* import java.io.File -import java.util.* -import kotlin.collections.ArrayList class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList, val listener: DirectoryOperationsListener?, recyclerView: MyRecyclerView, val isPickIntent: Boolean, fastScroller: FastScroller? = null, itemClick: (Any) -> Unit) : @@ -48,14 +46,6 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList + holder.bindView(dir, true, !isPickIntent) { itemView, adapterPosition -> setupView(itemView, dir) } - bindViewHolder(holder, position, view) + bindViewHolder(holder) } override fun getItemCount() = dirs.size override fun prepareActionMode(menu: Menu) { - if (getSelectedPaths().isEmpty()) { + val selectedPaths = getSelectedPaths() + if (selectedPaths.isEmpty()) { return } - val selectedPaths = getSelectedPaths() + val isOneItemSelected = isOneItemSelected() menu.apply { - 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_rename).isVisible = !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 + 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) + checkHideBtnVisibility(this, selectedPaths) + checkPinBtnVisibility(this, selectedPaths) } } override fun actionItemPressed(id: Int) { - if (selectedPositions.isEmpty()) { + if (selectedKeys.isEmpty()) { return } @@ -117,49 +108,33 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList 0 - menu.findItem(R.id.cab_unhide).isVisible = hiddenCnt > 0 + private fun checkHideBtnVisibility(menu: Menu, selectedPaths: ArrayList) { + menu.findItem(R.id.cab_hide).isVisible = selectedPaths.any { !File(it).doesThisOrParentHaveNoMedia() } + menu.findItem(R.id.cab_unhide).isVisible = selectedPaths.any { File(it).doesThisOrParentHaveNoMedia() } } - private fun checkPinBtnVisibility(menu: Menu) { + private fun checkPinBtnVisibility(menu: Menu, selectedPaths: ArrayList) { val pinnedFolders = config.pinnedFolders - var pinnedCnt = 0 - var unpinnedCnt = 0 - selectedPositions.mapNotNull { dirs.getOrNull(it)?.path }.forEach { - if (pinnedFolders.contains(it)) { - pinnedCnt++ - } else { - unpinnedCnt++ - } - } - - menu.findItem(R.id.cab_pin).isVisible = unpinnedCnt > 0 - menu.findItem(R.id.cab_unpin).isVisible = pinnedCnt > 0 + menu.findItem(R.id.cab_pin).isVisible = selectedPaths.any { !pinnedFolders.contains(it) } + menu.findItem(R.id.cab_unpin).isVisible = selectedPaths.any { pinnedFolders.contains(it) } } private fun showProperties() { - if (selectedPositions.size <= 1) { - val path = dirs[selectedPositions.first()].path + if (selectedKeys.size <= 1) { + val path = getFirstSelectedItemPath() ?: return if (path != FAVORITES && path != RECYCLE_BIN) { - PropertiesDialog(activity, dirs[selectedPositions.first()].path, config.shouldShowHidden) + PropertiesDialog(activity, path, config.shouldShowHidden) } } else { PropertiesDialog(activity, getSelectedPaths().filter { it != FAVORITES && it != RECYCLE_BIN }.toMutableList(), config.shouldShowHidden) @@ -167,26 +142,33 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList + RenameItemsDialog(activity, paths) { + listener?.refreshItems() } } } @@ -283,18 +265,6 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList() - val cnt = viewHolders.size() - for (i in 0..cnt) { - if (affectedPositions.contains(i)) { - continue - } - - val view = viewHolders.get(i, null) - val newIndex = i - selectedPositions.count { it <= i } - newViewHolders.put(newIndex, view) - } - viewHolders = newViewHolders currentDirectoriesHash = newDirs.hashCode() dirs = newDirs @@ -330,26 +300,24 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList() val showHidden = activity.config.shouldShowHidden - selectedPositions.forEach { - val path = dirs[it].path - if (path.startsWith(OTG_PATH)) { - paths.addAll(getOTGFilePaths(path, showHidden)) - } else if (path != FAVORITES) { - File(path).listFiles()?.filter { + getSelectedPaths().forEach { + if (it.startsWith(OTG_PATH)) { + paths.addAll(getOTGFilePaths(it, showHidden)) + } else if (it != FAVORITES) { + File(it).listFiles()?.filter { !activity.getIsPathDirectory(it.absolutePath) && it.isMediaFile() && (showHidden || !it.name.startsWith('.')) }?.mapTo(paths) { it.absolutePath } } @@ -378,9 +346,9 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList(selectedPositions.size) - val removeFolders = ArrayList(selectedPositions.size) - var SAFPath = "" - selectedPositions.forEach { - if (dirs.size > it) { - val path = dirs[it].path - if (activity.needsStupidWritePermissions(path) && config.treeUri.isEmpty()) { - SAFPath = path - } + val selectedDirs = getSelectedItems() + selectedDirs.forEach { + val path = it.path + if (activity.needsStupidWritePermissions(path) && config.treeUri.isEmpty()) { + SAFPath = path } } activity.handleSAFDialog(SAFPath) { - selectedPositions.sortedDescending().forEach { - val directory = dirs.getOrNull(it) - if (directory != null) { - if (directory.areFavorites() || directory.isRecycleBin()) { - if (directory.isRecycleBin()) { - tryEmptyRecycleBin(false) - } else { - Thread { - activity.galleryDB.MediumDao().clearFavorites() - listener?.refreshItems() - }.start() - } - - if (selectedPositions.size == 1) { - finishActMode() - } else { - selectedPositions.remove(it) - toggleItemSelection(false, it) - } + val foldersToDelete = ArrayList(selectedKeys.size) + selectedDirs.forEach { + if (it.areFavorites() || it.isRecycleBin()) { + if (it.isRecycleBin()) { + tryEmptyRecycleBin(false) } else { - folders.add(File(directory.path)) - removeFolders.add(directory) + Thread { + activity.galleryDB.MediumDao().clearFavorites() + listener?.refreshItems() + }.start() } + + if (selectedKeys.size == 1) { + finishActMode() + } + } else { + foldersToDelete.add(File(it.path)) } } - listener?.deleteFolders(folders) + listener?.deleteFolders(foldersToDelete) } } private fun changeAlbumCover(useDefault: Boolean) { - if (selectedPositions.size != 1) + if (selectedKeys.size != 1) return - val path = dirs[selectedPositions.first()].path + val path = getFirstSelectedItemPath() ?: return if (useDefault) { val albumCovers = getAlbumCoversWithout(path) @@ -480,15 +438,15 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList { - val paths = HashSet(selectedPositions.size) - selectedPositions.forEach { - (dirs.getOrNull(it))?.apply { - paths.add(path) - } - } - return paths - } + private fun getSelectedItems() = dirs.filter { selectedKeys.contains(it.path.hashCode()) } as ArrayList + + private fun getSelectedPaths() = getSelectedItems().map { it.path } as ArrayList + + private fun getFirstSelectedItem() = getItemWithKey(selectedKeys.first()) + + private fun getFirstSelectedItemPath() = getFirstSelectedItem()?.path + + private fun getItemWithKey(key: Int): Directory? = dirs.firstOrNull { it.path.hashCode() == key } fun updateDirs(newDirs: ArrayList) { val directories = newDirs.clone() as ArrayList @@ -516,6 +474,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList TYPE_IMAGES } + dir_check?.beVisibleIf(isSelected) + if (isSelected) { + dir_check.background?.applyColorFilter(primaryColor) + } + activity.loadImage(thumbnailType, directory.tmb, dir_thumbnail, scrollHorizontally, animateGifs, cropThumbnails) dir_pin.beVisibleIf(pinnedFolders.contains(directory.path)) dir_location.beVisibleIf(directory.location != LOCAITON_INTERNAL) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/FiltersAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/FiltersAdapter.kt index 046abda1f..db8aa9c7d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/FiltersAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/FiltersAdapter.kt @@ -1,37 +1,34 @@ package com.simplemobiletools.gallery.adapters import android.content.Context -import android.graphics.drawable.Drawable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.simplemobiletools.gallery.R -import com.simplemobiletools.gallery.interfaces.FilterAdapterListener import com.simplemobiletools.gallery.models.FilterItem import kotlinx.android.synthetic.main.editor_filter_item.view.* import java.util.* -class FiltersAdapter(val context: Context, val filterItems: ArrayList, val itemClick: (Int) -> Unit) : RecyclerView.Adapter(), - FilterAdapterListener { +class FiltersAdapter(val context: Context, val filterItems: ArrayList, val itemClick: (Int) -> Unit) : RecyclerView.Adapter() { private var currentSelection = filterItems.first() private var strokeBackground = context.resources.getDrawable(R.drawable.stroke_background) override fun onBindViewHolder(holder: ViewHolder, position: Int) { - holder.bindView(filterItems[position], strokeBackground) + holder.bindView(filterItems[position]) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.editor_filter_item, parent, false) - return ViewHolder(view, this) + return ViewHolder(view) } override fun getItemCount() = filterItems.size - override fun getCurrentFilter() = currentSelection + fun getCurrentFilter() = currentSelection - override fun setCurrentFilter(position: Int) { + private fun setCurrentFilter(position: Int) { val filterItem = filterItems.getOrNull(position) ?: return if (currentSelection != filterItem) { currentSelection = filterItem @@ -40,19 +37,19 @@ class FiltersAdapter(val context: Context, val filterItems: ArrayList removeSelection() @@ -41,20 +35,27 @@ class ManageFoldersAdapter(activity: BaseSimpleActivity, var folders: ArrayList< override fun getIsItemSelectable(position: Int) = true + override fun getItemSelectionKey(position: Int) = folders.getOrNull(position)?.hashCode() + + override fun getItemKeyPosition(key: Int) = folders.indexOfFirst { it.hashCode() == key } + 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, true, true) { itemView, adapterPosition -> + holder.bindView(folder, true, true) { itemView, adapterPosition -> setupView(itemView, folder) } - bindViewHolder(holder, position, view) + bindViewHolder(holder) } override fun getItemCount() = folders.size + private fun getSelectedItems() = folders.filter { selectedKeys.contains(it.hashCode()) } as ArrayList + private fun setupView(view: View, folder: String) { view.apply { + manage_folder_holder?.isSelected = selectedKeys.contains(folder.hashCode()) manage_folder_title.apply { text = folder setTextColor(config.textColor) @@ -63,20 +64,20 @@ class ManageFoldersAdapter(activity: BaseSimpleActivity, var folders: ArrayList< } private fun removeSelection() { - val removeFolders = ArrayList(selectedPositions.size) + val removeFolders = ArrayList(selectedKeys.size) + val positions = getSelectedItemPositions() - selectedPositions.sortedDescending().forEach { - val folder = folders[it] - removeFolders.add(folder) + getSelectedItems().forEach { + removeFolders.add(it) if (isShowingExcludedFolders) { - config.removeExcludedFolder(folder) + config.removeExcludedFolder(it) } else { - config.removeIncludedFolder(folder) + config.removeIncludedFolder(it) } } folders.removeAll(removeFolders) - removeSelectedItems() + removeSelectedItems(positions) if (folders.isEmpty()) { listener?.refreshItems() } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/ManageHiddenFoldersAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/ManageHiddenFoldersAdapter.kt index 101b12764..95e2c053f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/ManageHiddenFoldersAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/ManageHiddenFoldersAdapter.kt @@ -27,12 +27,6 @@ class ManageHiddenFoldersAdapter(activity: BaseSimpleActivity, var folders: Arra override fun prepareActionMode(menu: Menu) {} - override fun prepareItemSelection(viewHolder: ViewHolder) {} - - override fun markViewHolderSelection(select: Boolean, viewHolder: ViewHolder?) { - viewHolder?.itemView?.manage_folder_holder?.isSelected = select - } - override fun actionItemPressed(id: Int) { when (id) { R.id.cab_unhide -> tryUnhideFolders() @@ -43,20 +37,27 @@ class ManageHiddenFoldersAdapter(activity: BaseSimpleActivity, var folders: Arra override fun getIsItemSelectable(position: Int) = true + override fun getItemSelectionKey(position: Int) = folders.getOrNull(position)?.hashCode() + + override fun getItemKeyPosition(key: Int) = folders.indexOfFirst { it.hashCode() == key } + 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, true, true) { itemView, adapterPosition -> + holder.bindView(folder, true, true) { itemView, adapterPosition -> setupView(itemView, folder) } - bindViewHolder(holder, position, view) + bindViewHolder(holder) } override fun getItemCount() = folders.size + private fun getSelectedItems() = folders.filter { selectedKeys.contains(it.hashCode()) } as ArrayList + private fun setupView(view: View, folder: String) { view.apply { + manage_folder_holder?.isSelected = selectedKeys.contains(folder.hashCode()) manage_folder_title.apply { text = folder setTextColor(config.textColor) @@ -65,12 +66,12 @@ class ManageHiddenFoldersAdapter(activity: BaseSimpleActivity, var folders: Arra } private fun tryUnhideFolders() { - val removeFolders = ArrayList(selectedPositions.size) + val removeFolders = ArrayList(selectedKeys.size) val sdCardPaths = ArrayList() - selectedPositions.forEach { - if (activity.isPathOnSD(folders[it])) { - sdCardPaths.add(folders[it]) + getSelectedItems().forEach { + if (activity.isPathOnSD(it)) { + sdCardPaths.add(it) } } @@ -84,14 +85,14 @@ class ManageHiddenFoldersAdapter(activity: BaseSimpleActivity, var folders: Arra } private fun unhideFolders(removeFolders: ArrayList) { - selectedPositions.sortedDescending().forEach { - val folder = folders[it] - removeFolders.add(folder) - activity.removeNoMedia(folder) + val position = getSelectedItemPositions() + getSelectedItems().forEach { + removeFolders.add(it) + activity.removeNoMedia(it) } folders.removeAll(removeFolders) - removeSelectedItems() + removeSelectedItems(position) if (folders.isEmpty()) { listener?.refreshItems() } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MediaAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MediaAdapter.kt index d88895b59..52d40caf8 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MediaAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MediaAdapter.kt @@ -13,6 +13,7 @@ import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter import com.simplemobiletools.commons.dialogs.PropertiesDialog import com.simplemobiletools.commons.dialogs.RenameItemDialog +import com.simplemobiletools.commons.dialogs.RenameItemsDialog import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.OTG_PATH import com.simplemobiletools.commons.models.FileDirItem @@ -61,14 +62,6 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList + 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) + bindViewHolder(holder) } override fun getItemCount() = media.size @@ -111,19 +104,26 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList 0 - findItem(R.id.cab_restore_recycle_bin_files).isVisible = getSelectedPaths().all { it.startsWith(activity.filesDir.absolutePath) } + val selectedItems = getSelectedItems() + if (selectedItems.isEmpty()) { + return + } - checkHideBtnVisibility(this) - checkFavoriteBtnVisibility(this) + val isOneItemSelected = isOneItemSelected() + val selectedPaths = selectedItems.map { it.path } as ArrayList + menu.apply { + findItem(R.id.cab_rename).isVisible = selectedItems.firstOrNull()?.getIsInRecycleBin() == false + findItem(R.id.cab_open_with).isVisible = isOneItemSelected + findItem(R.id.cab_confirm_selection).isVisible = isAGetIntent && allowMultiplePicks && selectedKeys.isNotEmpty() + findItem(R.id.cab_restore_recycle_bin_files).isVisible = selectedPaths.all { it.startsWith(activity.filesDir.absolutePath) } + + checkHideBtnVisibility(this, selectedItems) + checkFavoriteBtnVisibility(this, selectedItems) } } override fun actionItemPressed(id: Int) { - if (selectedPositions.isEmpty()) { + if (selectedKeys.isEmpty()) { return } @@ -141,9 +141,9 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList copyMoveTo(true) R.id.cab_move_to -> copyMoveTo(false) R.id.cab_select_all -> selectAll() - R.id.cab_open_with -> activity.openPath(getCurrentPath(), true) + R.id.cab_open_with -> openPath() R.id.cab_fix_date_taken -> fixDateTaken() - R.id.cab_set_as -> activity.setAs(getCurrentPath()) + R.id.cab_set_as -> setAs() R.id.cab_delete -> checkDeleteConfirmation() } } @@ -152,12 +152,16 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList 0 && !isInRecycleBin - menu.findItem(R.id.cab_unhide).isVisible = hiddenCnt > 0 && !isInRecycleBin + private fun checkHideBtnVisibility(menu: Menu, selectedItems: ArrayList) { + val isInRecycleBin = selectedItems.firstOrNull()?.getIsInRecycleBin() == true + menu.findItem(R.id.cab_hide).isVisible = !isInRecycleBin && selectedItems.any { !it.isHidden() } + menu.findItem(R.id.cab_unhide).isVisible = !isInRecycleBin && selectedItems.any { it.isHidden() } } - 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 checkFavoriteBtnVisibility(menu: Menu, selectedItems: ArrayList) { + menu.findItem(R.id.cab_add_to_favorites).isVisible = selectedItems.any { !it.isFavorite } + menu.findItem(R.id.cab_remove_from_favorites).isVisible = selectedItems.any { it.isFavorite } } private fun confirmSelection() { @@ -202,8 +186,9 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList 1) { + if (selectedKeys.size == 1 && selectedKeys.first() != -1) { + activity.shareMediumPath(getSelectedItems().first().path) + } else if (selectedKeys.size > 1) { activity.shareMediaPaths(getSelectedPaths()) } } @@ -345,7 +349,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList(selectedPositions.size) - val removeMedia = ArrayList(selectedPositions.size) - - if (media.size <= selectedPositions.first()) { - finishActMode() - return - } - - val SAFPath = (media[selectedPositions.first()] as Medium).path + val SAFPath = getSelectedPaths().firstOrNull { activity.isPathOnSD(it) } ?: getFirstSelectedItemPath() ?: return activity.handleSAFDialog(SAFPath) { - selectedPositions.sortedDescending().forEach { - val thumbnailItem = media.getOrNull(it) - if (thumbnailItem is Medium) { - fileDirItems.add(FileDirItem(thumbnailItem.path, thumbnailItem.name)) - removeMedia.add(thumbnailItem) - } + val fileDirItems = ArrayList(selectedKeys.size) + val removeMedia = ArrayList(selectedKeys.size) + val position = getSelectedItemPositions() + + getSelectedItems().forEach { + fileDirItems.add(FileDirItem(it.path, it.name)) + removeMedia.add(it) } media.removeAll(removeMedia) listener?.tryDeleteFiles(fileDirItems) - removeSelectedItems() + removeSelectedItems(position) } } - private fun getSelectedMedia(): List { - val selectedMedia = ArrayList(selectedPositions.size) - selectedPositions.forEach { - (media.getOrNull(it) as? Medium)?.apply { - selectedMedia.add(this) - } - } - return selectedMedia - } + private fun getSelectedItems() = media.filter { selectedKeys.contains((it as? Medium)?.path?.hashCode()) } as ArrayList - private fun getSelectedPaths() = getSelectedMedia().map { it.path } as ArrayList + private fun getSelectedPaths() = getSelectedItems().map { it.path } as ArrayList + + private fun getFirstSelectedItemPath() = getItemWithKey(selectedKeys.first())?.path + + private fun getItemWithKey(key: Int): Medium? = media.firstOrNull { (it as? Medium)?.path?.hashCode() == key } as? Medium fun updateMedia(newMedia: ArrayList) { val thumbnailItems = newMedia.clone() as ArrayList @@ -437,12 +428,18 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList() var view = activity.layoutInflater.inflate(R.layout.dialog_directory_picker, null) var isGridViewType = activity.config.viewTypeFolders == VIEW_TYPE_GRID + var showHidden = activity.config.shouldShowHidden init { (view.directories_grid.layoutManager as MyGridLayoutManager).apply { @@ -36,10 +34,23 @@ class PickDirectoryDialog(val activity: BaseSimpleActivity, val sourcePath: Stri .setNegativeButton(R.string.cancel, null) .setNeutralButton(R.string.other_folder) { dialogInterface, i -> showOtherFolder() } .create().apply { - activity.setupDialogStuff(view, this, R.string.select_destination) + activity.setupDialogStuff(view, this, R.string.select_destination) { + view.directories_show_hidden.beVisibleIf(!context.config.shouldShowHidden) + view.directories_show_hidden.setOnClickListener { + activity.handleHiddenFolderPasswordProtection { + view.directories_show_hidden.beGone() + showHidden = true + fetchDirectories(true) + } + } + } } - activity.getCachedDirectories { + fetchDirectories(false) + } + + private fun fetchDirectories(forceShowHidden: Boolean) { + activity.getCachedDirectories(forceShowHidden = forceShowHidden) { if (it.isNotEmpty()) { activity.runOnUiThread { gotDirectories(activity.addTempFolderIfNeeded(it)) @@ -49,8 +60,7 @@ class PickDirectoryDialog(val activity: BaseSimpleActivity, val sourcePath: Stri } private fun showOtherFolder() { - val showHidden = activity.config.shouldShowHidden - FilePickerDialog(activity, sourcePath, false, showHidden, true) { + FilePickerDialog(activity, sourcePath, false, showHidden, true, true) { callback(it) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SaveAsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SaveAsDialog.kt index 9bb1f2ea9..35dc95274 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SaveAsDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SaveAsDialog.kt @@ -32,7 +32,7 @@ class SaveAsDialog(val activity: BaseSimpleActivity, val path: String, val appen save_as_name.setText(name) save_as_path.setOnClickListener { - FilePickerDialog(activity, realPath, false, false, true) { + FilePickerDialog(activity, realPath, false, false, true, true) { save_as_path.text = activity.humanizePath(it) realPath = it } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/Activity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/Activity.kt index 8993ebce3..d70cd507f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/Activity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/Activity.kt @@ -3,8 +3,8 @@ package com.simplemobiletools.gallery.extensions import android.app.Activity import android.content.Intent import android.provider.MediaStore -import androidx.appcompat.app.AppCompatActivity import android.view.View +import androidx.appcompat.app.AppCompatActivity import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.extensions.* @@ -60,8 +60,8 @@ fun Activity.launchCamera() { } fun SimpleActivity.launchAbout() { - val licenses = 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 or LICENSE_PICASSO or LICENSE_EXOPLAYER or LICENSE_PANORAMA_VIEW or LICENSE_SANSELAN or LICENSE_FILTERS + val licenses = LICENSE_GLIDE or LICENSE_CROPPER or LICENSE_RTL or LICENSE_SUBSAMPLING or LICENSE_PATTERN or LICENSE_REPRINT or LICENSE_GIF_DRAWABLE or + LICENSE_PHOTOVIEW or LICENSE_PICASSO or LICENSE_EXOPLAYER or LICENSE_PANORAMA_VIEW or LICENSE_SANSELAN or LICENSE_FILTERS val faqItems = arrayListOf( FAQItem(R.string.faq_5_title_commons, R.string.faq_5_text_commons), diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/Context.kt index 41cf947d1..846e44b21 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/Context.kt @@ -8,7 +8,6 @@ import android.database.sqlite.SQLiteException import android.graphics.Point import android.graphics.drawable.PictureDrawable import android.media.AudioManager -import android.os.Build import android.provider.MediaStore import android.view.WindowManager import android.widget.ImageView @@ -88,8 +87,7 @@ val Context.usableScreenSize: Point val Context.realScreenSize: Point get() { val size = Point() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) - windowManager.defaultDisplay.getRealSize(size) + windowManager.defaultDisplay.getRealSize(size) return size } @@ -125,6 +123,14 @@ fun Context.movePinnedDirectoriesToFront(dirs: ArrayList): ArrayList< dirs.add(0, newFolder) } } + + if (config.useRecycleBin && config.showRecycleBinAtFolders && config.showRecycleBinLast) { + val binIndex = dirs.indexOfFirst { it.isRecycleBin() } + if (binIndex != -1) { + val bin = dirs.removeAt(binIndex) + dirs.add(bin) + } + } return dirs } @@ -328,7 +334,7 @@ fun Context.loadSVG(path: String, target: MySquareImageView, cropThumbnails: Boo .into(target) } -fun Context.getCachedDirectories(getVideosOnly: Boolean = false, getImagesOnly: Boolean = false, directoryDao: DirectoryDao = galleryDB.DirectoryDao(), callback: (ArrayList) -> Unit) { +fun Context.getCachedDirectories(getVideosOnly: Boolean = false, getImagesOnly: Boolean = false, directoryDao: DirectoryDao = galleryDB.DirectoryDao(), forceShowHidden: Boolean = false, callback: (ArrayList) -> Unit) { Thread { val directories = try { directoryDao.getAll() as ArrayList @@ -336,11 +342,11 @@ fun Context.getCachedDirectories(getVideosOnly: Boolean = false, getImagesOnly: ArrayList() } - if (!config.showRecycleBinAtFolders) { + if (!config.showRecycleBinAtFolders || !config.useRecycleBin) { directories.removeAll { it.isRecycleBin() } } - val shouldShowHidden = config.shouldShowHidden + val shouldShowHidden = config.shouldShowHidden || forceShowHidden val excludedPaths = config.excludedFolders val includedPaths = config.includedFolders var filteredDirectories = directories.filter { it.path.shouldFolderBeVisible(excludedPaths, includedPaths, shouldShowHidden) } as ArrayList diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt index 1da94e93e..ed82b721c 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt @@ -1,6 +1,5 @@ package com.simplemobiletools.gallery.fragments -import android.annotation.SuppressLint import android.content.Intent import android.content.res.Configuration import android.graphics.Bitmap @@ -29,14 +28,15 @@ 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.isJellyBean1Plus -import com.simplemobiletools.commons.helpers.isLollipopPlus import com.simplemobiletools.gallery.R -import com.simplemobiletools.gallery.activities.PanoramaActivity +import com.simplemobiletools.gallery.activities.PanoramaPhotoActivity import com.simplemobiletools.gallery.activities.PhotoActivity import com.simplemobiletools.gallery.activities.ViewPagerActivity import com.simplemobiletools.gallery.extensions.* -import com.simplemobiletools.gallery.helpers.* +import com.simplemobiletools.gallery.helpers.MEDIUM +import com.simplemobiletools.gallery.helpers.PATH +import com.simplemobiletools.gallery.helpers.PicassoDecoder +import com.simplemobiletools.gallery.helpers.PicassoRegionDecoder import com.simplemobiletools.gallery.models.Medium import com.simplemobiletools.gallery.svg.SvgSoftwareLayerSetter import com.squareup.picasso.Callback @@ -73,6 +73,7 @@ class PhotoFragment : ViewPagerFragment() { private var storedAllowDeepZoomableImages = false private var storedShowHighestQuality = false private var storedAllowOneFingerZoom = false + private var mOriginalSubsamplingScale = 0f private var storedExtendedDetails = 0 lateinit var view: ViewGroup @@ -99,6 +100,20 @@ class PhotoFragment : ViewPagerFragment() { } } } + + if (context.config.allowDownGesture) { + gif_view.setOnTouchListener { v, event -> + handleEvent(event) + false + } + + subsampling_view.setOnTouchListener { v, event -> + if (view.subsampling_view.scale == mOriginalSubsamplingScale) { + handleEvent(event) + } + false + } + } } if (ViewPagerActivity.screenWidth == 0 || ViewPagerActivity.screenHeight == 0) { @@ -208,28 +223,18 @@ class PhotoFragment : ViewPagerFragment() { } } - @SuppressLint("NewApi") private fun measureScreen() { val metrics = DisplayMetrics() - if (isJellyBean1Plus()) { - activity!!.windowManager.defaultDisplay.getRealMetrics(metrics) - ViewPagerActivity.screenWidth = metrics.widthPixels - ViewPagerActivity.screenHeight = metrics.heightPixels - } else { - activity!!.windowManager.defaultDisplay.getMetrics(metrics) - ViewPagerActivity.screenWidth = metrics.widthPixels - ViewPagerActivity.screenHeight = metrics.heightPixels - } + activity!!.windowManager.defaultDisplay.getRealMetrics(metrics) + ViewPagerActivity.screenWidth = metrics.widthPixels + ViewPagerActivity.screenHeight = metrics.heightPixels } private fun photoFragmentVisibilityChanged(isVisible: Boolean) { if (isVisible) { scheduleZoomableView() } else { - isSubsamplingVisible = false - view.subsampling_view.recycle() - view.subsampling_view.beGone() - loadZoomableViewHandler.removeCallbacksAndMessages(null) + hideZoomableView() } } @@ -280,7 +285,7 @@ class PhotoFragment : ViewPagerFragment() { } private fun loadSVG() { - Glide.with(this) + Glide.with(context!!) .`as`(PictureDrawable::class.java) .listener(SvgSoftwareLayerSetter()) .load(medium.path) @@ -351,7 +356,7 @@ class PhotoFragment : ViewPagerFragment() { } private fun openPanorama() { - Intent(context, PanoramaActivity::class.java).apply { + Intent(context, PanoramaPhotoActivity::class.java).apply { putExtra(PATH, medium.path) startActivity(this) } @@ -380,7 +385,7 @@ class PhotoFragment : ViewPagerFragment() { maxScale = 10f beVisible() isQuickScaleEnabled = context.config.oneFingerZoom - setResetScaleOnSizeChange(context.config.screenRotation != ROTATE_BY_ASPECT_RATIO) + setResetScaleOnSizeChange(false) setImage(ImageSource.uri(path)) orientation = rotation setEagerLoadingEnabled(false) @@ -393,6 +398,7 @@ class PhotoFragment : ViewPagerFragment() { val useWidth = if (imageOrientation == ORIENTATION_ROTATE_90 || imageOrientation == ORIENTATION_ROTATE_270) sHeight else sWidth val useHeight = if (imageOrientation == ORIENTATION_ROTATE_90 || imageOrientation == ORIENTATION_ROTATE_270) sWidth else sHeight setDoubleTapZoomScale(getDoubleTapZoomScale(useWidth, useHeight)) + mOriginalSubsamplingScale = scale } override fun onTileLoadError(e: Exception?) { @@ -440,7 +446,7 @@ class PhotoFragment : ViewPagerFragment() { false } - view.panorama_outline.beVisibleIf(isPanorama && isLollipopPlus()) + view.panorama_outline.beVisibleIf(isPanorama) } private fun getImageOrientation(): Int { @@ -514,7 +520,7 @@ class PhotoFragment : ViewPagerFragment() { override fun onDestroyView() { super.onDestroyView() - if (activity?.isActivityDestroyed() == false) { + if (activity?.isDestroyed == false) { view.subsampling_view.recycle() } loadZoomableViewHandler.removeCallbacksAndMessages(null) @@ -531,12 +537,22 @@ class PhotoFragment : ViewPagerFragment() { }, 50) } } else { + hideZoomableView() loadImage() } initExtendedDetails() } + private fun hideZoomableView() { + if (context?.config?.allowZoomingImages == true) { + isSubsamplingVisible = false + view.subsampling_view.recycle() + view.subsampling_view.beGone() + loadZoomableViewHandler.removeCallbacksAndMessages(null) + } + } + private fun photoClicked() { listener?.fragmentClicked() } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt index 470a061e0..b4a09d681 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt @@ -1,13 +1,11 @@ package com.simplemobiletools.gallery.fragments -import android.annotation.TargetApi +import android.content.Intent import android.content.res.Configuration import android.graphics.Point import android.graphics.SurfaceTexture -import android.media.AudioManager import android.media.MediaMetadataRetriever import android.net.Uri -import android.os.Build import android.os.Bundle import android.os.Handler import android.util.DisplayMetrics @@ -28,31 +26,28 @@ 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.R +import com.simplemobiletools.gallery.activities.PanoramaVideoActivity import com.simplemobiletools.gallery.activities.VideoActivity import com.simplemobiletools.gallery.extensions.* -import com.simplemobiletools.gallery.helpers.MEDIUM -import com.simplemobiletools.gallery.helpers.MediaSideScroll +import com.simplemobiletools.gallery.helpers.* import com.simplemobiletools.gallery.models.Medium +import com.simplemobiletools.gallery.views.MediaSideScroll +import kotlinx.android.synthetic.main.bottom_video_time_holder.view.* import kotlinx.android.synthetic.main.pager_video_item.view.* import java.io.File 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 mTextureView: TextureView? = null private var mCurrTimeView: TextView? = 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 mHidePlayPauseHandler = Handler() private var mIsPlaying = false private var mIsDragged = false @@ -60,6 +55,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S private var mIsFragmentVisible = false private var mWasFragmentInit = false private var mIsExoPlayerInitialized = false + private var mIsPanorama = false private var mCurrTime = 0 private var mDuration = 0 @@ -68,8 +64,9 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S private var mStoredBottomActions = true private var mStoredExtendedDetails = 0 - private lateinit var brightnessSideScroll: MediaSideScroll - private lateinit var volumeSideScroll: MediaSideScroll + private lateinit var mTimeHolder: View + private lateinit var mBrightnessSideScroll: MediaSideScroll + private lateinit var mVolumeSideScroll: MediaSideScroll lateinit var medium: Medium @@ -77,11 +74,36 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S mView = inflater.inflate(R.layout.pager_video_item, container, false).apply { instant_prev_item.setOnClickListener { listener?.goToPrevItem() } instant_next_item.setOnClickListener { listener?.goToNextItem() } + video_curr_time.setOnClickListener { skip(false) } + video_duration.setOnClickListener { skip(true) } + video_holder.setOnClickListener { toggleFullscreen() } + video_preview.setOnClickListener { toggleFullscreen() } + panorama_outline.setOnClickListener { openPanorama() } + + // adding an empty click listener just to avoid ripple animation at toggling fullscreen + video_seekbar.setOnClickListener { } + mTimeHolder = video_time_holder + mBrightnessSideScroll = video_brightness_controller + mVolumeSideScroll = video_volume_controller + mCurrTimeView = video_curr_time + + if (context.config.allowDownGesture) { + video_preview.setOnTouchListener { v, event -> + handleEvent(event) + false + } + + video_surface.setOnTouchListener { v, event -> + handleEvent(event) + false + } + } } storeStateVariables() medium = arguments!!.getSerializable(MEDIUM) as Medium + Glide.with(context!!).load(medium.path).into(mView!!.video_preview) // setMenuVisibility is not called at VideoActivity (third party intent) if (!mIsFragmentVisible && activity is VideoActivity) { @@ -89,49 +111,58 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S } mIsFullscreen = activity!!.window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == View.SYSTEM_UI_FLAG_FULLSCREEN - - setupPlayer() - if (savedInstanceState != null) { - mCurrTime = savedInstanceState.getInt(PROGRESS) - } - - checkFullscreen() - mWasFragmentInit = true - - mView!!.apply { - brightnessSideScroll = video_brightness_controller - brightnessSideScroll.initialize(activity!!, slide_info, true, container) { x, y -> - video_holder.performClick() - } - - volumeSideScroll = video_volume_controller - volumeSideScroll.initialize(activity!!, slide_info, false, container) { x, y -> - video_holder.performClick() - } - - video_curr_time.setOnClickListener { skip(false) } - video_duration.setOnClickListener { skip(true) } - Glide.with(context!!).load(medium.path).into(video_preview) - } - - mExoPlayer = ExoPlayerFactory.newSimpleInstance(context, DefaultTrackSelector()) - mExoPlayer!!.setSeekParameters(SeekParameters.CLOSEST_SYNC) - initExoPlayerListeners() - + initTimeHolder() medium.path.getVideoResolution()?.apply { mVideoSize.x = x mVideoSize.y = y - setVideoSize() + mIsPanorama = x == y * 2 + if (mIsPanorama) { + mView!!.apply { + panorama_outline.beVisible() + video_play_outline.beGone() + mVolumeSideScroll.beGone() + mBrightnessSideScroll.beGone() + Glide.with(context!!).load(medium.path).into(video_preview) + } + } + } + + if (!mIsPanorama) { + setupPlayer() + if (savedInstanceState != null) { + mCurrTime = savedInstanceState.getInt(PROGRESS) + } + + checkFullscreen() + mWasFragmentInit = true + + mExoPlayer = ExoPlayerFactory.newSimpleInstance(context, DefaultTrackSelector()) + mExoPlayer!!.seekParameters = SeekParameters.CLOSEST_SYNC + initExoPlayerListeners() + + if (mVideoSize.x != 0 && mVideoSize.y != 0) { + setVideoSize() + } + + mView!!.apply { + mBrightnessSideScroll.initialize(activity!!, slide_info, true, container) { x, y -> + video_holder.performClick() + } + + mVolumeSideScroll.initialize(activity!!, slide_info, false, container) { x, y -> + video_holder.performClick() + } + + video_surface.onGlobalLayout { + if (mIsFragmentVisible && context?.config?.autoplayVideos == true) { + playVideo() + } + } + } } setupVideoDuration() - mView!!.video_surface.onGlobalLayout { - if (mIsFragmentVisible && context?.config?.autoplayVideos == true) { - playVideo() - } - } - return mView } @@ -142,8 +173,8 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S val allowVideoGestures = config.allowVideoGestures val allowInstantChange = config.allowInstantChange mView!!.apply { - video_volume_controller.beVisibleIf(allowVideoGestures) - video_brightness_controller.beVisibleIf(allowVideoGestures) + video_volume_controller.beVisibleIf(allowVideoGestures && !mIsPanorama) + video_brightness_controller.beVisibleIf(allowVideoGestures && !mIsPanorama) instant_prev_item.beVisibleIf(allowInstantChange) instant_next_item.beVisibleIf(allowInstantChange) @@ -157,7 +188,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S initTimeHolder() } - mView!!.video_time_holder.setBackgroundResource(if (config.bottomActions) 0 else R.drawable.gradient_background) + mTimeHolder.setBackgroundResource(if (config.bottomActions) 0 else R.drawable.gradient_background) storeStateVariables() } @@ -211,9 +242,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S mTextureView = mView!!.video_surface mTextureView!!.setOnClickListener { toggleFullscreen() } mTextureView!!.surfaceTextureListener = this - mView!!.video_holder.setOnClickListener { toggleFullscreen() } - initTimeHolder() checkExtendedDetails() } @@ -230,7 +259,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S val factory = DataSource.Factory { fileDataSource } val audioSource = ExtractorMediaSource(fileDataSource.uri, factory, DefaultExtractorsFactory(), null, null) - mExoPlayer!!.audioStreamType = AudioManager.STREAM_MUSIC + mExoPlayer!!.audioStreamType = C.STREAM_TYPE_MUSIC mExoPlayer!!.prepare(audioSource) } @@ -300,39 +329,29 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S bottom += resources.getDimension(R.dimen.bottom_actions_height).toInt() } - mTimeHolder!!.setPadding(left, top, right, bottom) + mTimeHolder.setPadding(left, top, right, bottom) - mCurrTimeView = mView!!.video_curr_time mSeekBar = mView!!.video_seekbar mSeekBar!!.setOnSeekBarChangeListener(this) - - if (mIsFullscreen) { - mTimeHolder!!.beInvisible() - } + mTimeHolder.beInvisibleIf(mIsFullscreen) } private fun hasNavBar(): Boolean { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - val display = context!!.windowManager.defaultDisplay + val display = context!!.windowManager.defaultDisplay - val realDisplayMetrics = DisplayMetrics() - display.getRealMetrics(realDisplayMetrics) + val realDisplayMetrics = DisplayMetrics() + display.getRealMetrics(realDisplayMetrics) - val realHeight = realDisplayMetrics.heightPixels - val realWidth = realDisplayMetrics.widthPixels + val realHeight = realDisplayMetrics.heightPixels + val realWidth = realDisplayMetrics.widthPixels - val displayMetrics = DisplayMetrics() - display.getMetrics(displayMetrics) + val displayMetrics = DisplayMetrics() + display.getMetrics(displayMetrics) - val displayHeight = displayMetrics.heightPixels - val displayWidth = displayMetrics.widthPixels + val displayHeight = displayMetrics.heightPixels + val displayWidth = displayMetrics.widthPixels - realWidth - displayWidth > 0 || realHeight - displayHeight > 0 - } else { - val hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey() - val hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK) - !hasMenuKey && !hasBackKey - } + return realWidth - displayWidth > 0 || realHeight - displayHeight > 0 } private fun setupTimeHolder() { @@ -376,7 +395,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S AnimationUtils.loadAnimation(activity, anim).apply { duration = 150 fillAfter = true - mTimeHolder?.startAnimation(this) + mTimeHolder.startAnimation(this) } } @@ -385,7 +404,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S return mIsPlaying = !mIsPlaying - mHidePauseHandler.removeCallbacksAndMessages(null) + mHidePlayPauseHandler.removeCallbacksAndMessages(null) if (mIsPlaying) { playVideo() } else { @@ -410,6 +429,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S mIsPlaying = true mExoPlayer?.playWhenReady = true mView!!.video_play_outline.setImageResource(R.drawable.ic_pause) + mView!!.video_play_outline.alpha = PLAY_PAUSE_VISIBLE_ALPHA activity!!.window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) schedulePlayPauseFadeOut() } @@ -431,16 +451,16 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S } private fun schedulePlayPauseFadeOut() { - mHidePauseHandler.removeCallbacksAndMessages(null) - mHidePauseHandler.postDelayed({ + mHidePlayPauseHandler.removeCallbacksAndMessages(null) + mHidePlayPauseHandler.postDelayed({ mView!!.video_play_outline.animate().alpha(0f).start() - }, HIDE_PAUSE_DELAY) + }, HIDE_PLAY_PAUSE_DELAY) } private fun videoEnded() = mExoPlayer?.currentPosition ?: 0 >= mExoPlayer?.duration ?: 0 private fun setProgress(seconds: Int) { - mExoPlayer!!.seekTo(seconds * 1000L) + mExoPlayer?.seekTo(seconds * 1000L) mSeekBar!!.progress = seconds mCurrTimeView!!.text = seconds.getFormattedDuration() } @@ -490,7 +510,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S releaseExoPlayer() mSeekBar?.progress = 0 mTimerHandler.removeCallbacksAndMessages(null) - mHidePauseHandler.removeCallbacksAndMessages(null) + mHidePlayPauseHandler.removeCallbacksAndMessages(null) mTextureView = null } @@ -514,7 +534,6 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S }.start() } - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) private fun setVideoSize() { if (activity == null || mTextureView == null) return @@ -524,15 +543,10 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S val screenWidth: Int val screenHeight: Int - if (isJellyBean1Plus()) { - val realMetrics = DisplayMetrics() - display.getRealMetrics(realMetrics) - screenWidth = realMetrics.widthPixels - screenHeight = realMetrics.heightPixels - } else { - screenWidth = display.width - screenHeight = display.height - } + val realMetrics = DisplayMetrics() + display.getRealMetrics(realMetrics) + screenWidth = realMetrics.widthPixels + screenHeight = realMetrics.heightPixels val screenProportion = screenWidth.toFloat() / screenHeight.toFloat() @@ -570,7 +584,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S } private fun skip(forward: Boolean) { - if (mExoPlayer == null) { + if (mExoPlayer == null || mIsPanorama) { return } @@ -603,15 +617,22 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S if (mExoPlayer == null) return - if (!mIsPlaying) { - togglePlayPause() - } else { + if (mIsPlaying) { mExoPlayer!!.playWhenReady = true + } else { + togglePlayPause() } mIsDragged = false } + private fun openPanorama() { + Intent(context, PanoramaVideoActivity::class.java).apply { + putExtra(PATH, medium.path) + startActivity(this) + } + } + override fun fullscreenToggled(isFullscreen: Boolean) { mIsFullscreen = isFullscreen checkFullscreen() @@ -628,7 +649,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S private fun getExtendedDetailsY(height: Int): Float { val smallMargin = resources.getDimension(R.dimen.small_margin) - val fullscreenOffset = smallMargin + if (mIsFullscreen) 0 else mTimeHolder!!.height + val fullscreenOffset = smallMargin + if (mIsFullscreen) 0 else mTimeHolder.height return context!!.realScreenSize.y.toFloat() - height - fullscreenOffset } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/ViewPagerFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/ViewPagerFragment.kt index bb37b58e2..3a999e10d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/ViewPagerFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/ViewPagerFragment.kt @@ -1,5 +1,6 @@ package com.simplemobiletools.gallery.fragments +import android.view.MotionEvent import androidx.fragment.app.Fragment import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.OTG_PATH @@ -11,6 +12,11 @@ import java.io.File abstract class ViewPagerFragment : Fragment() { var listener: FragmentListener? = null + protected var mTouchDownX = 0f + protected var mTouchDownY = 0f + protected var mCloseDownThreshold = 100f + protected var mIgnoreCloseDown = false + abstract fun fullscreenToggled(isFullscreen: Boolean) interface FragmentListener { @@ -68,4 +74,23 @@ abstract class ViewPagerFragment : Fragment() { } fun getPathToLoad(medium: Medium) = if (medium.path.startsWith(OTG_PATH)) medium.path.getOTGPublicPath(context!!) else medium.path + + protected fun handleEvent(event: MotionEvent) { + when (event.actionMasked) { + MotionEvent.ACTION_DOWN -> { + mTouchDownX = event.x + mTouchDownY = event.y + } + MotionEvent.ACTION_POINTER_DOWN -> mIgnoreCloseDown = true + MotionEvent.ACTION_UP -> { + val diffX = mTouchDownX - event.x + val diffY = mTouchDownY - event.y + + if (!mIgnoreCloseDown && Math.abs(diffY) > Math.abs(diffX) && diffY < -mCloseDownThreshold) { + activity?.supportFinishAfterTransition() + } + mIgnoreCloseDown = false + } + } + } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Config.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Config.kt index 11474c421..40838d5cd 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Config.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Config.kt @@ -89,6 +89,9 @@ class Config(context: Context) : BaseConfig(context) { val currPinnedFolders = HashSet(pinnedFolders) currPinnedFolders.addAll(paths) pinnedFolders = currPinnedFolders + if (paths.contains(RECYCLE_BIN)) { + showRecycleBinLast = false + } } fun removePinnedFolders(paths: Set) { @@ -392,4 +395,12 @@ class Config(context: Context) : BaseConfig(context) { var showHighestQuality: Boolean get() = prefs.getBoolean(SHOW_HIGHEST_QUALITY, false) set(showHighestQuality) = prefs.edit().putBoolean(SHOW_HIGHEST_QUALITY, showHighestQuality).apply() + + var showRecycleBinLast: Boolean + get() = prefs.getBoolean(SHOW_RECYCLE_BIN_LAST, false) + set(showRecycleBinLast) = prefs.edit().putBoolean(SHOW_RECYCLE_BIN_LAST, showRecycleBinLast).apply() + + var allowDownGesture: Boolean + get() = prefs.getBoolean(ALLOW_DOWN_GESTURE, true) + set(allowDownGesture) = prefs.edit().putBoolean(ALLOW_DOWN_GESTURE, allowDownGesture).apply() } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Constants.kt index 0db9f3129..29c738dfa 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Constants.kt @@ -58,10 +58,12 @@ const val USE_RECYCLE_BIN = "use_recycle_bin" const val GROUP_BY = "group_by" const val EVER_SHOWN_FOLDERS = "ever_shown_folders" const val SHOW_RECYCLE_BIN_AT_FOLDERS = "show_recycle_bin_at_folders" +const val SHOW_RECYCLE_BIN_LAST = "show_recycle_bin_last" const val ALLOW_ZOOMING_IMAGES = "allow_zooming_images" const val WAS_SVG_SHOWING_HANDLED = "was_svg_showing_handled" const val LAST_BIN_CHECK = "last_bin_check" const val SHOW_HIGHEST_QUALITY = "show_highest_quality" +const val ALLOW_DOWN_GESTURE = "allow_down_gesture" // slideshow const val SLIDESHOW_INTERVAL = "slideshow_interval" @@ -85,6 +87,9 @@ 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 HIDE_PLAY_PAUSE_DELAY = 500L +const val PLAY_PAUSE_VISIBLE_ALPHA = 0.8f +const val MIN_SKIP_LENGTH = 2000 const val DIRECTORY = "directory" const val MEDIUM = "medium" diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/interfaces/FilterAdapterListener.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/interfaces/FilterAdapterListener.kt deleted file mode 100644 index 379e9e964..000000000 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/interfaces/FilterAdapterListener.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.simplemobiletools.gallery.interfaces - -import com.simplemobiletools.gallery.models.FilterItem - -interface FilterAdapterListener { - fun getCurrentFilter(): FilterItem - - fun setCurrentFilter(position: Int) -} diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/interfaces/MediumDao.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/interfaces/MediumDao.kt index ab8f76c48..5a02476b0 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/interfaces/MediumDao.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/interfaces/MediumDao.kt @@ -33,7 +33,7 @@ interface MediumDao { @Query("DELETE FROM media WHERE full_path = :path COLLATE NOCASE") fun deleteMediumPath(path: String) - @Query("DELETE FROM media WHERE deleted_ts < :timestmap") + @Query("DELETE FROM media WHERE deleted_ts < :timestmap AND deleted_ts != 0") fun deleteOldRecycleBinItems(timestmap: Long) @Query("UPDATE OR REPLACE media SET filename = :newFilename, full_path = :newFullPath, parent_path = :newParentPath WHERE full_path = :oldPath COLLATE NOCASE") diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaSideScroll.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/views/MediaSideScroll.kt similarity index 89% rename from app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaSideScroll.kt rename to app/src/main/kotlin/com/simplemobiletools/gallery/views/MediaSideScroll.kt index 91c5f0a3c..bfb394eeb 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaSideScroll.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/views/MediaSideScroll.kt @@ -1,4 +1,4 @@ -package com.simplemobiletools.gallery.helpers +package com.simplemobiletools.gallery.views import android.app.Activity import android.content.Context @@ -13,6 +13,8 @@ import android.widget.TextView import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.activities.ViewPagerActivity import com.simplemobiletools.gallery.extensions.audioManager +import com.simplemobiletools.gallery.helpers.CLICK_MAX_DURATION +import com.simplemobiletools.gallery.helpers.DRAG_THRESHOLD // allow horizontal swipes through the layout, else it can cause glitches at zoomed in images class MediaSideScroll(context: Context, attrs: AttributeSet) : RelativeLayout(context, attrs) { @@ -30,8 +32,8 @@ class MediaSideScroll(context: Context, attrs: AttributeSet) : RelativeLayout(co private var mSlideInfoText = "" private var mSlideInfoFadeHandler = Handler() private var mParentView: ViewGroup? = null + private var activity: Activity? = null - private lateinit var activity: Activity private lateinit var slideInfoView: TextView private lateinit var callback: (Float, Float) -> Unit @@ -55,7 +57,7 @@ class MediaSideScroll(context: Context, attrs: AttributeSet) : RelativeLayout(co } override fun onTouchEvent(event: MotionEvent): Boolean { - if (mPassTouches) { + if (mPassTouches && activity == null) { return false } @@ -112,11 +114,11 @@ class MediaSideScroll(context: Context, attrs: AttributeSet) : RelativeLayout(co return true } - private fun getCurrentVolume() = activity.audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) + private fun getCurrentVolume() = activity!!.audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) private fun getCurrentBrightness(): Int { return try { - Settings.System.getInt(activity.contentResolver, Settings.System.SCREEN_BRIGHTNESS) + Settings.System.getInt(activity!!.contentResolver, Settings.System.SCREEN_BRIGHTNESS) } catch (e: Settings.SettingNotFoundException) { 70 } @@ -132,11 +134,11 @@ class MediaSideScroll(context: Context, attrs: AttributeSet) : RelativeLayout(co private fun volumePercentChanged(percent: Int) { val stream = AudioManager.STREAM_MUSIC - val maxVolume = activity.audioManager.getStreamMaxVolume(stream) + val maxVolume = activity!!.audioManager.getStreamMaxVolume(stream) val percentPerPoint = 100 / maxVolume val addPoints = percent / percentPerPoint val newVolume = Math.min(maxVolume, Math.max(0, mTouchDownValue + addPoints)) - activity.audioManager.setStreamVolume(stream, newVolume, 0) + activity!!.audioManager.setStreamVolume(stream, newVolume, 0) val absolutePercent = ((newVolume / maxVolume.toFloat()) * 100).toInt() showValue(absolutePercent) @@ -156,9 +158,9 @@ class MediaSideScroll(context: Context, attrs: AttributeSet) : RelativeLayout(co val absolutePercent = ((newBrightness / maxBrightness) * 100).toInt() showValue(absolutePercent) - val attributes = activity.window.attributes + val attributes = activity!!.window.attributes attributes.screenBrightness = absolutePercent / 100f - activity.window.attributes = attributes + activity!!.window.attributes = attributes mSlideInfoFadeHandler.removeCallbacksAndMessages(null) mSlideInfoFadeHandler.postDelayed({ diff --git a/app/src/main/res/layout/activity_panorama.xml b/app/src/main/res/layout/activity_panorama_photo.xml similarity index 81% rename from app/src/main/res/layout/activity_panorama.xml rename to app/src/main/res/layout/activity_panorama_photo.xml index ab146f09e..4592d8838 100644 --- a/app/src/main/res/layout/activity_panorama.xml +++ b/app/src/main/res/layout/activity_panorama_photo.xml @@ -12,12 +12,19 @@ android:layout_height="match_parent" android:visibility="gone"/> + + @@ -25,8 +32,8 @@ android:id="@+id/explore" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" + android:layout_alignParentBottom="true" android:padding="@dimen/activity_margin" android:src="@drawable/ic_explore"/> diff --git a/app/src/main/res/layout/activity_panorama_video.xml b/app/src/main/res/layout/activity_panorama_video.xml new file mode 100644 index 000000000..c384f958e --- /dev/null +++ b/app/src/main/res/layout/activity_panorama_video.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 41400e1cd..27fd9bd44 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -644,6 +644,30 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_directory_picker.xml b/app/src/main/res/layout/dialog_directory_picker.xml index 565382785..5c45c16de 100644 --- a/app/src/main/res/layout/dialog_directory_picker.xml +++ b/app/src/main/res/layout/dialog_directory_picker.xml @@ -1,43 +1,61 @@ - + android:layout_height="match_parent"> - - - - - - - - - + android:paddingTop="@dimen/activity_margin"> - + - - + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/pager_photo_item.xml b/app/src/main/res/layout/pager_photo_item.xml index 9be779d15..4bb227f80 100644 --- a/app/src/main/res/layout/pager_photo_item.xml +++ b/app/src/main/res/layout/pager_photo_item.xml @@ -47,7 +47,7 @@ android:visibility="gone" tools:text="My image\nAnother line"/> - - - @@ -60,13 +60,23 @@ android:alpha="0" android:background="@drawable/black_rounded_background" android:gravity="center" - android:paddingBottom="@dimen/medium_margin" android:paddingLeft="@dimen/activity_margin" - android:paddingRight="@dimen/activity_margin" android:paddingTop="@dimen/medium_margin" + android:paddingRight="@dimen/activity_margin" + android:paddingBottom="@dimen/medium_margin" android:textColor="@android:color/white" android:textSize="@dimen/extra_big_text_size"/> + + - - - - - - - - - + diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index b1a4035e7..5d6ee89c7 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -1,6 +1,12 @@ + Deep zoomable images Show images in the highest possible quality Show the Recycle Bin as the last item on the main screen + Allow closing the fullscreen view with a down gesture المصغرات diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml index 327be5e79..27136947b 100644 --- a/app/src/main/res/values-az/strings.xml +++ b/app/src/main/res/values-az/strings.xml @@ -162,6 +162,7 @@ Deep zoomable images Show images in the highest possible quality Show the Recycle Bin as the last item on the main screen + Allow closing the fullscreen view with a down gesture Thumbnails diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 37eb43858..07c2011a0 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -159,9 +159,10 @@ Fer una verificació addicional per evitar que es mostrin fitxers no vàlids Mostra alguns botons d\'acció a la part inferior de la pantalla Mostra la paperera de reciclatge a la pantalla de carpetes - Deep zoomable images - Show images in the highest possible quality - Show the Recycle Bin as the last item on the main screen + Imatges ampliades a mida + Mostra imatges amb la màxima qualitat possible + Mostra la paperera de reciclatge com a últim element a la pantalla principal + Permet tancar la vista de pantalla completa amb un gest avall Miniatures diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 97442b076..3da9d775a 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -162,6 +162,7 @@ Deep zoomable images Show images in the highest possible quality Show the Recycle Bin as the last item on the main screen + Allow closing the fullscreen view with a down gesture Thumbnails diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 8dbe74752..e29321873 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -162,6 +162,7 @@ Deep zoomable images Show images in the highest possible quality Show the Recycle Bin as the last item on the main screen + Allow closing the fullscreen view with a down gesture Thumbnails diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index e1fc39111..1339b5dda 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -162,6 +162,7 @@ Stark vergrösserbare Bilder Zeige Bilder in der höchstmöglichen Qualität Zeige den Papierkorb als letztes Element auf dem Hauptbildschirm + Allow closing the fullscreen view with a down gesture Thumbnails diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 6bfd6483f..8dcb0d264 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -162,6 +162,7 @@ Βαθιά μεγέθυνση εικόνων Εμφάνιση εικόνων με την υψηλότερη δυνατή ποιότητα Εμφάνιση του Κάδου ως τελευταίο στοιχείο στην κύρια οθόνη + Allow closing the fullscreen view with a down gesture Εικονίδια diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 90057a8cf..b47f2264e 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -159,9 +159,10 @@ Hacer una comprobación adicional para evitar mostrar archivos inválidos Mostrar algunos botones de acción en la parte inferior de la pantalla Mostrar la papelera de reciclaje en la pantalla de carpetas - Deep zoomable images - Show images in the highest possible quality - Show the Recycle Bin as the last item on the main screen + Imágenes ampliables con zoom + Muestra imágenes con la mayor calidad posible + Mostrar la Papelera de reciclaje como el último elemento en la pantalla principal + Permite cerrar la vista de pantalla completa con un gesto hacia abajo. Miniaturas diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 9084aa31a..6d86135e3 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -162,6 +162,7 @@ Deep zoomable images Show images in the highest possible quality Show the Recycle Bin as the last item on the main screen + Allow closing the fullscreen view with a down gesture Esikatselukuvat diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 8f99120ed..a0faec73c 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1,22 +1,22 @@ - Simple Galerie + Simple Gallery Galerie Édition - Ouvrir appareil photo - (caché) + Démarrer l\'appareil photo + (masqué) (exclu) Épingler le dossier Désépingler le dossier Épingler en haut Afficher le contenu de tous les dossiers Tous les dossiers - Permuter vers la vue du dossier + Affichage en vue \"Dossier\" Autre dossier Afficher sur la carte Position inconnue - Augmenter le nombre de colonnes - Réduire le nombre de colonnes + Ajouter une colonne + Supprimer une colonne Changer l\'image de couverture Sélectionner une photo Utiliser par défaut @@ -24,197 +24,200 @@ Luminosité Verrouiller la rotation Déverrouiller la rotation - Change orientation - Force portrait - Paysage de force + Orientation + Forcer la vue portrait + Forcer la vue paysage Utiliser l\'orientation par défaut - Fixe Date Valeur prise - Fixation.... - Dates fixées avec succès + Corriger la valeur des dates de prise des photos + Correction en cours.... + Dates corrigées Filtrer les médias Images Vidéos - GIF - RAW images + GIFs + Images RAW SVGs - Aucun fichier média trouvé avec les filtres sélectionnés. - Changer les filtres + Aucun fichier média trouvé avec les filtres sélectionnés + Modifier les filtres - Cette option masque le dossier en ajoutant un fichier \'.nomedia\' à l\'intérieur, cela masquera aussi tous les sous-dossiers. Vous pouvez les voir en modifiant l\'option \'Afficher les dossiers cachés\' dans les paramètres. Continuer ? + Cette option masque le dossier en ajoutant un fichier \".nomedia\" à l\'intérieur, cela masquera aussi tous les sous-dossiers. Vous pouvez les voir en appuyant sur le symbole \"Œil\" (permettant l\'affichage) depuis les paramètres. Continuer ? Exclure Dossiers exclus Gérer les dossiers exclus - Cela va exclure la sélection ainsi que ses sous-dossiers depuis Simple Galerie uniquement. Vous pouvez gérer les dossiers exclus depuis les paramètres. + Cela va exclure la sélection ainsi que ses sous-dossiers depuis Simple Gallery uniquement. Vous pouvez gérer les dossiers exclus depuis les paramètres. Exclure un dossier parent ? - Exclure des dossiers les masquera ainsi que leurs sous-dossiers uniquement dans Simple Galerie, ils seront toujours visibles depuis d\'autres applications.\\Si vous voulez aussi les masquer ailleurs, utilisez la fonction Masquer. + Exclure des dossiers les masquera ainsi que leurs sous-dossiers uniquement dans Simple Gallery, ils seront toujours visibles depuis d\'autres applications.\n\nSi vous voulez aussi les masquer ailleurs, utilisez la fonction \"Masquer\". Tout supprimer - Supprimer tous les dossiers de la liste des exclusions ? Ceci n\'effacera pas les dossiers. + Supprimer tous les dossiers de la liste des exclusions ? Cela n\'effacera pas les dossiers. Dossiers masqués Gérer les dossiers masqués - Il semblerait que vous n\'ayez pas de dossier cachés avec un fichier \".nomedia\". + Il semblerait que vous n\'ayez pas de dossier masqués avec un fichier \".nomedia\". - Dossiers inclus - Gérer les dossiers inclus + Dossiers ajoutés + Gérer les dossiers ajoutés Ajouter un dossier - Si vous avez des dossiers contenant des médias et qu\'ils ne sont pas reconnus par l\'application, vous pouvez les ajouter manuellement ici. + Si vous avez des dossiers contenant des médias qui ne sont pas affichés dans l\'application, vous pouvez les ajouter manuellement ici.\n\nCet ajout n\'exclura aucun autre dossier. Redimensionner Redimensionner la sélection et enregistrer Largeur Hauteur - Garder le ratio + Conserver le rapport d\'affichage Veuillez entrer une résolution valide Éditeur Sauvegarder - Tourner + Pivoter Chemin Chemin invalide Échec de l\'édition de l\'image - Éditer l\'image avec : + Modifier l\'image avec : Aucun éditeur d\'image trouvé - Emplacement du fichier inconnu. - Ne parvient pas à réécrire par dessus le fichier source + Emplacement du fichier inconnu + Impossible de remplacer le fichier source Pivoter à gauche Pivoter à droite Pivoter à 180º Retourner Retourner horizontalement Retourner verticalement - Éditer avec - Gratuit + Modifier avec + Libre - Simple fond d\'écran + Fond d\'écran simple Définir comme fond d\'écran - Échec de la définition en tant que fond d\'écran. + Échec de la définition en tant que fond d\'écran Définir comme fond d\'écran avec : - Paramètres de fond d\'écran… - Fond d\'écran défini avec succès - Ratio d\'aspect portrait - Ratio d\'aspect paysage - Page d\'accueil - Écran de verrouillage - Page d\'accueil et écran de verrouillage + Définition du fond d\'écran en cours… + Fond d\'écran défini + Rapport d\'affichage portrait + Rapport d\'affichage paysage + Écran d\'accueil + Écran de déverrouillage + Écran d\'accueil et écran de déverrouillage Diaporama Intervalle (secondes) : Inclure photos Inclure vidéos - Inclure GIF + Inclure GIFs Ordre aléatoire Utiliser un fondu - Revenir en arrière + Défilement inverse Diaporama en boucle Diaporama terminé Aucun média trouvé pour le diaporama - Changer le type de vue + Changer de mode d\'affichage Grille Liste Sous-dossiers de groupe direct Grouper par - Ne pas regrouper les fichiers + Ne pas grouper les fichiers Dossier - Dernière modification - Date de prise + Date de modification + Date de prise de vue Type de fichier Extension + Définir pour ce dossier uniquement Lecture automatique des vidéos Permuter la visibilité des noms de fichier - Lire en boucle les vidéos - GIF animés sur les miniatures - Luminosité maximale lors de l\'affichage de media - Rogner les miniatures en carrés - Pivoter les medias plein écran selon + Lecture en boucle des vidéos + GIFs animés sur les miniatures + Luminosité maximale + Recadrer les miniatures en carrés + Pivoter l\'affichage selon Paramètres système Rotation de l\'appareil - Ratio d\'aspect - Fond et barre de statut noir en plein écran + Rapport d\'affichage + Arrière-plan et barre d\'état noirs Défilement des miniatures horizontalement - Masquer automatiquement l\'interface utilisateur si média en plein écran + Masquer automatiquement l\'interface utilisateur Supprimer les dossiers vides après avoir supprimé leur contenu - Permettre le contrôle de la luminosité de la photo avec des gestes verticaux. - Permettre le contrôle du volume vidéo et de la luminosité avec des gestes verticaux - Afficher le nombre de fichiers dans les dossiers sur l\'écran principal - Remplacer Partager par Pivoter si menu en plein écran - Afficher les détails supplémentaires par dessus le média en plein écran - Gérer les détails supplémentaires - Autoriser le zoom avec un doigt sur un média en plein écran - Autoriser le changement instantané de média en cliquant sur les côtés de l\'écran - Permet de zoomer en profondeur - Masquer les détails supplémentaires lorsque la barre d\'état est masquée - Faire une vérification supplémentaire pour éviter de montrer des fichiers invalides - Afficher quelques boutons d\'action en bas de l\'écran - Afficher la corbeille à l\'écran Dossiers - Deep zoomable images - Show images in the highest possible quality - Show the Recycle Bin as the last item on the main screen + Contrôler la luminosité de la photo avec des gestes verticaux + Contrôler le volume et la luminosité de la vidéo avec des gestes verticaux + Afficher le nombre de fichiers dans les dossiers + Remplacer \"Partager\" par \"Pivoter\" en plein écran + Afficher en surimpression les informations supplémentaires du média en plein écran + Gérer les informations supplémentaires + Effectuer le zoom avec un doigt sur une image en plein écran + Changement instantané de média en appuyant sur les côtés de l\'écran + Utiliser le zoom maximal des images + Ne pas afficher les informations supplémentaires si la barre d\'état est masquée + Éviter l\'affichage de fichiers non conformes + Afficher les éléments masqués + Afficher les boutons d\'action + Afficher la corbeille en vue \"Dossier\" + Niveau de zoom maximal des images + Afficher les images avec la meilleur qualité possible + Afficher la corbeille en dernière place sur l\'écran principal + Fermeture de la vue plein écran par un geste vers le bas - Vignettes - Média plein écran + Miniatures + Affichage en plein écran Détails supplémentaires - Actions en bas + Menu d\'actions sur la bas de l\'écran - Gérer les actions visible du bas - Basculer favori + Gérer le menu d\'actions + Ajouter aux favoris Changer la visibilité des fichiers - Comment faire de Simple Galerie ma galerie par défaut ? - Il faut dans un premier temps trouver la galerie par défaut dans la section « Applications » des paramètres du téléphone, puis toucher « Ouvrir par défaut » et enfin selectionner « Réinitialiser les paramètres par défaut ». La prochaine fois que vous ouvrirez une image ou une vidéo, il vous sera proposé de choisir une application, choisissez Simple Gallery puis « Toujours ». - J\'ai verrouillé l\'appli avec un mot de passe et je ne m\'en rappelle plus. Que faire ? - Il y a deux façons de procéder. Soit vous reinstallez l\'appli, soit retrouver l\'appli dans les paramètres du téléphone et toucher « Effacer les données ». Cela va seulement remettre à zéro les paramètres de l\'appli et ne supprimera pas vos fichiers. - Comment faire pour qu\'un album soit toujours tout en haut ? - Vous avez juste à faire un appui long sur l\'album en question et choisir l\'icône « Epingler » dans le menu d\'actions. Vous pouvez en épingler plusieurs, les éléments épinglés seront alors triés dans l\'ordre par défaut. + Comment faire de Simple Gallery ma galerie par défaut ? + Il faut dans un premier temps, trouver l\'application \"galerie\" par défaut dans la section \"Applications\" des paramètres de l\'appareil, puis appuyer sur \"Ouvrir par défaut\", et enfin sélectionner \"Réinitialiser les paramètres par défaut\". La prochaine fois que vous ouvrirez une image ou une vidéo, il vous sera proposé de choisir une application, choisissez \"Simple Gallery\" puis \"Toujours\". + J\'ai verrouillé l\'application avec un mot de passe et je ne m\'en rappelle plus. Que faire ? + Il y a deux façons de procéder. Soit vous réinstallez l\'application, soit vous recherchez l\'application dans les paramètres de l\'appareil et appuyez sur \"Effacer les données\". Cela va seulement réinitialiser les paramètres de l\'application et ne supprimera pas vos fichiers. + Comment faire pour qu\'un album soit toujours affiché tout en haut ? + Vous devez simplement à effectuer un appui prolongé sur l\'album en question et choisir l\'icône \"Épingler\" dans le menu d\'actions. Vous pouvez en épingler plusieurs. Les éléments épinglés seront alors triés selon l\'ordre par défaut. Comment avancer rapidement dans les vidéos ? - Vous pouvez appuyer sur le temps actuel ou la durée totale de la vidéo sur la barre de progression, la vidéo reculera ou avancera selon votre choix. - Quelle est la différence entre cacher et exclure un répertoire ? - Exclure n\'affiche pas le dossier dans Simple Galerie uniquement, alors que Cacher le cache pour l\'intégralité du système, y compris les autres galeries. Dans le dernier cas, un fichier \".nomedia\" est créé dans le répertoire caché, et peut s\'enlever avec n\'importe quel explorateur de fichiers. - Pourquoi des répertoires avec des pochettes d\'albums musicaux ou des miniatures d\'images sont affichés ? - Cela peut arriver de voir des albums qui ne devraient pas être affichés. Vous pouvez les exclure facilement en faisaint un appui long sur eux puis en sélectionnant « Exclure », après quoi vous pouvez aussi sélectionner le répertoire parent, ce qui devrait éviter l\'apparition d\'albums similaires. + Vous pouvez appuyer sur la durée actuelle ou totale de la vidéo sur la barre de progression, la vidéo reculera ou avancera selon votre choix. + Quelle est la différence entre masquer et exclure un dossier ? + \"Exclure un dossier\" permet de ne pas l\'afficher uniquement dans Simple Gallery, alors que \"Masquer un dossier\" rend le dossier invisible sur l\'ensemble de l\'appareil, y compris les autres applications de galerie. Dans le dernier cas, un fichier \".nomedia\" est créé dans le dossier masqué, et peut être supprimé avec n\'importe quel explorateur de fichiers. + Pourquoi des dossiers avec des pochettes d\'albums musicaux ou des miniatures d\'images sont affichés ? + Il est possible que des albums qui ne devraient pas être affichés le soient. Vous pouvez les exclure facilement en les sélectionnant par un appui prolongé, puis en choisissant l\'option \"Exclure\", après quoi vous pouvez aussi sélectionner le dossier parent, ce qui devrait éviter l\'apparition d\'albums similaires. Un dossier avec des images n\'apparaît pas. Que faire ? - Cela peut arriver pour de multiples raisons, mais c\'est facile à résoudre. Allez dans « Paramètres » puis « Gérer les dossiers inclus », sélectionnez le plus et sélectionnez le dossier voulu. + Cela peut arriver pour de multiples raisons, mais c\'est facile à résoudre. Allez dans \"Paramètres\", puis \"Gérer les dossiers inclus\", appuyez sur \"+\" et sélectionnez le dossier voulu. Comment faire apparaître uniquement certains dossiers ? - Ajouter un répértoire dans les dossiers inclus n\'exclut rien automatiquement. Pour ce faire, il faut aller dans « Paramètres » puis « Gérer les dossiers exclus », exclure le répertoire racine \"/\", puis ajouter les répertoires souhaités dans « Paramètres » puis « Gérer les répertoires inclus ». Seuls les répertoires selectionnés seront visibles, du fait que les exclusions et inclusions sont récursives, et si un répertoire est à la fois exclus et inclus, il sera affiché. - Les images en plein écran contiennent des artéfacts, est-ce possible d\'améliorer la qualité ? - 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. - Puis-je recadrer des images avec cette application? - 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. - Puis-je en quelque sorte regrouper les vignettes des fichiers multimédias ? - Bien sûr, il vous suffit d\'utiliser l\'option de menu \"Grouper par\" lorsque vous êtes dans l\'affichage des vignettes. Vous pouvez regrouper les fichiers selon plusieurs critères, y compris la date de prise de vue. Si vous utilisez la fonction \"Afficher le contenu de tous les dossiers\", vous pouvez également les regrouper par dossiers. - Le tri par date prise ne semble pas fonctionner correctement, comment puis-je le corriger ? - Il est très probablement causé par les fichiers copiés quelque part. Vous pouvez le corriger en sélectionnant les vignettes du fichier et en sélectionnant \"Fix Date Taken value\". - I see some color banding on the images. How can I improve the quality? - The current solution for displaying images works fine in the vast majority of cases, but if you want even better image quality, you can enable the \"Show images in the highest possible quality\" at the app settings, in the \"Deep zoomable images\" section. - I have hidden a file/folder. How can I unhide it? - You can either press the \"Temporarily show hidden items\" menu item at the main screen, or toggle \"Show hidden items\" in the app settings to see the hidden item. If you want to unhide it, just long press it and select \"Unhide\". Folders are hidden by adding a hidden \".nomedia\" file into them, you can delete the file with any file manager too. + Ajouter un dossier dans les \"Dossiers inclus\" rend visible l\'ensemble du contenu du dossier. Pour exclure certains dossiers, il faut aller dans \"Paramètres\", puis \"Gérer les dossiers exclus\", exclure le dossier racine \"/\", puis ajouter les dossiers souhaités dans \"Paramètres\", puis \"Gérer les dossiers inclus\". Seuls les dossiers sélectionnés seront visibles, du fait que les exclusions et inclusions sont récursives, et si un dossier est à la fois exclus et inclus, il sera affiché. + Les images en plein écran contiennent des artefacts, est-ce possible d\'améliorer la qualité ? + Oui, il existe dans \"Paramètres\" une option \"Afficher les images avec la plus haute qualité possible\", mais les images seront alors floues si vous zoomez trop. + Puis-je recadrer des images avec cette application ? + 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. + Puis-je regrouper les miniatures des fichiers multimédias ? + Bien sûr, il vous suffit d\'utiliser l\'option de menu \"Grouper par\" lorsque vous êtes dans l\'affichage des miniatures. Vous pouvez regrouper les fichiers selon plusieurs critères, y compris la date de prise de vue. Si vous utilisez la fonction \"Afficher le contenu de tous les dossiers\", vous pouvez également les regrouper par dossier. + Le tri par date de prise de vue ne semble pas fonctionner correctement, comment puis-je le corriger ? + Il est très probablement causé par les fichiers copiés quelque part. Vous pouvez le corriger en sélectionnant les miniatures du fichier et en sélectionnant \"Corriger la valeur des dates de prise des photos\". + Je vois des bandes de couleurs sur les images. Comment puis-je améliorer la qualité ? + La solution actuelle d\'affichage des images fonctionne bien dans la grande majorité des cas, mais si vous voulez une qualité d\'image encore meilleure, vous pouvez activer l\'option \"Afficher les images avec la plus haute qualité possible\" dans la section \"Niveau de zoom maximal des images\" des paramètres de l\'application. + J\'ai masqué un fichier ou un dossier. Comment puis-je en rétablir l\'affichage ? + Vous pouvez soit appuyer sur l\'option \"Afficher les fichiers masqués\" du menu de l\'écran principal, ou appuyer sur le bouton \"Afficher les éléments masqués\" dans les paramètres de l\'application. Si vous voulez rétablir leur affichage, effectuez un appui prolongé dessus et appuyez sur le symbole \"Œil\" permettant l\'affichage. Les dossiers sont masqués en ajoutant un fichier \".nomedia\" à leur racine, vous pouvez également supprimer ce fichier avec n\’importe quel explorateur de fichiers. - Un album pour visionner photos et vidéos sans publicité. + Une galerie pour visionner photos et vidéos sans publicité. - Un simple outil pour visionner les photos et les vidéos. Elles peuvent être triées par dates, tailles, noms dans les deux sens (alphabétique comme désalphabétique), il est possible de zoomer sur les photos. Les fichiers sont affichés sur de multiples colonnes en fonction de la taille de l\'écran, vous pouvez changer le nombre de colonnes par pincement. Elles peuvent être renommées, partagées, supprimées, copiées et déplacées. Les images peuvent en plus être tournées, rognées ou être définies comme fond d\'écran directement depuis l\'application. + Un outil simple pour visionner les photos et les vidéos. Elles peuvent être triées par dates, dimensions, noms dans les deux ordres (alphabétique ou alphabétique inversé), il est possible de zoomer sur les photos. Les fichiers sont affichés sur de multiples colonnes en fonction de la dimension de l\'écran, vous pouvez changer le nombre de colonnes par pincement. Elles peuvent être renommées, partagées, supprimées, copiées et déplacées. Les images peuvent en plus être pivotées, rognées ou être définies comme fond d\'écran directement depuis l\'application. - La galerie est également proposée pour une utilisation comme tierce partie pour la prévisualisation des images/vidéos, ajouter des pièces jointes aux clients email, etc… C\'est parfait pour un usage au quotidien. + La galerie est également proposée pour une utilisation comme tierce partie pour la prévisualisation des images/vidéos, ajouter des pièces jointes aux clients de courriel, etc… C\'est parfait pour un usage au quotidien. - L\'autorisation d\'empreinte digitale est nécessaire pour verrouiller les dossiers cachés et/ou l\'application. + L\'autorisation d\'empreinte digitale est nécessaire pour verrouiller les dossiers masqués et/ou l\'application. - L\'application ne contient ni publicité ni autorisation inutile. Elle est totalement opensource et est également fournie avec des couleurs personnalisables. + L\'application ne contient ni publicité, ni autorisation inutile. Elle est totalement opensource et est également fournie avec des couleurs personnalisables. Cette application fait partie d\'une plus grande suite. Vous pouvez trouver les autres applications sur https://www.simplemobiletools.com diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 362c84db6..ef72b9d18 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -162,6 +162,7 @@ Deep zoomable images Show images in the highest possible quality Show the Recycle Bin as the last item on the main screen + Allow closing the fullscreen view with a down gesture Iconas diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 69780e427..c6d7d6baa 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -162,6 +162,7 @@ Deep zoomable images Show images in the highest possible quality Show the Recycle Bin as the last item on the main screen + Allow closing the fullscreen view with a down gesture Sličice diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 7d4198bbc..fd22bfba8 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -162,6 +162,7 @@ Deep zoomable images Show images in the highest possible quality Show the Recycle Bin as the last item on the main screen + Allow closing the fullscreen view with a down gesture Thumbnails diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 21cee6961..5483a5f27 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -162,6 +162,7 @@ Immagini ingrandibili a fondo Mostra le immagini alla massima qualità possibile Mostra il cestino come ultimo elemento nella schermata principale + Allow closing the fullscreen view with a down gesture Miniature diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index ceba51c02..8ee43c035 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -132,36 +132,37 @@ 拡張子 - ビデオを自動再生する + ビデオを自動再生 ファイル名の表示を切り替え - ビデオを繰り返し再生する - アニメーションGIFのサムネイルを動かす - メディア再生時に明るさを最大にする + ビデオを繰り返し再生 + アニメーションGIFを動かす + 再生時には明るさを最大にする サムネイルを正方形に切り取る - メディア再生時のフルスクリーン表示切り替え + フルスクリーン再生の表示切り替え システム設定に従う 端末の向きに従う メディアの縦横比に従う - 表示の背景色とステータスバーの背景色を黒にする + メディア表示の背景色を黒にする サムネイル画面を横方向にスクロール - フルスクリーン時にシステムUIを非表示にする - フォルダが空になったらフォルダも削除する - 垂直のジェスチャーで写真の明るさを制御する - 音量と明るさを縦のジェスチャーで変更する - フォルダ内のメディアの数を表示する + 全画面ではシステムUIを非表示 + 空になったフォルダは削除する + 垂直の動作で写真の明るさを制御 + 音量と明るさを縦の動作で変更 + フォルダ内のメディア数を表示する フルスクリーン時の「共有」を「回転」に置き換える フルスクリーンに詳細を重ねて表示する 詳細表示を管理する - メディアを指ひとつでズーム可能にする - 画面の端を押してメディアをスライドする - Allow deep zooming images + メディアを指だけでズームする + 端を押してメディアをスライド + 深いズームを許可 ステータスバーが非表示の時は詳細を隠す - 無効なファイルを見せない調整を行う - 画面下部にアクションボタンを表示する - フォルダ画面にごみ箱を表示する - Deep zoomable images - Show images in the highest possible quality - Show the Recycle Bin as the last item on the main screen + 無効なファイルは見せない + 画面の下にはアクションを表示 + フォルダ画面にごみ箱を表示 + 画像のズームを深くする + 可能な限り高品質で画像を表示 + ごみ箱をメイン画面の最後に表示 + Allow closing the fullscreen view with a down gesture サムネイル設定 diff --git a/app/src/main/res/values-ko-rKR/strings.xml b/app/src/main/res/values-ko-rKR/strings.xml index 3010341ef..ff6a97400 100644 --- a/app/src/main/res/values-ko-rKR/strings.xml +++ b/app/src/main/res/values-ko-rKR/strings.xml @@ -162,6 +162,7 @@ Deep zoomable images Show images in the highest possible quality Show the Recycle Bin as the last item on the main screen + Allow closing the fullscreen view with a down gesture 섬네일 diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index eb33a9d4b..138b4f17d 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -162,6 +162,7 @@ Deep zoomable images Show images in the highest possible quality Show the Recycle Bin as the last item on the main screen + Allow closing the fullscreen view with a down gesture Miniatiūros diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index 540ccff27..dbaa4a07f 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -162,6 +162,7 @@ Deep zoomable images Show images in the highest possible quality Show the Recycle Bin as the last item on the main screen + Allow closing the fullscreen view with a down gesture Minibilder diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 63b22808e..46790ef4a 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -162,6 +162,7 @@ Afbeeldingen ver inzoomen Afbeeldingen in de hoogst mogelijke kwaliteit weergeven Prullenbak als laatste item tonen + Allow closing the fullscreen view with a down gesture Miniatuurvoorbeelden diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index eeaf4a66f..3cbb219cb 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -38,7 +38,7 @@ Filmy GIFy Obrazy RAW - SVGs + Obrazy SVG Nie znalazłem multimediów z wybranymi filtrami. Zmień filtry @@ -159,9 +159,10 @@    Dodatkowe sprawdzenie w celu uniknięcia pokazywania niewłaściwych plików Pokazuj niektóre przyciski akcji na dole ekranu Pokazuj kosz w widoku folderów - Deep zoomable images - Show images in the highest possible quality - Show the Recycle Bin as the last item on the main screen + Duże powiększanie obrazów + Pokazuj obrazy w najwyższej możliwej rozdzielczości + Pokazuj kosz jako ostatni element na głównym ekranie + Zezwalaj na zamykanie pełnoekranowego widoku gestem pociągnięcia w dół    Miniatury @@ -199,10 +200,10 @@ 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. Sortowanie według daty utworzenia nie działa poprawnie. Dlaczego tak się dzieje i jak mogę to naprawić? Dzieje się tak, gdyż prawdopodobnie pliki zostały skądś do urządzenia skopiowane. Naprawić to można wybierając miniatury plików, a następnie opcję \'Napraw datę utworzenia\'. - I see some color banding on the images. How can I improve the quality? - The current solution for displaying images works fine in the vast majority of cases, but if you want even better image quality, you can enable the \"Show images in the highest possible quality\" at the app settings, in the \"Deep zoomable images\" section. - I have hidden a file/folder. How can I unhide it? - You can either press the \"Temporarily show hidden items\" menu item at the main screen, or toggle \"Show hidden items\" in the app settings to see the hidden item. If you want to unhide it, just long press it and select \"Unhide\". Folders are hidden by adding a hidden \".nomedia\" file into them, you can delete the file with any file manager too. + Na obrazach widzę wyraźne zmiany w kolorach. Jak mogę to naprawić? + Obecne rozwiązanie służące wyświetlaniu obrazów działa jak powinno w większości w przypadków. Jeśli jednak tak nie jest, pomocna może okazać się opcja \"Pokazuj obrazy w najwyższej możliwej jakości\" w sekcji \"Duże powiększanie obrazów\". + Mam ukryte pliki i / lub foldery. Jak mogę zobaczyć? + Możesz to zrobić albo wybierając opcję \"Tymczasowo pokaż ukryte multimedia\" w menu na ekranie głównym, lub \"Pokazuj ukryte elementy\" w ustawieniach. Foldery są ukrywane poprzez dodanie do nich pustego, ukrytego pliku \".nomedia\", usunąć go możesz dowolnym menedżerem plików. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 1e51da9ad..51aa5c2f7 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -162,6 +162,7 @@ Deep zoomable images Show images in the highest possible quality Show the Recycle Bin as the last item on the main screen + Allow closing the fullscreen view with a down gesture Miniaturas diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index fd59f697f..088dd1885 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -162,6 +162,7 @@ Deep zoomable images Mostrar fotos com a melhor qualidade possível Mostrar a reciclagem como o último item do ecrã principal + Allow closing the fullscreen view with a down gesture Miniaturas diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 2eb9e31ff..7b7cba427 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -162,6 +162,7 @@ Масштабируемые изображения Показывать изображения с максимально высоким качеством Показывать корзину как последний элемент на главном экране + Allow closing the fullscreen view with a down gesture Миниатюры diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 4c0a92e53..f4cbde3f0 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -146,7 +146,7 @@ Prehliadať miniatúry vodorovne Automaticky skrývať systémové lišty pri celoobrazovkových médiách Odstrániť prázdne priečinky po vymazaní ich obsahu - Allow controlling photo brightness with vertical gestures + Povoliť ovládanie jasu vertikálnymi ťahmi Povoliť ovládanie hlasitosti a jasu videí vertikálnymi ťahmi Zobraziť počet médií v priečinku na hlavnej obrazovke Nahradiť Zdieľanie s Otočením v celoobrazovkovom menu @@ -162,6 +162,7 @@ Hlboko priblížiteľné obrázky Zobrazovať obrázky v najlepšej možnej kvalite Zobraziť odpadkový kôš ako poslednú položku na hlavnej obrazovke + Povoliť zatváranie celoobrazovkového režimu potiahnutím prsta dole Náhľady diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index a5ee7bd35..0eeff1265 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -162,6 +162,7 @@ Deep zoomable images Show images in the highest possible quality Show the Recycle Bin as the last item on the main screen + Allow closing the fullscreen view with a down gesture Miniatyrer diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 783118413..765c5f261 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -162,6 +162,7 @@ Deep zoomable images Show images in the highest possible quality Show the Recycle Bin as the last item on the main screen + Allow closing the fullscreen view with a down gesture Thumbnails diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml new file mode 100644 index 000000000..5bf73200e --- /dev/null +++ b/app/src/main/res/values-uk/strings.xml @@ -0,0 +1,229 @@ + + + Simple Gallery + Галерея + Редагувати + Запустити камеру + (приховане) + (виключене) + Закріпити теку + Відкріпити теку + Закріпити зверху + Показати вміст усіх тек + Усі теки + Перемкнути у перегляд за теками + Інша тека + Показати на мапі + Невідоме місцерозташування + Збільшити кількість колонок + Зменшити кількість колонок + Змінити обкладинку + Вибрати фото + Використовувати за-замовчуванням + Об\'єм + Яскравість + Закріпити орієнтацію + Відкріпити орієнтацію + Змінити орієнтацію + Примусова портретна орієнтація + Примусова ландшафтна орієнтація + Орієнтація за-замовчуванням + Виправити дату зйомки + Виправлення… + Дати успішно виправлені + + + Фільтр мультимедійних файлів + Зображення + Відео + GIF-зображення + RAW-зображення + SVG-зображення + З вибраними фільтрами мультимедійні файли не знайдено. + Змінити фільтри + + + Ця функція приховує теку шляхом додавання в неї файлу \".nomedia\"; це також приховає і підтеки. Ви можете побачити приховані теки, обравши опцію \'Показати приховані елементи\' в \"Налаштуваннях\". Продовжити? + Виключити + Виключені теки + Керування виключеними теками + Ця дія виключить обрані теки з їх підтеками тільки з Simple Gallery. Керувати виключеними теками можна у \"Налаштуваннях\". + Виключити батьківську теку натомість? + Виключення тек приховає їх разом з їх підтеками тільки у Simple Gallery, але вони все ще будуть видимі у інших додатках.\n\nЯкщо ви хочете приховати їх і від інших додатків, використовуйте функцію \"Приховати\". + Видалити все + Видалити всі теки зі списку виключених? Це не видалить теки з пристрою. + Приховані теки + Керування прихованими теками + Схоже, у вас немає тек, прихованих за допомогою файлу \".nomedia\". + + + Включені теки + Керування включеними теками + Додати теку + Якщо у вас є теки з медіафайлами, але вони не були розпізнані додатком, ви можете додати їх тут вручну.\n\nДодавання елементів сюди не виключить будь-яку іншу теку. + + + Змінити розмір + Змінити розмір вибраного і зберегти + Ширина + Висота + Зберігати співвідношення сторін + Введіть допустиму роздільну здатність + + + Редактор + Зберегти + Обернути + Шлях + Неприпустимий шлях до зображення + Не вдалося редагувати зображення + Редагувати зображення за допомогою: + Не знайдено редакторів зображень + Невідоме розташування файлу + Не вдалося перезаписати вихідний файл + Обернути ліворуч + Обернути праворуч + Обернути на 180º + Віддзеркалити + Віддзеркалити горизонтально + Віддзеркалити вертикально + Редагувати за допомогою + Вільне співвідношення сторін + + + Simple Wallpaper + Встановити як шпалери + Не вдалося встановити шпалери + Встановити шпалери за допомогою: + Встановлення шпалер… + Шпалери успішно встановлено + Співвідношення сторін в портретній орієнтації + Співвідношення сторін в ландшафтній орієнтації + Домашній екран + Екран блокування + Домашній екран і екран блокування + + + Слайдшоу + Інтервал (секунди): + Включити фото + Включити відео + Включити GIF-зображення + Випадковий порядок + Використовувати анімацію затухання + Рухатися назад + Зациклити показ слайдів + Слайдшоу закінчено + Не знайдено медіафайлів для показу у слайдшоу + + + Змінити тип перегляду + Сітка + Список + Групувати безпосередні підтеки + + + Групувати за… + Не групувати файли + текою + останньою зміною + датою зйомки + типом файлу + розширенням + + + Відтворювати відео автоматично + Перемкнути відображення імені файлу + Зациклити відео + Анімувати ескізи GIF-файлів + Максимальна яскравість екрану при повноекранному перегляді медіафайлу + Обрізати ескізи у квадрат + При повноекранному перегляді обертати за… + системними налаштуваннями + поворотом пристрою + співвідношенням сторін + Чорне тло і рядок стану при повноекранному перегляді + Гортати ескізи горизонтально + Автоматично приховувати системний інтерфейс при повноекранному перегляді + Видаляти порожні теки після видалення їх вмісту + Дозволити керування яскравістю фотографій вертикальними жестами + Дозволити керування яскравістю та гучністю відео вертикальними жестами + Показувати кількість файлів у теці на головному екрані + Замінити \"Поділитися\" на \"Обернути\" в повноекранному меню + Показувати розширені подробиці при повноекранному перегляді + Керування розширеними подробицями + Дозволити масштабування одним пальцем при повноекранному перегляді + Дозволити миттєво змінювати медіафайл натисканням на сторони екрану + Дозволити глибоке масштабування зображень + Приховати розширені подробиці, коли рядок стану прихований + Робити додаткову перевірку для запобігання відображенню недійсних файлів + Показати деякі кнопки дій внизу екрану + Показувати \"Кошик\" на головному екрані + Глибокомасштабовані зображення + Показувати зображення в найвищій можливій якості + Показувати \"Кошик\" останнім елементом на головному екрані + Дозволити закриття повноекранного перегляду свайпом згори вниз + + + Ескізи + Повноекранний перегляд + Розширені подробиці + Кнопки дій внизу екрану + + + Керування видимими кнопками дій внизу екрану + Перемкнути улюблене + Перемкнути видимість файлу + + + Як зробити Simple Gallery галереєю за-замовчуванням? + Спочатку необхідно знайти поточну галерею за-замовчуванням в розділі \"Додатки\" налаштувань вашого пристрою. Знайдіть і натисніть на кнопку \"Використовувати за-замовчуванням\" абощо, потім оберіть \"Очистити замовчування\". + Наступного разу коли ви намагатиметеся відкрити зображення або відео, ви побачите вікно з вибором додатків для цього. Оберіть Simple Gallery та зробіть його додатком за-замовчуванням. + Я заблокував додаток за допомогою паролю і забув його. Що я можу зробити? + Ви можете вирішити цю проблему двома способами: перевстановити додаток або знайти його в розділі \"Додатки\" налаштувань вашого пристрою та обрати \"Очистити дані\". Це скине усі ваші налаштування додатка, але не видалить жодного медіафайлу. + Як зробити альбом завжди доступним у верхній частині? + Ви можете виконати довге натискання на бажаному альбомі і вибрати піктограму \"Закріпити\" у меню дій, що закріпить його вгорі. Ви також можете закріпити декілька тек; закріплені елементи будуть відсортовані за методом сортування за-замовчуванням. + Як я можу швидко прокручувати відео? + Ви можете натиснути на текст поточного таймінгу або на текст загальної тривалості відео на прогрес-барі, що перемістить відео або назад, або вперед. + В чому полягає різниця між приховуванням та виключенням теки? + \"Виключити\" запобігає відображенню теки тільки в додатку Simple Gallery, в той час як \"Приховати\" працює на системному рівні і приховує теку і в інших галереях також. Це здійснюється шляхом створення порожнього файлу \".nomedia\" в заданій теці, який може бути видалений пізніше будь-яким файловим менеджером. + Чому відображаються теки з музичними обкладинками або стікерами? + Може так трапитися, що з\'являться деякі незвичні альбоми. Їх можна легко виключити довгим натисканням і вибором \"Виключити\". В наступному діалозі у вас буде можливість обрати бітьківську теку. Швидше за все, це дозволить також запобігти появі інших пов\'язаних альбомів. + Тека з зображеннями не відображається, що мені робити? + У цього може бути кілька причин, проте вирішення доволі просте. Перейдіть в \"Налаштування\" -> \"Керування виключеними теками\", оберіть \"Плюс\" та перейдіть до потрібної теки. + Що робити, якщо я хочу, щоб лише кілька окремих тек були видимими? + Додавання теки до \"Включених тек\" автоматично не виключає нічого. Що ви можете зробити, то це перейти в \"Налаштування\" -> \"Керування виключеними теками\", виключити кореневу теку \"/\", потім додати бажані теки через \"Налаштування\" -> \"Керування включеними теками\". + Це зробить видимими лише обрані теки. Якщо тека є одночасно і виключеною, і включеною, вона відобразиться, оскільки і виключення, і включення є рекурсивним. + Повноекранні зображення мають дивні артефакти. Чи можна якось покращити якість? + Так, у \"Налаштуваннях\" є перемикач з текстом \"Замінити глибокомасштабовані зображення іншими кращої якості\", скористайтеся ним. Він покращить якість зображень, але вони будуть розмиватися, якщо ви занадто їх збільшуватимете. + Чи можу я обрізати зображення у цьому додатку? + Так, обрізати зображення можна у редакторі шляхом перетягування кутів зображення. Відкрити редактор можна або довгим натисканням на ескіз зображення і наступним вибором \"Редагувати\", або вибором \"Редагувати\" при повноекранному перегляді. + Чи можу я якимось чином згрупувати ескізи медіафайлів? + Звісно, просто скористайтеся пунктом меню \"Групувати за…\", знаходячись на екрані ескізів. Групувати файли можна за кількома критеріями, включаючи дату зйомки. Якщо ви використовуєте функцію \"Показати вміст усіх тек\", ви також можете групувати їх за теками. + Сортування за датою зйомки, здається, працює некоректно. Як я можу це виправити? + Найбільш вірогідна причина цього - копіювання фалів з іншого місця. Це можна виправити, обравши ескізи файлів і потім - \"Виправити дату зйомки\". + Я бачу деякі кольорові нашарування на зображенні. Як я можу покращити якість? + Поточне рішення для показу зображень відмінно працює в переважній більшості випадків, але якщо вам потрібна ще краща якість зображень, ви можете увімкнути опцію \"Показувати зображення в найвищій можливій якості\" в розділі \"Глибокомасштабовані зображення\" налаштувань додатку. + Я приховав файл / теку. Як я можу відмінити цю дію? + Щоб побачити приховані елементи, ви можете або натиснути пункт меню \"Тимчасово показати приховані елементи\" на головному екрані, або перемкнути опцію \"Показати приховані елементи\" в налаштуваннях додатку. Якщо ви більше не хочете приховувати елемент, довго натисніть на нього і оберіть \"Не приховувати\". Теки приховуються шляхом створення прихованого файлу \".nomedia\" в них, тож ви також можете видалити цей файл будь-яким файловим менеджером. + + + + Галерея для перегляду фото та відео без реклами. + + Простий інструмент для перегляду фотографій і відео. Елементи можна сортувати за датою, розміром, ім\'ям як за зростанням, так і за спаданням, фотографії можна масштабувати. Медіафайли показуються у кілька колонок залежно від розміру екрану, їх кількість може бути змінена жестом \"щипок екрану\". Медіафайли можна перейменовувати, копіювати, переміщувати, видаляти або ділитися ними. Зображення також можна обрізати, обертати, віддзеркалювати або встановлювати як шпалери безпосередньо з додатку. + + Галерея також пропонується для використання третіми сторонами для перегляду зображень / відео, додавання долучень до клієнтів електронної пошти тощо. Вона ідеально підходить для щоденного використання. + + Дозвіл на доступ до відбитків пальців потрібен для блокування відображення прихованих елементів або для блокування всього застосунку. + + Не містить реклами або непотрібних дозволів. Додаток повністю OpenSource, забезпечує налаштування кольорів. + + Цей додаток є частиною великої серії схожих додатків. Ви можете знайти решту з них на https://www.simplemobiletools.com + + + + diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml deleted file mode 100644 index 7f1ac50b0..000000000 --- a/app/src/main/res/values-v21/styles.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 9cd3d2a65..0e5981b3a 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -24,13 +24,13 @@ 亮度 锁定方向 解锁方向 - Change orientation - Force portrait - Force landscape - Use default orientation - Fix Date Taken value - Fixing… - Dates fixed successfully + 改变方向 + 强制竖屏 + 强制横屏 + 默认 + 修复拍摄日期 + 正在修复… + 日期修复成功 要显示的媒体文件 @@ -88,7 +88,7 @@ 水平翻转 垂直翻转 编辑方式 - Free + 自由 简约壁纸 @@ -154,25 +154,26 @@ 要显示的详细信息项目 单指缩放 通过单击屏幕边缘来切换媒体 - Allow deep zooming images + 允许深度放大图像 当状态栏隐藏时隐藏扩展详情 额外检查以避免显示无效的文件 - 在屏幕底部显示一些操作按钮 - Show the Recycle Bin at the folders screen - Deep zoomable images - Show images in the highest possible quality - Show the Recycle Bin as the last item on the main screen + 显示底栏 + 在文件夹界面显示回收站 + 深度放大图像 + 以最高质量显示图像 + 在主屏幕界面的最后一项显示回收站 + Allow closing the fullscreen view with a down gesture 缩略图 全屏显示媒体 扩展详情 - Bottom actions + 底栏选项 - Manage visible bottom actions - Toggle favorite - Toggle file visibility + 管理底栏选项 + 收藏 + 隐藏文件 如何把简约图库设置为设备的默认图库? @@ -197,12 +198,12 @@ 当然,通过长按图片缩略图并选择编辑,或在全屏视图中选择编辑来打开编辑器。你可以通过拖动图片边角来剪裁图像。 我能将媒体文件缩略图分组吗? 当然,只需在缩略图视图中使用\"分组依据\"菜单项即可。您可以依据多个条件对文件进行分组,包括拍摄日期。如果您使用了\"显示所有文件夹内容\"功能,则可以按文件夹对它们进行分组。 - Sorting by Date Taken doesn\'t seem to work properly, how can I fix it? - It is most likely caused by the files being copied from somewhere. You can fix it by selecting the file thumbnails and selecting \"Fix Date Taken value\". - I see some color banding on the images. How can I improve the quality? - The current solution for displaying images works fine in the vast majority of cases, but if you want even better image quality, you can enable the \"Show images in the highest possible quality\" at the app settings, in the \"Deep zoomable images\" section. - I have hidden a file/folder. How can I unhide it? - You can either press the \"Temporarily show hidden items\" menu item at the main screen, or toggle \"Show hidden items\" in the app settings to see the hidden item. If you want to unhide it, just long press it and select \"Unhide\". Folders are hidden by adding a hidden \".nomedia\" file into them, you can delete the file with any file manager too. + 按拍摄日期排序似乎有异常,我该如何解决? + 很可能是因为图片是从某处复制过来的。您可以长按文件缩略图并选择\"修复拍摄日期\"来修复它。 + 我看到图像上有一些色带。如何提高提高质量? + 目前显示图像的方案在绝大多数情况下都能正常工作,如果您想要更好的图像质量,您可以在设置中启用\"以最高质量显示图像\"。 + 我隐藏了某个文件/文件夹。如何取消隐藏? + 您可以点击主界面上的\"暂时显示隐藏的项目\"选项,或在设置中开启\"显示隐藏的项目\"。 如果你想取消隐藏它,长按它并选择\"取消隐藏\"即可。 我们是通过向文件夹中添加\".nomedia\"文件来隐藏文件夹的,使用文件管理器删除该文件也可以取消隐藏。 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 9d2a97151..c2b62bb11 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -162,6 +162,7 @@ 可深度縮放的圖片 以最高品質顯示圖片 回收桶顯示在主畫面最後一項 + Allow closing the fullscreen view with a down gesture 縮圖 diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index f7e4703aa..ec39823c1 100644 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -2,6 +2,7 @@ + Added a new option for showing the Recycle Bin as the last folder Added a new settings toggle \"Show images in the highest possible quality\"\n Allow faster video seeking by dragging a finger at the bottom seekbar diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c7c603683..24264a8ba 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -162,7 +162,7 @@ Deep zoomable images Show images in the highest possible quality Show the Recycle Bin as the last item on the main screen - + Allow closing the fullscreen view with a down gesture Thumbnails diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 9bb53721a..fdde24e05 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -4,6 +4,7 @@