Merge pull request #33 from SimpleMobileTools/master

upd
This commit is contained in:
solokot 2018-07-23 20:17:39 +03:00 committed by GitHub
commit fe8d666c86
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
123 changed files with 1392 additions and 406 deletions

View file

@ -1,6 +1,27 @@
Changelog Changelog
========== ==========
Version 4.3.5 *(2018-07-17)*
----------------------------
* Fixed some Recycle bin related issues
* A few more UX and stability improvements
Version 4.3.4 *(2018-07-15)*
----------------------------
* Fixed disappearing launcher icon after changing its color on some devices
* Fixed some video related errors
* Added "Set as" as an available action at the fullscreen bottom actions
* Do the appropriate actions at trying to delete the Recycle Bin or Favorites folders
* Fixed a glitch with some panorama images not recognized properly
* Avoid blank screen at toggling "Temporarily show hidden"
Version 4.3.3 *(2018-07-06)*
----------------------------
* Couple stability improvements and glitch fixes
Version 4.3.2 *(2018-07-04)* Version 4.3.2 *(2018-07-04)*
---------------------------- ----------------------------

View file

@ -11,8 +11,8 @@ android {
applicationId "com.simplemobiletools.gallery" applicationId "com.simplemobiletools.gallery"
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 27 targetSdkVersion 27
versionCode 184 versionCode 187
versionName "4.3.2" versionName "4.3.5"
multiDexEnabled true multiDexEnabled true
setProperty("archivesBaseName", "gallery") setProperty("archivesBaseName", "gallery")
} }
@ -47,7 +47,7 @@ ext {
} }
dependencies { dependencies {
implementation 'com.simplemobiletools:commons:4.3.27' implementation 'com.simplemobiletools:commons:4.5.3'
implementation 'com.theartofdev.edmodo:android-image-cropper:2.7.0' implementation 'com.theartofdev.edmodo:android-image-cropper:2.7.0'
implementation 'com.android.support:multidex:1.0.3' implementation 'com.android.support:multidex:1.0.3'
implementation 'it.sephiroth.android.exif:library:1.0.1' implementation 'it.sephiroth.android.exif:library:1.0.1'
@ -57,6 +57,7 @@ dependencies {
implementation 'com.google.android.exoplayer:exoplayer-core:2.8.2' implementation 'com.google.android.exoplayer:exoplayer-core:2.8.2'
implementation 'com.google.vr:sdk-panowidget:1.150.0' implementation 'com.google.vr:sdk-panowidget:1.150.0'
implementation 'org.apache.sanselan:sanselan:0.97-incubator' implementation 'org.apache.sanselan:sanselan:0.97-incubator'
implementation 'info.androidhive:imagefilters:1.0.7'
kapt "android.arch.persistence.room:compiler:1.1.1" kapt "android.arch.persistence.room:compiler:1.1.1"
implementation "android.arch.persistence.room:runtime:1.1.1" implementation "android.arch.persistence.room:runtime:1.1.1"

View file

@ -7,6 +7,9 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.SET_WALLPAPER"/> <uses-permission android:name="android.permission.SET_WALLPAPER"/>
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE"
tools:node="remove"/>
<uses-sdk <uses-sdk
tools:overrideLibrary="com.google.vr.widgets.common, com.google.vr.sdk.widgets.pano"/> tools:overrideLibrary="com.google.vr.widgets.common, com.google.vr.sdk.widgets.pano"/>
@ -18,17 +21,12 @@
android:label="@string/app_launcher_name" android:label="@string/app_launcher_name"
android:roundIcon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme"
tools:replace="android:label">
<activity <activity
android:name=".activities.SplashActivity" android:name=".activities.SplashActivity"
android:theme="@style/SplashTheme"> android:theme="@style/SplashTheme"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity <activity
android:name=".activities.MainActivity" android:name=".activities.MainActivity"
@ -222,19 +220,6 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- Do not append ".Orange" to the default alias "name", it would remove the old homescreen launcher of users at upgrade -->
<activity-alias
android:name=".activities.SplashActivity"
android:enabled="true"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias <activity-alias
android:name=".activities.SplashActivity.Red" android:name=".activities.SplashActivity.Red"
android:enabled="false" android:enabled="false"
@ -417,6 +402,18 @@
</intent-filter> </intent-filter>
</activity-alias> </activity-alias>
<activity-alias
android:name=".activities.SplashActivity.Orange"
android:enabled="true"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher"
android:targetActivity=".activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity-alias <activity-alias
android:name=".activities.SplashActivity.Deep_orange" android:name=".activities.SplashActivity.Deep_orange"
android:enabled="false" android:enabled="false"

View file

@ -4,40 +4,83 @@ import android.app.Activity
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat import android.graphics.Bitmap.CompressFormat
import android.graphics.Color
import android.graphics.Point import android.graphics.Point
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.provider.MediaStore import android.provider.MediaStore
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.widget.RelativeLayout
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.OTG_PATH import com.simplemobiletools.commons.helpers.OTG_PATH
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE
import com.simplemobiletools.commons.helpers.REAL_FILE_PATH import com.simplemobiletools.commons.helpers.REAL_FILE_PATH
import com.simplemobiletools.commons.models.FileDirItem import com.simplemobiletools.commons.models.FileDirItem
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.adapters.FiltersAdapter
import com.simplemobiletools.gallery.dialogs.ResizeDialog import com.simplemobiletools.gallery.dialogs.ResizeDialog
import com.simplemobiletools.gallery.dialogs.SaveAsDialog import com.simplemobiletools.gallery.dialogs.SaveAsDialog
import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.extensions.openEditor import com.simplemobiletools.gallery.extensions.openEditor
import com.simplemobiletools.gallery.helpers.FilterThumbnailsManager
import com.simplemobiletools.gallery.models.FilterItem
import com.theartofdev.edmodo.cropper.CropImageView import com.theartofdev.edmodo.cropper.CropImageView
import kotlinx.android.synthetic.main.view_crop_image.* import com.zomato.photofilters.FilterPack
import com.zomato.photofilters.imageprocessors.Filter
import kotlinx.android.synthetic.main.activity_edit.*
import kotlinx.android.synthetic.main.bottom_actions_aspect_ratio.*
import kotlinx.android.synthetic.main.bottom_editor_actions_filter.*
import kotlinx.android.synthetic.main.bottom_editor_crop_rotate_actions.*
import kotlinx.android.synthetic.main.bottom_editor_primary_actions.*
import java.io.* import java.io.*
class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener { class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener {
companion object {
init {
System.loadLibrary("NativeImageProcessor")
}
}
private val ASPECT_X = "aspectX" private val ASPECT_X = "aspectX"
private val ASPECT_Y = "aspectY" private val ASPECT_Y = "aspectY"
private val CROP = "crop" private val CROP = "crop"
private val ASPECT_RATIO_FREE = 0
private val ASPECT_RATIO_ONE_ONE = 1
private val ASPECT_RATIO_FOUR_THREE = 2
private val ASPECT_RATIO_SIXTEEN_NINE = 3
// constants for bottom primary action groups
private val PRIMARY_ACTION_NONE = 0
private val PRIMARY_ACTION_FILTER = 1
private val PRIMARY_ACTION_CROP_ROTATE = 2
private val CROP_ROTATE_NONE = 0
private val CROP_ROTATE_ASPECT_RATIO = 1
private lateinit var uri: Uri private lateinit var uri: Uri
private lateinit var saveUri: Uri private lateinit var saveUri: Uri
private var resizeWidth = 0 private var resizeWidth = 0
private var resizeHeight = 0 private var resizeHeight = 0
private var currPrimaryAction = PRIMARY_ACTION_NONE
private var currCropRotateAction = CROP_ROTATE_NONE
private var currAspectRatio = ASPECT_RATIO_FREE
private var isCropIntent = false private var isCropIntent = false
private var isEditingWithThirdParty = false private var isEditingWithThirdParty = false
private var initialBitmap: Bitmap? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.view_crop_image) setContentView(R.layout.activity_edit)
handlePermission(PERMISSION_WRITE_STORAGE) { handlePermission(PERMISSION_WRITE_STORAGE) {
if (it) { if (it) {
@ -82,14 +125,13 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
} }
isCropIntent = intent.extras?.get(CROP) == "true" isCropIntent = intent.extras?.get(CROP) == "true"
if (isCropIntent) {
crop_image_view.apply { bottom_editor_primary_actions.beGone()
setOnCropImageCompleteListener(this@EditActivity) (bottom_editor_crop_rotate_actions.layoutParams as RelativeLayout.LayoutParams).addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, 1)
setImageUriAsync(uri)
if (isCropIntent && shouldCropSquare())
setFixedAspectRatio(true)
} }
loadDefaultImageView()
setupBottomActions()
} }
override fun onResume() { override fun onResume() {
@ -106,23 +148,288 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_editor, menu) menuInflater.inflate(R.menu.menu_editor, menu)
menu.findItem(R.id.resize).isVisible = !isCropIntent
return true return true
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.save_as -> crop_image_view.getCroppedImageAsync() R.id.save_as -> saveImage()
R.id.rotate -> crop_image_view.rotateImage(90)
R.id.resize -> resizeImage()
R.id.flip_horizontally -> flipImage(true)
R.id.flip_vertically -> flipImage(false)
R.id.edit -> editWith() R.id.edit -> editWith()
else -> return super.onOptionsItemSelected(item) else -> return super.onOptionsItemSelected(item)
} }
return true return true
} }
private fun loadDefaultImageView() {
default_image_view.beVisible()
crop_image_view.beGone()
val options = RequestOptions()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
Glide.with(this)
.asBitmap()
.load(uri)
.apply(options)
.listener(object : RequestListener<Bitmap> {
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Bitmap>?, isFirstResource: Boolean) = false
override fun onResourceReady(bitmap: Bitmap?, model: Any?, target: Target<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
val currentFilter = getFiltersAdapter()?.getCurrentFilter()
if (initialBitmap != null && currentFilter != null && currentFilter.filter.name != getString(R.string.none)) {
default_image_view.onGlobalLayout {
applyFilter(currentFilter)
}
} else {
initialBitmap = bitmap
}
if (isCropIntent) {
loadCropImageView()
bottom_primary_filter.beGone()
bottomCropRotateClicked()
}
return false
}
}).into(default_image_view)
}
private fun loadCropImageView() {
default_image_view.beGone()
crop_image_view.apply {
beVisible()
setOnCropImageCompleteListener(this@EditActivity)
setImageUriAsync(uri)
guidelines = CropImageView.Guidelines.ON
if (isCropIntent && shouldCropSquare()) {
currAspectRatio = ASPECT_RATIO_ONE_ONE
setFixedAspectRatio(true)
bottom_aspect_ratio.beGone()
}
}
}
private fun saveImage() {
if (crop_image_view.isVisible()) {
crop_image_view.getCroppedImageAsync()
} else {
val currentFilter = getFiltersAdapter()?.getCurrentFilter() ?: return
val filePathGetter = getNewFilePath()
SaveAsDialog(this, filePathGetter.first, filePathGetter.second) {
toast(R.string.saving)
// clean up everything to free as much memory as possible
default_image_view.setImageResource(0)
crop_image_view.setImageBitmap(null)
bottom_actions_filter_list.adapter = null
bottom_actions_filter_list.beGone()
Thread {
val originalBitmap = Glide.with(applicationContext).asBitmap().load(uri).submit(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL).get()
currentFilter.filter.processFilter(originalBitmap)
saveBitmapToFile(originalBitmap, it, false)
}.start()
}
}
}
private fun getFiltersAdapter() = bottom_actions_filter_list.adapter as? FiltersAdapter
private fun setupBottomActions() {
setupPrimaryActionButtons()
setupCropRotateActionButtons()
setupAspectRatioButtons()
}
private fun setupPrimaryActionButtons() {
bottom_primary_filter.setOnClickListener {
bottomFilterClicked()
}
bottom_primary_crop_rotate.setOnClickListener {
bottomCropRotateClicked()
}
}
private fun bottomFilterClicked() {
currPrimaryAction = if (currPrimaryAction == PRIMARY_ACTION_FILTER) {
PRIMARY_ACTION_NONE
} else {
PRIMARY_ACTION_FILTER
}
updatePrimaryActionButtons()
}
private fun bottomCropRotateClicked() {
currPrimaryAction = if (currPrimaryAction == PRIMARY_ACTION_CROP_ROTATE) {
PRIMARY_ACTION_NONE
} else {
PRIMARY_ACTION_CROP_ROTATE
}
updatePrimaryActionButtons()
}
private fun setupCropRotateActionButtons() {
bottom_rotate.setOnClickListener {
crop_image_view.rotateImage(90)
}
bottom_resize.beGoneIf(isCropIntent)
bottom_resize.setOnClickListener {
resizeImage()
}
bottom_flip_horizontally.setOnClickListener {
crop_image_view.flipImageHorizontally()
}
bottom_flip_vertically.setOnClickListener {
crop_image_view.flipImageVertically()
}
bottom_aspect_ratio.setOnClickListener {
currCropRotateAction = if (currCropRotateAction == CROP_ROTATE_ASPECT_RATIO) {
crop_image_view.guidelines = CropImageView.Guidelines.OFF
bottom_aspect_ratios.beGone()
CROP_ROTATE_NONE
} else {
crop_image_view.guidelines = CropImageView.Guidelines.ON
bottom_aspect_ratios.beVisible()
CROP_ROTATE_ASPECT_RATIO
}
updateCropRotateActionButtons()
}
}
private fun setupAspectRatioButtons() {
bottom_aspect_ratio_free.setOnClickListener {
updateAspectRatio(ASPECT_RATIO_FREE)
}
bottom_aspect_ratio_one_one.setOnClickListener {
updateAspectRatio(ASPECT_RATIO_ONE_ONE)
}
bottom_aspect_ratio_four_three.setOnClickListener {
updateAspectRatio(ASPECT_RATIO_FOUR_THREE)
}
bottom_aspect_ratio_sixteen_nine.setOnClickListener {
updateAspectRatio(ASPECT_RATIO_SIXTEEN_NINE)
}
updateAspectRatioButtons()
}
private fun updatePrimaryActionButtons() {
if (crop_image_view.isGone() && currPrimaryAction == PRIMARY_ACTION_CROP_ROTATE) {
loadCropImageView()
} else if (default_image_view.isGone() && currPrimaryAction == PRIMARY_ACTION_FILTER) {
loadDefaultImageView()
}
arrayOf(bottom_primary_filter, bottom_primary_crop_rotate).forEach {
it.applyColorFilter(Color.WHITE)
}
val currentPrimaryActionButton = when (currPrimaryAction) {
PRIMARY_ACTION_FILTER -> bottom_primary_filter
PRIMARY_ACTION_CROP_ROTATE -> bottom_primary_crop_rotate
else -> null
}
currentPrimaryActionButton?.applyColorFilter(config.primaryColor)
bottom_editor_filter_actions.beVisibleIf(currPrimaryAction == PRIMARY_ACTION_FILTER)
bottom_editor_crop_rotate_actions.beVisibleIf(currPrimaryAction == PRIMARY_ACTION_CROP_ROTATE)
if (currPrimaryAction == PRIMARY_ACTION_FILTER && bottom_actions_filter_list.adapter == null) {
Thread {
val size = resources.getDimension(R.dimen.bottom_filters_thumbnail_height).toInt()
val bitmap = Glide.with(this).asBitmap().load(uri).submit(size, size).get()
runOnUiThread {
val filterThumbnailsManager = FilterThumbnailsManager()
filterThumbnailsManager.clearThumbs()
val noFilter = Filter(getString(R.string.none))
filterThumbnailsManager.addThumb(FilterItem(bitmap, noFilter))
FilterPack.getFilterPack(this).forEach {
val filterItem = FilterItem(bitmap, it)
filterThumbnailsManager.addThumb(filterItem)
}
val filterItems = filterThumbnailsManager.processThumbs()
val adapter = FiltersAdapter(applicationContext, filterItems) {
applyFilter(it)
}
bottom_actions_filter_list.adapter = adapter
adapter.notifyDataSetChanged()
}
}.start()
}
if (currPrimaryAction != PRIMARY_ACTION_CROP_ROTATE) {
bottom_aspect_ratios.beGone()
currCropRotateAction = CROP_ROTATE_NONE
updateCropRotateActionButtons()
}
}
private fun applyFilter(filterItem: FilterItem) {
val newBitmap = Bitmap.createBitmap(initialBitmap)
default_image_view.setImageBitmap(filterItem.filter.processFilter(newBitmap))
}
private fun updateAspectRatio(aspectRatio: Int) {
currAspectRatio = aspectRatio
updateAspectRatioButtons()
crop_image_view.apply {
if (aspectRatio == ASPECT_RATIO_FREE) {
setFixedAspectRatio(false)
} else {
val newAspectRatio = when (aspectRatio) {
ASPECT_RATIO_ONE_ONE -> Pair(1, 1)
ASPECT_RATIO_FOUR_THREE -> Pair(4, 3)
else -> Pair(16, 9)
}
setAspectRatio(newAspectRatio.first, newAspectRatio.second)
}
}
}
private fun updateAspectRatioButtons() {
arrayOf(bottom_aspect_ratio_free, bottom_aspect_ratio_one_one, bottom_aspect_ratio_four_three, bottom_aspect_ratio_sixteen_nine).forEach {
it.setTextColor(Color.WHITE)
}
val currentAspectRatioButton = when (currAspectRatio) {
ASPECT_RATIO_FREE -> bottom_aspect_ratio_free
ASPECT_RATIO_ONE_ONE -> bottom_aspect_ratio_one_one
ASPECT_RATIO_FOUR_THREE -> bottom_aspect_ratio_four_three
else -> bottom_aspect_ratio_sixteen_nine
}
currentAspectRatioButton.setTextColor(config.primaryColor)
}
private fun updateCropRotateActionButtons() {
arrayOf(bottom_aspect_ratio).forEach {
it.applyColorFilter(Color.WHITE)
}
val primaryActionView = when (currCropRotateAction) {
CROP_ROTATE_ASPECT_RATIO -> bottom_aspect_ratio
else -> null
}
primaryActionView?.applyColorFilter(config.primaryColor)
}
private fun resizeImage() { private fun resizeImage() {
val point = getAreaSize() val point = getAreaSize()
if (point == null) { if (point == null) {
@ -160,7 +467,7 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
if (result.error == null) { if (result.error == null) {
if (isCropIntent) { if (isCropIntent) {
if (saveUri.scheme == "file") { if (saveUri.scheme == "file") {
saveBitmapToFile(result.bitmap, saveUri.path) saveBitmapToFile(result.bitmap, saveUri.path, true)
} else { } else {
var inputStream: InputStream? = null var inputStream: InputStream? = null
var outputStream: OutputStream? = null var outputStream: OutputStream? = null
@ -184,9 +491,22 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
} }
} else if (saveUri.scheme == "file") { } else if (saveUri.scheme == "file") {
SaveAsDialog(this, saveUri.path, true) { SaveAsDialog(this, saveUri.path, true) {
saveBitmapToFile(result.bitmap, it) saveBitmapToFile(result.bitmap, it, true)
} }
} else if (saveUri.scheme == "content") { } else if (saveUri.scheme == "content") {
val filePathGetter = getNewFilePath()
SaveAsDialog(this, filePathGetter.first, filePathGetter.second) {
saveBitmapToFile(result.bitmap, it, true)
}
} else {
toast(R.string.unknown_file_location)
}
} else {
toast("${getString(R.string.image_editing_failed)}: ${result.error.message}")
}
}
private fun getNewFilePath(): Pair<String, Boolean> {
var newPath = applicationContext.getRealPathFromURI(saveUri) ?: "" var newPath = applicationContext.getRealPathFromURI(saveUri) ?: ""
var shouldAppendFilename = true var shouldAppendFilename = true
if (newPath.isEmpty()) { if (newPath.isEmpty()) {
@ -203,25 +523,17 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
shouldAppendFilename = false shouldAppendFilename = false
} }
SaveAsDialog(this, newPath, shouldAppendFilename) { return Pair(newPath, shouldAppendFilename)
saveBitmapToFile(result.bitmap, it)
}
} else {
toast(R.string.unknown_file_location)
}
} else {
toast("${getString(R.string.image_editing_failed)}: ${result.error.message}")
}
} }
private fun saveBitmapToFile(bitmap: Bitmap, path: String) { private fun saveBitmapToFile(bitmap: Bitmap, path: String, showSavingToast: Boolean) {
try { try {
Thread { Thread {
val file = File(path) val file = File(path)
val fileDirItem = FileDirItem(path, path.getFilenameFromPath()) val fileDirItem = FileDirItem(path, path.getFilenameFromPath())
getFileOutputStream(fileDirItem, true) { getFileOutputStream(fileDirItem, true) {
if (it != null) { if (it != null) {
saveBitmap(file, bitmap, it) saveBitmap(file, bitmap, it, showSavingToast)
} else { } else {
toast(R.string.image_editing_failed) toast(R.string.image_editing_failed)
} }
@ -234,8 +546,11 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
} }
} }
private fun saveBitmap(file: File, bitmap: Bitmap, out: OutputStream) { private fun saveBitmap(file: File, bitmap: Bitmap, out: OutputStream, showSavingToast: Boolean) {
if (showSavingToast) {
toast(R.string.saving) toast(R.string.saving)
}
if (resizeWidth > 0 && resizeHeight > 0) { if (resizeWidth > 0 && resizeHeight > 0) {
val resized = Bitmap.createScaledBitmap(bitmap, resizeWidth, resizeHeight, false) val resized = Bitmap.createScaledBitmap(bitmap, resizeWidth, resizeHeight, false)
resized.compress(file.absolutePath.getCompressionFormat(), 90, out) resized.compress(file.absolutePath.getCompressionFormat(), 90, out)
@ -247,14 +562,6 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
out.close() out.close()
} }
private fun flipImage(horizontally: Boolean) {
if (horizontally) {
crop_image_view.flipImageHorizontally()
} else {
crop_image_view.flipImageVertically()
}
}
private fun editWith() { private fun editWith() {
openEditor(uri.toString()) openEditor(uri.toString())
isEditingWithThirdParty = true isEditingWithThirdParty = true

View file

@ -58,6 +58,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
private var mLoadedInitialPhotos = false private var mLoadedInitialPhotos = false
private var mIsPasswordProtectionPending = false private var mIsPasswordProtectionPending = false
private var mWasProtectionHandled = false private var mWasProtectionHandled = false
private var mShouldStopFetching = false
private var mLatestMediaId = 0L private var mLatestMediaId = 0L
private var mLatestMediaDateId = 0L private var mLatestMediaDateId = 0L
private var mLastMediaHandler = Handler() private var mLastMediaHandler = Handler()
@ -323,6 +324,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
return return
} }
mShouldStopFetching = true
mIsGettingDirs = true mIsGettingDirs = true
val getImagesOnly = mIsPickImageIntent || mIsGetImageContentIntent val getImagesOnly = mIsPickImageIntent || mIsGetImageContentIntent
val getVideosOnly = mIsPickVideoIntent || mIsGetVideoContentIntent val getVideosOnly = mIsPickVideoIntent || mIsGetVideoContentIntent
@ -347,7 +349,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
private fun showFilterMediaDialog() { private fun showFilterMediaDialog() {
FilterMediaDialog(this) { FilterMediaDialog(this) {
mLoadedInitialPhotos = false mShouldStopFetching = true
directories_refresh_layout.isRefreshing = true directories_refresh_layout.isRefreshing = true
directories_grid.adapter = null directories_grid.adapter = null
getDirectories() getDirectories()
@ -662,6 +664,8 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
private fun gotDirectories(newDirs: ArrayList<Directory>) { private fun gotDirectories(newDirs: ArrayList<Directory>) {
// if hidden item showing is disabled but all Favorite items are hidden, hide the Favorites folder // if hidden item showing is disabled but all Favorite items are hidden, hide the Favorites folder
mIsGettingDirs = false
mShouldStopFetching = false
if (!config.shouldShowHidden) { if (!config.shouldShowHidden) {
val favoritesFolder = newDirs.firstOrNull { it.areFavorites() } val favoritesFolder = newDirs.firstOrNull { it.areFavorites() }
if (favoritesFolder != null && favoritesFolder.tmb.getFilenameFromPath().startsWith('.')) { if (favoritesFolder != null && favoritesFolder.tmb.getFilenameFromPath().startsWith('.')) {
@ -696,6 +700,10 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
try { try {
for (directory in dirs) { for (directory in dirs) {
if (mShouldStopFetching) {
return
}
val curMedia = mediaFetcher.getFilesFrom(directory.path, getImagesOnly, getVideosOnly, getProperDateTaken, favoritePaths) val curMedia = mediaFetcher.getFilesFrom(directory.path, getImagesOnly, getVideosOnly, getProperDateTaken, favoritePaths)
val newDir = if (curMedia.isEmpty()) { val newDir = if (curMedia.isEmpty()) {
directory directory
@ -741,13 +749,22 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
val foldersToScan = mediaFetcher.getFoldersToScan() val foldersToScan = mediaFetcher.getFoldersToScan()
foldersToScan.add(FAVORITES) foldersToScan.add(FAVORITES)
if (config.showRecycleBinAtFolders) {
foldersToScan.add(RECYCLE_BIN) foldersToScan.add(RECYCLE_BIN)
} else {
foldersToScan.remove(RECYCLE_BIN)
}
dirs.forEach { dirs.forEach {
foldersToScan.remove(it.path) foldersToScan.remove(it.path)
} }
// check the remaining folders which were not cached at all yet // check the remaining folders which were not cached at all yet
for (folder in foldersToScan) { for (folder in foldersToScan) {
if (mShouldStopFetching) {
return
}
val newMedia = mediaFetcher.getFilesFrom(folder, getImagesOnly, getVideosOnly, getProperDateTaken, favoritePaths) val newMedia = mediaFetcher.getFilesFrom(folder, getImagesOnly, getVideosOnly, getProperDateTaken, favoritePaths)
if (newMedia.isEmpty()) { if (newMedia.isEmpty()) {
continue continue
@ -771,7 +788,6 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
} }
} }
mIsGettingDirs = false
mLoadedInitialPhotos = true mLoadedInitialPhotos = true
checkLastMediaChanged() checkLastMediaChanged()
@ -798,7 +814,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
} }
private fun showSortedDirs(dirs: ArrayList<Directory>) { private fun showSortedDirs(dirs: ArrayList<Directory>) {
var sortedDirs = getSortedDirectories(dirs).clone() as ArrayList<Directory> var sortedDirs = getSortedDirectories(dirs)
sortedDirs = sortedDirs.distinctBy { it.path.getDistinctPath() } as ArrayList<Directory> sortedDirs = sortedDirs.distinctBy { it.path.getDistinctPath() } as ArrayList<Directory>
runOnUiThread { runOnUiThread {
@ -836,11 +852,10 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
private fun setupAdapter(dirs: ArrayList<Directory>) { private fun setupAdapter(dirs: ArrayList<Directory>) {
val currAdapter = directories_grid.adapter val currAdapter = directories_grid.adapter
val directories = dirs.clone() as ArrayList<Directory>
if (currAdapter == null) { if (currAdapter == null) {
initZoomListener() initZoomListener()
val fastscroller = if (config.scrollHorizontally) directories_horizontal_fastscroller else directories_vertical_fastscroller val fastscroller = if (config.scrollHorizontally) directories_horizontal_fastscroller else directories_vertical_fastscroller
DirectoryAdapter(this, directories, this, directories_grid, isPickIntent(intent) || isGetAnyContentIntent(intent), fastscroller) { DirectoryAdapter(this, dirs.clone() as ArrayList<Directory>, this, directories_grid, isPickIntent(intent) || isGetAnyContentIntent(intent), fastscroller) {
val path = (it as Directory).path val path = (it as Directory).path
if (path != config.tempFolderPath) { if (path != config.tempFolderPath) {
itemClicked(path) itemClicked(path)
@ -850,7 +865,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
directories_grid.adapter = this directories_grid.adapter = this
} }
} else { } else {
(currAdapter as DirectoryAdapter).updateDirs(directories) (currAdapter as DirectoryAdapter).updateDirs(dirs)
} }
getRecyclerAdapter()?.dirs?.apply { getRecyclerAdapter()?.dirs?.apply {

View file

@ -261,7 +261,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
private fun setupSearch(menu: Menu) { private fun setupSearch(menu: Menu) {
val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
mSearchMenuItem = menu.findItem(R.id.search) mSearchMenuItem = menu.findItem(R.id.search)
(mSearchMenuItem!!.actionView as SearchView).apply { (mSearchMenuItem?.actionView as? SearchView)?.apply {
setSearchableInfo(searchManager.getSearchableInfo(componentName)) setSearchableInfo(searchManager.getSearchableInfo(componentName))
isSubmitButtonEnabled = false isSubmitButtonEnabled = false
setOnQueryTextListener(object : SearchView.OnQueryTextListener { setOnQueryTextListener(object : SearchView.OnQueryTextListener {
@ -317,7 +317,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
mPath.startsWith(OTG_PATH) -> mPath.trimEnd('/').substringAfterLast('/') mPath.startsWith(OTG_PATH) -> mPath.trimEnd('/').substringAfterLast('/')
else -> getHumanizedFilename(mPath) else -> getHumanizedFilename(mPath)
} }
supportActionBar?.title = if (mShowAll) resources.getString(R.string.all_folders) else dirName updateActionBarTitle(if (mShowAll) resources.getString(R.string.all_folders) else dirName)
getMedia() getMedia()
setupLayoutManager() setupLayoutManager()
} else { } else {
@ -338,7 +338,8 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
if (currAdapter == null) { if (currAdapter == null) {
initZoomListener() initZoomListener()
val fastscroller = if (config.scrollHorizontally) media_horizontal_fastscroller else media_vertical_fastscroller val fastscroller = if (config.scrollHorizontally) media_horizontal_fastscroller else media_vertical_fastscroller
MediaAdapter(this, mMedia, this, mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent, mAllowPickingMultiple, media_grid, fastscroller) { MediaAdapter(this, mMedia.clone() as ArrayList<ThumbnailItem>, this, mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent,
mAllowPickingMultiple, media_grid, fastscroller) {
if (it is Medium) { if (it is Medium) {
itemClicked(it.path) itemClicked(it.path)
} }
@ -806,7 +807,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
mLatestMediaId = getLatestMediaId() mLatestMediaId = getLatestMediaId()
mLatestMediaDateId = getLatestMediaByDateId() mLatestMediaDateId = getLatestMediaByDateId()
if (!isFromCache) { if (!isFromCache) {
val mediaToInsert = (mMedia.clone() as ArrayList<ThumbnailItem>).filter { it is Medium && it.deletedTS == 0L }.map { it as Medium } val mediaToInsert = (mMedia).filter { it is Medium && it.deletedTS == 0L }.map { it as Medium }
galleryDB.MediumDao().insertAll(mediaToInsert) galleryDB.MediumDao().insertAll(mediaToInsert)
} }
} }
@ -816,7 +817,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
val deletingItems = resources.getQuantityString(R.plurals.deleting_items, filtered.size, filtered.size) val deletingItems = resources.getQuantityString(R.plurals.deleting_items, filtered.size, filtered.size)
toast(deletingItems) toast(deletingItems)
if (config.useRecycleBin && !filtered.first().path.startsWith(filesDir.toString())) { if (config.useRecycleBin && !filtered.first().path.startsWith(filesDir.absolutePath)) {
movePathsInRecycleBin(filtered.map { it.path } as ArrayList<String>) { movePathsInRecycleBin(filtered.map { it.path } as ArrayList<String>) {
if (it) { if (it) {
deleteFilteredFiles(filtered) deleteFilteredFiles(filtered)

View file

@ -48,8 +48,6 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
finish() finish()
} }
} }
initBottomActions()
} }
override fun onResume() { override fun onResume() {
@ -88,14 +86,15 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
showSystemUI(true) showSystemUI(true)
val bundle = Bundle() val bundle = Bundle()
val file = File(mUri.toString()) val file = File(mUri.toString())
val filename = getFilenameFromUri(mUri!!)
val type = when { val type = when {
file.isImageFast() -> TYPE_IMAGES filename.isImageFast() -> TYPE_IMAGES
file.isVideoFast() -> TYPE_VIDEOS filename.isVideoFast() -> TYPE_VIDEOS
file.isGif() -> TYPE_GIFS filename.isGif() -> TYPE_GIFS
else -> TYPE_RAWS else -> TYPE_RAWS
} }
mMedium = Medium(null, getFilenameFromUri(mUri!!), mUri.toString(), mUri!!.path.getParentPath(), 0, 0, file.length(), type, false, 0L) mMedium = Medium(null, filename, mUri.toString(), mUri!!.path.getParentPath(), 0, 0, file.length(), type, false, 0L)
supportActionBar?.title = mMedium!!.name supportActionBar?.title = mMedium!!.name
bundle.putSerializable(MEDIUM, mMedium) bundle.putSerializable(MEDIUM, mMedium)
@ -114,6 +113,8 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
val isFullscreen = visibility and View.SYSTEM_UI_FLAG_FULLSCREEN != 0 val isFullscreen = visibility and View.SYSTEM_UI_FLAG_FULLSCREEN != 0
mFragment?.fullscreenToggled(isFullscreen) mFragment?.fullscreenToggled(isFullscreen)
} }
initBottomActions()
} }
override fun onConfigurationChanged(newConfig: Configuration?) { override fun onConfigurationChanged(newConfig: Configuration?) {
@ -132,12 +133,13 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.photo_video_menu, menu) menuInflater.inflate(R.menu.photo_video_menu, menu)
val visibleBottomActions = if (config.bottomActions) config.visibleBottomActions else 0
menu.apply { menu.apply {
findItem(R.id.menu_set_as).isVisible = mMedium?.isImage() == true findItem(R.id.menu_set_as).isVisible = mMedium?.isImage() == true && visibleBottomActions and BOTTOM_ACTION_SET_AS == 0
findItem(R.id.menu_edit).isVisible = mMedium?.isImage() == true && mUri?.scheme == "file" && !config.bottomActions findItem(R.id.menu_edit).isVisible = mMedium?.isImage() == true && mUri?.scheme == "file" && visibleBottomActions and BOTTOM_ACTION_EDIT == 0
findItem(R.id.menu_properties).isVisible = mUri?.scheme == "file" findItem(R.id.menu_properties).isVisible = mUri?.scheme == "file" && visibleBottomActions and BOTTOM_ACTION_PROPERTIES == 0
findItem(R.id.menu_share).isVisible = !config.bottomActions findItem(R.id.menu_share).isVisible = visibleBottomActions and BOTTOM_ACTION_SHARE == 0
} }
return true return true
@ -183,7 +185,7 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
} }
val visibleBottomActions = if (config.bottomActions) config.visibleBottomActions else 0 val visibleBottomActions = if (config.bottomActions) config.visibleBottomActions else 0
bottom_edit.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_EDIT != 0) bottom_edit.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_EDIT != 0 && mMedium?.isImage() == true)
bottom_edit.setOnClickListener { bottom_edit.setOnClickListener {
if (mUri != null && bottom_actions.alpha == 1f) { if (mUri != null && bottom_actions.alpha == 1f) {
openEditor(mUri!!.toString()) openEditor(mUri!!.toString())
@ -196,6 +198,11 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
sharePath(mUri!!.toString()) sharePath(mUri!!.toString())
} }
} }
bottom_set_as.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_SET_AS != 0 && mMedium?.isImage() == true)
bottom_set_as.setOnClickListener {
setAs(mUri!!.toString())
}
} }
override fun fragmentClicked() { override fun fragmentClicked() {

View file

@ -16,7 +16,7 @@ import com.simplemobiletools.commons.helpers.isNougatPlus
import com.simplemobiletools.commons.models.RadioItem import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.R
import com.theartofdev.edmodo.cropper.CropImageView import com.theartofdev.edmodo.cropper.CropImageView
import kotlinx.android.synthetic.main.view_crop_image.* import kotlinx.android.synthetic.main.activity_edit.*
class SetWallpaperActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener { class SetWallpaperActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener {
private val PICK_IMAGE = 1 private val PICK_IMAGE = 1
@ -28,7 +28,7 @@ class SetWallpaperActivity : SimpleActivity(), CropImageView.OnCropImageComplete
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.view_crop_image) setContentView(R.layout.activity_set_wallpaper)
if (intent.data == null) { if (intent.data == null) {
val pickIntent = Intent(applicationContext, MainActivity::class.java) val pickIntent = Intent(applicationContext, MainActivity::class.java)

View file

@ -38,6 +38,7 @@ class SettingsActivity : SimpleActivity() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
setupPurchaseThankYou()
setupCustomizeColors() setupCustomizeColors()
setupUseEnglish() setupUseEnglish()
setupAvoidWhatsNew() setupAvoidWhatsNew()
@ -74,6 +75,7 @@ class SettingsActivity : SimpleActivity() {
setupSkipDeleteConfirmation() setupSkipDeleteConfirmation()
setupManageBottomActions() setupManageBottomActions()
setupUseRecycleBin() setupUseRecycleBin()
setupShowRecycleBin()
setupEmptyRecycleBin() setupEmptyRecycleBin()
updateTextColors(settings_holder) updateTextColors(settings_holder)
setupSectionColors() setupSectionColors()
@ -87,6 +89,13 @@ class SettingsActivity : SimpleActivity() {
} }
} }
private fun setupPurchaseThankYou() {
settings_purchase_thank_you_holder.beVisibleIf(config.appRunCount > 10 && !isThankYouInstalled())
settings_purchase_thank_you_holder.setOnClickListener {
launchPurchaseThankYouIntent()
}
}
private fun setupCustomizeColors() { private fun setupCustomizeColors() {
settings_customize_colors_holder.setOnClickListener { settings_customize_colors_holder.setOnClickListener {
startCustomizationActivity() startCustomizationActivity()
@ -433,6 +442,7 @@ class SettingsActivity : SimpleActivity() {
private fun setupUseRecycleBin() { private fun setupUseRecycleBin() {
settings_empty_recycle_bin_holder.beVisibleIf(config.useRecycleBin) settings_empty_recycle_bin_holder.beVisibleIf(config.useRecycleBin)
settings_show_recycle_bin_holder.beVisibleIf(config.useRecycleBin)
settings_use_recycle_bin.isChecked = config.useRecycleBin settings_use_recycle_bin.isChecked = config.useRecycleBin
settings_use_recycle_bin_holder.setOnClickListener { settings_use_recycle_bin_holder.setOnClickListener {
settings_use_recycle_bin.toggle() settings_use_recycle_bin.toggle()
@ -441,6 +451,14 @@ class SettingsActivity : SimpleActivity() {
} }
} }
private fun setupShowRecycleBin() {
settings_show_recycle_bin.isChecked = config.showRecycleBinAtFolders
settings_show_recycle_bin_holder.setOnClickListener {
settings_show_recycle_bin.toggle()
config.showRecycleBinAtFolders = settings_show_recycle_bin.isChecked
}
}
private fun setupEmptyRecycleBin() { private fun setupEmptyRecycleBin() {
Thread { Thread {
mRecycleBinContentSize = galleryDB.MediumDao().getDeletedMedia().sumByLong { it.size } mRecycleBinContentSize = galleryDB.MediumDao().getDeletedMedia().sumByLong { it.size }

View file

@ -230,6 +230,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
} }
refreshViewPager() refreshViewPager()
view_pager.offscreenPageLimit = 2
if (config.blackBackground) { if (config.blackBackground) {
view_pager.background = ColorDrawable(Color.BLACK) view_pager.background = ColorDrawable(Color.BLACK)
@ -295,12 +296,13 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
findItem(R.id.menu_edit).isVisible = visibleBottomActions and BOTTOM_ACTION_EDIT == 0 findItem(R.id.menu_edit).isVisible = visibleBottomActions and BOTTOM_ACTION_EDIT == 0
findItem(R.id.menu_rename).isVisible = visibleBottomActions and BOTTOM_ACTION_RENAME == 0 findItem(R.id.menu_rename).isVisible = visibleBottomActions and BOTTOM_ACTION_RENAME == 0
findItem(R.id.menu_rotate).isVisible = currentMedium.isImage() && visibleBottomActions and BOTTOM_ACTION_ROTATE == 0 findItem(R.id.menu_rotate).isVisible = currentMedium.isImage() && visibleBottomActions and BOTTOM_ACTION_ROTATE == 0
findItem(R.id.menu_set_as).isVisible = visibleBottomActions and BOTTOM_ACTION_SET_AS == 0
findItem(R.id.menu_save_as).isVisible = mRotationDegrees != 0 findItem(R.id.menu_save_as).isVisible = mRotationDegrees != 0
findItem(R.id.menu_hide).isVisible = !currentMedium.isHidden() && visibleBottomActions and BOTTOM_ACTION_TOGGLE_VISIBILITY == 0 findItem(R.id.menu_hide).isVisible = !currentMedium.isHidden() && visibleBottomActions and BOTTOM_ACTION_TOGGLE_VISIBILITY == 0
findItem(R.id.menu_unhide).isVisible = currentMedium.isHidden() && visibleBottomActions and BOTTOM_ACTION_TOGGLE_VISIBILITY == 0 findItem(R.id.menu_unhide).isVisible = currentMedium.isHidden() && visibleBottomActions and BOTTOM_ACTION_TOGGLE_VISIBILITY == 0
findItem(R.id.menu_add_to_favorites).isVisible = !currentMedium.isFavorite && visibleBottomActions and BOTTOM_ACTION_TOGGLE_FAVORITE == 0 findItem(R.id.menu_add_to_favorites).isVisible = !currentMedium.isFavorite && visibleBottomActions and BOTTOM_ACTION_TOGGLE_FAVORITE == 0
findItem(R.id.menu_remove_from_favorites).isVisible = currentMedium.isFavorite && visibleBottomActions and BOTTOM_ACTION_TOGGLE_FAVORITE == 0 findItem(R.id.menu_remove_from_favorites).isVisible = currentMedium.isFavorite && visibleBottomActions and BOTTOM_ACTION_TOGGLE_FAVORITE == 0
findItem(R.id.menu_restore_file).isVisible = currentMedium.path.startsWith(filesDir.toString()) findItem(R.id.menu_restore_file).isVisible = currentMedium.path.startsWith(filesDir.absolutePath)
findItem(R.id.menu_change_orientation).isVisible = mRotationDegrees == 0 && visibleBottomActions and BOTTOM_ACTION_CHANGE_ORIENTATION == 0 findItem(R.id.menu_change_orientation).isVisible = mRotationDegrees == 0 && visibleBottomActions and BOTTOM_ACTION_CHANGE_ORIENTATION == 0
findItem(R.id.menu_change_orientation).icon = resources.getDrawable(getChangeOrientationIcon()) findItem(R.id.menu_change_orientation).icon = resources.getDrawable(getChangeOrientationIcon())
findItem(R.id.menu_rotate).setShowAsAction( findItem(R.id.menu_rotate).setShowAsAction(
@ -585,7 +587,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
} }
} }
val tmpPath = "$filesDir/.tmp_${newPath.getFilenameFromPath()}" val tmpPath = "${filesDir.absolutePath}/.tmp_${newPath.getFilenameFromPath()}"
val tmpFileDirItem = FileDirItem(tmpPath, tmpPath.getFilenameFromPath()) val tmpFileDirItem = FileDirItem(tmpPath, tmpPath.getFilenameFromPath())
try { try {
getFileOutputStream(tmpFileDirItem) { getFileOutputStream(tmpFileDirItem) {
@ -841,6 +843,11 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
bottom_rename.setOnClickListener { bottom_rename.setOnClickListener {
renameFile() renameFile()
} }
bottom_set_as.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_SET_AS != 0)
bottom_set_as.setOnClickListener {
setAs(getCurrentPath())
}
} }
private fun updateBottomActionIcons(medium: Medium?) { private fun updateBottomActionIcons(medium: Medium?) {
@ -915,7 +922,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun deleteConfirmed() { private fun deleteConfirmed() {
val path = getCurrentMedia().getOrNull(mPos)?.path ?: return val path = getCurrentMedia().getOrNull(mPos)?.path ?: return
if (getIsPathDirectory(path)) { if (getIsPathDirectory(path) || !path.isImageVideoGif()) {
return return
} }
@ -1104,10 +1111,6 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {} override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
override fun onPageSelected(position: Int) { override fun onPageSelected(position: Int) {
if (view_pager.offscreenPageLimit == 1) {
view_pager.offscreenPageLimit = 2
}
if (mPos != position) { if (mPos != position) {
mPos = position mPos = position
updateActionbarTitle() updateActionbarTitle()

View file

@ -72,6 +72,10 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
override fun getItemCount() = dirs.size override fun getItemCount() = dirs.size
override fun prepareActionMode(menu: Menu) { override fun prepareActionMode(menu: Menu) {
if (getSelectedPaths().isEmpty()) {
return
}
val selectedPaths = getSelectedPaths() val selectedPaths = getSelectedPaths()
menu.apply { menu.apply {
findItem(R.id.cab_rename).isVisible = isOneItemSelected() && !selectedPaths.contains(FAVORITES) && !selectedPaths.contains(RECYCLE_BIN) findItem(R.id.cab_rename).isVisible = isOneItemSelected() && !selectedPaths.contains(FAVORITES) && !selectedPaths.contains(RECYCLE_BIN)
@ -95,9 +99,9 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
R.id.cab_rename -> renameDir() R.id.cab_rename -> renameDir()
R.id.cab_pin -> pinFolders(true) R.id.cab_pin -> pinFolders(true)
R.id.cab_unpin -> pinFolders(false) R.id.cab_unpin -> pinFolders(false)
R.id.cab_hide -> toggleFoldersVisibility(true) R.id.cab_empty_recycle_bin -> tryEmptyRecycleBin(true)
R.id.cab_empty_recycle_bin -> emptyRecycleBin()
R.id.cab_empty_disable_recycle_bin -> emptyAndDisableRecycleBin() R.id.cab_empty_disable_recycle_bin -> emptyAndDisableRecycleBin()
R.id.cab_hide -> toggleFoldersVisibility(true)
R.id.cab_unhide -> toggleFoldersVisibility(false) R.id.cab_unhide -> toggleFoldersVisibility(false)
R.id.cab_exclude -> tryExcludeFolder() R.id.cab_exclude -> tryExcludeFolder()
R.id.cab_copy_to -> copyMoveTo(true) R.id.cab_copy_to -> copyMoveTo(true)
@ -214,13 +218,21 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
} }
} }
private fun emptyRecycleBin() { private fun tryEmptyRecycleBin(askConfirmation: Boolean) {
if (askConfirmation) {
activity.showRecycleBinEmptyingDialog { activity.showRecycleBinEmptyingDialog {
emptyRecycleBin()
}
} else {
emptyRecycleBin()
}
}
private fun emptyRecycleBin() {
activity.emptyTheRecycleBin { activity.emptyTheRecycleBin {
listener?.refreshItems() listener?.refreshItems()
} }
} }
}
private fun emptyAndDisableRecycleBin() { private fun emptyAndDisableRecycleBin() {
activity.showRecycleBinEmptyingDialog { activity.showRecycleBinEmptyingDialog {
@ -285,7 +297,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
} }
private fun tryExcludeFolder() { private fun tryExcludeFolder() {
val paths = getSelectedPaths().filter { it != PATH }.toSet() val paths = getSelectedPaths().filter { it != PATH && it != RECYCLE_BIN && it != FAVORITES }.toSet()
if (paths.size == 1) { if (paths.size == 1) {
ExcludeFolderDialog(activity, paths.toMutableList()) { ExcludeFolderDialog(activity, paths.toMutableList()) {
listener?.refreshItems() listener?.refreshItems()
@ -346,21 +358,27 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
private fun askConfirmDelete() { private fun askConfirmDelete() {
if (config.skipDeleteConfirmation) { if (config.skipDeleteConfirmation) {
deleteFiles() deleteFolders()
} else { } else {
val itemsCnt = selectedPositions.size val itemsCnt = selectedPositions.size
val items = resources.getQuantityString(R.plurals.delete_items, itemsCnt, itemsCnt) val items = resources.getQuantityString(R.plurals.delete_items, itemsCnt, itemsCnt)
val baseString = if (config.useRecycleBin) R.string.move_to_recycle_bin_confirmation else R.string.deletion_confirmation val fileDirItem = dirs.getOrNull(selectedPositions.first()) ?: return
val baseString = if (!config.useRecycleBin || (isOneItemSelected() && fileDirItem.isRecycleBin()) || (isOneItemSelected() && fileDirItem.areFavorites())) {
R.string.deletion_confirmation
} else {
R.string.move_to_recycle_bin_confirmation
}
var question = String.format(resources.getString(baseString), items) var question = String.format(resources.getString(baseString), items)
val warning = resources.getQuantityString(R.plurals.delete_warning, itemsCnt, itemsCnt) val warning = resources.getQuantityString(R.plurals.delete_warning, itemsCnt, itemsCnt)
question += "\n\n$warning" question += "\n\n$warning"
ConfirmationDialog(activity, question) { ConfirmationDialog(activity, question) {
deleteFiles() deleteFolders()
} }
} }
} }
private fun deleteFiles() { private fun deleteFolders() {
if (selectedPositions.isEmpty()) { if (selectedPositions.isEmpty()) {
return return
} }
@ -380,8 +398,18 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
activity.handleSAFDialog(SAFPath) { activity.handleSAFDialog(SAFPath) {
selectedPositions.sortedDescending().forEach { selectedPositions.sortedDescending().forEach {
val directory = dirs[it] val directory = dirs.getOrNull(it)
if (directory != null) {
if (directory.areFavorites() || directory.isRecycleBin()) { if (directory.areFavorites() || directory.isRecycleBin()) {
if (directory.isRecycleBin()) {
tryEmptyRecycleBin(false)
} else {
Thread {
activity.galleryDB.MediumDao().clearFavorites()
listener?.refreshItems()
}.start()
}
if (selectedPositions.size == 1) { if (selectedPositions.size == 1) {
finishActMode() finishActMode()
} else { } else {
@ -393,6 +421,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
removeFolders.add(directory) removeFolders.add(directory)
} }
} }
}
dirs.removeAll(removeFolders) dirs.removeAll(removeFolders)
listener?.deleteFolders(folders) listener?.deleteFolders(folders)
@ -436,14 +465,19 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
private fun getSelectedPaths(): HashSet<String> { private fun getSelectedPaths(): HashSet<String> {
val paths = HashSet<String>(selectedPositions.size) val paths = HashSet<String>(selectedPositions.size)
selectedPositions.forEach { paths.add(dirs[it].path) } selectedPositions.forEach {
(dirs.getOrNull(it))?.apply {
paths.add(path)
}
}
return paths return paths
} }
fun updateDirs(newDirs: ArrayList<Directory>) { fun updateDirs(newDirs: ArrayList<Directory>) {
if (newDirs.hashCode() != currentDirectoriesHash) { val directories = newDirs.clone() as ArrayList<Directory>
currentDirectoriesHash = newDirs.hashCode() if (directories.hashCode() != currentDirectoriesHash) {
dirs = newDirs currentDirectoriesHash = directories.hashCode()
dirs = directories
notifyDataSetChanged() notifyDataSetChanged()
finishActMode() finishActMode()
} }

View file

@ -0,0 +1,60 @@
package com.simplemobiletools.gallery.adapters
import android.content.Context
import android.graphics.drawable.Drawable
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
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<FilterItem>, val itemClick: (FilterItem) -> Unit) : RecyclerView.Adapter<FiltersAdapter.ViewHolder>(),
FilterAdapterListener {
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)
}
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)
}
override fun getItemCount() = filterItems.size
override fun getCurrentFilter() = currentSelection
override fun setCurrentFilter(filterItem: FilterItem) {
if (currentSelection != filterItem) {
currentSelection = filterItem
notifyDataSetChanged()
itemClick.invoke(filterItem)
}
}
class ViewHolder(view: View, val filterAdapterListener: FilterAdapterListener) : RecyclerView.ViewHolder(view) {
fun bindView(filterItem: FilterItem, strokeBackground: Drawable): View {
itemView.apply {
editor_filter_item_label.text = filterItem.filter.name
editor_filter_item_thumbnail.setImageBitmap(filterItem.bitmap)
editor_filter_item_thumbnail.background = if (filterAdapterListener.getCurrentFilter() == filterItem) {
strokeBackground
} else {
null
}
setOnClickListener {
filterAdapterListener.setCurrentFilter(filterItem)
}
}
return itemView
}
}
}

View file

@ -109,7 +109,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
findItem(R.id.cab_rename).isVisible = isOneItemSelected() findItem(R.id.cab_rename).isVisible = isOneItemSelected()
findItem(R.id.cab_open_with).isVisible = isOneItemSelected() findItem(R.id.cab_open_with).isVisible = isOneItemSelected()
findItem(R.id.cab_confirm_selection).isVisible = isAGetIntent && allowMultiplePicks && selectedPositions.size > 0 findItem(R.id.cab_confirm_selection).isVisible = isAGetIntent && allowMultiplePicks && selectedPositions.size > 0
findItem(R.id.cab_restore_recycle_bin_files).isVisible = getSelectedPaths().all { it.startsWith(activity.filesDir.toString()) } findItem(R.id.cab_restore_recycle_bin_files).isVisible = getSelectedPaths().all { it.startsWith(activity.filesDir.absolutePath) }
checkHideBtnVisibility(this) checkHideBtnVisibility(this)
checkFavoriteBtnVisibility(this) checkFavoriteBtnVisibility(this)
@ -289,7 +289,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
private fun askConfirmDelete() { private fun askConfirmDelete() {
val items = resources.getQuantityString(R.plurals.delete_items, selectedPositions.size, selectedPositions.size) val items = resources.getQuantityString(R.plurals.delete_items, selectedPositions.size, selectedPositions.size)
val isRecycleBin = getSelectedPaths().first().startsWith(activity.filesDir.toString()) val isRecycleBin = getSelectedPaths().first().startsWith(activity.filesDir.absolutePath)
val baseString = if (config.useRecycleBin && !isRecycleBin) R.string.move_to_recycle_bin_confirmation else R.string.deletion_confirmation val baseString = if (config.useRecycleBin && !isRecycleBin) R.string.move_to_recycle_bin_confirmation else R.string.deletion_confirmation
val question = String.format(resources.getString(baseString), items) val question = String.format(resources.getString(baseString), items)
DeleteWithRememberDialog(activity, question) { DeleteWithRememberDialog(activity, question) {
@ -316,7 +316,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
val SAFPath = (media[selectedPositions.first()] as Medium).path val SAFPath = (media[selectedPositions.first()] as Medium).path
activity.handleSAFDialog(SAFPath) { activity.handleSAFDialog(SAFPath) {
selectedPositions.sortedDescending().forEach { selectedPositions.sortedDescending().forEach {
val thumbnailItem = media[it] val thumbnailItem = media.getOrNull(it)
if (thumbnailItem is Medium) { if (thumbnailItem is Medium) {
fileDirItems.add(FileDirItem(thumbnailItem.path, thumbnailItem.name)) fileDirItems.add(FileDirItem(thumbnailItem.path, thumbnailItem.name))
removeMedia.add(thumbnailItem) removeMedia.add(thumbnailItem)
@ -342,10 +342,11 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
private fun getSelectedPaths() = getSelectedMedia().map { it.path } as ArrayList<String> private fun getSelectedPaths() = getSelectedMedia().map { it.path } as ArrayList<String>
fun updateMedia(newMedia: ArrayList<ThumbnailItem>) { fun updateMedia(newMedia: ArrayList<ThumbnailItem>) {
if (newMedia.hashCode() != currentMediaHash) { val thumbnailItems = newMedia.clone() as ArrayList<ThumbnailItem>
currentMediaHash = newMedia.hashCode() if (thumbnailItems.hashCode() != currentMediaHash) {
currentMediaHash = thumbnailItems.hashCode()
Handler().postDelayed({ Handler().postDelayed({
media = newMedia media = thumbnailItems
enableInstantLoad() enableInstantLoad()
notifyDataSetChanged() notifyDataSetChanged()
finishActMode() finishActMode()

View file

@ -5,7 +5,9 @@ import android.os.AsyncTask
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_TAKEN import com.simplemobiletools.commons.helpers.SORT_BY_DATE_TAKEN
import com.simplemobiletools.gallery.extensions.config import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.extensions.getFavoritePaths import com.simplemobiletools.gallery.extensions.getFavoritePaths
import com.simplemobiletools.gallery.helpers.FAVORITES
import com.simplemobiletools.gallery.helpers.MediaFetcher import com.simplemobiletools.gallery.helpers.MediaFetcher
import com.simplemobiletools.gallery.helpers.RECYCLE_BIN
import com.simplemobiletools.gallery.helpers.SHOW_ALL import com.simplemobiletools.gallery.helpers.SHOW_ALL
import com.simplemobiletools.gallery.models.Medium import com.simplemobiletools.gallery.models.Medium
import com.simplemobiletools.gallery.models.ThumbnailItem import com.simplemobiletools.gallery.models.ThumbnailItem
@ -21,7 +23,7 @@ class GetMediaAsynctask(val context: Context, val mPath: String, val isPickImage
val getProperDateTaken = context.config.getFileSorting(pathToUse) and SORT_BY_DATE_TAKEN != 0 val getProperDateTaken = context.config.getFileSorting(pathToUse) and SORT_BY_DATE_TAKEN != 0
val favoritePaths = context.getFavoritePaths() val favoritePaths = context.getFavoritePaths()
val media = if (showAll) { val media = if (showAll) {
val foldersToScan = mediaFetcher.getFoldersToScan() val foldersToScan = mediaFetcher.getFoldersToScan().filter { it != RECYCLE_BIN && it != FAVORITES }
val media = ArrayList<Medium>() val media = ArrayList<Medium>()
foldersToScan.forEach { foldersToScan.forEach {
val newMedia = mediaFetcher.getFilesFrom(it, isPickImage, isPickVideo, getProperDateTaken, favoritePaths) val newMedia = mediaFetcher.getFilesFrom(it, isPickImage, isPickVideo, getProperDateTaken, favoritePaths)

View file

@ -25,6 +25,7 @@ class ManageBottomActionsDialog(val activity: BaseSimpleActivity, val callback:
manage_bottom_actions_show_on_map.isChecked = actions and BOTTOM_ACTION_SHOW_ON_MAP != 0 manage_bottom_actions_show_on_map.isChecked = actions and BOTTOM_ACTION_SHOW_ON_MAP != 0
manage_bottom_actions_toggle_visibility.isChecked = actions and BOTTOM_ACTION_TOGGLE_VISIBILITY != 0 manage_bottom_actions_toggle_visibility.isChecked = actions and BOTTOM_ACTION_TOGGLE_VISIBILITY != 0
manage_bottom_actions_rename.isChecked = actions and BOTTOM_ACTION_RENAME != 0 manage_bottom_actions_rename.isChecked = actions and BOTTOM_ACTION_RENAME != 0
manage_bottom_actions_set_as.isChecked = actions and BOTTOM_ACTION_SET_AS != 0
} }
AlertDialog.Builder(activity) AlertDialog.Builder(activity)
@ -60,6 +61,8 @@ class ManageBottomActionsDialog(val activity: BaseSimpleActivity, val callback:
result += BOTTOM_ACTION_TOGGLE_VISIBILITY result += BOTTOM_ACTION_TOGGLE_VISIBILITY
if (manage_bottom_actions_rename.isChecked) if (manage_bottom_actions_rename.isChecked)
result += BOTTOM_ACTION_RENAME result += BOTTOM_ACTION_RENAME
if (manage_bottom_actions_set_as.isChecked)
result += BOTTOM_ACTION_SET_AS
} }
activity.config.visibleBottomActions = result activity.config.visibleBottomActions = result

View file

@ -61,7 +61,7 @@ class PickDirectoryDialog(val activity: BaseSimpleActivity, val sourcePath: Stri
return return
shownDirectories = dirs shownDirectories = dirs
val adapter = DirectoryAdapter(activity, dirs, null, view.directories_grid, true) { val adapter = DirectoryAdapter(activity, dirs.clone() as ArrayList<Directory>, null, view.directories_grid, true) {
if ((it as Directory).path.trimEnd('/') == sourcePath) { if ((it as Directory).path.trimEnd('/') == sourcePath) {
activity.toast(R.string.source_and_destination_same) activity.toast(R.string.source_and_destination_same)
return@DirectoryAdapter return@DirectoryAdapter

View file

@ -64,7 +64,7 @@ class PickMediumDialog(val activity: BaseSimpleActivity, val path: String, val c
return return
shownMedia = media shownMedia = media
val adapter = MediaAdapter(activity, shownMedia, null, true, false, view.media_grid, null) { val adapter = MediaAdapter(activity, shownMedia.clone() as ArrayList<ThumbnailItem>, null, true, false, view.media_grid, null) {
if (it is Medium) { if (it is Medium) {
callback(it.path) callback(it.path)
dialog.dismiss() dialog.dismiss()

View file

@ -151,6 +151,11 @@ fun BaseSimpleActivity.removeNoMedia(path: String, callback: (() -> Unit)? = nul
fun BaseSimpleActivity.toggleFileVisibility(oldPath: String, hide: Boolean, callback: ((newPath: String) -> Unit)? = null) { fun BaseSimpleActivity.toggleFileVisibility(oldPath: String, hide: Boolean, callback: ((newPath: String) -> Unit)? = null) {
val path = oldPath.getParentPath() val path = oldPath.getParentPath()
var filename = oldPath.getFilenameFromPath() var filename = oldPath.getFilenameFromPath()
if ((hide && filename.startsWith('.')) || (!hide && !filename.startsWith('.'))) {
callback?.invoke(oldPath)
return
}
filename = if (hide) { filename = if (hide) {
".${filename.trimStart('.')}" ".${filename.trimStart('.')}"
} else { } else {
@ -196,14 +201,16 @@ fun BaseSimpleActivity.tryDeleteFileDirItem(fileDirItem: FileDirItem, allowDelet
fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, callback: ((wasSuccess: Boolean) -> Unit)?) { fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, callback: ((wasSuccess: Boolean) -> Unit)?) {
Thread { Thread {
val mediumDao = galleryDB.MediumDao()
var pathsCnt = paths.size var pathsCnt = paths.size
paths.forEach { paths.forEach {
val file = File(it) val file = File(it)
val internalFile = File(filesDir, it) val internalFile = File(filesDir.absolutePath, it)
try { try {
file.copyRecursively(internalFile, true) if (file.copyRecursively(internalFile, true)) {
galleryDB.MediumDao().updateDeleted(it, System.currentTimeMillis()) mediumDao.updateDeleted(it, System.currentTimeMillis())
pathsCnt-- pathsCnt--
}
} catch (ignored: Exception) { } catch (ignored: Exception) {
} }
} }
@ -220,7 +227,7 @@ fun BaseSimpleActivity.restoreRecycleBinPaths(paths: ArrayList<String>, callback
val mediumDao = galleryDB.MediumDao() val mediumDao = galleryDB.MediumDao()
paths.forEach { paths.forEach {
val source = it val source = it
val destination = it.removePrefix(filesDir.toString()) val destination = it.removePrefix(filesDir.absolutePath)
var inputStream: InputStream? = null var inputStream: InputStream? = null
var out: OutputStream? = null var out: OutputStream? = null

View file

@ -288,6 +288,11 @@ fun Context.getCachedDirectories(getVideosOnly: Boolean = false, getImagesOnly:
} catch (e: SQLiteException) { } catch (e: SQLiteException) {
ArrayList<Directory>() ArrayList<Directory>()
} }
if (!config.showRecycleBinAtFolders) {
directories.removeAll { it.isRecycleBin() }
}
val shouldShowHidden = config.shouldShowHidden val shouldShowHidden = config.shouldShowHidden
val excludedPaths = config.excludedFolders val excludedPaths = config.excludedFolders
val includedPaths = config.includedFolders val includedPaths = config.includedFolders
@ -365,7 +370,7 @@ fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImag
val grouped = mediaFetcher.groupMedia(media, pathToUse) val grouped = mediaFetcher.groupMedia(media, pathToUse)
callback(grouped.clone() as ArrayList<ThumbnailItem>) callback(grouped.clone() as ArrayList<ThumbnailItem>)
val recycleBinPath = filesDir.toString() val recycleBinPath = filesDir.absolutePath
media.filter { !getDoesFilePathExist(it.path) }.forEach { media.filter { !getDoesFilePathExist(it.path) }.forEach {
if (it.path.startsWith(recycleBinPath)) { if (it.path.startsWith(recycleBinPath)) {
mediumDao.deleteMediumPath(it.path.removePrefix(recycleBinPath)) mediumDao.deleteMediumPath(it.path.removePrefix(recycleBinPath))
@ -402,7 +407,7 @@ fun Context.getFavoritePaths() = galleryDB.MediumDao().getFavoritePaths() as Arr
fun Context.getUpdatedDeletedMedia(mediumDao: MediumDao): ArrayList<Medium> { fun Context.getUpdatedDeletedMedia(mediumDao: MediumDao): ArrayList<Medium> {
val media = mediumDao.getDeletedMedia() as ArrayList<Medium> val media = mediumDao.getDeletedMedia() as ArrayList<Medium>
media.forEach { media.forEach {
it.path = File(filesDir, it.path).toString() it.path = File(filesDir.absolutePath, it.path).toString()
} }
return media return media
} }

View file

@ -47,7 +47,9 @@ import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
class PhotoFragment : ViewPagerFragment() { class PhotoFragment : ViewPagerFragment() {
private var DEFAULT_DOUBLE_TAP_ZOOM = 2f private val DEFAULT_DOUBLE_TAP_ZOOM = 2f
private val ZOOMABLE_VIEW_LOAD_DELAY = 1500L
private var isFragmentVisible = false private var isFragmentVisible = false
private var isFullscreen = false private var isFullscreen = false
private var wasInit = false private var wasInit = false
@ -55,6 +57,7 @@ class PhotoFragment : ViewPagerFragment() {
private var isPanorama = false private var isPanorama = false
private var imageOrientation = -1 private var imageOrientation = -1
private var gifDrawable: GifDrawable? = null private var gifDrawable: GifDrawable? = null
private var loadZoomableViewHandler = Handler()
private var storedShowExtendedDetails = false private var storedShowExtendedDetails = false
private var storedHideExtendedDetails = false private var storedHideExtendedDetails = false
@ -184,7 +187,9 @@ class PhotoFragment : ViewPagerFragment() {
private fun photoFragmentVisibilityChanged(isVisible: Boolean) { private fun photoFragmentVisibilityChanged(isVisible: Boolean) {
if (isVisible) { if (isVisible) {
addZoomableView() scheduleZoomableView()
} else {
loadZoomableViewHandler.removeCallbacksAndMessages(null)
} }
} }
@ -276,8 +281,9 @@ class PhotoFragment : ViewPagerFragment() {
} }
override fun onResourceReady(resource: Bitmap?, model: Any?, target: Target<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean { override fun onResourceReady(resource: Bitmap?, model: Any?, target: Target<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
if (isFragmentVisible) if (isFragmentVisible) {
addZoomableView() scheduleZoomableView()
}
return false return false
} }
}).into(view.photo_view) }).into(view.photo_view)
@ -302,8 +308,16 @@ class PhotoFragment : ViewPagerFragment() {
} }
} }
private fun scheduleZoomableView() {
loadZoomableViewHandler.removeCallbacksAndMessages(null)
loadZoomableViewHandler.postDelayed({
if (isFragmentVisible && !context!!.config.replaceZoomableImages && medium.isImage() && view.subsampling_view.isGone()) {
addZoomableView()
}
}, ZOOMABLE_VIEW_LOAD_DELAY)
}
private fun addZoomableView() { private fun addZoomableView() {
if (!context!!.config.replaceZoomableImages && medium.isImage() && isFragmentVisible && view.subsampling_view.isGone()) {
ViewPagerActivity.wasDecodedByGlide = false ViewPagerActivity.wasDecodedByGlide = false
view.subsampling_view.apply { view.subsampling_view.apply {
maxScale = 10f maxScale = 10f
@ -343,13 +357,12 @@ class PhotoFragment : ViewPagerFragment() {
}) })
} }
} }
}
private fun checkIfPanorama() { private fun checkIfPanorama() {
isPanorama = try { isPanorama = try {
val inputStream = if (medium.path.startsWith("content:/")) context!!.contentResolver.openInputStream(Uri.parse(medium.path)) else File(medium.path).inputStream() val inputStream = if (medium.path.startsWith("content:/")) context!!.contentResolver.openInputStream(Uri.parse(medium.path)) else File(medium.path).inputStream()
val imageParser = JpegImageParser().getXmpXml(ByteSourceInputStream(inputStream, medium.name), HashMap<String, Any>()) val imageParser = JpegImageParser().getXmpXml(ByteSourceInputStream(inputStream, medium.name), HashMap<String, Any>())
imageParser.contains("GPano:UsePanoramaViewer=\"True\"", true) imageParser.contains("GPano:UsePanoramaViewer=\"True\"", true) || imageParser.contains("<GPano:UsePanoramaViewer>True</GPano:UsePanoramaViewer>", true)
} catch (e: Exception) { } catch (e: Exception) {
false false
} }
@ -431,6 +444,7 @@ class PhotoFragment : ViewPagerFragment() {
Glide.with(context!!).clear(view.photo_view) Glide.with(context!!).clear(view.photo_view)
view.subsampling_view.recycle() view.subsampling_view.recycle()
} }
loadZoomableViewHandler.removeCallbacksAndMessages(null)
} }
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {

View file

@ -5,6 +5,7 @@ import android.content.res.Configuration
import android.graphics.Point import android.graphics.Point
import android.graphics.SurfaceTexture import android.graphics.SurfaceTexture
import android.media.AudioManager import android.media.AudioManager
import android.media.MediaMetadataRetriever
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
@ -14,6 +15,7 @@ import android.view.*
import android.view.animation.AnimationUtils import android.view.animation.AnimationUtils
import android.widget.SeekBar import android.widget.SeekBar
import android.widget.TextView import android.widget.TextView
import com.bumptech.glide.Glide
import com.google.android.exoplayer2.* import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
import com.google.android.exoplayer2.source.ExtractorMediaSource import com.google.android.exoplayer2.source.ExtractorMediaSource
@ -56,7 +58,8 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
private var mIsDragged = false private var mIsDragged = false
private var mIsFullscreen = false private var mIsFullscreen = false
private var mIsFragmentVisible = false private var mIsFragmentVisible = false
private var mWasInit = false private var mWasFragmentInit = false
private var mIsExoPlayerInitialized = false
private var mCurrTime = 0 private var mCurrTime = 0
private var mDuration = 0 private var mDuration = 0
@ -94,7 +97,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
} }
checkFullscreen() checkFullscreen()
mWasInit = true mWasFragmentInit = true
mView!!.apply { mView!!.apply {
brightnessSideScroll = video_brightness_controller brightnessSideScroll = video_brightness_controller
@ -109,76 +112,35 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
video_curr_time.setOnClickListener { skip(false) } video_curr_time.setOnClickListener { skip(false) }
video_duration.setOnClickListener { skip(true) } video_duration.setOnClickListener { skip(true) }
Glide.with(context!!).load(medium.path).into(video_preview)
} }
mExoPlayer = ExoPlayerFactory.newSimpleInstance(context, DefaultTrackSelector()) mExoPlayer = ExoPlayerFactory.newSimpleInstance(context, DefaultTrackSelector())
mExoPlayer!!.addListener(object : Player.EventListener { initExoPlayerListeners()
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {}
override fun onSeekProcessed() {}
override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) {}
override fun onPlayerError(error: ExoPlaybackException?) {
activity?.showErrorToast(error.toString())
}
override fun onLoadingChanged(isLoading: Boolean) {}
override fun onPositionDiscontinuity(reason: Int) {}
override fun onRepeatModeChanged(repeatMode: Int) {}
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {}
override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) {}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
when (playbackState) {
Player.STATE_READY -> videoPrepared()
Player.STATE_ENDED -> videoCompleted()
}
}
})
mExoPlayer!!.addVideoListener(object : VideoListener {
override fun onVideoSizeChanged(width: Int, height: Int, unappliedRotationDegrees: Int, pixelWidthHeightRatio: Float) {
mVideoSize.x = width
mVideoSize.y = height
setVideoSize()
}
override fun onRenderedFirstFrame() {}
})
val isContentUri = medium.path.startsWith("content://")
val uri = if (isContentUri) Uri.parse(medium.path) else Uri.fromFile(File(medium.path))
val dataSpec = DataSpec(uri)
val fileDataSource = if (isContentUri) ContentDataSource(context) else FileDataSource()
try {
fileDataSource.open(dataSpec)
} catch (e: Exception) {
activity?.showErrorToast(e)
}
val factory = DataSource.Factory { fileDataSource }
val audioSource = ExtractorMediaSource(fileDataSource.uri, factory, DefaultExtractorsFactory(), null, null)
mExoPlayer!!.audioStreamType = AudioManager.STREAM_MUSIC
mExoPlayer!!.prepare(audioSource)
medium.path.getVideoResolution()?.apply { medium.path.getVideoResolution()?.apply {
mVideoSize.x = x mVideoSize.x = x
mVideoSize.y = y mVideoSize.y = y
setVideoSize() setVideoSize()
} }
setupVideoDuration()
mView!!.video_surface.onGlobalLayout {
if (mIsFragmentVisible && context?.config?.autoplayVideos == true) {
playVideo()
}
}
return mView return mView
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
activity!!.updateTextColors(mView!!.video_holder) activity!!.updateTextColors(mView!!.video_holder)
val allowVideoGestures = context!!.config.allowVideoGestures val config = context!!.config
val allowInstantChange = context!!.config.allowInstantChange val allowVideoGestures = config.allowVideoGestures
val allowInstantChange = config.allowInstantChange
mView!!.apply { mView!!.apply {
video_volume_controller.beVisibleIf(allowVideoGestures) video_volume_controller.beVisibleIf(allowVideoGestures)
video_brightness_controller.beVisibleIf(allowVideoGestures) video_brightness_controller.beVisibleIf(allowVideoGestures)
@ -187,14 +149,15 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
instant_next_item.beVisibleIf(allowInstantChange) instant_next_item.beVisibleIf(allowInstantChange)
} }
if (context!!.config.showExtendedDetails != mStoredShowExtendedDetails || context!!.config.extendedDetails != mStoredExtendedDetails) { if (config.showExtendedDetails != mStoredShowExtendedDetails || config.extendedDetails != mStoredExtendedDetails) {
checkExtendedDetails() checkExtendedDetails()
} }
if (context!!.config.bottomActions != mStoredBottomActions) { if (config.bottomActions != mStoredBottomActions) {
initTimeHolder() initTimeHolder()
} }
mView!!.video_time_holder.setBackgroundResource(if (config.bottomActions) 0 else R.drawable.gradient_background)
storeStateVariables() storeStateVariables()
} }
@ -211,6 +174,25 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
} }
} }
override fun setMenuVisibility(menuVisible: Boolean) {
super.setMenuVisibility(menuVisible)
if (mIsFragmentVisible && !menuVisible) {
pauseVideo()
}
mIsFragmentVisible = menuVisible
if (mWasFragmentInit && menuVisible && context?.config?.autoplayVideos == true) {
playVideo()
}
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
setVideoSize()
initTimeHolder()
checkExtendedDetails()
}
private fun storeStateVariables() { private fun storeStateVariables() {
context!!.config.apply { context!!.config.apply {
mStoredShowExtendedDetails = showExtendedDetails mStoredShowExtendedDetails = showExtendedDetails
@ -235,25 +217,63 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
checkExtendedDetails() checkExtendedDetails()
} }
override fun setMenuVisibility(menuVisible: Boolean) { private fun initExoPlayer() {
super.setMenuVisibility(menuVisible) val isContentUri = medium.path.startsWith("content://")
if (mIsFragmentVisible && !menuVisible) { val uri = if (isContentUri) Uri.parse(medium.path) else Uri.fromFile(File(medium.path))
pauseVideo() val dataSpec = DataSpec(uri)
val fileDataSource = if (isContentUri) ContentDataSource(context) else FileDataSource()
try {
fileDataSource.open(dataSpec)
} catch (e: Exception) {
activity?.showErrorToast(e)
} }
mIsFragmentVisible = menuVisible val factory = DataSource.Factory { fileDataSource }
if (menuVisible && mWasInit) { val audioSource = ExtractorMediaSource(fileDataSource.uri, factory, DefaultExtractorsFactory(), null, null)
if (context?.config?.autoplayVideos == true) { mExoPlayer!!.audioStreamType = AudioManager.STREAM_MUSIC
playVideo() mExoPlayer!!.prepare(audioSource)
}
}
} }
override fun onConfigurationChanged(newConfig: Configuration) { private fun initExoPlayerListeners() {
super.onConfigurationChanged(newConfig) mExoPlayer!!.addListener(object : Player.EventListener {
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {}
override fun onSeekProcessed() {}
override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) {}
override fun onPlayerError(error: ExoPlaybackException?) {
mIsExoPlayerInitialized = false
}
override fun onLoadingChanged(isLoading: Boolean) {}
override fun onPositionDiscontinuity(reason: Int) {}
override fun onRepeatModeChanged(repeatMode: Int) {}
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {}
override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) {}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
mIsExoPlayerInitialized = playbackState == Player.STATE_READY || playbackState == Player.STATE_ENDED
when (playbackState) {
Player.STATE_READY -> videoPrepared()
Player.STATE_ENDED -> videoCompleted()
}
}
})
mExoPlayer!!.addVideoListener(object : VideoListener {
override fun onVideoSizeChanged(width: Int, height: Int, unappliedRotationDegrees: Int, pixelWidthHeightRatio: Float) {
mVideoSize.x = width
mVideoSize.y = height
setVideoSize() setVideoSize()
initTimeHolder() }
checkExtendedDetails()
override fun onRenderedFirstFrame() {}
})
} }
private fun toggleFullscreen() { private fun toggleFullscreen() {
@ -378,13 +398,18 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
return return
} }
if (mView!!.video_preview.isVisible()) {
mView!!.video_preview.beGone()
initExoPlayer()
}
if (videoEnded()) { if (videoEnded()) {
setProgress(0) setProgress(0)
} }
mIsPlaying = true mIsPlaying = true
mExoPlayer?.playWhenReady = true mExoPlayer?.playWhenReady = true
mView!!.video_play_outline.setImageDrawable(resources.getDrawable(R.drawable.img_pause_outline_big)) mView!!.video_play_outline.setImageResource(R.drawable.ic_pause)
activity!!.window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) activity!!.window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
mHidePauseHandler.postDelayed({ mHidePauseHandler.postDelayed({
mView!!.video_play_outline.animate().alpha(0f).start() mView!!.video_play_outline.animate().alpha(0f).start()
@ -401,13 +426,12 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
mExoPlayer?.playWhenReady = false mExoPlayer?.playWhenReady = false
} }
mView?.video_play_outline?.setImageDrawable(resources.getDrawable(R.drawable.img_play_outline_big)) mView?.video_play_outline?.setImageResource(R.drawable.ic_play)
mView!!.video_play_outline.alpha = PLAY_PAUSE_VISIBLE_ALPHA mView?.video_play_outline?.alpha = PLAY_PAUSE_VISIBLE_ALPHA
activity!!.window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} }
private fun videoEnded() = mExoPlayer!!.currentPosition >= mExoPlayer!!.duration private fun videoEnded() = mExoPlayer?.currentPosition ?: 0 >= mExoPlayer?.duration ?: 0
private fun setProgress(seconds: Int) { private fun setProgress(seconds: Int) {
mExoPlayer!!.seekTo(seconds * 1000L) mExoPlayer!!.seekTo(seconds * 1000L)
@ -415,6 +439,18 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
mCurrTimeView!!.text = seconds.getFormattedDuration() mCurrTimeView!!.text = seconds.getFormattedDuration()
} }
private fun setupVideoDuration() {
try {
val retriever = MediaMetadataRetriever()
retriever.setDataSource(medium.path)
mDuration = Math.round(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION).toInt() / 1000f)
} catch (ignored: Exception) {
}
setupTimeHolder()
setProgress(0)
}
private fun videoPrepared() { private fun videoPrepared() {
if (mDuration == 0) { if (mDuration == 0) {
mDuration = (mExoPlayer!!.duration / 1000).toInt() mDuration = (mExoPlayer!!.duration / 1000).toInt()
@ -454,15 +490,15 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
private fun releaseExoPlayer() { private fun releaseExoPlayer() {
mExoPlayer?.stop() mExoPlayer?.stop()
Thread {
mExoPlayer?.release() mExoPlayer?.release()
mExoPlayer = null mExoPlayer = null
}.start()
} }
override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture?, width: Int, height: Int) { override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture?, width: Int, height: Int) {}
}
override fun onSurfaceTextureUpdated(surface: SurfaceTexture?) { override fun onSurfaceTextureUpdated(surface: SurfaceTexture?) {}
}
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture?): Boolean { override fun onSurfaceTextureDestroyed(surface: SurfaceTexture?): Boolean {
releaseExoPlayer() releaseExoPlayer()
@ -559,6 +595,9 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
} }
override fun onStopTrackingTouch(seekBar: SeekBar) { override fun onStopTrackingTouch(seekBar: SeekBar) {
if (mExoPlayer == null)
return
if (!mIsPlaying) { if (!mIsPlaying) {
togglePlayPause() togglePlayPause()
} else { } else {

View file

@ -2,6 +2,7 @@ package com.simplemobiletools.gallery.helpers
import android.content.Context import android.content.Context
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Environment
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import com.simplemobiletools.commons.helpers.BaseConfig import com.simplemobiletools.commons.helpers.BaseConfig
@ -367,6 +368,16 @@ class Config(context: Context) : BaseConfig(context) {
// if a user hides a folder, then enables temporary hidden folder displaying, make sure we show it properly // if a user hides a folder, then enables temporary hidden folder displaying, make sure we show it properly
var everShownFolders: Set<String> var everShownFolders: Set<String>
get() = prefs.getStringSet(EVER_SHOWN_FOLDERS, HashSet<String>()) get() = prefs.getStringSet(EVER_SHOWN_FOLDERS, getEverShownFolders())
set(everShownFolders) = prefs.edit().putStringSet(EVER_SHOWN_FOLDERS, everShownFolders).apply() set(everShownFolders) = prefs.edit().putStringSet(EVER_SHOWN_FOLDERS, everShownFolders).apply()
fun getEverShownFolders() = hashSetOf(
internalStoragePath,
Environment.DIRECTORY_DCIM,
Environment.DIRECTORY_PICTURES
)
var showRecycleBinAtFolders: Boolean
get() = prefs.getBoolean(SHOW_RECYCLE_BIN_AT_FOLDERS, true)
set(showRecycleBinAtFolders) = prefs.edit().putBoolean(SHOW_RECYCLE_BIN_AT_FOLDERS, showRecycleBinAtFolders).apply()
} }

View file

@ -58,6 +58,7 @@ const val WAS_RECYCLE_BIN_PINNED = "was_recycle_bin_pinned"
const val USE_RECYCLE_BIN = "use_recycle_bin" const val USE_RECYCLE_BIN = "use_recycle_bin"
const val GROUP_BY = "group_by" const val GROUP_BY = "group_by"
const val EVER_SHOWN_FOLDERS = "ever_shown_folders" const val EVER_SHOWN_FOLDERS = "ever_shown_folders"
const val SHOW_RECYCLE_BIN_AT_FOLDERS = "show_recycle_bin_at_folders"
// slideshow // slideshow
const val SLIDESHOW_INTERVAL = "slideshow_interval" const val SLIDESHOW_INTERVAL = "slideshow_interval"
@ -144,5 +145,6 @@ const val BOTTOM_ACTION_SLIDESHOW = 128
const val BOTTOM_ACTION_SHOW_ON_MAP = 256 const val BOTTOM_ACTION_SHOW_ON_MAP = 256
const val BOTTOM_ACTION_TOGGLE_VISIBILITY = 512 const val BOTTOM_ACTION_TOGGLE_VISIBILITY = 512
const val BOTTOM_ACTION_RENAME = 1024 const val BOTTOM_ACTION_RENAME = 1024
const val BOTTOM_ACTION_SET_AS = 2048
const val DEFAULT_BOTTOM_ACTIONS = BOTTOM_ACTION_TOGGLE_FAVORITE or BOTTOM_ACTION_EDIT or BOTTOM_ACTION_SHARE or BOTTOM_ACTION_DELETE const val DEFAULT_BOTTOM_ACTIONS = BOTTOM_ACTION_TOGGLE_FAVORITE or BOTTOM_ACTION_EDIT or BOTTOM_ACTION_SHARE or BOTTOM_ACTION_DELETE

View file

@ -0,0 +1,27 @@
package com.simplemobiletools.gallery.helpers
import android.graphics.Bitmap
import com.simplemobiletools.gallery.models.FilterItem
import java.util.*
class FilterThumbnailsManager {
private var filterThumbnails = ArrayList<FilterItem>(10)
private var processedThumbnails = ArrayList<FilterItem>(10)
fun addThumb(filterItem: FilterItem) {
filterThumbnails.add(filterItem)
}
fun processThumbs(): ArrayList<FilterItem> {
for (filterItem in filterThumbnails) {
filterItem.bitmap = filterItem.filter.processFilter(Bitmap.createBitmap(filterItem.bitmap))
processedThumbnails.add(filterItem)
}
return processedThumbnails
}
fun clearThumbs() {
filterThumbnails = ArrayList()
processedThumbnails = ArrayList()
}
}

View file

@ -0,0 +1,9 @@
package com.simplemobiletools.gallery.interfaces
import com.simplemobiletools.gallery.models.FilterItem
interface FilterAdapterListener {
fun getCurrentFilter(): FilterItem
fun setCurrentFilter(filterItem: FilterItem)
}

View file

@ -40,4 +40,7 @@ interface MediumDao {
@Query("DELETE FROM media WHERE deleted_ts != 0") @Query("DELETE FROM media WHERE deleted_ts != 0")
fun clearRecycleBin() fun clearRecycleBin()
@Query("UPDATE media SET is_favorite = 0")
fun clearFavorites()
} }

View file

@ -0,0 +1,6 @@
package com.simplemobiletools.gallery.models
import android.graphics.Bitmap
import com.zomato.photofilters.imageprocessors.Filter
data class FilterItem(var bitmap: Bitmap, val filter: Filter)

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

View file

Before

Width:  |  Height:  |  Size: 203 B

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 877 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 682 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

View file

Before

Width:  |  Height:  |  Size: 187 B

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 622 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

View file

Before

Width:  |  Height:  |  Size: 259 B

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 940 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

View file

Before

Width:  |  Height:  |  Size: 324 B

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6 KiB

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/circle_black_background"
android:insetBottom="@dimen/activity_margin"
android:insetLeft="@dimen/activity_margin"
android:insetRight="@dimen/activity_margin"
android:insetTop="@dimen/activity_margin"/>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<stroke android:width="1dp" android:color="#FFFFFFFF"/>
</shape>
</item>
</selector>

View file

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/fragment_holder"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/default_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/activity_margin"/>
<com.theartofdev.edmodo.cropper.CropImageView
android:id="@+id/crop_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/activity_margin"
android:visibility="gone"
app:cropBackgroundColor="@color/crop_image_view_background"
app:cropInitialCropWindowPaddingRatio="0"/>
<include
android:id="@+id/bottom_aspect_ratios"
layout="@layout/bottom_actions_aspect_ratio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/bottom_editor_crop_rotate_actions"
android:visibility="gone"/>
<include
android:id="@+id/bottom_editor_filter_actions"
layout="@layout/bottom_editor_actions_filter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/bottom_editor_primary_actions"
android:visibility="gone"/>
<include
android:id="@+id/bottom_editor_crop_rotate_actions"
layout="@layout/bottom_editor_crop_rotate_actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/bottom_editor_primary_actions"
android:visibility="gone"/>
<include
android:id="@+id/bottom_editor_primary_actions"
layout="@layout/bottom_editor_primary_actions"/>
</RelativeLayout>

View file

@ -11,6 +11,28 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<RelativeLayout
android:id="@+id/settings_purchase_thank_you_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_purchase_thank_you"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:text="@string/purchase_simple_thank_you"/>
</RelativeLayout>
<RelativeLayout <RelativeLayout
android:id="@+id/settings_customize_colors_holder" android:id="@+id/settings_customize_colors_holder"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -1023,6 +1045,29 @@
</RelativeLayout> </RelativeLayout>
<RelativeLayout
android:id="@+id/settings_show_recycle_bin_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_margin"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/normal_margin"
android:paddingRight="@dimen/normal_margin"
android:paddingTop="@dimen/activity_margin">
<com.simplemobiletools.commons.views.MySwitchCompat
android:id="@+id/settings_show_recycle_bin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:paddingLeft="@dimen/medium_margin"
android:paddingStart="@dimen/medium_margin"
android:text="@string/show_recycle_bin"/>
</RelativeLayout>
<RelativeLayout <RelativeLayout
android:id="@+id/settings_empty_recycle_bin_holder" android:id="@+id/settings_empty_recycle_bin_holder"
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -126,8 +126,19 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="@dimen/medium_margin" android:padding="@dimen/medium_margin"
android:src="@drawable/ic_rename_new" android:src="@drawable/ic_rename_new"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="@+id/bottom_set_as"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_toggle_file_visibility"/> app:layout_constraintStart_toEndOf="@+id/bottom_toggle_file_visibility"/>
<ImageView
android:id="@+id/bottom_set_as"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/medium_margin"
android:src="@drawable/ic_set_as"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_rename"/>
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>

View file

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/bottom_aspect_ratios_wrapper"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_actions_height"
android:paddingTop="@dimen/medium_margin">
<TextView
android:id="@+id/bottom_aspect_ratio_free"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/activity_margin"
android:text="@string/free_aspect_ratio"
android:textAllCaps="true"
android:textColor="@android:color/white"
android:textSize="@dimen/big_text_size"
app:layout_constraintEnd_toStartOf="@+id/bottom_aspect_ratio_one_one"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"/>
<TextView
android:id="@+id/bottom_aspect_ratio_one_one"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/activity_margin"
android:text="1:1"
android:textColor="@android:color/white"
android:textSize="@dimen/big_text_size"
app:layout_constraintEnd_toStartOf="@+id/bottom_aspect_ratio_four_three"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_aspect_ratio_free"/>
<TextView
android:id="@+id/bottom_aspect_ratio_four_three"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/activity_margin"
android:text="4:3"
android:textColor="@android:color/white"
android:textSize="@dimen/big_text_size"
app:layout_constraintEnd_toStartOf="@+id/bottom_aspect_ratio_sixteen_nine"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_aspect_ratio_one_one"/>
<TextView
android:id="@+id/bottom_aspect_ratio_sixteen_nine"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/activity_margin"
android:text="16:9"
android:textColor="@android:color/white"
android:textSize="@dimen/big_text_size"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_aspect_ratio_four_three"/>
</android.support.constraint.ConstraintLayout>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/bottom_actions_filter_wrapper"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_filters_height"
android:paddingTop="@dimen/medium_margin">
<com.simplemobiletools.commons.views.MyRecyclerView
android:id="@+id/bottom_actions_filter_list"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_filters_height"
android:background="@color/crop_image_view_background"
android:orientation="horizontal"
android:overScrollMode="never"
app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager"/>
</RelativeLayout>

View file

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/bottom_editor_actions_wrapper"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_actions_height"
android:layout_alignParentBottom="true">
<ImageView
android:id="@+id/bottom_rotate"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_rotate_right"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/bottom_resize"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/bottom_resize"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_minimize"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/bottom_aspect_ratio"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_rotate"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/bottom_aspect_ratio"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_aspect_ratio"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/bottom_flip_horizontally"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_resize"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/bottom_flip_horizontally"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_flip_horizontally"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/bottom_flip_vertically"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_aspect_ratio"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/bottom_flip_vertically"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_flip_vertically"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_flip_horizontally"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/bottom_editor_primary_actions_wrapper"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_actions_height"
android:layout_alignParentBottom="true"
android:background="@drawable/gradient_background_lighter">
<ImageView
android:id="@+id/bottom_primary_filter"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_photo_filter"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/bottom_primary_crop_rotate"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/bottom_primary_crop_rotate"
style="@style/MyBorderlessBackgroundStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_crop_rotate"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/bottom_primary_filter"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>

View file

@ -102,5 +102,13 @@
android:paddingTop="@dimen/activity_margin" android:paddingTop="@dimen/activity_margin"
android:text="@string/rename"/> android:text="@string/rename"/>
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/manage_bottom_actions_set_as"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:text="@string/set_as"/>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/editor_filter_item_holder"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/editor_filter_item_thumbnail"
android:layout_width="@dimen/bottom_filters_thumbnail_height"
android:layout_height="@dimen/bottom_filters_thumbnail_height"
android:layout_above="@+id/editor_filter_item_label"
android:background="@drawable/stroke_background"
android:padding="1dp"/>
<TextView
android:id="@+id/editor_filter_item_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:gravity="center_horizontal"
android:textColor="@android:color/white"
android:textSize="@dimen/smaller_text_size"
tools:text="Filter"/>
</RelativeLayout>

View file

@ -23,8 +23,8 @@
android:layout_width="@dimen/play_outline_size_big" android:layout_width="@dimen/play_outline_size_big"
android:layout_height="@dimen/play_outline_size_big" android:layout_height="@dimen/play_outline_size_big"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:background="@android:color/transparent" android:background="@drawable/circle_black_background_with_inset"
android:padding="@dimen/big_margin" android:padding="28dp"
android:src="@drawable/ic_panorama" android:src="@drawable/ic_panorama"
android:visibility="gone"/> android:visibility="gone"/>

View file

@ -6,6 +6,11 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<ImageView
android:id="@+id/video_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextureView <TextureView
android:id="@+id/video_surface" android:id="@+id/video_surface"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -41,9 +46,9 @@
android:layout_width="@dimen/play_outline_size_big" android:layout_width="@dimen/play_outline_size_big"
android:layout_height="@dimen/play_outline_size_big" android:layout_height="@dimen/play_outline_size_big"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:background="@android:color/transparent" android:background="@drawable/circle_black_background_with_inset"
android:padding="@dimen/big_margin" android:padding="26dp"
android:src="@drawable/img_play_outline_big"/> android:src="@drawable/ic_play"/>
<TextView <TextView
android:id="@+id/slide_info" android:id="@+id/slide_info"
@ -80,8 +85,7 @@
android:id="@+id/video_time_holder" android:id="@+id/video_time_holder"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true">
android:background="@drawable/gradient_background">
<TextView <TextView
android:id="@+id/video_curr_time" android:id="@+id/video_curr_time"

View file

@ -5,33 +5,10 @@
android:id="@+id/save_as" android:id="@+id/save_as"
android:icon="@drawable/ic_check" android:icon="@drawable/ic_check"
android:title="@string/save_as" android:title="@string/save_as"
app:showAsAction="always"/>
<item
android:id="@+id/rotate"
android:icon="@drawable/ic_rotate_right"
android:title="@string/rotate"
app:showAsAction="ifRoom"/> app:showAsAction="ifRoom"/>
<item
android:id="@+id/resize"
android:icon="@drawable/ic_minimize"
android:title="@string/resize"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/flip"
android:icon="@drawable/ic_flip"
android:title="@string/flip"
app:showAsAction="ifRoom">
<menu>
<item
android:id="@+id/flip_horizontally"
android:title="@string/flip_horizontally"/>
<item
android:id="@+id/flip_vertically"
android:title="@string/flip_vertically"/>
</menu>
</item>
<item <item
android:id="@+id/edit" android:id="@+id/edit"
android:icon="@drawable/ic_edit"
android:title="@string/edit_with" android:title="@string/edit_with"
app:showAsAction="never"/> app:showAsAction="ifRoom"/>
</menu> </menu>

View file

@ -73,10 +73,6 @@
android:id="@+id/menu_move_to" android:id="@+id/menu_move_to"
android:title="@string/move_to" android:title="@string/move_to"
app:showAsAction="never"/> app:showAsAction="never"/>
<item
android:id="@+id/menu_set_as"
android:title="@string/set_as"
app:showAsAction="never"/>
<item <item
android:id="@+id/menu_open_with" android:id="@+id/menu_open_with"
android:title="@string/open_with" android:title="@string/open_with"
@ -104,6 +100,11 @@
android:icon="@drawable/ic_slideshow" android:icon="@drawable/ic_slideshow"
android:title="@string/slideshow" android:title="@string/slideshow"
app:showAsAction="ifRoom"/> app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_set_as"
android:icon="@drawable/ic_set_as"
android:title="@string/set_as"
app:showAsAction="ifRoom"/>
<item <item
android:id="@+id/menu_rename" android:id="@+id/menu_rename"
android:icon="@drawable/ic_rename_new" android:icon="@drawable/ic_rename_new"

View file

@ -18,8 +18,9 @@
app:showAsAction="ifRoom"/> app:showAsAction="ifRoom"/>
<item <item
android:id="@+id/menu_set_as" android:id="@+id/menu_set_as"
android:icon="@drawable/ic_set_as"
android:title="@string/set_as" android:title="@string/set_as"
app:showAsAction="never"/> app:showAsAction="ifRoom"/>
<item <item
android:id="@+id/menu_open_with" android:id="@+id/menu_open_with"
android:title="@string/open_with" android:title="@string/open_with"

View file

@ -88,13 +88,14 @@
<string name="flip_horizontally">قلب أفقيا</string> <string name="flip_horizontally">قلب أفقيا</string>
<string name="flip_vertically">قلب عموديا</string> <string name="flip_vertically">قلب عموديا</string>
<string name="edit_with">تعديل باستخدام</string> <string name="edit_with">تعديل باستخدام</string>
<string name="free_aspect_ratio">Free</string> <!-- available as an option: 1:1, 4:3, 16:9, free -->
<!-- Set wallpaper --> <!-- Set wallpaper -->
<string name="simple_wallpaper">خلفية بسيطة</string> <string name="simple_wallpaper">خلفية بسيطة</string>
<string name="set_as_wallpaper">تعيين كخلفية الشاشة</string> <string name="set_as_wallpaper">تعيين كخلفية الشاشة</string>
<string name="set_as_wallpaper_failed">فشل الإعداد كخلفية</string> <string name="set_as_wallpaper_failed">فشل الإعداد كخلفية</string>
<string name="set_as_wallpaper_with">تعيين كخلفية بواسطة:</string> <string name="set_as_wallpaper_with">تعيين كخلفية بواسطة:</string>
<string name="setting_wallpaper">... جار تعيين الخلفية ...</string> <string name="setting_wallpaper"> جار تعيين الخلفية ...</string>
<string name="wallpaper_set_successfully">تم تعيبن الخلفية بنجاح</string> <string name="wallpaper_set_successfully">تم تعيبن الخلفية بنجاح</string>
<string name="portrait_aspect_ratio">صورة نسبة العرض إلى الارتفاع</string> <string name="portrait_aspect_ratio">صورة نسبة العرض إلى الارتفاع</string>
<string name="landscape_aspect_ratio">نسبة العرض إلى الارتفاع في المناظر الطبيعية</string> <string name="landscape_aspect_ratio">نسبة العرض إلى الارتفاع في المناظر الطبيعية</string>
@ -157,6 +158,7 @@
<string name="hide_extended_details">إخفاء التفاصيل الموسعة عند إخفاء شريط الحالة</string> <string name="hide_extended_details">إخفاء التفاصيل الموسعة عند إخفاء شريط الحالة</string>
<string name="do_extra_check">قم بإجراء فحص إضافي لتجنب إظهار الملفات التالفة</string> <string name="do_extra_check">قم بإجراء فحص إضافي لتجنب إظهار الملفات التالفة</string>
<string name="show_at_bottom">Show some action buttons at the bottom of the screen</string> <string name="show_at_bottom">Show some action buttons at the bottom of the screen</string>
<string name="show_recycle_bin">Show the Recycle Bin at the folders screen</string>
<!-- Setting sections --> <!-- Setting sections -->
<string name="thumbnails">المصغرات</string> <string name="thumbnails">المصغرات</string>

View file

@ -24,17 +24,17 @@
<string name="brightness">Brillantor</string> <string name="brightness">Brillantor</string>
<string name="lock_orientation">Bloquejar orientació</string> <string name="lock_orientation">Bloquejar orientació</string>
<string name="unlock_orientation">Desbloquejar orientació</string> <string name="unlock_orientation">Desbloquejar orientació</string>
<string name="change_orientation">Change orientation</string> <string name="change_orientation">Canviar orientació</string>
<string name="force_portrait">Force portrait</string> <string name="force_portrait">Forçar vertical</string>
<string name="force_landscape">Force landscape</string> <string name="force_landscape">Forçar horitzontal</string>
<string name="use_default_orientation">Use default orientation</string> <string name="use_default_orientation">Fer servir la orientació per defecte</string>
<!-- Filter --> <!-- Filter -->
<string name="filter_media">Filtre d\'arxius</string> <string name="filter_media">Filtre d\'arxius</string>
<string name="images">Imatges</string> <string name="images">Imatges</string>
<string name="videos">Vídeos</string> <string name="videos">Vídeos</string>
<string name="gifs">GIFs</string> <string name="gifs">GIFs</string>
<string name="raw_images">RAW images</string> <string name="raw_images">Imatges RAW</string>
<string name="no_media_with_filters">No s\'han tronat arxius amb els filtres seleccionats.</string> <string name="no_media_with_filters">No s\'han tronat arxius amb els filtres seleccionats.</string>
<string name="change_filters_underlined"><u>Canviar filtres</u></string> <string name="change_filters_underlined"><u>Canviar filtres</u></string>
@ -84,6 +84,7 @@
<string name="flip_horizontally">Horizontalment</string> <string name="flip_horizontally">Horizontalment</string>
<string name="flip_vertically">Verticalment</string> <string name="flip_vertically">Verticalment</string>
<string name="edit_with">Editar amb</string> <string name="edit_with">Editar amb</string>
<string name="free_aspect_ratio">Lliure</string> <!-- available as an option: 1:1, 4:3, 16:9, free -->
<!-- Set wallpaper --> <!-- Set wallpaper -->
<string name="simple_wallpaper">Fons de pantalla de Simple Gallery</string> <string name="simple_wallpaper">Fons de pantalla de Simple Gallery</string>
@ -152,18 +153,19 @@
<string name="replace_zoomable_images">Substituïr imatges ampliades per les de millor quialitat</string> <string name="replace_zoomable_images">Substituïr imatges ampliades per les de millor quialitat</string>
<string name="hide_extended_details">Amaga els detalls estesos quan la barra d\'estat està amagada</string> <string name="hide_extended_details">Amaga els detalls estesos quan la barra d\'estat està amagada</string>
<string name="do_extra_check">Fer una verificació addicional per evitar que es mostrin fitxers no vàlids</string> <string name="do_extra_check">Fer una verificació addicional per evitar que es mostrin fitxers no vàlids</string>
<string name="show_at_bottom">Show some action buttons at the bottom of the screen</string> <string name="show_at_bottom">Mostra alguns botons d\'acció a la part inferior de la pantalla</string>
<string name="show_recycle_bin">Mostra la paperera de reciclatge a la pantalla de carpetes</string>
<!-- Setting sections --> <!-- Setting sections -->
<string name="thumbnails">Miniatures</string> <string name="thumbnails">Miniatures</string>
<string name="fullscreen_media">Mitjans a pantalla completa</string> <string name="fullscreen_media">Mitjans a pantalla completa</string>
<string name="extended_details">Detalls estesos</string> <string name="extended_details">Detalls estesos</string>
<string name="bottom_actions">Bottom actions</string> <string name="bottom_actions">Accions de la part inferior</string>
<!-- Bottom actions --> <!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string> <string name="manage_bottom_actions">Administra les accions de la part inferior</string>
<string name="toggle_favorite">Toggle favorite</string> <string name="toggle_favorite">Activa favorits</string>
<string name="toggle_file_visibility">Toggle file visibility</string> <string name="toggle_file_visibility">Activa la visibilitat del fitxer</string>
<!-- FAQ --> <!-- FAQ -->
<string name="faq_1_title">Com puc fer que Simple Gallery sigui la galeria de dispositius predeterminada?</string> <string name="faq_1_title">Com puc fer que Simple Gallery sigui la galeria de dispositius predeterminada?</string>
@ -188,8 +190,8 @@
<string name="faq_9_text">Sí, hi ha un commutador a la configuració que diu \"Substituïu imatges ampliades i de gran qualitat\", podeu fer-ho. Millora la qualitat de les imatges, però es borraran una vegada que intenteu fer zoom massa.</string> <string name="faq_9_text">Sí, hi ha un commutador a la configuració que diu \"Substituïu imatges ampliades i de gran qualitat\", podeu fer-ho. Millora la qualitat de les imatges, però es borraran una vegada que intenteu fer zoom massa.</string>
<string name="faq_10_title">Puc retallar imatges amb aquesta aplicació?</string> <string name="faq_10_title">Puc retallar imatges amb aquesta aplicació?</string>
<string name="faq_10_text">Sí, pots retallar imatges a l\'editor, arrossegant les cantonades de la imatge. Pots accedir a l\'editor prement una miniatura d\'imatge i seleccionant Edita o seleccionant Edita des de la visualització de pantalla completa.</string> <string name="faq_10_text">Sí, pots retallar imatges a l\'editor, arrossegant les cantonades de la imatge. Pots accedir a l\'editor prement una miniatura d\'imatge i seleccionant Edita o seleccionant Edita des de la visualització de pantalla completa.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string> <string name="faq_11_title">Puc agrupar d\'alguna manera les miniatures del fitxer multimèdia?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string> <string name="faq_11_text">Si, només heu d\'utilitzar l\'ítem del menú \"Agrupar per\" mentre es troba a la vista en miniatura. Podeu agrupar fitxers amb diversos criteris, inclòs data de presa. Si utilitzeu la funció \"Mostra el contingut de totes les carpetes\", també podeu agrupar-les per carpetes.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have --> <!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars --> <!-- Short description has to have less than 80 chars -->

View file

@ -84,6 +84,7 @@
<string name="flip_horizontally">Překlopit vodorovně</string> <string name="flip_horizontally">Překlopit vodorovně</string>
<string name="flip_vertically">Překlopit svisle</string> <string name="flip_vertically">Překlopit svisle</string>
<string name="edit_with">Edit with</string> <string name="edit_with">Edit with</string>
<string name="free_aspect_ratio">Free</string> <!-- available as an option: 1:1, 4:3, 16:9, free -->
<!-- Set wallpaper --> <!-- Set wallpaper -->
<string name="simple_wallpaper">Jednoduchá tapeta</string> <string name="simple_wallpaper">Jednoduchá tapeta</string>
@ -153,6 +154,7 @@
<string name="hide_extended_details">Hide extended details when status bar is hidden</string> <string name="hide_extended_details">Hide extended details when status bar is hidden</string>
<string name="do_extra_check">Do an extra check to avoid showing invalid files</string> <string name="do_extra_check">Do an extra check to avoid showing invalid files</string>
<string name="show_at_bottom">Show some action buttons at the bottom of the screen</string> <string name="show_at_bottom">Show some action buttons at the bottom of the screen</string>
<string name="show_recycle_bin">Show the Recycle Bin at the folders screen</string>
<!-- Setting sections --> <!-- Setting sections -->
<string name="thumbnails">Thumbnails</string> <string name="thumbnails">Thumbnails</string>

View file

@ -84,6 +84,7 @@
<string name="flip_horizontally">Spejlvend vandret</string> <string name="flip_horizontally">Spejlvend vandret</string>
<string name="flip_vertically">Spejlvend lodret</string> <string name="flip_vertically">Spejlvend lodret</string>
<string name="edit_with">Rediger med</string> <string name="edit_with">Rediger med</string>
<string name="free_aspect_ratio">Free</string> <!-- available as an option: 1:1, 4:3, 16:9, free -->
<!-- Set wallpaper --> <!-- Set wallpaper -->
<string name="simple_wallpaper">Simple Wallpaper</string> <string name="simple_wallpaper">Simple Wallpaper</string>
@ -153,6 +154,7 @@
<string name="hide_extended_details">Skjul udvidede oplysninger når statuslinjen er skjult</string> <string name="hide_extended_details">Skjul udvidede oplysninger når statuslinjen er skjult</string>
<string name="do_extra_check">Tjek en ekstra gang for at undgå visning af ugyldige filer</string> <string name="do_extra_check">Tjek en ekstra gang for at undgå visning af ugyldige filer</string>
<string name="show_at_bottom">Show some action buttons at the bottom of the screen</string> <string name="show_at_bottom">Show some action buttons at the bottom of the screen</string>
<string name="show_recycle_bin">Show the Recycle Bin at the folders screen</string>
<!-- Setting sections --> <!-- Setting sections -->
<string name="thumbnails">Thumbnails</string> <string name="thumbnails">Thumbnails</string>

View file

@ -25,9 +25,9 @@
<string name="lock_orientation">Bildschirmausrichtung sperren</string> <string name="lock_orientation">Bildschirmausrichtung sperren</string>
<string name="unlock_orientation">Bildschirmausrichtung entsperren</string> <string name="unlock_orientation">Bildschirmausrichtung entsperren</string>
<string name="change_orientation">Change orientation</string> <string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string> <string name="force_portrait">Hochkant erzwingen</string>
<string name="force_landscape">Force landscape</string> <string name="force_landscape">Breitbild erzwingen</string>
<string name="use_default_orientation">Use default orientation</string> <string name="use_default_orientation">Standard Ausrichtung benutzen</string>
<!-- Filter --> <!-- Filter -->
<string name="filter_media">Filter</string> <string name="filter_media">Filter</string>
@ -84,6 +84,7 @@
<string name="flip_horizontally">Horizontal spiegeln</string> <string name="flip_horizontally">Horizontal spiegeln</string>
<string name="flip_vertically">Vertikal spiegeln</string> <string name="flip_vertically">Vertikal spiegeln</string>
<string name="edit_with">Bearbeiten mit</string> <string name="edit_with">Bearbeiten mit</string>
<string name="free_aspect_ratio">Free</string> <!-- available as an option: 1:1, 4:3, 16:9, free -->
<!-- Set wallpaper --> <!-- Set wallpaper -->
<string name="simple_wallpaper">Schlichter Hintergrund</string> <string name="simple_wallpaper">Schlichter Hintergrund</string>
@ -153,6 +154,7 @@
<string name="hide_extended_details">Erweiterte Details nicht anzeigen, wenn die Systemleiste versteckt ist</string> <string name="hide_extended_details">Erweiterte Details nicht anzeigen, wenn die Systemleiste versteckt ist</string>
<string name="do_extra_check">Zusätzliche Überprüfung, um ungültige Dateien nicht anzuzeigen</string> <string name="do_extra_check">Zusätzliche Überprüfung, um ungültige Dateien nicht anzuzeigen</string>
<string name="show_at_bottom">Show some action buttons at the bottom of the screen</string> <string name="show_at_bottom">Show some action buttons at the bottom of the screen</string>
<string name="show_recycle_bin">Show the Recycle Bin at the folders screen</string>
<!-- Setting sections --> <!-- Setting sections -->
<string name="thumbnails">Thumbnails</string> <string name="thumbnails">Thumbnails</string>

View file

@ -84,6 +84,7 @@
<string name="flip_horizontally">Οριζόντιο αναποδογύρισμα</string> <string name="flip_horizontally">Οριζόντιο αναποδογύρισμα</string>
<string name="flip_vertically">Κατακόρυφο αναποδογύρισμα</string> <string name="flip_vertically">Κατακόρυφο αναποδογύρισμα</string>
<string name="edit_with">Επεξεργασία με</string> <string name="edit_with">Επεξεργασία με</string>
<string name="free_aspect_ratio">Free</string> <!-- available as an option: 1:1, 4:3, 16:9, free -->
<!-- Set wallpaper --> <!-- Set wallpaper -->
<string name="simple_wallpaper">Simple Wallpaper</string> <string name="simple_wallpaper">Simple Wallpaper</string>
@ -154,6 +155,7 @@
<string name="hide_extended_details">Απόκρυψη λεπτομερειών όταν η μπάρα κατάστασης είναι κρυμμένη</string> <string name="hide_extended_details">Απόκρυψη λεπτομερειών όταν η μπάρα κατάστασης είναι κρυμμένη</string>
<string name="do_extra_check">Επιπλέον έλεγχος για την αποφυγή εμφάνισης λανθασμένων αρχείων</string> <string name="do_extra_check">Επιπλέον έλεγχος για την αποφυγή εμφάνισης λανθασμένων αρχείων</string>
<string name="show_at_bottom">Show some action buttons at the bottom of the screen</string> <string name="show_at_bottom">Show some action buttons at the bottom of the screen</string>
<string name="show_recycle_bin">Show the Recycle Bin at the folders screen</string>
<!-- Setting sections --> <!-- Setting sections -->
<string name="thumbnails">Εικονίδια</string> <string name="thumbnails">Εικονίδια</string>

View file

@ -24,17 +24,17 @@
<string name="brightness">Brillo</string> <string name="brightness">Brillo</string>
<string name="lock_orientation">Bloquear orientación</string> <string name="lock_orientation">Bloquear orientación</string>
<string name="unlock_orientation">Desbloquear orientación</string> <string name="unlock_orientation">Desbloquear orientación</string>
<string name="change_orientation">Change orientation</string> <string name="change_orientation">Cambiar orientación</string>
<string name="force_portrait">Force portrait</string> <string name="force_portrait">Forzar retrato</string>
<string name="force_landscape">Force landscape</string> <string name="force_landscape">Forzar paisaje</string>
<string name="use_default_orientation">Use default orientation</string> <string name="use_default_orientation">Usar la orientación por defecto</string>
<!-- Filter --> <!-- Filter -->
<string name="filter_media">Filtro de medios</string> <string name="filter_media">Filtro de medios</string>
<string name="images">Imágenes</string> <string name="images">Imágenes</string>
<string name="videos">Vídeos</string> <string name="videos">Vídeos</string>
<string name="gifs">GIFs</string> <string name="gifs">GIFs</string>
<string name="raw_images">RAW images</string> <string name="raw_images">Imagenes RAW</string>
<string name="no_media_with_filters">No se han encontrado ficheros con los filtros seleccionados.</string> <string name="no_media_with_filters">No se han encontrado ficheros con los filtros seleccionados.</string>
<string name="change_filters_underlined"><u>Cambiar filtros</u></string> <string name="change_filters_underlined"><u>Cambiar filtros</u></string>
@ -84,6 +84,7 @@
<string name="flip_horizontally">Horizontalmente</string> <string name="flip_horizontally">Horizontalmente</string>
<string name="flip_vertically">Verticalmente</string> <string name="flip_vertically">Verticalmente</string>
<string name="edit_with">Editar con</string> <string name="edit_with">Editar con</string>
<string name="free_aspect_ratio">Libre</string> <!-- available as an option: 1:1, 4:3, 16:9, free -->
<!-- Set wallpaper --> <!-- Set wallpaper -->
<string name="simple_wallpaper">Fondos de pantalla Simple Gallery</string> <string name="simple_wallpaper">Fondos de pantalla Simple Gallery</string>
@ -152,18 +153,19 @@
<string name="replace_zoomable_images">Reemplace las imágenes con mucho zoom por otras de mejor calidad</string> <string name="replace_zoomable_images">Reemplace las imágenes con mucho zoom por otras de mejor calidad</string>
<string name="hide_extended_details">Ocultar detalles ampliados cuando la barra de estado está oculta</string> <string name="hide_extended_details">Ocultar detalles ampliados cuando la barra de estado está oculta</string>
<string name="do_extra_check">Hacer una comprobación adicional para evitar mostrar archivos inválidos</string> <string name="do_extra_check">Hacer una comprobación adicional para evitar mostrar archivos inválidos</string>
<string name="show_at_bottom">Show some action buttons at the bottom of the screen</string> <string name="show_at_bottom">Mostrar algunos botones de acción en la parte inferior de la pantalla</string>
<string name="show_recycle_bin">Muestra la papelera de reciclaje en la pantalla de carpetas</string>
<!-- Setting sections --> <!-- Setting sections -->
<string name="thumbnails">Miniaturas</string> <string name="thumbnails">Miniaturas</string>
<string name="fullscreen_media">Medios a pantalla compelta</string> <string name="fullscreen_media">Medios a pantalla compelta</string>
<string name="extended_details">Detalles ampliados</string> <string name="extended_details">Detalles ampliados</string>
<string name="bottom_actions">Bottom actions</string> <string name="bottom_actions">Acciones en la parte inferior</string>
<!-- Bottom actions --> <!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string> <string name="manage_bottom_actions">Administrar los botones de la parte inferior</string>
<string name="toggle_favorite">Toggle favorite</string> <string name="toggle_favorite">Activar favoritos</string>
<string name="toggle_file_visibility">Toggle file visibility</string> <string name="toggle_file_visibility">Activar visibilidad de fichero</string>
<!-- FAQ --> <!-- FAQ -->
<string name="faq_1_title">¿Cómo puedo hacer que Simple Gallery sea la galería de dispositivos predeterminada?</string> <string name="faq_1_title">¿Cómo puedo hacer que Simple Gallery sea la galería de dispositivos predeterminada?</string>
@ -188,8 +190,8 @@
<string name="faq_9_text">Sí, hay una alternancia en Configuración que dice \"Reemplazar imágenes con zoom profundo con las de mejor calidad\", puedes usar eso. Mejorará la calidad de las imágenes, pero se volverán borrosas una vez que intente ampliar demasiado.</string> <string name="faq_9_text">Sí, hay una alternancia en Configuración que dice \"Reemplazar imágenes con zoom profundo con las de mejor calidad\", puedes usar eso. Mejorará la calidad de las imágenes, pero se volverán borrosas una vez que intente ampliar demasiado.</string>
<string name="faq_10_title">¿Puedo recortar imágenes con esta aplicación?</string> <string name="faq_10_title">¿Puedo recortar imágenes con esta aplicación?</string>
<string name="faq_10_text">Sí, puede recortar imágenes en el editor arrastrando las esquinas de la imagen. Puede acceder al editor pulsando prolongadamente una imagen en miniatura y seleccionando Editar, o seleccionando Editar en la vista de pantalla completa.</string> <string name="faq_10_text">Sí, puede recortar imágenes en el editor arrastrando las esquinas de la imagen. Puede acceder al editor pulsando prolongadamente una imagen en miniatura y seleccionando Editar, o seleccionando Editar en la vista de pantalla completa.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string> <string name="faq_11_title">¿Puedo de alguna manera agrupar miniaturas de archivos multimedia?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string> <string name="faq_11_text">Claro, solo use el elemento de menú \"Agrupar por \" mientras esté en la vista de miniaturas. Puede agrupar archivos según varios criterios, incluida la Fecha de toma. Si usa la función \"Mostrar todo el contenido de las carpetas\" también puede agruparlas por carpetas.</string>
<!-- Strings displayed only on Google Playstore. Optional, but good to have --> <!-- Strings displayed only on Google Playstore. Optional, but good to have -->
<!-- Short description has to have less than 80 chars --> <!-- Short description has to have less than 80 chars -->

View file

@ -84,6 +84,7 @@
<string name="flip_horizontally">Pyöräytä vaakasuoraan</string> <string name="flip_horizontally">Pyöräytä vaakasuoraan</string>
<string name="flip_vertically">Pyöräytä pystysuoraan</string> <string name="flip_vertically">Pyöräytä pystysuoraan</string>
<string name="edit_with">Muokkaa sovelluksella</string> <string name="edit_with">Muokkaa sovelluksella</string>
<string name="free_aspect_ratio">Free</string> <!-- available as an option: 1:1, 4:3, 16:9, free -->
<!-- Set wallpaper --> <!-- Set wallpaper -->
<string name="simple_wallpaper">Simple Wallpaper</string> <string name="simple_wallpaper">Simple Wallpaper</string>
@ -153,6 +154,7 @@
<string name="hide_extended_details">Piilota yksityiskohtaiset tiedot kun tilapalkki on piilotettu</string> <string name="hide_extended_details">Piilota yksityiskohtaiset tiedot kun tilapalkki on piilotettu</string>
<string name="do_extra_check">Tee ylimääräinen tarkistus rikkinäisten tiedostojen varalta</string> <string name="do_extra_check">Tee ylimääräinen tarkistus rikkinäisten tiedostojen varalta</string>
<string name="show_at_bottom">Show some action buttons at the bottom of the screen</string> <string name="show_at_bottom">Show some action buttons at the bottom of the screen</string>
<string name="show_recycle_bin">Show the Recycle Bin at the folders screen</string>
<!-- Setting sections --> <!-- Setting sections -->
<string name="thumbnails">Esikatselukuvat</string> <string name="thumbnails">Esikatselukuvat</string>

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