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
==========
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)*
----------------------------

View file

@ -11,8 +11,8 @@ android {
applicationId "com.simplemobiletools.gallery"
minSdkVersion 16
targetSdkVersion 27
versionCode 184
versionName "4.3.2"
versionCode 187
versionName "4.3.5"
multiDexEnabled true
setProperty("archivesBaseName", "gallery")
}
@ -47,7 +47,7 @@ ext {
}
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.android.support:multidex:1.0.3'
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.vr:sdk-panowidget:1.150.0'
implementation 'org.apache.sanselan:sanselan:0.97-incubator'
implementation 'info.androidhive:imagefilters:1.0.7'
kapt "android.arch.persistence.room:compiler: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.SET_WALLPAPER"/>
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE"
tools:node="remove"/>
<uses-sdk
tools:overrideLibrary="com.google.vr.widgets.common, com.google.vr.sdk.widgets.pano"/>
@ -18,17 +21,12 @@
android:label="@string/app_launcher_name"
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
tools:replace="android:label">
<activity
android:name=".activities.SplashActivity"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
android:theme="@style/SplashTheme"/>
<activity
android:name=".activities.MainActivity"
@ -222,19 +220,6 @@
</intent-filter>
</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
android:name=".activities.SplashActivity.Red"
android:enabled="false"
@ -417,6 +402,18 @@
</intent-filter>
</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
android:name=".activities.SplashActivity.Deep_orange"
android:enabled="false"

View file

@ -4,40 +4,83 @@ import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat
import android.graphics.Color
import android.graphics.Point
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.view.Menu
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.helpers.OTG_PATH
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE
import com.simplemobiletools.commons.helpers.REAL_FILE_PATH
import com.simplemobiletools.commons.models.FileDirItem
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.adapters.FiltersAdapter
import com.simplemobiletools.gallery.dialogs.ResizeDialog
import com.simplemobiletools.gallery.dialogs.SaveAsDialog
import com.simplemobiletools.gallery.extensions.config
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 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.*
class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener {
companion object {
init {
System.loadLibrary("NativeImageProcessor")
}
}
private val ASPECT_X = "aspectX"
private val ASPECT_Y = "aspectY"
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 saveUri: Uri
private var resizeWidth = 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 isEditingWithThirdParty = false
private var initialBitmap: Bitmap? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.view_crop_image)
setContentView(R.layout.activity_edit)
handlePermission(PERMISSION_WRITE_STORAGE) {
if (it) {
@ -82,14 +125,13 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
}
isCropIntent = intent.extras?.get(CROP) == "true"
crop_image_view.apply {
setOnCropImageCompleteListener(this@EditActivity)
setImageUriAsync(uri)
if (isCropIntent && shouldCropSquare())
setFixedAspectRatio(true)
if (isCropIntent) {
bottom_editor_primary_actions.beGone()
(bottom_editor_crop_rotate_actions.layoutParams as RelativeLayout.LayoutParams).addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, 1)
}
loadDefaultImageView()
setupBottomActions()
}
override fun onResume() {
@ -106,23 +148,288 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_editor, menu)
menu.findItem(R.id.resize).isVisible = !isCropIntent
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.save_as -> crop_image_view.getCroppedImageAsync()
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.save_as -> saveImage()
R.id.edit -> editWith()
else -> return super.onOptionsItemSelected(item)
}
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() {
val point = getAreaSize()
if (point == null) {
@ -160,7 +467,7 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
if (result.error == null) {
if (isCropIntent) {
if (saveUri.scheme == "file") {
saveBitmapToFile(result.bitmap, saveUri.path)
saveBitmapToFile(result.bitmap, saveUri.path, true)
} else {
var inputStream: InputStream? = null
var outputStream: OutputStream? = null
@ -184,27 +491,12 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
}
} else if (saveUri.scheme == "file") {
SaveAsDialog(this, saveUri.path, true) {
saveBitmapToFile(result.bitmap, it)
saveBitmapToFile(result.bitmap, it, true)
}
} else if (saveUri.scheme == "content") {
var newPath = applicationContext.getRealPathFromURI(saveUri) ?: ""
var shouldAppendFilename = true
if (newPath.isEmpty()) {
val filename = applicationContext.getFilenameFromContentUri(saveUri) ?: ""
if (filename.isNotEmpty()) {
val path = if (intent.extras?.containsKey(REAL_FILE_PATH) == true) intent.getStringExtra(REAL_FILE_PATH).getParentPath() else internalStoragePath
newPath = "$path/$filename"
shouldAppendFilename = false
}
}
if (newPath.isEmpty()) {
newPath = "$internalStoragePath/${getCurrentFormattedDateTime()}.${saveUri.toString().getFilenameExtension()}"
shouldAppendFilename = false
}
SaveAsDialog(this, newPath, shouldAppendFilename) {
saveBitmapToFile(result.bitmap, it)
val filePathGetter = getNewFilePath()
SaveAsDialog(this, filePathGetter.first, filePathGetter.second) {
saveBitmapToFile(result.bitmap, it, true)
}
} else {
toast(R.string.unknown_file_location)
@ -214,14 +506,34 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
}
}
private fun saveBitmapToFile(bitmap: Bitmap, path: String) {
private fun getNewFilePath(): Pair<String, Boolean> {
var newPath = applicationContext.getRealPathFromURI(saveUri) ?: ""
var shouldAppendFilename = true
if (newPath.isEmpty()) {
val filename = applicationContext.getFilenameFromContentUri(saveUri) ?: ""
if (filename.isNotEmpty()) {
val path = if (intent.extras?.containsKey(REAL_FILE_PATH) == true) intent.getStringExtra(REAL_FILE_PATH).getParentPath() else internalStoragePath
newPath = "$path/$filename"
shouldAppendFilename = false
}
}
if (newPath.isEmpty()) {
newPath = "$internalStoragePath/${getCurrentFormattedDateTime()}.${saveUri.toString().getFilenameExtension()}"
shouldAppendFilename = false
}
return Pair(newPath, shouldAppendFilename)
}
private fun saveBitmapToFile(bitmap: Bitmap, path: String, showSavingToast: Boolean) {
try {
Thread {
val file = File(path)
val fileDirItem = FileDirItem(path, path.getFilenameFromPath())
getFileOutputStream(fileDirItem, true) {
if (it != null) {
saveBitmap(file, bitmap, it)
saveBitmap(file, bitmap, it, showSavingToast)
} else {
toast(R.string.image_editing_failed)
}
@ -234,8 +546,11 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
}
}
private fun saveBitmap(file: File, bitmap: Bitmap, out: OutputStream) {
toast(R.string.saving)
private fun saveBitmap(file: File, bitmap: Bitmap, out: OutputStream, showSavingToast: Boolean) {
if (showSavingToast) {
toast(R.string.saving)
}
if (resizeWidth > 0 && resizeHeight > 0) {
val resized = Bitmap.createScaledBitmap(bitmap, resizeWidth, resizeHeight, false)
resized.compress(file.absolutePath.getCompressionFormat(), 90, out)
@ -247,14 +562,6 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
out.close()
}
private fun flipImage(horizontally: Boolean) {
if (horizontally) {
crop_image_view.flipImageHorizontally()
} else {
crop_image_view.flipImageVertically()
}
}
private fun editWith() {
openEditor(uri.toString())
isEditingWithThirdParty = true

View file

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

View file

@ -261,7 +261,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
private fun setupSearch(menu: Menu) {
val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
mSearchMenuItem = menu.findItem(R.id.search)
(mSearchMenuItem!!.actionView as SearchView).apply {
(mSearchMenuItem?.actionView as? SearchView)?.apply {
setSearchableInfo(searchManager.getSearchableInfo(componentName))
isSubmitButtonEnabled = false
setOnQueryTextListener(object : SearchView.OnQueryTextListener {
@ -317,7 +317,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
mPath.startsWith(OTG_PATH) -> mPath.trimEnd('/').substringAfterLast('/')
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()
setupLayoutManager()
} else {
@ -338,7 +338,8 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
if (currAdapter == null) {
initZoomListener()
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) {
itemClicked(it.path)
}
@ -806,7 +807,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
mLatestMediaId = getLatestMediaId()
mLatestMediaDateId = getLatestMediaByDateId()
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)
}
}
@ -816,7 +817,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
val deletingItems = resources.getQuantityString(R.plurals.deleting_items, filtered.size, filtered.size)
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>) {
if (it) {
deleteFilteredFiles(filtered)

View file

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

View file

@ -16,7 +16,7 @@ import com.simplemobiletools.commons.helpers.isNougatPlus
import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.gallery.R
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 {
private val PICK_IMAGE = 1
@ -28,7 +28,7 @@ class SetWallpaperActivity : SimpleActivity(), CropImageView.OnCropImageComplete
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.view_crop_image)
setContentView(R.layout.activity_set_wallpaper)
if (intent.data == null) {
val pickIntent = Intent(applicationContext, MainActivity::class.java)

View file

@ -38,6 +38,7 @@ class SettingsActivity : SimpleActivity() {
override fun onResume() {
super.onResume()
setupPurchaseThankYou()
setupCustomizeColors()
setupUseEnglish()
setupAvoidWhatsNew()
@ -74,6 +75,7 @@ class SettingsActivity : SimpleActivity() {
setupSkipDeleteConfirmation()
setupManageBottomActions()
setupUseRecycleBin()
setupShowRecycleBin()
setupEmptyRecycleBin()
updateTextColors(settings_holder)
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() {
settings_customize_colors_holder.setOnClickListener {
startCustomizationActivity()
@ -433,6 +442,7 @@ class SettingsActivity : SimpleActivity() {
private fun setupUseRecycleBin() {
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_holder.setOnClickListener {
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() {
Thread {
mRecycleBinContentSize = galleryDB.MediumDao().getDeletedMedia().sumByLong { it.size }

View file

@ -230,6 +230,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
}
refreshViewPager()
view_pager.offscreenPageLimit = 2
if (config.blackBackground) {
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_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_set_as).isVisible = visibleBottomActions and BOTTOM_ACTION_SET_AS == 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_unhide).isVisible = currentMedium.isHidden() && visibleBottomActions and BOTTOM_ACTION_TOGGLE_VISIBILITY == 0
findItem(R.id.menu_add_to_favorites).isVisible = !currentMedium.isFavorite && visibleBottomActions and BOTTOM_ACTION_TOGGLE_FAVORITE == 0
findItem(R.id.menu_remove_from_favorites).isVisible = currentMedium.isFavorite && visibleBottomActions and BOTTOM_ACTION_TOGGLE_FAVORITE == 0
findItem(R.id.menu_restore_file).isVisible = currentMedium.path.startsWith(filesDir.toString())
findItem(R.id.menu_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).icon = resources.getDrawable(getChangeOrientationIcon())
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())
try {
getFileOutputStream(tmpFileDirItem) {
@ -841,6 +843,11 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
bottom_rename.setOnClickListener {
renameFile()
}
bottom_set_as.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_SET_AS != 0)
bottom_set_as.setOnClickListener {
setAs(getCurrentPath())
}
}
private fun updateBottomActionIcons(medium: Medium?) {
@ -915,7 +922,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun deleteConfirmed() {
val path = getCurrentMedia().getOrNull(mPos)?.path ?: return
if (getIsPathDirectory(path)) {
if (getIsPathDirectory(path) || !path.isImageVideoGif()) {
return
}
@ -1104,10 +1111,6 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
override fun onPageSelected(position: Int) {
if (view_pager.offscreenPageLimit == 1) {
view_pager.offscreenPageLimit = 2
}
if (mPos != position) {
mPos = position
updateActionbarTitle()

View file

@ -72,6 +72,10 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
override fun getItemCount() = dirs.size
override fun prepareActionMode(menu: Menu) {
if (getSelectedPaths().isEmpty()) {
return
}
val selectedPaths = getSelectedPaths()
menu.apply {
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_pin -> pinFolders(true)
R.id.cab_unpin -> pinFolders(false)
R.id.cab_hide -> toggleFoldersVisibility(true)
R.id.cab_empty_recycle_bin -> emptyRecycleBin()
R.id.cab_empty_recycle_bin -> tryEmptyRecycleBin(true)
R.id.cab_empty_disable_recycle_bin -> emptyAndDisableRecycleBin()
R.id.cab_hide -> toggleFoldersVisibility(true)
R.id.cab_unhide -> toggleFoldersVisibility(false)
R.id.cab_exclude -> tryExcludeFolder()
R.id.cab_copy_to -> copyMoveTo(true)
@ -214,11 +218,19 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
}
}
private fun emptyRecycleBin() {
activity.showRecycleBinEmptyingDialog {
activity.emptyTheRecycleBin {
listener?.refreshItems()
private fun tryEmptyRecycleBin(askConfirmation: Boolean) {
if (askConfirmation) {
activity.showRecycleBinEmptyingDialog {
emptyRecycleBin()
}
} else {
emptyRecycleBin()
}
}
private fun emptyRecycleBin() {
activity.emptyTheRecycleBin {
listener?.refreshItems()
}
}
@ -285,7 +297,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
}
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) {
ExcludeFolderDialog(activity, paths.toMutableList()) {
listener?.refreshItems()
@ -346,21 +358,27 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
private fun askConfirmDelete() {
if (config.skipDeleteConfirmation) {
deleteFiles()
deleteFolders()
} else {
val itemsCnt = selectedPositions.size
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)
val warning = resources.getQuantityString(R.plurals.delete_warning, itemsCnt, itemsCnt)
question += "\n\n$warning"
ConfirmationDialog(activity, question) {
deleteFiles()
deleteFolders()
}
}
}
private fun deleteFiles() {
private fun deleteFolders() {
if (selectedPositions.isEmpty()) {
return
}
@ -380,17 +398,28 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
activity.handleSAFDialog(SAFPath) {
selectedPositions.sortedDescending().forEach {
val directory = dirs[it]
if (directory.areFavorites() || directory.isRecycleBin()) {
if (selectedPositions.size == 1) {
finishActMode()
val directory = dirs.getOrNull(it)
if (directory != null) {
if (directory.areFavorites() || directory.isRecycleBin()) {
if (directory.isRecycleBin()) {
tryEmptyRecycleBin(false)
} else {
Thread {
activity.galleryDB.MediumDao().clearFavorites()
listener?.refreshItems()
}.start()
}
if (selectedPositions.size == 1) {
finishActMode()
} else {
selectedPositions.remove(it)
toggleItemSelection(false, it)
}
} else {
selectedPositions.remove(it)
toggleItemSelection(false, it)
folders.add(File(directory.path))
removeFolders.add(directory)
}
} else {
folders.add(File(directory.path))
removeFolders.add(directory)
}
}
@ -436,14 +465,19 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
private fun getSelectedPaths(): HashSet<String> {
val paths = HashSet<String>(selectedPositions.size)
selectedPositions.forEach { paths.add(dirs[it].path) }
selectedPositions.forEach {
(dirs.getOrNull(it))?.apply {
paths.add(path)
}
}
return paths
}
fun updateDirs(newDirs: ArrayList<Directory>) {
if (newDirs.hashCode() != currentDirectoriesHash) {
currentDirectoriesHash = newDirs.hashCode()
dirs = newDirs
val directories = newDirs.clone() as ArrayList<Directory>
if (directories.hashCode() != currentDirectoriesHash) {
currentDirectoriesHash = directories.hashCode()
dirs = directories
notifyDataSetChanged()
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_open_with).isVisible = isOneItemSelected()
findItem(R.id.cab_confirm_selection).isVisible = isAGetIntent && allowMultiplePicks && selectedPositions.size > 0
findItem(R.id.cab_restore_recycle_bin_files).isVisible = getSelectedPaths().all { it.startsWith(activity.filesDir.toString()) }
findItem(R.id.cab_restore_recycle_bin_files).isVisible = getSelectedPaths().all { it.startsWith(activity.filesDir.absolutePath) }
checkHideBtnVisibility(this)
checkFavoriteBtnVisibility(this)
@ -289,7 +289,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
private fun askConfirmDelete() {
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 question = String.format(resources.getString(baseString), items)
DeleteWithRememberDialog(activity, question) {
@ -316,7 +316,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
val SAFPath = (media[selectedPositions.first()] as Medium).path
activity.handleSAFDialog(SAFPath) {
selectedPositions.sortedDescending().forEach {
val thumbnailItem = media[it]
val thumbnailItem = media.getOrNull(it)
if (thumbnailItem is Medium) {
fileDirItems.add(FileDirItem(thumbnailItem.path, thumbnailItem.name))
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>
fun updateMedia(newMedia: ArrayList<ThumbnailItem>) {
if (newMedia.hashCode() != currentMediaHash) {
currentMediaHash = newMedia.hashCode()
val thumbnailItems = newMedia.clone() as ArrayList<ThumbnailItem>
if (thumbnailItems.hashCode() != currentMediaHash) {
currentMediaHash = thumbnailItems.hashCode()
Handler().postDelayed({
media = newMedia
media = thumbnailItems
enableInstantLoad()
notifyDataSetChanged()
finishActMode()

View file

@ -5,7 +5,9 @@ import android.os.AsyncTask
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_TAKEN
import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.extensions.getFavoritePaths
import com.simplemobiletools.gallery.helpers.FAVORITES
import com.simplemobiletools.gallery.helpers.MediaFetcher
import com.simplemobiletools.gallery.helpers.RECYCLE_BIN
import com.simplemobiletools.gallery.helpers.SHOW_ALL
import com.simplemobiletools.gallery.models.Medium
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 favoritePaths = context.getFavoritePaths()
val media = if (showAll) {
val foldersToScan = mediaFetcher.getFoldersToScan()
val foldersToScan = mediaFetcher.getFoldersToScan().filter { it != RECYCLE_BIN && it != FAVORITES }
val media = ArrayList<Medium>()
foldersToScan.forEach {
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_toggle_visibility.isChecked = actions and BOTTOM_ACTION_TOGGLE_VISIBILITY != 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)
@ -60,6 +61,8 @@ class ManageBottomActionsDialog(val activity: BaseSimpleActivity, val callback:
result += BOTTOM_ACTION_TOGGLE_VISIBILITY
if (manage_bottom_actions_rename.isChecked)
result += BOTTOM_ACTION_RENAME
if (manage_bottom_actions_set_as.isChecked)
result += BOTTOM_ACTION_SET_AS
}
activity.config.visibleBottomActions = result

View file

@ -61,7 +61,7 @@ class PickDirectoryDialog(val activity: BaseSimpleActivity, val sourcePath: Stri
return
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) {
activity.toast(R.string.source_and_destination_same)
return@DirectoryAdapter

View file

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

View file

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

View file

@ -47,7 +47,9 @@ import java.io.File
import java.io.FileOutputStream
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 isFullscreen = false
private var wasInit = false
@ -55,6 +57,7 @@ class PhotoFragment : ViewPagerFragment() {
private var isPanorama = false
private var imageOrientation = -1
private var gifDrawable: GifDrawable? = null
private var loadZoomableViewHandler = Handler()
private var storedShowExtendedDetails = false
private var storedHideExtendedDetails = false
@ -184,7 +187,9 @@ class PhotoFragment : ViewPagerFragment() {
private fun photoFragmentVisibilityChanged(isVisible: Boolean) {
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 {
if (isFragmentVisible)
addZoomableView()
if (isFragmentVisible) {
scheduleZoomableView()
}
return false
}
}).into(view.photo_view)
@ -302,46 +308,53 @@ class PhotoFragment : ViewPagerFragment() {
}
}
private fun addZoomableView() {
if (!context!!.config.replaceZoomableImages && medium.isImage() && isFragmentVisible && view.subsampling_view.isGone()) {
ViewPagerActivity.wasDecodedByGlide = false
view.subsampling_view.apply {
maxScale = 10f
beVisible()
isQuickScaleEnabled = context.config.oneFingerZoom
setResetScaleOnSizeChange(context.config.screenRotation != ROTATE_BY_ASPECT_RATIO)
setImage(ImageSource.uri(getPathToLoad(medium)))
orientation = if (imageOrientation == -1) SubsamplingScaleImageView.ORIENTATION_USE_EXIF else degreesForRotation(imageOrientation)
setEagerLoadingEnabled(false)
setExecutor(AsyncTask.SERIAL_EXECUTOR)
setOnImageEventListener(object : SubsamplingScaleImageView.OnImageEventListener {
override fun onImageLoaded() {
}
override fun onReady() {
background = ColorDrawable(if (context.config.blackBackground) Color.BLACK else context.config.backgroundColor)
val useWidth = if (imageOrientation == ORIENTATION_ROTATE_90 || imageOrientation == ORIENTATION_ROTATE_270) sHeight else sWidth
val useHeight = if (imageOrientation == ORIENTATION_ROTATE_90 || imageOrientation == ORIENTATION_ROTATE_270) sWidth else sHeight
setDoubleTapZoomScale(getDoubleTapZoomScale(useWidth, useHeight))
}
override fun onTileLoadError(e: Exception?) {
}
override fun onPreviewReleased() {
}
override fun onImageLoadError(e: Exception) {
background = ColorDrawable(Color.TRANSPARENT)
beGone()
}
override fun onPreviewLoadError(e: Exception?) {
background = ColorDrawable(Color.TRANSPARENT)
beGone()
}
})
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() {
ViewPagerActivity.wasDecodedByGlide = false
view.subsampling_view.apply {
maxScale = 10f
beVisible()
isQuickScaleEnabled = context.config.oneFingerZoom
setResetScaleOnSizeChange(context.config.screenRotation != ROTATE_BY_ASPECT_RATIO)
setImage(ImageSource.uri(getPathToLoad(medium)))
orientation = if (imageOrientation == -1) SubsamplingScaleImageView.ORIENTATION_USE_EXIF else degreesForRotation(imageOrientation)
setEagerLoadingEnabled(false)
setExecutor(AsyncTask.SERIAL_EXECUTOR)
setOnImageEventListener(object : SubsamplingScaleImageView.OnImageEventListener {
override fun onImageLoaded() {
}
override fun onReady() {
background = ColorDrawable(if (context.config.blackBackground) Color.BLACK else context.config.backgroundColor)
val useWidth = if (imageOrientation == ORIENTATION_ROTATE_90 || imageOrientation == ORIENTATION_ROTATE_270) sHeight else sWidth
val useHeight = if (imageOrientation == ORIENTATION_ROTATE_90 || imageOrientation == ORIENTATION_ROTATE_270) sWidth else sHeight
setDoubleTapZoomScale(getDoubleTapZoomScale(useWidth, useHeight))
}
override fun onTileLoadError(e: Exception?) {
}
override fun onPreviewReleased() {
}
override fun onImageLoadError(e: Exception) {
background = ColorDrawable(Color.TRANSPARENT)
beGone()
}
override fun onPreviewLoadError(e: Exception?) {
background = ColorDrawable(Color.TRANSPARENT)
beGone()
}
})
}
}
@ -349,7 +362,7 @@ class PhotoFragment : ViewPagerFragment() {
isPanorama = try {
val inputStream = if (medium.path.startsWith("content:/")) context!!.contentResolver.openInputStream(Uri.parse(medium.path)) else File(medium.path).inputStream()
val imageParser = JpegImageParser().getXmpXml(ByteSourceInputStream(inputStream, medium.name), HashMap<String, Any>())
imageParser.contains("GPano:UsePanoramaViewer=\"True\"", true)
imageParser.contains("GPano:UsePanoramaViewer=\"True\"", true) || imageParser.contains("<GPano:UsePanoramaViewer>True</GPano:UsePanoramaViewer>", true)
} catch (e: Exception) {
false
}
@ -431,6 +444,7 @@ class PhotoFragment : ViewPagerFragment() {
Glide.with(context!!).clear(view.photo_view)
view.subsampling_view.recycle()
}
loadZoomableViewHandler.removeCallbacksAndMessages(null)
}
override fun onConfigurationChanged(newConfig: Configuration) {

View file

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

View file

@ -2,6 +2,7 @@ package com.simplemobiletools.gallery.helpers
import android.content.Context
import android.content.res.Configuration
import android.os.Environment
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
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
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()
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 GROUP_BY = "group_by"
const val EVER_SHOWN_FOLDERS = "ever_shown_folders"
const val SHOW_RECYCLE_BIN_AT_FOLDERS = "show_recycle_bin_at_folders"
// slideshow
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_TOGGLE_VISIBILITY = 512
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

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")
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: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
android:id="@+id/settings_customize_colors_holder"
android:layout_width="match_parent"
@ -1023,6 +1045,29 @@
</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
android:id="@+id/settings_empty_recycle_bin_holder"
android:layout_width="match_parent"

View file

@ -126,8 +126,19 @@
android:layout_height="wrap_content"
android:padding="@dimen/medium_margin"
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_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>

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: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>
</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_height="@dimen/play_outline_size_big"
android:layout_centerInParent="true"
android:background="@android:color/transparent"
android:padding="@dimen/big_margin"
android:background="@drawable/circle_black_background_with_inset"
android:padding="28dp"
android:src="@drawable/ic_panorama"
android:visibility="gone"/>

View file

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

View file

@ -5,33 +5,10 @@
android:id="@+id/save_as"
android:icon="@drawable/ic_check"
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"/>
<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
android:id="@+id/edit"
android:icon="@drawable/ic_edit"
android:title="@string/edit_with"
app:showAsAction="never"/>
app:showAsAction="ifRoom"/>
</menu>

View file

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

View file

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

View file

@ -88,13 +88,14 @@
<string name="flip_horizontally">قلب أفقيا</string>
<string name="flip_vertically">قلب عموديا</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 -->
<string name="simple_wallpaper">خلفية بسيطة</string>
<string name="set_as_wallpaper">تعيين كخلفية الشاشة</string>
<string name="set_as_wallpaper_failed">فشل الإعداد كخلفية</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="portrait_aspect_ratio">صورة نسبة العرض إلى الارتفاع</string>
<string name="landscape_aspect_ratio">نسبة العرض إلى الارتفاع في المناظر الطبيعية</string>
@ -157,6 +158,7 @@
<string name="hide_extended_details">إخفاء التفاصيل الموسعة عند إخفاء شريط الحالة</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_recycle_bin">Show the Recycle Bin at the folders screen</string>
<!-- Setting sections -->
<string name="thumbnails">المصغرات</string>

View file

@ -24,17 +24,17 @@
<string name="brightness">Brillantor</string>
<string name="lock_orientation">Bloquejar orientació</string>
<string name="unlock_orientation">Desbloquejar orientació</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<string name="change_orientation">Canviar orientació</string>
<string name="force_portrait">Forçar vertical</string>
<string name="force_landscape">Forçar horitzontal</string>
<string name="use_default_orientation">Fer servir la orientació per defecte</string>
<!-- Filter -->
<string name="filter_media">Filtre d\'arxius</string>
<string name="images">Imatges</string>
<string name="videos">Vídeos</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="change_filters_underlined"><u>Canviar filtres</u></string>
@ -84,6 +84,7 @@
<string name="flip_horizontally">Horizontalment</string>
<string name="flip_vertically">Verticalment</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 -->
<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="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="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 -->
<string name="thumbnails">Miniatures</string>
<string name="fullscreen_media">Mitjans a pantalla completa</string>
<string name="extended_details">Detalls estesos</string>
<string name="bottom_actions">Bottom actions</string>
<string name="bottom_actions">Accions de la part inferior</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<string name="manage_bottom_actions">Administra les accions de la part inferior</string>
<string name="toggle_favorite">Activa favorits</string>
<string name="toggle_file_visibility">Activa la visibilitat del fitxer</string>
<!-- FAQ -->
<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_10_title">Puc retallar imatges amb aquesta aplicació?</string>
<string name="faq_10_text">Sí, pots retallar imatges a l\'editor, arrossegant les cantonades de la imatge. Pots accedir a l\'editor prement una miniatura d\'imatge i seleccionant Edita o seleccionant Edita des de la visualització de pantalla completa.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<string name="faq_11_title">Puc agrupar d\'alguna manera les miniatures del fitxer multimèdia?</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 -->
<!-- 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_vertically">Překlopit svisle</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 -->
<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="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_recycle_bin">Show the Recycle Bin at the folders screen</string>
<!-- Setting sections -->
<string name="thumbnails">Thumbnails</string>

View file

@ -84,6 +84,7 @@
<string name="flip_horizontally">Spejlvend vandret</string>
<string name="flip_vertically">Spejlvend lodret</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 -->
<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="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_recycle_bin">Show the Recycle Bin at the folders screen</string>
<!-- Setting sections -->
<string name="thumbnails">Thumbnails</string>

View file

@ -25,9 +25,9 @@
<string name="lock_orientation">Bildschirmausrichtung sperren</string>
<string name="unlock_orientation">Bildschirmausrichtung entsperren</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<string name="force_portrait">Hochkant erzwingen</string>
<string name="force_landscape">Breitbild erzwingen</string>
<string name="use_default_orientation">Standard Ausrichtung benutzen</string>
<!-- Filter -->
<string name="filter_media">Filter</string>
@ -84,6 +84,7 @@
<string name="flip_horizontally">Horizontal spiegeln</string>
<string name="flip_vertically">Vertikal spiegeln</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 -->
<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="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_recycle_bin">Show the Recycle Bin at the folders screen</string>
<!-- Setting sections -->
<string name="thumbnails">Thumbnails</string>

View file

@ -84,6 +84,7 @@
<string name="flip_horizontally">Οριζόντιο αναποδογύρισμα</string>
<string name="flip_vertically">Κατακόρυφο αναποδογύρισμα</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 -->
<string name="simple_wallpaper">Simple Wallpaper</string>
@ -154,6 +155,7 @@
<string name="hide_extended_details">Απόκρυψη λεπτομερειών όταν η μπάρα κατάστασης είναι κρυμμένη</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_recycle_bin">Show the Recycle Bin at the folders screen</string>
<!-- Setting sections -->
<string name="thumbnails">Εικονίδια</string>

View file

@ -24,17 +24,17 @@
<string name="brightness">Brillo</string>
<string name="lock_orientation">Bloquear orientación</string>
<string name="unlock_orientation">Desbloquear orientación</string>
<string name="change_orientation">Change orientation</string>
<string name="force_portrait">Force portrait</string>
<string name="force_landscape">Force landscape</string>
<string name="use_default_orientation">Use default orientation</string>
<string name="change_orientation">Cambiar orientación</string>
<string name="force_portrait">Forzar retrato</string>
<string name="force_landscape">Forzar paisaje</string>
<string name="use_default_orientation">Usar la orientación por defecto</string>
<!-- Filter -->
<string name="filter_media">Filtro de medios</string>
<string name="images">Imágenes</string>
<string name="videos">Vídeos</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="change_filters_underlined"><u>Cambiar filtros</u></string>
@ -84,6 +84,7 @@
<string name="flip_horizontally">Horizontalmente</string>
<string name="flip_vertically">Verticalmente</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 -->
<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="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="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 -->
<string name="thumbnails">Miniaturas</string>
<string name="fullscreen_media">Medios a pantalla compelta</string>
<string name="extended_details">Detalles ampliados</string>
<string name="bottom_actions">Bottom actions</string>
<string name="bottom_actions">Acciones en la parte inferior</string>
<!-- Bottom actions -->
<string name="manage_bottom_actions">Manage visible bottom actions</string>
<string name="toggle_favorite">Toggle favorite</string>
<string name="toggle_file_visibility">Toggle file visibility</string>
<string name="manage_bottom_actions">Administrar los botones de la parte inferior</string>
<string name="toggle_favorite">Activar favoritos</string>
<string name="toggle_file_visibility">Activar visibilidad de fichero</string>
<!-- FAQ -->
<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_10_title">¿Puedo recortar imágenes con esta aplicación?</string>
<string name="faq_10_text">Sí, puede recortar imágenes en el editor arrastrando las esquinas de la imagen. Puede acceder al editor pulsando prolongadamente una imagen en miniatura y seleccionando Editar, o seleccionando Editar en la vista de pantalla completa.</string>
<string name="faq_11_title">Can I somehow group media file thumbnails?</string>
<string name="faq_11_text">Sure, just use the \"Group by\" menu item while at the thumbnails view. You can group files by multiple criteria, including Date Taken. If you use the \"Show all folders content\" function you can group them by folders too.</string>
<string name="faq_11_title">¿Puedo de alguna manera agrupar miniaturas de archivos multimedia?</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 -->
<!-- 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_vertically">Pyöräytä pystysuoraan</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 -->
<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="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_recycle_bin">Show the Recycle Bin at the folders screen</string>
<!-- Setting sections -->
<string name="thumbnails">Esikatselukuvat</string>

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