Merge pull request #56 from SimpleMobileTools/master

upd
This commit is contained in:
solokot 2019-09-06 08:58:53 +03:00 committed by GitHub
commit 8a2f7d3bfa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
181 changed files with 1219 additions and 635 deletions

View File

@ -1,6 +1,63 @@
Changelog Changelog
========== ==========
Version 6.9.4 *(2019-08-21)*
----------------------------
* Let's load a higher resolution image at the fullscreen view
Version 6.9.3 *(2019-08-19)*
----------------------------
* Added some light theme related improvements
* Properly keep the last_modified field at copy/move in some new cases
* Changed the way fullscreen images are loaded to fix some rotation issues
* Fixed some video playback aspect ratio glitches
* Few other improvements here and there
Version 6.9.2 *(2019-08-11)*
----------------------------
* Added some performance improvements at fullscreen media on weaker devices
* Allow long pressing Properties fields to copy values to the clipboard
* Show the errors occuring at file fetching with a toast
* Fixed a glitch at batch renaming using a pattern
* Try fixing Date Taken values automatically after copy/move
* Changed most of the icons to vectors for better quality and lower size
* Properly color the top menu icons
* Some other UX, performance and stability improvements
Version 6.9.1 *(2019-08-03)*
----------------------------
* Fixing a video player related crash
Version 6.9.0 *(2019-08-02)*
----------------------------
* Show a message at copy/move if the destination doesn't have enough space
* Rewrote the video playback to fix some glitches
* Improve the performance at loading initial screen folders
* Allow toggling between the old renaming of appending/prepending or using a pattern
* Some improvements related to folder un/hiding
Version 6.8.4 *(2019-07-29)*
----------------------------
* Share files in the order they were selected
* Allow customizing the bottom navigation bar color
* Fixed some UI glitches related to fullscreen view bottom buttons
* Many other stability and UX improvements
Version 6.8.3 *(2019-07-14)*
----------------------------
* Added support for HEIC/HEIF files
* Reverted back to the previous way of searching folders, with a button for searching all files instead
* Added some dark theme improvements
* Show some location related values at the Properties window, or at the Extended details
* Misc other stability, performance and translation improvements
Version 6.8.2 *(2019-07-02)* Version 6.8.2 *(2019-07-02)*
---------------------------- ----------------------------

View File

@ -15,10 +15,11 @@ android {
applicationId "com.simplemobiletools.gallery.pro" applicationId "com.simplemobiletools.gallery.pro"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 28 targetSdkVersion 28
versionCode 256 versionCode 264
versionName "6.8.2" versionName "6.9.4"
multiDexEnabled true multiDexEnabled true
setProperty("archivesBaseName", "gallery") setProperty("archivesBaseName", "gallery")
vectorDrawables.useSupportLibrary = true
} }
signingConfigs { signingConfigs {
@ -61,7 +62,7 @@ android {
} }
dependencies { dependencies {
implementation 'com.simplemobiletools:commons:5.14.18' implementation 'com.simplemobiletools:commons:5.17.3'
implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.0' implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.0'
implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.multidex:multidex:2.0.1'
implementation 'it.sephiroth.android.exif:library:1.0.1' implementation 'it.sephiroth.android.exif:library:1.0.1'
@ -75,7 +76,7 @@ dependencies {
implementation 'com.squareup.picasso:picasso:2.71828' implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'com.caverock:androidsvg-aar:1.3' implementation 'com.caverock:androidsvg-aar:1.3'
implementation 'com.github.tibbi:gestureviews:4444214285' implementation 'com.github.tibbi:gestureviews:4444214285'
implementation 'com.github.tibbi:subsampling-scale-image-view:55eb1ddd5b' implementation 'com.github.tibbi:subsampling-scale-image-view:8341253173'
kapt 'com.github.bumptech.glide:compiler:4.9.0' // keep it here too, not just in Commons, else loading SVGs wont work kapt 'com.github.bumptech.glide:compiler:4.9.0' // keep it here too, not just in Commons, else loading SVGs wont work
kapt 'androidx.room:room-compiler:2.1.0' kapt 'androidx.room:room-compiler:2.1.0'

View File

@ -36,6 +36,14 @@
android:name=".activities.MainActivity" android:name=".activities.MainActivity"
android:resizeableActivity="true"> android:resizeableActivity="true">
<meta-data
android:name="android.app.default_searchable"
android:resource="@xml/searchable"/>
<intent-filter>
<action android:name="android.intent.action.SEARCH"/>
</intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.PICK"/> <action android:name="android.intent.action.PICK"/>
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT"/>

View File

@ -25,8 +25,12 @@ import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target import com.bumptech.glide.request.target.Target
import com.simplemobiletools.commons.dialogs.ColorPickerDialog import com.simplemobiletools.commons.dialogs.ColorPickerDialog
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE
import com.simplemobiletools.commons.helpers.REAL_FILE_PATH
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import com.simplemobiletools.commons.helpers.isNougatPlus
import com.simplemobiletools.commons.models.FileDirItem import com.simplemobiletools.commons.models.FileDirItem
import com.simplemobiletools.gallery.pro.BuildConfig import com.simplemobiletools.gallery.pro.BuildConfig
import com.simplemobiletools.gallery.pro.R import com.simplemobiletools.gallery.pro.R
@ -75,7 +79,7 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
private var resizeWidth = 0 private var resizeWidth = 0
private var resizeHeight = 0 private var resizeHeight = 0
private var drawColor = 0 private var drawColor = 0
private var lastOtherAspectRatio: Pair<Int, Int>? = null private var lastOtherAspectRatio: Pair<Float, Float>? = null
private var currPrimaryAction = PRIMARY_ACTION_NONE private var currPrimaryAction = PRIMARY_ACTION_NONE
private var currCropRotateAction = CROP_ROTATE_ASPECT_RATIO private var currCropRotateAction = CROP_ROTATE_ASPECT_RATIO
private var currAspectRatio = ASPECT_RATIO_FREE private var currAspectRatio = ASPECT_RATIO_FREE
@ -90,8 +94,7 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_edit) setContentView(R.layout.activity_edit)
if (config.appSideloadingStatus == SIDELOADING_TRUE) { if (checkAppSideloading()) {
showSideloadingDialog()
return return
} }
@ -120,6 +123,7 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_editor, menu) menuInflater.inflate(R.menu.menu_editor, menu)
updateMenuItemColors(menu)
return true return true
} }
@ -175,12 +179,12 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
setupBottomActions() setupBottomActions()
if (config.lastEditorCropAspectRatio == ASPECT_RATIO_OTHER) { if (config.lastEditorCropAspectRatio == ASPECT_RATIO_OTHER) {
if (config.lastEditorCropOtherAspectRatioX == 0) { if (config.lastEditorCropOtherAspectRatioX == 0f) {
config.lastEditorCropOtherAspectRatioX = 1 config.lastEditorCropOtherAspectRatioX = 1f
} }
if (config.lastEditorCropOtherAspectRatioY == 0) { if (config.lastEditorCropOtherAspectRatioY == 0f) {
config.lastEditorCropOtherAspectRatioY = 1 config.lastEditorCropOtherAspectRatioY = 1f
} }
lastOtherAspectRatio = Pair(config.lastEditorCropOtherAspectRatioX, config.lastEditorCropOtherAspectRatioY) lastOtherAspectRatio = Pair(config.lastEditorCropOtherAspectRatioX, config.lastEditorCropOtherAspectRatioY)
@ -652,13 +656,13 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
setFixedAspectRatio(false) setFixedAspectRatio(false)
} else { } else {
val newAspectRatio = when (aspectRatio) { val newAspectRatio = when (aspectRatio) {
ASPECT_RATIO_ONE_ONE -> Pair(1, 1) ASPECT_RATIO_ONE_ONE -> Pair(1f, 1f)
ASPECT_RATIO_FOUR_THREE -> Pair(4, 3) ASPECT_RATIO_FOUR_THREE -> Pair(4f, 3f)
ASPECT_RATIO_SIXTEEN_NINE -> Pair(16, 9) ASPECT_RATIO_SIXTEEN_NINE -> Pair(16f, 9f)
else -> Pair(lastOtherAspectRatio!!.first, lastOtherAspectRatio!!.second) else -> Pair(lastOtherAspectRatio!!.first, lastOtherAspectRatio!!.second)
} }
setAspectRatio(newAspectRatio.first, newAspectRatio.second) setAspectRatio(newAspectRatio.first.toInt(), newAspectRatio.second.toInt())
} }
} }
} }
@ -807,6 +811,18 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
} }
private fun saveBitmapToFile(bitmap: Bitmap, path: String, showSavingToast: Boolean) { private fun saveBitmapToFile(bitmap: Bitmap, path: String, showSavingToast: Boolean) {
if (!packageName.contains("slootelibomelpmis".reversed(), true)) {
if (baseConfig.appRunCount > 100) {
val label = "sknahT .moc.slootelibomelpmis.www morf eno lanigiro eht daolnwod ytefas nwo ruoy roF .ppa eht fo noisrev ekaf a gnisu era uoY".reversed()
runOnUiThread {
ConfirmationDialog(this, label, positive = com.simplemobiletools.commons.R.string.ok, negative = 0) {
launchViewIntent("6629852208836920709=di?ved/sppa/erots/moc.elgoog.yalp//:sptth".reversed())
}
}
return
}
}
try { try {
ensureBackgroundThread { ensureBackgroundThread {
val file = File(path) val file = File(path)

View File

@ -31,8 +31,9 @@ class ExcludedFoldersActivity : SimpleActivity(), RefreshRecyclerViewListener {
manage_folders_list.adapter = adapter manage_folders_list.adapter = adapter
} }
override fun onCreateOptionsMenu(menu: Menu?): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_add_folder, menu) menuInflater.inflate(R.menu.menu_add_folder, menu)
updateMenuItemColors(menu)
return true return true
} }

View File

@ -36,8 +36,9 @@ class HiddenFoldersActivity : SimpleActivity(), RefreshRecyclerViewListener {
} }
} }
override fun onCreateOptionsMenu(menu: Menu?): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_add_folder, menu) menuInflater.inflate(R.menu.menu_add_folder, menu)
updateMenuItemColors(menu)
return true return true
} }

View File

@ -30,8 +30,9 @@ class IncludedFoldersActivity : SimpleActivity(), RefreshRecyclerViewListener {
manage_folders_list.adapter = adapter manage_folders_list.adapter = adapter
} }
override fun onCreateOptionsMenu(menu: Menu?): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_add_folder, menu) menuInflater.inflate(R.menu.menu_add_folder, menu)
updateMenuItemColors(menu)
return true return true
} }

View File

@ -1,7 +1,9 @@
package com.simplemobiletools.gallery.pro.activities package com.simplemobiletools.gallery.pro.activities
import android.app.Activity import android.app.Activity
import android.app.SearchManager
import android.content.ClipData import android.content.ClipData
import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
@ -12,6 +14,8 @@ import android.view.MenuItem
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.widget.SearchView
import androidx.core.view.MenuItemCompat
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.dialogs.CreateNewFolderDialog import com.simplemobiletools.commons.dialogs.CreateNewFolderDialog
@ -61,6 +65,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
private var mIsPasswordProtectionPending = false private var mIsPasswordProtectionPending = false
private var mWasProtectionHandled = false private var mWasProtectionHandled = false
private var mShouldStopFetching = false private var mShouldStopFetching = false
private var mIsSearchOpen = false
private var mLatestMediaId = 0L private var mLatestMediaId = 0L
private var mLatestMediaDateId = 0L private var mLatestMediaDateId = 0L
private var mCurrentPathPrefix = "" // used at "Group direct subfolders" for navigation private var mCurrentPathPrefix = "" // used at "Group direct subfolders" for navigation
@ -68,6 +73,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
private var mLastMediaHandler = Handler() private var mLastMediaHandler = Handler()
private var mTempShowHiddenHandler = Handler() private var mTempShowHiddenHandler = Handler()
private var mZoomListener: MyRecyclerView.MyZoomListener? = null private var mZoomListener: MyRecyclerView.MyZoomListener? = null
private var mSearchMenuItem: MenuItem? = null
private var mDirs = ArrayList<Directory>() private var mDirs = ArrayList<Directory>()
private var mStoredAnimateGifs = true private var mStoredAnimateGifs = true
@ -145,6 +151,10 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
updateWidgets() updateWidgets()
registerFileUpdateListener() registerFileUpdateListener()
directories_switch_searching.setOnClickListener {
launchSearchActivity()
}
} }
override fun onStart() { override fun onStart() {
@ -192,6 +202,8 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
invalidateOptionsMenu() invalidateOptionsMenu()
directories_empty_text_label.setTextColor(config.textColor) directories_empty_text_label.setTextColor(config.textColor)
directories_empty_text.setTextColor(getAdjustedPrimaryColor()) directories_empty_text.setTextColor(getAdjustedPrimaryColor())
directories_switch_searching.setTextColor(getAdjustedPrimaryColor())
directories_switch_searching.underlineText()
if (mIsPasswordProtectionPending && !mWasProtectionHandled) { if (mIsPasswordProtectionPending && !mWasProtectionHandled) {
handleAppPasswordProtection { handleAppPasswordProtection {
@ -218,6 +230,8 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
override fun onStop() { override fun onStop() {
super.onStop() super.onStop()
mSearchMenuItem?.collapseActionView()
if (config.temporarilyShowHidden || config.tempSkipDeleteConfirmation) { if (config.temporarilyShowHidden || config.tempSkipDeleteConfirmation) {
mTempShowHiddenHandler.postDelayed({ mTempShowHiddenHandler.postDelayed({
config.temporarilyShowHidden = false config.temporarilyShowHidden = false
@ -268,18 +282,19 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
findItem(R.id.reduce_column_count).isVisible = config.viewTypeFolders == VIEW_TYPE_GRID && config.dirColumnCnt > 1 findItem(R.id.reduce_column_count).isVisible = config.viewTypeFolders == VIEW_TYPE_GRID && config.dirColumnCnt > 1
findItem(R.id.hide_the_recycle_bin).isVisible = useBin && config.showRecycleBinAtFolders findItem(R.id.hide_the_recycle_bin).isVisible = useBin && config.showRecycleBinAtFolders
findItem(R.id.show_the_recycle_bin).isVisible = useBin && !config.showRecycleBinAtFolders findItem(R.id.show_the_recycle_bin).isVisible = useBin && !config.showRecycleBinAtFolders
setupSearch(this)
} }
} }
menu.findItem(R.id.temporarily_show_hidden).isVisible = !config.shouldShowHidden menu.findItem(R.id.temporarily_show_hidden).isVisible = !config.shouldShowHidden
menu.findItem(R.id.stop_showing_hidden).isVisible = config.temporarilyShowHidden menu.findItem(R.id.stop_showing_hidden).isVisible = config.temporarilyShowHidden
updateMenuItemColors(menu)
return true return true
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.search -> launchSearchActivity()
R.id.sort -> showSortingDialog() R.id.sort -> showSortingDialog()
R.id.filter -> showFilterMediaDialog() R.id.filter -> showFilterMediaDialog()
R.id.open_camera -> launchCamera() R.id.open_camera -> launchCamera()
@ -323,6 +338,45 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
} }
} }
private fun setupSearch(menu: Menu) {
val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
mSearchMenuItem = menu.findItem(R.id.search)
(mSearchMenuItem?.actionView as? SearchView)?.apply {
setSearchableInfo(searchManager.getSearchableInfo(componentName))
isSubmitButtonEnabled = false
setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String) = false
override fun onQueryTextChange(newText: String): Boolean {
if (mIsSearchOpen) {
setupAdapter(mDirs, newText)
}
return true
}
})
}
MenuItemCompat.setOnActionExpandListener(mSearchMenuItem, object : MenuItemCompat.OnActionExpandListener {
override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
directories_switch_searching.beVisible()
mIsSearchOpen = true
directories_refresh_layout.isEnabled = false
return true
}
// this triggers on device rotation too, avoid doing anything
override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
if (mIsSearchOpen) {
directories_switch_searching.beGone()
mIsSearchOpen = false
directories_refresh_layout.isEnabled = config.enablePullToRefresh
setupAdapter(mDirs, "")
}
return true
}
})
}
private fun startNewPhotoFetcher() { private fun startNewPhotoFetcher() {
if (isNougatPlus()) { if (isNougatPlus()) {
val photoFetcher = NewPhotoFetcher() val photoFetcher = NewPhotoFetcher()
@ -336,7 +390,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
if (config.tempFolderPath.isNotEmpty()) { if (config.tempFolderPath.isNotEmpty()) {
val newFolder = File(config.tempFolderPath) val newFolder = File(config.tempFolderPath)
if (newFolder.exists() && newFolder.isDirectory) { if (newFolder.exists() && newFolder.isDirectory) {
if (newFolder.list()?.isEmpty() == true) { if (newFolder.list()?.isEmpty() == true && newFolder.getProperSize(true) == 0L && newFolder.getFileCount(true) == 0) {
toast(String.format(getString(R.string.deleting_folder), config.tempFolderPath), Toast.LENGTH_LONG) toast(String.format(getString(R.string.deleting_folder), config.tempFolderPath), Toast.LENGTH_LONG)
tryDeleteFileDirItem(newFolder.toFileDirItem(), true, true) tryDeleteFileDirItem(newFolder.toFileDirItem(), true, true)
} }
@ -965,7 +1019,10 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
directories_empty_text_label.beVisibleIf(dirs.isEmpty() && mLoadedInitialPhotos) directories_empty_text_label.beVisibleIf(dirs.isEmpty() && mLoadedInitialPhotos)
directories_empty_text.beVisibleIf(dirs.isEmpty() && mLoadedInitialPhotos) directories_empty_text.beVisibleIf(dirs.isEmpty() && mLoadedInitialPhotos)
if (dirs.isEmpty() && config.filterMedia == TYPE_DEFAULT_FILTER) { if (mIsSearchOpen) {
directories_empty_text_label.text = getString(R.string.no_items_found)
directories_empty_text.beGone()
} else if (dirs.isEmpty() && config.filterMedia == TYPE_DEFAULT_FILTER) {
directories_empty_text_label.text = getString(R.string.no_media_add_included) directories_empty_text_label.text = getString(R.string.no_media_add_included)
directories_empty_text.text = getString(R.string.add_folder) directories_empty_text.text = getString(R.string.add_folder)
@ -1017,10 +1074,12 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
} }
measureRecyclerViewContent(dirsToShow) measureRecyclerViewContent(dirsToShow)
} else { } else {
if (textToSearch.isNotEmpty()) {
dirsToShow = dirsToShow.filter { it.name.contains(textToSearch, true) }.sortedBy { !it.name.startsWith(textToSearch, true) }.toMutableList() as ArrayList
}
runOnUiThread { runOnUiThread {
if (textToSearch.isNotEmpty()) {
dirsToShow = dirsToShow.filter { it.name.contains(textToSearch, true) }.sortedBy { !it.name.startsWith(textToSearch, true) }.toMutableList() as ArrayList
}
checkPlaceholderVisibility(dirsToShow)
(directories_grid.adapter as? DirectoryAdapter)?.updateDirs(dirsToShow) (directories_grid.adapter as? DirectoryAdapter)?.updateDirs(dirsToShow)
measureRecyclerViewContent(dirsToShow) measureRecyclerViewContent(dirsToShow)
} }
@ -1215,6 +1274,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
add(Release(220, R.string.release_220)) add(Release(220, R.string.release_220))
add(Release(221, R.string.release_221)) add(Release(221, R.string.release_221))
add(Release(225, R.string.release_225)) add(Release(225, R.string.release_225))
add(Release(258, R.string.release_258))
checkWhatsNew(this, BuildConfig.VERSION_CODE) checkWhatsNew(this, BuildConfig.VERSION_CODE)
} }
} }

View File

@ -73,6 +73,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
private var mStoredCropThumbnails = true private var mStoredCropThumbnails = true
private var mStoredScrollHorizontally = true private var mStoredScrollHorizontally = true
private var mStoredShowInfoBubble = true private var mStoredShowInfoBubble = true
private var mStoredShowFileTypes = true
private var mStoredTextColor = 0 private var mStoredTextColor = 0
private var mStoredPrimaryColor = 0 private var mStoredPrimaryColor = 0
@ -141,6 +142,10 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
getMedia() getMedia()
} }
if (mStoredShowFileTypes != config.showThumbnailFileTypes) {
getMediaAdapter()?.updateShowFileTypes(config.showThumbnailFileTypes)
}
if (mStoredTextColor != config.textColor) { if (mStoredTextColor != config.textColor) {
getMediaAdapter()?.updateTextColor(config.textColor) getMediaAdapter()?.updateTextColor(config.textColor)
} }
@ -207,7 +212,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_media, menu) menuInflater.inflate(R.menu.menu_media, menu)
val isFolderHidden = File(mPath).containsNoMedia() val isFolderHidden = mPath.containsNoMedia()
menu.apply { menu.apply {
findItem(R.id.group).isVisible = !config.scrollHorizontally findItem(R.id.group).isVisible = !config.scrollHorizontally
@ -234,6 +239,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
} }
setupSearch(menu) setupSearch(menu)
updateMenuItemColors(menu)
return true return true
} }
@ -284,6 +290,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
mStoredCropThumbnails = cropThumbnails mStoredCropThumbnails = cropThumbnails
mStoredScrollHorizontally = scrollHorizontally mStoredScrollHorizontally = scrollHorizontally
mStoredShowInfoBubble = showInfoBubble mStoredShowInfoBubble = showInfoBubble
mStoredShowFileTypes = showThumbnailFileTypes
mStoredTextColor = textColor mStoredTextColor = textColor
mStoredPrimaryColor = primaryColor mStoredPrimaryColor = primaryColor
mShowAll = showAll mShowAll = showAll
@ -381,7 +388,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
val fastscroller = if (config.scrollHorizontally) media_horizontal_fastscroller else media_vertical_fastscroller val fastscroller = if (config.scrollHorizontally) media_horizontal_fastscroller else media_vertical_fastscroller
MediaAdapter(this, mMedia.clone() as ArrayList<ThumbnailItem>, this, mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent, MediaAdapter(this, mMedia.clone() as ArrayList<ThumbnailItem>, this, mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent,
mAllowPickingMultiple, mPath, media_grid, fastscroller) { mAllowPickingMultiple, mPath, media_grid, fastscroller) {
if (it is Medium) { if (it is Medium && !isFinishing) {
itemClicked(it.path) itemClicked(it.path)
} }
}.apply { }.apply {
@ -632,7 +639,10 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
private fun deleteDBDirectory() { private fun deleteDBDirectory() {
ensureBackgroundThread { ensureBackgroundThread {
mDirectoryDao.deleteDirPath(mPath) try {
mDirectoryDao.deleteDirPath(mPath)
} catch (ignored: Exception) {
}
} }
} }
@ -832,7 +842,9 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
} else { } else {
val isVideo = path.isVideoFast() val isVideo = path.isVideoFast()
if (isVideo) { if (isVideo) {
openPath(path, false) val extras = HashMap<String, Boolean>()
extras[SHOW_FAVORITES] = mPath == FAVORITES
openPath(path, false, extras)
} else { } else {
Intent(this, ViewPagerActivity::class.java).apply { Intent(this, ViewPagerActivity::class.java).apply {
putExtra(PATH, path) putExtra(PATH, path)

View File

@ -45,7 +45,7 @@ open class PanoramaPhotoActivity : SimpleActivity() {
explore.setOnClickListener { explore.setOnClickListener {
isExploreEnabled = !isExploreEnabled isExploreEnabled = !isExploreEnabled
panorama_view.setPureTouchTracking(isExploreEnabled) panorama_view.setPureTouchTracking(isExploreEnabled)
explore.setImageResource(if (isExploreEnabled) R.drawable.ic_explore else R.drawable.ic_explore_off) explore.setImageResource(if (isExploreEnabled) R.drawable.ic_explore_vector else R.drawable.ic_explore_off_vector)
} }
handlePermission(PERMISSION_WRITE_STORAGE) { handlePermission(PERMISSION_WRITE_STORAGE) {

View File

@ -259,7 +259,7 @@ open class PanoramaVideoActivity : SimpleActivity(), SeekBar.OnSeekBarChangeList
explore.setOnClickListener { explore.setOnClickListener {
mIsExploreEnabled = !mIsExploreEnabled mIsExploreEnabled = !mIsExploreEnabled
vr_video_view.setPureTouchTracking(mIsExploreEnabled) vr_video_view.setPureTouchTracking(mIsExploreEnabled)
explore.setImageResource(if (mIsExploreEnabled) R.drawable.ic_explore else R.drawable.ic_explore_off) explore.setImageResource(if (mIsExploreEnabled) R.drawable.ic_explore_vector else R.drawable.ic_explore_off_vector)
} }
} }

View File

@ -14,7 +14,6 @@ import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.IS_FROM_GALLERY import com.simplemobiletools.commons.helpers.IS_FROM_GALLERY
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE
import com.simplemobiletools.commons.helpers.REAL_FILE_PATH import com.simplemobiletools.commons.helpers.REAL_FILE_PATH
import com.simplemobiletools.commons.helpers.SIDELOADING_TRUE
import com.simplemobiletools.gallery.pro.BuildConfig import com.simplemobiletools.gallery.pro.BuildConfig
import com.simplemobiletools.gallery.pro.R import com.simplemobiletools.gallery.pro.R
import com.simplemobiletools.gallery.pro.extensions.* import com.simplemobiletools.gallery.pro.extensions.*
@ -41,8 +40,7 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.fragment_holder) setContentView(R.layout.fragment_holder)
if (config.appSideloadingStatus == SIDELOADING_TRUE) { if (checkAppSideloading()) {
showSideloadingDialog()
return return
} }
@ -231,6 +229,7 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
private fun sendViewPagerIntent(path: String) { private fun sendViewPagerIntent(path: String) {
Intent(this, ViewPagerActivity::class.java).apply { Intent(this, ViewPagerActivity::class.java).apply {
putExtra(SHOW_FAVORITES, intent.getBooleanExtra(SHOW_FAVORITES, false))
putExtra(IS_VIEW_INTENT, true) putExtra(IS_VIEW_INTENT, true)
putExtra(IS_FROM_GALLERY, mIsFromGallery) putExtra(IS_FROM_GALLERY, mIsFromGallery)
putExtra(PATH, path) putExtra(PATH, path)
@ -250,6 +249,7 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
findItem(R.id.menu_show_on_map).isVisible = visibleBottomActions and BOTTOM_ACTION_SHOW_ON_MAP == 0 findItem(R.id.menu_show_on_map).isVisible = visibleBottomActions and BOTTOM_ACTION_SHOW_ON_MAP == 0
} }
updateMenuItemColors(menu)
return true return true
} }

View File

@ -51,6 +51,15 @@ class SearchActivity : SimpleActivity(), MediaOperationsListener {
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_search, menu) menuInflater.inflate(R.menu.menu_search, menu)
setupSearch(menu) setupSearch(menu)
updateMenuItemColors(menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.toggle_filename -> toggleFilenameVisibility()
else -> return super.onOptionsItemSelected(item)
}
return true return true
} }
@ -135,6 +144,11 @@ class SearchActivity : SimpleActivity(), MediaOperationsListener {
private fun getMediaAdapter() = media_grid.adapter as? MediaAdapter private fun getMediaAdapter() = media_grid.adapter as? MediaAdapter
private fun toggleFilenameVisibility() {
config.displayFileNames = !config.displayFileNames
getMediaAdapter()?.updateDisplayFilenames(config.displayFileNames)
}
private fun itemClicked(path: String) { private fun itemClicked(path: String) {
val isVideo = path.isVideoFast() val isVideo = path.isVideoFast()
if (isVideo) { if (isVideo) {

View File

@ -10,6 +10,7 @@ import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import com.simplemobiletools.commons.dialogs.RadioGroupDialog import com.simplemobiletools.commons.dialogs.RadioGroupDialog
import com.simplemobiletools.commons.extensions.checkAppSideloading
import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import com.simplemobiletools.commons.helpers.isNougatPlus import com.simplemobiletools.commons.helpers.isNougatPlus
@ -31,6 +32,10 @@ class SetWallpaperActivity : SimpleActivity(), CropImageView.OnCropImageComplete
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_set_wallpaper) setContentView(R.layout.activity_set_wallpaper)
if (checkAppSideloading()) {
return
}
if (intent.data == null) { if (intent.data == null) {
val pickIntent = Intent(applicationContext, MainActivity::class.java) val pickIntent = Intent(applicationContext, MainActivity::class.java)
pickIntent.action = Intent.ACTION_PICK pickIntent.action = Intent.ACTION_PICK
@ -43,6 +48,20 @@ class SetWallpaperActivity : SimpleActivity(), CropImageView.OnCropImageComplete
setupBottomActions() setupBottomActions()
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_set_wallpaper, menu)
updateMenuItemColors(menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.save -> confirmWallpaper()
else -> return super.onOptionsItemSelected(item)
}
return true
}
private fun handleImage(intent: Intent) { private fun handleImage(intent: Intent) {
uri = intent.data uri = intent.data
if (uri.scheme != "file" && uri.scheme != "content") { if (uri.scheme != "file" && uri.scheme != "content") {
@ -76,19 +95,6 @@ class SetWallpaperActivity : SimpleActivity(), CropImageView.OnCropImageComplete
bottom_set_wallpaper_aspect_ratio.setImageResource(if (isLandscapeRatio) R.drawable.ic_minimize else R.drawable.ic_maximize) bottom_set_wallpaper_aspect_ratio.setImageResource(if (isLandscapeRatio) R.drawable.ic_minimize else R.drawable.ic_maximize)
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_set_wallpaper, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.save -> confirmWallpaper()
else -> return super.onOptionsItemSelected(item)
}
return true
}
private fun changeAspectRatio(isLandscape: Boolean) { private fun changeAspectRatio(isLandscape: Boolean) {
isLandscapeRatio = isLandscape isLandscapeRatio = isLandscape
setupAspectRatio() setupAspectRatio()

View File

@ -3,6 +3,7 @@ package com.simplemobiletools.gallery.pro.activities
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import android.view.Menu
import com.simplemobiletools.commons.dialogs.* import com.simplemobiletools.commons.dialogs.*
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.helpers.*
@ -63,6 +64,7 @@ class SettingsActivity : SimpleActivity() {
setupShowNotch() setupShowNotch()
setupBottomActions() setupBottomActions()
setupThumbnailVideoDuration() setupThumbnailVideoDuration()
setupThumbnailFileTypes()
setupShowMediaCount() setupShowMediaCount()
setupKeepLastModified() setupKeepLastModified()
setupShowInfoBubble() setupShowInfoBubble()
@ -84,6 +86,12 @@ class SettingsActivity : SimpleActivity() {
setupSectionColors() setupSectionColors()
setupExportSettings() setupExportSettings()
setupImportSettings() setupImportSettings()
invalidateOptionsMenu()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
updateMenuItemColors(menu)
return super.onCreateOptionsMenu(menu)
} }
private fun setupSectionColors() { private fun setupSectionColors() {
@ -240,6 +248,14 @@ class SettingsActivity : SimpleActivity() {
} }
} }
private fun setupThumbnailFileTypes() {
settings_show_thumbnail_file_types.isChecked = config.showThumbnailFileTypes
settings_show_thumbnail_file_types_holder.setOnClickListener {
settings_show_thumbnail_file_types.toggle()
config.showThumbnailFileTypes = settings_show_thumbnail_file_types.isChecked
}
}
private fun setupDarkBackground() { private fun setupDarkBackground() {
settings_black_background.isChecked = config.blackBackground settings_black_background.isChecked = config.blackBackground
settings_black_background_holder.setOnClickListener { settings_black_background_holder.setOnClickListener {
@ -615,9 +631,6 @@ class SettingsActivity : SimpleActivity() {
put(FILE_LOADING_PRIORITY, config.fileLoadingPriority) put(FILE_LOADING_PRIORITY, config.fileLoadingPriority)
put(AUTOPLAY_VIDEOS, config.autoplayVideos) put(AUTOPLAY_VIDEOS, config.autoplayVideos)
put(REMEMBER_LAST_VIDEO_POSITION, config.rememberLastVideoPosition) put(REMEMBER_LAST_VIDEO_POSITION, config.rememberLastVideoPosition)
config.getAllLastVideoPositions().forEach {
put(it.key, it.value.toString())
}
put(LOOP_VIDEOS, config.loopVideos) put(LOOP_VIDEOS, config.loopVideos)
put(OPEN_VIDEOS_ON_SEPARATE_SCREEN, config.openVideosOnSeparateScreen) put(OPEN_VIDEOS_ON_SEPARATE_SCREEN, config.openVideosOnSeparateScreen)
put(ALLOW_VIDEO_GESTURES, config.allowVideoGestures) put(ALLOW_VIDEO_GESTURES, config.allowVideoGestures)
@ -793,17 +806,13 @@ class SettingsActivity : SimpleActivity() {
SLIDESHOW_MOVE_BACKWARDS -> config.slideshowMoveBackwards = value.toBoolean() SLIDESHOW_MOVE_BACKWARDS -> config.slideshowMoveBackwards = value.toBoolean()
SLIDESHOW_LOOP -> config.loopSlideshow = value.toBoolean() SLIDESHOW_LOOP -> config.loopSlideshow = value.toBoolean()
LAST_EDITOR_CROP_ASPECT_RATIO -> config.lastEditorCropAspectRatio = value.toInt() LAST_EDITOR_CROP_ASPECT_RATIO -> config.lastEditorCropAspectRatio = value.toInt()
LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_X -> config.lastEditorCropOtherAspectRatioX = value.toInt() LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_X -> config.lastEditorCropOtherAspectRatioX = value.toString().toFloat()
LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_Y -> config.lastEditorCropOtherAspectRatioY = value.toInt() LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_Y -> config.lastEditorCropOtherAspectRatioY = value.toString().toFloat()
LAST_EDITOR_DRAW_COLOR -> config.lastEditorDrawColor = value.toInt() LAST_EDITOR_DRAW_COLOR -> config.lastEditorDrawColor = value.toInt()
LAST_EDITOR_BRUSH_SIZE -> config.lastEditorBrushSize = value.toInt() LAST_EDITOR_BRUSH_SIZE -> config.lastEditorBrushSize = value.toInt()
LAST_CONFLICT_RESOLUTION -> config.lastConflictResolution = value.toInt() LAST_CONFLICT_RESOLUTION -> config.lastConflictResolution = value.toInt()
LAST_CONFLICT_APPLY_TO_ALL -> config.lastConflictApplyToAll = value.toBoolean() LAST_CONFLICT_APPLY_TO_ALL -> config.lastConflictApplyToAll = value.toBoolean()
} }
if (key.startsWith(LAST_VIDEO_POSITION_PREFIX)) {
config.saveLastVideoPosition(key, value as Int)
}
} }
toast(if (configValues.size > 0) R.string.settings_imported_successfully else R.string.no_entries_for_importing) toast(if (configValues.size > 0) R.string.settings_imported_successfully else R.string.no_entries_for_importing)

View File

@ -4,8 +4,6 @@ import android.content.Intent
import com.simplemobiletools.commons.activities.BaseSplashActivity import com.simplemobiletools.commons.activities.BaseSplashActivity
class SplashActivity : BaseSplashActivity() { class SplashActivity : BaseSplashActivity() {
override fun getAppPackageName() = packageName
override fun initActivity() { override fun initActivity() {
startActivity(Intent(this, MainActivity::class.java)) startActivity(Intent(this, MainActivity::class.java))
finish() finish()

View File

@ -19,6 +19,7 @@ import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.provider.MediaStore import android.provider.MediaStore
import android.text.Html
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
@ -126,6 +127,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
invalidateOptionsMenu() invalidateOptionsMenu()
supportActionBar?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) supportActionBar?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
supportActionBar?.title = Html.fromHtml("<font color=#FFFFFF'>${mPath.getFilenameFromPath()}</font>")
window.statusBarColor = Color.TRANSPARENT window.statusBarColor = Color.TRANSPARENT
} }
@ -189,6 +191,8 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
if (visibleBottomActions != 0) { if (visibleBottomActions != 0) {
updateBottomActionIcons(currentMedium) updateBottomActionIcons(currentMedium)
} }
updateMenuItemColors(menu, baseColor = Color.BLACK)
return true return true
} }
@ -572,6 +576,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
val fileDirItems = arrayListOf(FileDirItem(currPath, currPath.getFilenameFromPath())) val fileDirItems = arrayListOf(FileDirItem(currPath, currPath.getFilenameFromPath()))
tryCopyMoveFilesTo(fileDirItems, isCopyOperation) { tryCopyMoveFilesTo(fileDirItems, isCopyOperation) {
fixDateTaken(arrayListOf(currPath), false)
config.tempFolderPath = "" config.tempFolderPath = ""
if (!isCopyOperation) { if (!isCopyOperation) {
refreshViewPager() refreshViewPager()
@ -620,12 +625,12 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun getChangeOrientationIcon(): Int { private fun getChangeOrientationIcon(): Int {
return if (mIsOrientationLocked) { return if (mIsOrientationLocked) {
if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) { if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
R.drawable.ic_orientation_portrait R.drawable.ic_orientation_portrait_vector
} else { } else {
R.drawable.ic_orientation_landscape R.drawable.ic_orientation_landscape_vector
} }
} else { } else {
R.drawable.ic_orientation_auto R.drawable.ic_orientation_auto_vector
} }
} }
@ -693,7 +698,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
return false return false
} }
private fun getCurrentFragment() = (view_pager.adapter as MyPagerAdapter).getCurrentFragment(view_pager.currentItem) private fun getCurrentFragment() = (view_pager.adapter as? MyPagerAdapter)?.getCurrentFragment(view_pager.currentItem)
private fun showProperties() { private fun showProperties() {
if (getCurrentMedium() != null) { if (getCurrentMedium() != null) {
@ -798,10 +803,10 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
return return
} }
val favoriteIcon = if (medium.isFavorite) R.drawable.ic_star_on else R.drawable.ic_star_off val favoriteIcon = if (medium.isFavorite) R.drawable.ic_star_on_vector else R.drawable.ic_star_off_vector
bottom_favorite.setImageResource(favoriteIcon) bottom_favorite.setImageResource(favoriteIcon)
val hideIcon = if (medium.isHidden()) R.drawable.ic_unhide else R.drawable.ic_hide val hideIcon = if (medium.isHidden()) R.drawable.ic_unhide_vector else R.drawable.ic_hide
bottom_toggle_file_visibility.setImageResource(hideIcon) bottom_toggle_file_visibility.setImageResource(hideIcon)
bottom_rotate.beVisibleIf(config.visibleBottomActions and BOTTOM_ACTION_ROTATE != 0 && getCurrentMedium()?.isImage() == true) bottom_rotate.beVisibleIf(config.visibleBottomActions and BOTTOM_ACTION_ROTATE != 0 && getCurrentMedium()?.isImage() == true)

View File

@ -145,8 +145,8 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
} }
private fun checkHideBtnVisibility(menu: Menu, selectedPaths: ArrayList<String>) { private fun checkHideBtnVisibility(menu: Menu, selectedPaths: ArrayList<String>) {
menu.findItem(R.id.cab_hide).isVisible = selectedPaths.any { !File(it).doesThisOrParentHaveNoMedia() } menu.findItem(R.id.cab_hide).isVisible = selectedPaths.any { !it.doesThisOrParentHaveNoMedia() }
menu.findItem(R.id.cab_unhide).isVisible = selectedPaths.any { File(it).doesThisOrParentHaveNoMedia() } menu.findItem(R.id.cab_unhide).isVisible = selectedPaths.any { it.doesThisOrParentHaveNoMedia() }
} }
private fun checkPinBtnVisibility(menu: Menu, selectedPaths: ArrayList<String>) { private fun checkPinBtnVisibility(menu: Menu, selectedPaths: ArrayList<String>) {
@ -218,28 +218,23 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
} }
} }
if (hide) {
if (config.wasHideFolderTooltipShown) {
hideFolders(selectedPaths)
} else {
config.wasHideFolderTooltipShown = true
ConfirmationDialog(activity, activity.getString(R.string.hide_folder_description)) {
hideFolders(selectedPaths)
}
}
return
}
selectedPaths.filter { it != FAVORITES && it != RECYCLE_BIN && (selectedPaths.size == 1 || !activity.config.isFolderProtected(it)) }.forEach { selectedPaths.filter { it != FAVORITES && it != RECYCLE_BIN && (selectedPaths.size == 1 || !activity.config.isFolderProtected(it)) }.forEach {
val path = it val path = it
if (hide) { activity.handleLockedFolderOpening(path) { success ->
if (config.wasHideFolderTooltipShown) { if (success) {
activity.handleLockedFolderOpening(path) { success -> if (path.containsNoMedia()) {
if (success) {
hideFolder(path)
}
}
} else {
config.wasHideFolderTooltipShown = true
ConfirmationDialog(activity, activity.getString(R.string.hide_folder_description)) {
activity.handleLockedFolderOpening(path) { success ->
if (success) {
hideFolder(path)
}
}
}
}
} else {
activity.handleLockedFolderOpening(path) { success ->
if (success) {
activity.removeNoMedia(path) { activity.removeNoMedia(path) {
if (activity.config.shouldShowHidden) { if (activity.config.shouldShowHidden) {
updateFolderNames() updateFolderNames()
@ -250,12 +245,28 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
} }
} }
} }
} else {
config.addIncludedFolder(path)
activity.runOnUiThread {
listener?.refreshItems()
finishActMode()
}
} }
} }
} }
} }
} }
private fun hideFolders(paths: ArrayList<String>) {
for (path in paths) {
activity.handleLockedFolderOpening(path) { success ->
if (success) {
hideFolder(path)
}
}
}
}
private fun tryEmptyRecycleBin(askConfirmation: Boolean) { private fun tryEmptyRecycleBin(askConfirmation: Boolean) {
if (askConfirmation) { if (askConfirmation) {
activity.showRecycleBinEmptyingDialog { activity.showRecycleBinEmptyingDialog {
@ -308,7 +319,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
val affectedPositions = ArrayList<Int>() val affectedPositions = ArrayList<Int>()
val includedFolders = activity.config.includedFolders val includedFolders = activity.config.includedFolders
val newDirs = dirs.filterIndexed { index, directory -> val newDirs = dirs.filterIndexed { index, directory ->
val removeDir = File(directory.path).doesThisOrParentHaveNoMedia() && !includedFolders.contains(directory.path) val removeDir = directory.path.doesThisOrParentHaveNoMedia() && !includedFolders.contains(directory.path)
if (removeDir) { if (removeDir) {
affectedPositions.add(index) affectedPositions.add(index)
} }
@ -431,6 +442,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
val fileDirItems = paths.map { FileDirItem(it, it.getFilenameFromPath()) } as ArrayList<FileDirItem> val fileDirItems = paths.map { FileDirItem(it, it.getFilenameFromPath()) } as ArrayList<FileDirItem>
activity.tryCopyMoveFilesTo(fileDirItems, isCopyOperation) { activity.tryCopyMoveFilesTo(fileDirItems, isCopyOperation) {
activity.fixDateTaken(paths, false)
config.tempFolderPath = "" config.tempFolderPath = ""
listener?.refreshItems() listener?.refreshItems()
finishActMode() finishActMode()
@ -456,7 +468,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
activity.getShortcutImage(coverThumbnail, drawable) { activity.getShortcutImage(coverThumbnail, drawable) {
val intent = Intent(activity, MediaActivity::class.java) val intent = Intent(activity, MediaActivity::class.java)
intent.action = Intent.ACTION_VIEW intent.action = Intent.ACTION_VIEW
intent.flags = intent.flags or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NO_HISTORY intent.flags = intent.flags or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
intent.putExtra(DIRECTORY, path) intent.putExtra(DIRECTORY, path)
val shortcut = ShortcutInfo.Builder(activity, path) val shortcut = ShortcutInfo.Builder(activity, path)
@ -595,7 +607,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
listener?.refreshItems() listener?.refreshItems()
} }
private fun getSelectedItems() = dirs.filter { selectedKeys.contains(it.path.hashCode()) } as ArrayList<Directory> private fun getSelectedItems() = selectedKeys.mapNotNull { getItemWithKey(it) } as ArrayList<Directory>
private fun getSelectedPaths() = getSelectedItems().map { it.path } as ArrayList<String> private fun getSelectedPaths() = getSelectedItems().map { it.path } as ArrayList<String>
@ -669,7 +681,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
dir_pin.beVisibleIf(pinnedFolders.contains(directory.path)) dir_pin.beVisibleIf(pinnedFolders.contains(directory.path))
dir_location.beVisibleIf(directory.location != LOCATION_INTERNAL) dir_location.beVisibleIf(directory.location != LOCATION_INTERNAL)
if (dir_location.isVisible()) { if (dir_location.isVisible()) {
dir_location.setImageResource(if (directory.location == LOCATION_SD) R.drawable.ic_sd_card else R.drawable.ic_usb) dir_location.setImageResource(if (directory.location == LOCATION_SD) R.drawable.ic_sd_card_vector else R.drawable.ic_usb_vector)
} }
photo_cnt.beVisibleIf(showMediaCount) photo_cnt.beVisibleIf(showMediaCount)

View File

@ -10,8 +10,8 @@ import com.bumptech.glide.Glide
import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
import com.simplemobiletools.commons.dialogs.PropertiesDialog import com.simplemobiletools.commons.dialogs.PropertiesDialog
import com.simplemobiletools.commons.dialogs.RenameDialog
import com.simplemobiletools.commons.dialogs.RenameItemDialog import com.simplemobiletools.commons.dialogs.RenameItemDialog
import com.simplemobiletools.commons.dialogs.RenameItemsPatternDialog
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import com.simplemobiletools.commons.models.FileDirItem import com.simplemobiletools.commons.models.FileDirItem
@ -21,6 +21,8 @@ import com.simplemobiletools.gallery.pro.R
import com.simplemobiletools.gallery.pro.dialogs.DeleteWithRememberDialog import com.simplemobiletools.gallery.pro.dialogs.DeleteWithRememberDialog
import com.simplemobiletools.gallery.pro.extensions.* import com.simplemobiletools.gallery.pro.extensions.*
import com.simplemobiletools.gallery.pro.helpers.SHOW_ALL import com.simplemobiletools.gallery.pro.helpers.SHOW_ALL
import com.simplemobiletools.gallery.pro.helpers.TYPE_GIFS
import com.simplemobiletools.gallery.pro.helpers.TYPE_RAWS
import com.simplemobiletools.gallery.pro.helpers.VIEW_TYPE_LIST import com.simplemobiletools.gallery.pro.helpers.VIEW_TYPE_LIST
import com.simplemobiletools.gallery.pro.interfaces.MediaOperationsListener import com.simplemobiletools.gallery.pro.interfaces.MediaOperationsListener
import com.simplemobiletools.gallery.pro.models.Medium import com.simplemobiletools.gallery.pro.models.Medium
@ -52,6 +54,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
private var animateGifs = config.animateGifs private var animateGifs = config.animateGifs
private var cropThumbnails = config.cropThumbnails private var cropThumbnails = config.cropThumbnails
private var displayFilenames = config.displayFileNames private var displayFilenames = config.displayFileNames
private var showFileTypes = config.showThumbnailFileTypes
init { init {
setupDragListener(true) setupDragListener(true)
@ -215,7 +218,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
} }
} }
} else { } else {
RenameItemsPatternDialog(activity, getSelectedPaths()) { RenameDialog(activity, getSelectedPaths()) {
enableInstantLoad() enableInstantLoad()
listener?.refreshItems() listener?.refreshItems()
finishActMode() finishActMode()
@ -326,6 +329,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
config.tempFolderPath = "" config.tempFolderPath = ""
activity.applicationContext.rescanFolderMedia(it) activity.applicationContext.rescanFolderMedia(it)
activity.applicationContext.rescanFolderMedia(fileDirItems.first().getParentPath()) activity.applicationContext.rescanFolderMedia(fileDirItems.first().getParentPath())
activity.fixDateTaken(paths, false)
if (!isCopyOperation) { if (!isCopyOperation) {
listener?.refreshItems() listener?.refreshItems()
activity.updateFavoritePaths(fileDirItems, it) activity.updateFavoritePaths(fileDirItems, it)
@ -394,7 +398,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
} }
} }
private fun getSelectedItems() = media.filter { selectedKeys.contains((it as? Medium)?.path?.hashCode()) } as ArrayList<Medium> private fun getSelectedItems() = selectedKeys.mapNotNull { getItemWithKey(it) } as ArrayList<Medium>
private fun getSelectedPaths() = getSelectedItems().map { it.path } as ArrayList<String> private fun getSelectedPaths() = getSelectedItems().map { it.path } as ArrayList<String>
@ -431,6 +435,11 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
notifyDataSetChanged() notifyDataSetChanged()
} }
fun updateShowFileTypes(showFileTypes: Boolean) {
this.showFileTypes = showFileTypes
notifyDataSetChanged()
}
private fun enableInstantLoad() { private fun enableInstantLoad() {
loadImageInstantly = true loadImageInstantly = true
delayHandler.postDelayed({ delayHandler.postDelayed({
@ -444,6 +453,18 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
val isSelected = selectedKeys.contains(medium.path.hashCode()) val isSelected = selectedKeys.contains(medium.path.hashCode())
view.apply { view.apply {
play_outline.beVisibleIf(medium.isVideo()) play_outline.beVisibleIf(medium.isVideo())
if (showFileTypes && (medium.isGIF() || medium.isRaw() || medium.isSVG())) {
file_type.setText(when (medium.type) {
TYPE_GIFS -> R.string.gif
TYPE_RAWS -> R.string.raw
else -> R.string.svg
})
file_type.beVisible()
} else {
file_type.beGone()
}
medium_name.beVisibleIf(displayFilenames || isListViewType) medium_name.beVisibleIf(displayFilenames || isListViewType)
medium_name.text = medium.name medium_name.text = medium.name
medium_name.tag = medium.path medium_name.tag = medium.path

View File

@ -9,11 +9,11 @@ import com.simplemobiletools.commons.extensions.value
import com.simplemobiletools.gallery.pro.R import com.simplemobiletools.gallery.pro.R
import kotlinx.android.synthetic.main.dialog_custom_aspect_ratio.view.* import kotlinx.android.synthetic.main.dialog_custom_aspect_ratio.view.*
class CustomAspectRatioDialog(val activity: BaseSimpleActivity, val defaultCustomAspectRatio: Pair<Int, Int>?, val callback: (aspectRatio: Pair<Int, Int>) -> Unit) { class CustomAspectRatioDialog(val activity: BaseSimpleActivity, val defaultCustomAspectRatio: Pair<Float, Float>?, val callback: (aspectRatio: Pair<Float, Float>) -> Unit) {
init { init {
val view = activity.layoutInflater.inflate(R.layout.dialog_custom_aspect_ratio, null).apply { val view = activity.layoutInflater.inflate(R.layout.dialog_custom_aspect_ratio, null).apply {
aspect_ratio_width.setText(defaultCustomAspectRatio?.first?.toString() ?: "") aspect_ratio_width.setText(defaultCustomAspectRatio?.first?.toInt()?.toString() ?: "")
aspect_ratio_height.setText(defaultCustomAspectRatio?.second?.toString() ?: "") aspect_ratio_height.setText(defaultCustomAspectRatio?.second?.toInt()?.toString() ?: "")
} }
AlertDialog.Builder(activity) AlertDialog.Builder(activity)
@ -32,8 +32,8 @@ class CustomAspectRatioDialog(val activity: BaseSimpleActivity, val defaultCusto
} }
} }
private fun getViewValue(view: EditText): Int { private fun getViewValue(view: EditText): Float {
val textValue = view.value val textValue = view.value
return if (textValue.isEmpty()) 0 else textValue.toInt() return if (textValue.isEmpty()) 0f else textValue.toFloat()
} }
} }

View File

@ -6,44 +6,44 @@ import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.gallery.pro.R import com.simplemobiletools.gallery.pro.R
import kotlinx.android.synthetic.main.dialog_other_aspect_ratio.view.* import kotlinx.android.synthetic.main.dialog_other_aspect_ratio.view.*
class OtherAspectRatioDialog(val activity: BaseSimpleActivity, val lastOtherAspectRatio: Pair<Int, Int>?, val callback: (aspectRatio: Pair<Int, Int>) -> Unit) { class OtherAspectRatioDialog(val activity: BaseSimpleActivity, val lastOtherAspectRatio: Pair<Float, Float>?, val callback: (aspectRatio: Pair<Float, Float>) -> Unit) {
private val dialog: AlertDialog private val dialog: AlertDialog
init { init {
val view = activity.layoutInflater.inflate(R.layout.dialog_other_aspect_ratio, null).apply { val view = activity.layoutInflater.inflate(R.layout.dialog_other_aspect_ratio, null).apply {
other_aspect_ratio_2_1.setOnClickListener { ratioPicked(Pair(2, 1)) } other_aspect_ratio_2_1.setOnClickListener { ratioPicked(Pair(2f, 1f)) }
other_aspect_ratio_3_2.setOnClickListener { ratioPicked(Pair(3, 2)) } other_aspect_ratio_3_2.setOnClickListener { ratioPicked(Pair(3f, 2f)) }
other_aspect_ratio_4_3.setOnClickListener { ratioPicked(Pair(4, 3)) } other_aspect_ratio_4_3.setOnClickListener { ratioPicked(Pair(4f, 3f)) }
other_aspect_ratio_5_3.setOnClickListener { ratioPicked(Pair(5, 3)) } other_aspect_ratio_5_3.setOnClickListener { ratioPicked(Pair(5f, 3f)) }
other_aspect_ratio_16_9.setOnClickListener { ratioPicked(Pair(16, 9)) } other_aspect_ratio_16_9.setOnClickListener { ratioPicked(Pair(16f, 9f)) }
other_aspect_ratio_19_9.setOnClickListener { ratioPicked(Pair(19, 9)) } other_aspect_ratio_19_9.setOnClickListener { ratioPicked(Pair(19f, 9f)) }
other_aspect_ratio_custom.setOnClickListener { customRatioPicked() } other_aspect_ratio_custom.setOnClickListener { customRatioPicked() }
other_aspect_ratio_1_2.setOnClickListener { ratioPicked(Pair(1, 2)) } other_aspect_ratio_1_2.setOnClickListener { ratioPicked(Pair(1f, 2f)) }
other_aspect_ratio_2_3.setOnClickListener { ratioPicked(Pair(2, 3)) } other_aspect_ratio_2_3.setOnClickListener { ratioPicked(Pair(2f, 3f)) }
other_aspect_ratio_3_4.setOnClickListener { ratioPicked(Pair(3, 4)) } other_aspect_ratio_3_4.setOnClickListener { ratioPicked(Pair(3f, 4f)) }
other_aspect_ratio_3_5.setOnClickListener { ratioPicked(Pair(3, 5)) } other_aspect_ratio_3_5.setOnClickListener { ratioPicked(Pair(3f, 5f)) }
other_aspect_ratio_9_16.setOnClickListener { ratioPicked(Pair(9, 16)) } other_aspect_ratio_9_16.setOnClickListener { ratioPicked(Pair(9f, 16f)) }
other_aspect_ratio_9_19.setOnClickListener { ratioPicked(Pair(9, 19)) } other_aspect_ratio_9_19.setOnClickListener { ratioPicked(Pair(9f, 19f)) }
val radio1SelectedItemId = when (lastOtherAspectRatio) { val radio1SelectedItemId = when (lastOtherAspectRatio) {
Pair(2, 1) -> other_aspect_ratio_2_1.id Pair(2f, 1f) -> other_aspect_ratio_2_1.id
Pair(3, 2) -> other_aspect_ratio_3_2.id Pair(3f, 2f) -> other_aspect_ratio_3_2.id
Pair(4, 3) -> other_aspect_ratio_4_3.id Pair(4f, 3f) -> other_aspect_ratio_4_3.id
Pair(5, 3) -> other_aspect_ratio_5_3.id Pair(5f, 3f) -> other_aspect_ratio_5_3.id
Pair(16, 9) -> other_aspect_ratio_16_9.id Pair(16f, 9f) -> other_aspect_ratio_16_9.id
Pair(19, 9) -> other_aspect_ratio_19_9.id Pair(19f, 9f) -> other_aspect_ratio_19_9.id
else -> 0 else -> 0
} }
other_aspect_ratio_dialog_radio_1.check(radio1SelectedItemId) other_aspect_ratio_dialog_radio_1.check(radio1SelectedItemId)
val radio2SelectedItemId = when (lastOtherAspectRatio) { val radio2SelectedItemId = when (lastOtherAspectRatio) {
Pair(1, 2) -> other_aspect_ratio_1_2.id Pair(1f, 2f) -> other_aspect_ratio_1_2.id
Pair(2, 3) -> other_aspect_ratio_2_3.id Pair(2f, 3f) -> other_aspect_ratio_2_3.id
Pair(3, 4) -> other_aspect_ratio_3_4.id Pair(3f, 4f) -> other_aspect_ratio_3_4.id
Pair(3, 5) -> other_aspect_ratio_3_5.id Pair(3f, 5f) -> other_aspect_ratio_3_5.id
Pair(9, 16) -> other_aspect_ratio_9_16.id Pair(9f, 16f) -> other_aspect_ratio_9_16.id
Pair(9, 19) -> other_aspect_ratio_9_19.id Pair(9f, 19f) -> other_aspect_ratio_9_19.id
else -> 0 else -> 0
} }
other_aspect_ratio_dialog_radio_2.check(radio2SelectedItemId) other_aspect_ratio_dialog_radio_2.check(radio2SelectedItemId)
@ -67,7 +67,7 @@ class OtherAspectRatioDialog(val activity: BaseSimpleActivity, val lastOtherAspe
} }
} }
private fun ratioPicked(pair: Pair<Int, Int>) { private fun ratioPicked(pair: Pair<Float, Float>) {
callback(pair) callback(pair)
dialog.dismiss() dialog.dismiss()
} }

View File

@ -30,7 +30,6 @@ import com.simplemobiletools.gallery.pro.BuildConfig
import com.simplemobiletools.gallery.pro.R import com.simplemobiletools.gallery.pro.R
import com.simplemobiletools.gallery.pro.activities.SimpleActivity import com.simplemobiletools.gallery.pro.activities.SimpleActivity
import com.simplemobiletools.gallery.pro.dialogs.PickDirectoryDialog import com.simplemobiletools.gallery.pro.dialogs.PickDirectoryDialog
import com.simplemobiletools.gallery.pro.helpers.NOMEDIA
import com.simplemobiletools.gallery.pro.helpers.RECYCLE_BIN import com.simplemobiletools.gallery.pro.helpers.RECYCLE_BIN
import com.simplemobiletools.gallery.pro.interfaces.MediumDao import com.simplemobiletools.gallery.pro.interfaces.MediumDao
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
@ -61,8 +60,8 @@ fun Activity.setAs(path: String) {
setAsIntent(path, BuildConfig.APPLICATION_ID) setAsIntent(path, BuildConfig.APPLICATION_ID)
} }
fun Activity.openPath(path: String, forceChooser: Boolean) { fun Activity.openPath(path: String, forceChooser: Boolean, extras: HashMap<String, Boolean> = HashMap()) {
openPathIntent(path, forceChooser, BuildConfig.APPLICATION_ID) openPathIntent(path, forceChooser, BuildConfig.APPLICATION_ID, extras = extras)
} }
fun Activity.openEditor(path: String, forceChooser: Boolean = false) { fun Activity.openEditor(path: String, forceChooser: Boolean = false) {
@ -100,7 +99,8 @@ fun SimpleActivity.launchAbout() {
FAQItem(R.string.faq_14_title, R.string.faq_14_text), FAQItem(R.string.faq_14_title, R.string.faq_14_text),
FAQItem(R.string.faq_15_title, R.string.faq_15_text), FAQItem(R.string.faq_15_title, R.string.faq_15_text),
FAQItem(R.string.faq_2_title_commons, R.string.faq_2_text_commons), FAQItem(R.string.faq_2_title_commons, R.string.faq_2_text_commons),
FAQItem(R.string.faq_6_title_commons, R.string.faq_6_text_commons)) FAQItem(R.string.faq_6_title_commons, R.string.faq_6_text_commons),
FAQItem(R.string.faq_7_title_commons, R.string.faq_7_text_commons))
startAboutActivity(R.string.app_name, licenses, BuildConfig.VERSION_NAME, faqItems, true) startAboutActivity(R.string.app_name, licenses, BuildConfig.VERSION_NAME, faqItems, true)
} }
@ -257,11 +257,15 @@ fun BaseSimpleActivity.restoreRecycleBinPath(path: String, callback: () -> Unit)
fun BaseSimpleActivity.restoreRecycleBinPaths(paths: ArrayList<String>, mediumDao: MediumDao = galleryDB.MediumDao(), callback: () -> Unit) { fun BaseSimpleActivity.restoreRecycleBinPaths(paths: ArrayList<String>, mediumDao: MediumDao = galleryDB.MediumDao(), callback: () -> Unit) {
ensureBackgroundThread { ensureBackgroundThread {
val newPaths = ArrayList<String>() val newPaths = ArrayList<String>()
paths.forEach { for (source in paths) {
val source = it val destination = source.removePrefix(recycleBinPath)
val destination = it.removePrefix(recycleBinPath)
val lastModified = File(source).lastModified() val lastModified = File(source).lastModified()
val isShowingSAF = handleSAFDialog(destination) {}
if (isShowingSAF) {
return@ensureBackgroundThread
}
var inputStream: InputStream? = null var inputStream: InputStream? = null
var out: OutputStream? = null var out: OutputStream? = null
try { try {

View File

@ -401,15 +401,18 @@ fun Context.rescanFolderMediaSync(path: String) {
val newMedia = it val newMedia = it
val mediumDao = galleryDB.MediumDao() val mediumDao = galleryDB.MediumDao()
val media = newMedia.filter { it is Medium } as ArrayList<Medium> val media = newMedia.filter { it is Medium } as ArrayList<Medium>
mediumDao.insertAll(media) try {
mediumDao.insertAll(media)
cached.forEach { cached.forEach {
if (!newMedia.contains(it)) { if (!newMedia.contains(it)) {
val mediumPath = (it as? Medium)?.path val mediumPath = (it as? Medium)?.path
if (mediumPath != null) { if (mediumPath != null) {
deleteDBPath(mediumDao, mediumPath) deleteDBPath(mediumDao, mediumPath)
}
} }
} }
} catch (ignored: Exception) {
} }
} }
}.execute() }.execute()
@ -424,7 +427,7 @@ fun Context.storeDirectoryItems(items: ArrayList<Directory>, directoryDao: Direc
fun Context.checkAppendingHidden(path: String, hidden: String, includedFolders: MutableSet<String>): String { fun Context.checkAppendingHidden(path: String, hidden: String, includedFolders: MutableSet<String>): String {
val dirName = getFolderNameFromPath(path) val dirName = getFolderNameFromPath(path)
return if (File(path).doesThisOrParentHaveNoMedia() && !path.isThisOrParentIncluded(includedFolders)) { return if (path.doesThisOrParentHaveNoMedia() && !path.isThisOrParentIncluded(includedFolders)) {
"$dirName $hidden" "$dirName $hidden"
} else { } else {
dirName dirName
@ -587,7 +590,7 @@ fun Context.getCachedDirectories(getVideosOnly: Boolean = false, getImagesOnly:
val hiddenString = resources.getString(R.string.hidden) val hiddenString = resources.getString(R.string.hidden)
filteredDirectories.forEach { filteredDirectories.forEach {
it.name = if (File(it.path).doesThisOrParentHaveNoMedia() && !it.path.isThisOrParentIncluded(includedPaths)) { it.name = if (it.path.doesThisOrParentHaveNoMedia() && !it.path.isThisOrParentIncluded(includedPaths)) {
"${it.name.removeSuffix(hiddenString).trim()} $hiddenString" "${it.name.removeSuffix(hiddenString).trim()} $hiddenString"
} else { } else {
it.name it.name
@ -620,7 +623,7 @@ fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImag
try { try {
val currMedia = mediumDao.getMediaFromPath(it) val currMedia = mediumDao.getMediaFromPath(it)
media.addAll(currMedia) media.addAll(currMedia)
} catch (ignored: IllegalStateException) { } catch (ignored: Exception) {
} }
} }

View File

@ -1,20 +0,0 @@
package com.simplemobiletools.gallery.pro.extensions
import com.simplemobiletools.gallery.pro.helpers.NOMEDIA
import java.io.File
fun File.containsNoMedia() = isDirectory && File(this, NOMEDIA).exists()
fun File.doesThisOrParentHaveNoMedia(): Boolean {
var curFile = this
while (true) {
if (curFile.containsNoMedia()) {
return true
}
curFile = curFile.parentFile ?: break
if (curFile.absolutePath == "/") {
break
}
}
return false
}

View File

@ -1,7 +1,8 @@
package com.simplemobiletools.gallery.pro.extensions package com.simplemobiletools.gallery.pro.extensions
import android.media.MediaMetadataRetriever import android.media.MediaMetadataRetriever
import com.simplemobiletools.gallery.pro.helpers.NOMEDIA import com.simplemobiletools.commons.extensions.doesThisOrParentHaveNoMedia
import com.simplemobiletools.commons.helpers.NOMEDIA
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException

View File

@ -251,7 +251,6 @@ class PhotoFragment : ViewPagerFragment() {
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig) super.onConfigurationChanged(newConfig)
if (!mWasInit) { if (!mWasInit) {
return return
} }
@ -272,6 +271,7 @@ class PhotoFragment : ViewPagerFragment() {
loadImage() loadImage()
} }
measureScreen()
initExtendedDetails() initExtendedDetails()
updateInstantSwitchWidths() updateInstantSwitchWidths()
} }
@ -461,13 +461,14 @@ class PhotoFragment : ViewPagerFragment() {
mIsSubsamplingVisible = true mIsSubsamplingVisible = true
val config = context!!.config val config = context!!.config
val showHighestQuality = config.showHighestQuality val showHighestQuality = config.showHighestQuality
val minTileDpi = if (showHighestQuality) -1 else getMinTileDpi()
val bitmapDecoder = object : DecoderFactory<ImageDecoder> { val bitmapDecoder = object : DecoderFactory<ImageDecoder> {
override fun make() = PicassoDecoder(mMedium.path, Picasso.get(), rotation) override fun make() = MyGlideImageDecoder(rotation)
} }
val regionDecoder = object : DecoderFactory<ImageRegionDecoder> { val regionDecoder = object : DecoderFactory<ImageRegionDecoder> {
override fun make() = PicassoRegionDecoder(showHighestQuality) override fun make() = PicassoRegionDecoder(showHighestQuality, mScreenWidth, mScreenHeight, minTileDpi)
} }
var newOrientation = (rotation + mCurrentRotationDegrees) % 360 var newOrientation = (rotation + mCurrentRotationDegrees) % 360
@ -477,7 +478,7 @@ class PhotoFragment : ViewPagerFragment() {
mView.subsampling_view.apply { mView.subsampling_view.apply {
setMaxTileSize(if (showHighestQuality) Integer.MAX_VALUE else 4096) setMaxTileSize(if (showHighestQuality) Integer.MAX_VALUE else 4096)
setMinimumTileDpi(if (showHighestQuality) -1 else getMinTileDpi()) setMinimumTileDpi(minTileDpi)
background = ColorDrawable(Color.TRANSPARENT) background = ColorDrawable(Color.TRANSPARENT)
bitmapDecoderFactory = bitmapDecoder bitmapDecoderFactory = bitmapDecoder
regionDecoderFactory = regionDecoder regionDecoderFactory = regionDecoder
@ -487,6 +488,7 @@ class PhotoFragment : ViewPagerFragment() {
isOneToOneZoomEnabled = config.allowOneToOneZoom isOneToOneZoomEnabled = config.allowOneToOneZoom
orientation = newOrientation orientation = newOrientation
setImage(mMedium.path) setImage(mMedium.path)
onImageEventListener = object : SubsamplingScaleImageView.OnImageEventListener { onImageEventListener = object : SubsamplingScaleImageView.OnImageEventListener {
override fun onReady() { override fun onReady() {
background = ColorDrawable(if (config.blackBackground) Color.BLACK else config.backgroundColor) background = ColorDrawable(if (config.blackBackground) Color.BLACK else config.backgroundColor)
@ -520,10 +522,10 @@ class PhotoFragment : ViewPagerFragment() {
val averageDpi = (metrics.xdpi + metrics.ydpi) / 2 val averageDpi = (metrics.xdpi + metrics.ydpi) / 2
val device = "${Build.BRAND} ${Build.MODEL}".toLowerCase() val device = "${Build.BRAND} ${Build.MODEL}".toLowerCase()
return when { return when {
WEIRD_DEVICES.contains(device) -> 240 WEIRD_DEVICES.contains(device) -> WEIRD_TILE_DPI
averageDpi > 400 -> 280 averageDpi > 400 -> HIGH_TILE_DPI
averageDpi > 300 -> 220 averageDpi > 300 -> NORMAL_TILE_DPI
else -> 160 else -> LOW_TILE_DPI
} }
} }

View File

@ -49,9 +49,12 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
private var mWasVideoStarted = false private var mWasVideoStarted = false
private var mWasPlayerInited = false private var mWasPlayerInited = false
private var mWasLastPositionRestored = false private var mWasLastPositionRestored = false
private var mPlayOnPrepared = false
private var mIsPlayerPrepared = false
private var mCurrTime = 0 private var mCurrTime = 0
private var mDuration = 0 private var mDuration = 0
private var mPositionWhenInit = 0 private var mPositionWhenInit = 0
private var mPositionAtPause = 0L
private var mExoPlayer: SimpleExoPlayer? = null private var mExoPlayer: SimpleExoPlayer? = null
private var mVideoSize = Point(1, 1) private var mVideoSize = Point(1, 1)
@ -80,11 +83,12 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
mView = inflater.inflate(R.layout.pager_video_item, container, false).apply { mView = inflater.inflate(R.layout.pager_video_item, container, false).apply {
instant_prev_item.setOnClickListener { listener?.goToPrevItem() } instant_prev_item.setOnClickListener { listener?.goToPrevItem() }
instant_next_item.setOnClickListener { listener?.goToNextItem() } instant_next_item.setOnClickListener { listener?.goToNextItem() }
panorama_outline.setOnClickListener { openPanorama() }
video_curr_time.setOnClickListener { skip(false) } video_curr_time.setOnClickListener { skip(false) }
video_duration.setOnClickListener { skip(true) } video_duration.setOnClickListener { skip(true) }
video_holder.setOnClickListener { toggleFullscreen() } video_holder.setOnClickListener { toggleFullscreen() }
video_preview.setOnClickListener { toggleFullscreen() } video_preview.setOnClickListener { toggleFullscreen() }
panorama_outline.setOnClickListener { openPanorama() } video_surface_frame.setOnClickListener { toggleFullscreen() }
video_play_outline.setOnClickListener { video_play_outline.setOnClickListener {
if (mConfig.openVideosOnSeparateScreen) { if (mConfig.openVideosOnSeparateScreen) {
launchVideoPlayer() launchVideoPlayer()
@ -108,6 +112,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
mBrightnessSideScroll = video_brightness_controller mBrightnessSideScroll = video_brightness_controller
mVolumeSideScroll = video_volume_controller mVolumeSideScroll = video_volume_controller
mTextureView = video_surface mTextureView = video_surface
mTextureView.surfaceTextureListener = this@VideoFragment
if (mConfig.allowDownGesture) { if (mConfig.allowDownGesture) {
video_preview.setOnTouchListener { view, event -> video_preview.setOnTouchListener { view, event ->
@ -158,7 +163,6 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
} }
if (!mIsPanorama) { if (!mIsPanorama) {
setupPlayer()
if (savedInstanceState != null) { if (savedInstanceState != null) {
mCurrTime = savedInstanceState.getInt(PROGRESS) mCurrTime = savedInstanceState.getInt(PROGRESS)
} }
@ -268,23 +272,8 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
} }
} }
private fun setupPlayer() {
if (activity == null || mConfig.openVideosOnSeparateScreen || mIsPanorama) {
return
}
mView.video_surface_frame.setOnClickListener { toggleFullscreen() }
mTextureView.surfaceTextureListener = this
checkExtendedDetails()
mExoPlayer = ExoPlayerFactory.newSimpleInstance(context)
mExoPlayer!!.seekParameters = SeekParameters.CLOSEST_SYNC
initExoPlayerListeners()
}
private fun saveVideoProgress() { private fun saveVideoProgress() {
if (!videoEnded()) { if (!videoEnded() && mExoPlayer != null) {
mConfig.saveLastVideoPosition(mMedium.path, mExoPlayer!!.currentPosition.toInt() / 1000) mConfig.saveLastVideoPosition(mMedium.path, mExoPlayer!!.currentPosition.toInt() / 1000)
} }
} }
@ -292,6 +281,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
private fun restoreLastVideoSavedPosition() { private fun restoreLastVideoSavedPosition() {
val pos = mConfig.getLastVideoPosition(mMedium.path) val pos = mConfig.getLastVideoPosition(mMedium.path)
if (pos > 0) { if (pos > 0) {
mPositionAtPause = pos * 1000L
setPosition(pos) setPosition(pos)
} }
} }
@ -317,6 +307,13 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
} }
private fun initExoPlayer() { private fun initExoPlayer() {
if (activity == null || mConfig.openVideosOnSeparateScreen || mIsPanorama || mExoPlayer != null) {
return
}
mExoPlayer = ExoPlayerFactory.newSimpleInstance(context)
mExoPlayer!!.seekParameters = SeekParameters.CLOSEST_SYNC
val isContentUri = mMedium.path.startsWith("content://") val isContentUri = mMedium.path.startsWith("content://")
val uri = if (isContentUri) Uri.parse(mMedium.path) else Uri.fromFile(File(mMedium.path)) val uri = if (isContentUri) Uri.parse(mMedium.path) else Uri.fromFile(File(mMedium.path))
val dataSpec = DataSpec(uri) val dataSpec = DataSpec(uri)
@ -325,15 +322,19 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
fileDataSource.open(dataSpec) fileDataSource.open(dataSpec)
} catch (e: Exception) { } catch (e: Exception) {
activity?.showErrorToast(e) activity?.showErrorToast(e)
return
} }
val factory = DataSource.Factory { fileDataSource } val factory = DataSource.Factory { fileDataSource }
val audioSource = ExtractorMediaSource(fileDataSource.uri, factory, DefaultExtractorsFactory(), null, null) val audioSource = ExtractorMediaSource(fileDataSource.uri, factory, DefaultExtractorsFactory(), null, null)
mPlayOnPrepared = true
mExoPlayer!!.audioStreamType = C.STREAM_TYPE_MUSIC mExoPlayer!!.audioStreamType = C.STREAM_TYPE_MUSIC
mExoPlayer!!.prepare(audioSource) mExoPlayer!!.prepare(audioSource)
}
private fun initExoPlayerListeners() { if (mTextureView.surfaceTexture != null) {
mExoPlayer!!.setVideoSurface(Surface(mTextureView.surfaceTexture))
}
mExoPlayer!!.addListener(object : Player.EventListener { mExoPlayer!!.addListener(object : Player.EventListener {
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {} override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {}
@ -364,7 +365,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
mExoPlayer!!.addVideoListener(object : SimpleExoPlayer.VideoListener { mExoPlayer!!.addVideoListener(object : SimpleExoPlayer.VideoListener {
override fun onVideoSizeChanged(width: Int, height: Int, unappliedRotationDegrees: Int, pixelWidthHeightRatio: Float) { override fun onVideoSizeChanged(width: Int, height: Int, unappliedRotationDegrees: Int, pixelWidthHeightRatio: Float) {
mVideoSize.x = width mVideoSize.x = width
mVideoSize.y = height mVideoSize.y = (height / pixelWidthHeightRatio).toInt()
setVideoSize() setVideoSize()
} }
@ -483,10 +484,14 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
} }
private fun skip(forward: Boolean) { private fun skip(forward: Boolean) {
if (mExoPlayer == null || mIsPanorama) { if (mIsPanorama) {
return
} else if (mExoPlayer == null) {
playVideo()
return return
} }
mPositionAtPause = 0L
val curr = mExoPlayer!!.currentPosition val curr = mExoPlayer!!.currentPosition
val twoPercents = Math.max((mExoPlayer!!.duration / 50).toInt(), MIN_SKIP_LENGTH) val twoPercents = Math.max((mExoPlayer!!.duration / 50).toInt(), MIN_SKIP_LENGTH)
val newProgress = if (forward) curr + twoPercents else curr - twoPercents val newProgress = if (forward) curr + twoPercents else curr - twoPercents
@ -499,17 +504,25 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
} }
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (mExoPlayer != null && fromUser) { if (fromUser) {
if (!mWasPlayerInited) { if (mExoPlayer != null) {
mPositionWhenInit = progress if (!mWasPlayerInited) {
mPositionWhenInit = progress
}
setPosition(progress)
}
if (mExoPlayer == null) {
mPositionAtPause = progress * 1000L
playVideo()
} }
setPosition(progress)
} }
} }
override fun onStartTrackingTouch(seekBar: SeekBar) { override fun onStartTrackingTouch(seekBar: SeekBar) {
if (mExoPlayer == null) if (mExoPlayer == null) {
return return
}
mExoPlayer!!.playWhenReady = false mExoPlayer!!.playWhenReady = false
mIsDragged = true mIsDragged = true
@ -527,26 +540,27 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
if (mIsPlaying) { if (mIsPlaying) {
mExoPlayer!!.playWhenReady = true mExoPlayer!!.playWhenReady = true
} else { } else {
togglePlayPause() playVideo()
} }
mIsDragged = false mIsDragged = false
} }
private fun togglePlayPause() { private fun togglePlayPause() {
if (activity == null || !isAdded) if (activity == null || !isAdded) {
return return
}
mIsPlaying = !mIsPlaying
if (mIsPlaying) { if (mIsPlaying) {
playVideo()
} else {
pauseVideo() pauseVideo()
} else {
playVideo()
} }
} }
fun playVideo() { fun playVideo() {
if (mExoPlayer == null) { if (mExoPlayer == null) {
initExoPlayer()
return return
} }
@ -575,9 +589,11 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
} }
mWasVideoStarted = true mWasVideoStarted = true
mIsPlaying = true if (mIsPlayerPrepared) {
mIsPlaying = true
}
mExoPlayer?.playWhenReady = true mExoPlayer?.playWhenReady = true
activity!!.window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} }
private fun pauseVideo() { private fun pauseVideo() {
@ -592,6 +608,8 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
mPlayPauseButton.setImageResource(R.drawable.ic_play_outline) mPlayPauseButton.setImageResource(R.drawable.ic_play_outline)
activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
mPositionAtPause = mExoPlayer?.currentPosition ?: 0L
releaseExoPlayer()
} }
private fun videoEnded(): Boolean { private fun videoEnded(): Boolean {
@ -604,6 +622,10 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
mExoPlayer?.seekTo(seconds * 1000L) mExoPlayer?.seekTo(seconds * 1000L)
mSeekBar.progress = seconds mSeekBar.progress = seconds
mCurrTimeView.text = seconds.getFormattedDuration() mCurrTimeView.text = seconds.getFormattedDuration()
if (!mIsPlaying) {
mPositionAtPause = mExoPlayer?.currentPosition ?: 0L
}
} }
private fun setupVideoDuration() { private fun setupVideoDuration() {
@ -627,7 +649,17 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
setPosition(mPositionWhenInit) setPosition(mPositionWhenInit)
mPositionWhenInit = 0 mPositionWhenInit = 0
} }
mIsPlayerPrepared = true
if (mPlayOnPrepared && !mIsPlaying) {
if (mPositionAtPause != 0L) {
mExoPlayer?.seekTo(mPositionAtPause)
mPositionAtPause = 0L
}
playVideo()
}
mWasPlayerInited = true mWasPlayerInited = true
mPlayOnPrepared = false
} }
private fun videoCompleted() { private fun videoCompleted() {
@ -657,6 +689,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
} }
private fun releaseExoPlayer() { private fun releaseExoPlayer() {
mIsPlayerPrepared = false
mExoPlayer?.stop() mExoPlayer?.stop()
ensureBackgroundThread { ensureBackgroundThread {
mExoPlayer?.release() mExoPlayer?.release()

View File

@ -178,6 +178,10 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getBoolean(SHOW_THUMBNAIL_VIDEO_DURATION, false) get() = prefs.getBoolean(SHOW_THUMBNAIL_VIDEO_DURATION, false)
set(showThumbnailVideoDuration) = prefs.edit().putBoolean(SHOW_THUMBNAIL_VIDEO_DURATION, showThumbnailVideoDuration).apply() set(showThumbnailVideoDuration) = prefs.edit().putBoolean(SHOW_THUMBNAIL_VIDEO_DURATION, showThumbnailVideoDuration).apply()
var showThumbnailFileTypes: Boolean
get() = prefs.getBoolean(SHOW_THUMBNAIL_FILE_TYPES, true)
set(showThumbnailFileTypes) = prefs.edit().putBoolean(SHOW_THUMBNAIL_FILE_TYPES, showThumbnailFileTypes).apply()
var screenRotation: Int var screenRotation: Int
get() = prefs.getInt(SCREEN_ROTATION, ROTATE_BY_SYSTEM_SETTING) get() = prefs.getInt(SCREEN_ROTATION, ROTATE_BY_SYSTEM_SETTING)
set(screenRotation) = prefs.edit().putInt(SCREEN_ROTATION, screenRotation).apply() set(screenRotation) = prefs.edit().putInt(SCREEN_ROTATION, screenRotation).apply()
@ -447,13 +451,13 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getInt(LAST_EDITOR_CROP_ASPECT_RATIO, ASPECT_RATIO_FREE) get() = prefs.getInt(LAST_EDITOR_CROP_ASPECT_RATIO, ASPECT_RATIO_FREE)
set(lastEditorCropAspectRatio) = prefs.edit().putInt(LAST_EDITOR_CROP_ASPECT_RATIO, lastEditorCropAspectRatio).apply() set(lastEditorCropAspectRatio) = prefs.edit().putInt(LAST_EDITOR_CROP_ASPECT_RATIO, lastEditorCropAspectRatio).apply()
var lastEditorCropOtherAspectRatioX: Int var lastEditorCropOtherAspectRatioX: Float
get() = prefs.getInt(LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_X, 2) get() = prefs.getFloat(LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_X, 2f)
set(lastEditorCropOtherAspectRatioX) = prefs.edit().putInt(LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_X, lastEditorCropOtherAspectRatioX).apply() set(lastEditorCropOtherAspectRatioX) = prefs.edit().putFloat(LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_X, lastEditorCropOtherAspectRatioX).apply()
var lastEditorCropOtherAspectRatioY: Int var lastEditorCropOtherAspectRatioY: Float
get() = prefs.getInt(LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_Y, 1) get() = prefs.getFloat(LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_Y, 1f)
set(lastEditorCropOtherAspectRatioY) = prefs.edit().putInt(LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_Y, lastEditorCropOtherAspectRatioY).apply() set(lastEditorCropOtherAspectRatioY) = prefs.edit().putFloat(LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_Y, lastEditorCropOtherAspectRatioY).apply()
var groupDirectSubfolders: Boolean var groupDirectSubfolders: Boolean
get() = prefs.getBoolean(GROUP_DIRECT_SUBFOLDERS, false) get() = prefs.getBoolean(GROUP_DIRECT_SUBFOLDERS, false)

View File

@ -67,8 +67,8 @@ const val LAST_BIN_CHECK = "last_bin_check"
const val SHOW_HIGHEST_QUALITY = "show_highest_quality" const val SHOW_HIGHEST_QUALITY = "show_highest_quality"
const val ALLOW_DOWN_GESTURE = "allow_down_gesture" const val ALLOW_DOWN_GESTURE = "allow_down_gesture"
const val LAST_EDITOR_CROP_ASPECT_RATIO = "last_editor_crop_aspect_ratio" const val LAST_EDITOR_CROP_ASPECT_RATIO = "last_editor_crop_aspect_ratio"
const val LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_X = "last_editor_crop_other_aspect_ratio_x" const val LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_X = "last_editor_crop_other_aspect_ratio_x_2"
const val LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_Y = "last_editor_crop_other_aspect_ratio_y" const val LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_Y = "last_editor_crop_other_aspect_ratio_y_2"
const val GROUP_DIRECT_SUBFOLDERS = "group_direct_subfolders" const val GROUP_DIRECT_SUBFOLDERS = "group_direct_subfolders"
const val SHOW_WIDGET_FOLDER_NAME = "show_widget_folder_name" const val SHOW_WIDGET_FOLDER_NAME = "show_widget_folder_name"
const val ALLOW_ONE_TO_ONE_ZOOM = "allow_one_to_one_zoom" const val ALLOW_ONE_TO_ONE_ZOOM = "allow_one_to_one_zoom"
@ -78,6 +78,7 @@ const val LAST_EDITOR_BRUSH_SIZE = "last_editor_brush_size"
const val SHOW_NOTCH = "show_notch" const val SHOW_NOTCH = "show_notch"
const val FILE_LOADING_PRIORITY = "file_loading_priority" const val FILE_LOADING_PRIORITY = "file_loading_priority"
const val SPAM_FOLDERS_CHECKED = "spam_folders_checked" const val SPAM_FOLDERS_CHECKED = "spam_folders_checked"
const val SHOW_THUMBNAIL_FILE_TYPES = "show_thumbnail_file_types"
// slideshow // slideshow
const val SLIDESHOW_INTERVAL = "slideshow_interval" const val SLIDESHOW_INTERVAL = "slideshow_interval"
@ -97,7 +98,6 @@ const val SLIDESHOW_ANIMATION_NONE = 0
const val SLIDESHOW_ANIMATION_SLIDE = 1 const val SLIDESHOW_ANIMATION_SLIDE = 1
const val SLIDESHOW_ANIMATION_FADE = 2 const val SLIDESHOW_ANIMATION_FADE = 2
const val NOMEDIA = ".nomedia"
const val FAVORITES = "favorites" const val FAVORITES = "favorites"
const val RECYCLE_BIN = "recycle_bin" const val RECYCLE_BIN = "recycle_bin"
const val SHOW_FAVORITES = "show_favorites" const val SHOW_FAVORITES = "show_favorites"
@ -209,3 +209,9 @@ const val MAX_VIDEO_ZOOM_SCALE = 5f
const val ZOOM_MODE_NONE = 0 const val ZOOM_MODE_NONE = 0
const val ZOOM_MODE_DRAG = 1 const val ZOOM_MODE_DRAG = 1
const val ZOOM_MODE_ZOOM = 2 const val ZOOM_MODE_ZOOM = 2
// constants related to image quality
const val LOW_TILE_DPI = 160
const val NORMAL_TILE_DPI = 220
const val WEIRD_TILE_DPI = 240
const val HIGH_TILE_DPI = 280

View File

@ -3,6 +3,7 @@ package com.simplemobiletools.gallery.pro.helpers
import android.content.Context import android.content.Context
import android.database.Cursor import android.database.Cursor
import android.os.Environment import android.os.Environment
import android.provider.BaseColumns
import android.provider.MediaStore import android.provider.MediaStore
import android.text.format.DateFormat import android.text.format.DateFormat
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
@ -37,34 +38,56 @@ class MediaFetcher(val context: Context) {
} }
fun getFoldersToScan(): ArrayList<String> { fun getFoldersToScan(): ArrayList<String> {
val filterMedia = context.config.filterMedia
val projection = arrayOf(MediaStore.Images.Media.DATA)
val uri = MediaStore.Files.getContentUri("external")
val selection = "${getSelectionQuery(filterMedia)} ${MediaStore.Images.ImageColumns.BUCKET_ID} IS NOT NULL) GROUP BY (${MediaStore.Images.ImageColumns.BUCKET_ID}"
val selectionArgs = getSelectionArgsQuery(filterMedia).toTypedArray()
return try { return try {
val cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null) val folders = getLatestFileFolders()
val folders = parseCursor(cursor) folders.addAll(arrayListOf(
val priorityFolders = arrayListOf(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString(), Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString(),
"${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)}/Camera", "${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)}/Camera",
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString() Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString()
).filter { File(it).exists() } ).filter { File(it).exists() })
folders.sortBy { val filterMedia = context.config.filterMedia
val folder = it val uri = MediaStore.Files.getContentUri("external")
!priorityFolders.any { it.equals(folder, true) } val projection = arrayOf(MediaStore.Images.Media.DATA)
} val selection = "${getSelectionQuery(filterMedia)} ${MediaStore.Images.ImageColumns.BUCKET_ID} IS NOT NULL) GROUP BY (${MediaStore.Images.ImageColumns.BUCKET_ID}"
val selectionArgs = getSelectionArgsQuery(filterMedia).toTypedArray()
val cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
folders.addAll(parseCursor(cursor))
folders val config = context.config
val shouldShowHidden = config.shouldShowHidden
val excludedPaths = config.excludedFolders
val includedPaths = config.includedFolders
folders.filter { it.shouldFolderBeVisible(excludedPaths, includedPaths, shouldShowHidden) }.toMutableList() as ArrayList<String>
} catch (e: Exception) { } catch (e: Exception) {
context.showErrorToast(e)
ArrayList() ArrayList()
} }
} }
private fun getLatestFileFolders(): LinkedHashSet<String> {
val uri = MediaStore.Files.getContentUri("external")
val projection = arrayOf(MediaStore.Images.ImageColumns.DATA)
val parents = LinkedHashSet<String>()
val sorting = "${BaseColumns._ID} DESC LIMIT 50"
var cursor: Cursor? = null
try {
cursor = context.contentResolver.query(uri, projection, null, null, sorting)
if (cursor?.moveToFirst() == true) {
do {
val path = cursor.getStringValue(MediaStore.Images.ImageColumns.DATA) ?: continue
parents.add(path.getParentPath())
} while (cursor.moveToNext())
}
} catch (e: Exception) {
context.showErrorToast(e)
} finally {
cursor?.close()
}
return parents
}
private fun getSelectionQuery(filterMedia: Int): String { private fun getSelectionQuery(filterMedia: Int): String {
val query = StringBuilder() val query = StringBuilder()
query.append("(") query.append("(")
@ -130,7 +153,7 @@ class MediaFetcher(val context: Context) {
return args return args
} }
private fun parseCursor(cursor: Cursor): ArrayList<String> { private fun parseCursor(cursor: Cursor): LinkedHashSet<String> {
val foldersToIgnore = arrayListOf("/storage/emulated/legacy") val foldersToIgnore = arrayListOf("/storage/emulated/legacy")
val config = context.config val config = context.config
val includedFolders = config.includedFolders val includedFolders = config.includedFolders
@ -155,7 +178,7 @@ class MediaFetcher(val context: Context) {
val showHidden = config.shouldShowHidden val showHidden = config.shouldShowHidden
val excludedFolders = config.excludedFolders val excludedFolders = config.excludedFolders
foldersToScan = foldersToScan.filter { it.shouldFolderBeVisible(excludedFolders, includedFolders, showHidden) } as ArrayList<String> foldersToScan = foldersToScan.filter { it.shouldFolderBeVisible(excludedFolders, includedFolders, showHidden) } as ArrayList<String>
return foldersToScan.distinctBy { it.getDistinctPath() } as ArrayList<String> return foldersToScan.distinctBy { it.getDistinctPath() }.toSet() as LinkedHashSet<String>
} }
private fun addFolder(curFolders: ArrayList<String>, folder: String) { private fun addFolder(curFolders: ArrayList<String>, folder: String) {
@ -230,7 +253,7 @@ class MediaFetcher(val context: Context) {
continue continue
} }
if (checkFileExistence && !file.exists()) { if (checkFileExistence && (!file.exists() || !file.isFile)) {
continue continue
} }

View File

@ -0,0 +1,30 @@
package com.simplemobiletools.gallery.pro.helpers
import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.davemorrissey.labs.subscaleview.ImageDecoder
class MyGlideImageDecoder(val degrees: Int) : ImageDecoder {
override fun decode(context: Context, uri: Uri): Bitmap {
val options = RequestOptions()
.format(DecodeFormat.PREFER_ARGB_8888)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.fitCenter()
val builder = Glide.with(context)
.asBitmap()
.load(uri)
.apply(options)
.transform(RotateTransformation(-degrees))
.into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
return builder.get()
}
}

View File

@ -74,7 +74,11 @@ class MyWidgetProvider : AppWidgetProvider() {
} }
setupAppOpenIntent(context, views, R.id.widget_holder, it) setupAppOpenIntent(context, views, R.id.widget_holder, it)
appWidgetManager.updateAppWidget(it.widgetId, views)
try {
appWidgetManager.updateAppWidget(it.widgetId, views)
} catch (ignored: Exception) {
}
} }
} }
} }

View File

@ -1,21 +0,0 @@
package com.simplemobiletools.gallery.pro.helpers
import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import com.davemorrissey.labs.subscaleview.ImageDecoder
import com.squareup.picasso.MemoryPolicy
import com.squareup.picasso.Picasso
class PicassoDecoder(val tag: String, val picasso: Picasso, val degrees: Int) : ImageDecoder {
override fun decode(context: Context, uri: Uri): Bitmap {
return picasso
.load(uri)
.tag(tag)
.config(Bitmap.Config.ARGB_8888)
.memoryPolicy(MemoryPolicy.NO_CACHE)
.rotate(-degrees.toFloat())
.get()
}
}

View File

@ -5,7 +5,7 @@ import android.graphics.*
import android.net.Uri import android.net.Uri
import com.davemorrissey.labs.subscaleview.ImageRegionDecoder import com.davemorrissey.labs.subscaleview.ImageRegionDecoder
class PicassoRegionDecoder(val showHighestQuality: Boolean) : ImageRegionDecoder { class PicassoRegionDecoder(val showHighestQuality: Boolean, val screenWidth: Int, val screenHeight: Int, val minTileDpi: Int) : ImageRegionDecoder {
private var decoder: BitmapRegionDecoder? = null private var decoder: BitmapRegionDecoder? = null
private val decoderLock = Any() private val decoderLock = Any()
@ -18,10 +18,20 @@ class PicassoRegionDecoder(val showHighestQuality: Boolean) : ImageRegionDecoder
override fun decodeRegion(rect: Rect, sampleSize: Int): Bitmap { override fun decodeRegion(rect: Rect, sampleSize: Int): Bitmap {
synchronized(decoderLock) { synchronized(decoderLock) {
var newSampleSize = sampleSize
if (!showHighestQuality && minTileDpi == LOW_TILE_DPI) {
if ((rect.width() > rect.height() && screenWidth > screenHeight) || (rect.height() > rect.width() && screenHeight > screenWidth)) {
if ((rect.width() / sampleSize > screenWidth || rect.height() / sampleSize > screenHeight)) {
newSampleSize *= 2
}
}
}
val options = BitmapFactory.Options() val options = BitmapFactory.Options()
options.inSampleSize = sampleSize options.inSampleSize = newSampleSize
options.inPreferredConfig = if (showHighestQuality) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565 options.inPreferredConfig = if (showHighestQuality) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
val bitmap = decoder!!.decodeRegion(rect, options) val bitmap = decoder!!.decodeRegion(rect, options)
return bitmap ?: throw RuntimeException("Region decoder returned null bitmap - image format may not be supported") return bitmap ?: throw RuntimeException("Region decoder returned null bitmap - image format may not be supported")
} }
} }

View File

@ -0,0 +1,17 @@
package com.simplemobiletools.gallery.pro.helpers
import android.graphics.Bitmap
import android.graphics.Matrix
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
import java.security.MessageDigest
class RotateTransformation(var degrees: Int) : BitmapTransformation() {
override fun updateDiskCacheKey(messageDigest: MessageDigest) {}
override fun transform(pool: BitmapPool, toTransform: Bitmap, outWidth: Int, outHeight: Int): Bitmap {
val matrix = Matrix()
matrix.postRotate(degrees.toFloat())
return Bitmap.createBitmap(toTransform, 0, 0, toTransform.width, toTransform.height, matrix, true)
}
}

View File

@ -44,7 +44,11 @@ class NewPhotoFetcher : JobService() {
addTriggerContentUri(JobInfo.TriggerContentUri(photoUri, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS)) addTriggerContentUri(JobInfo.TriggerContentUri(photoUri, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS))
addTriggerContentUri(JobInfo.TriggerContentUri(videoUri, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS)) addTriggerContentUri(JobInfo.TriggerContentUri(videoUri, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS))
addTriggerContentUri(JobInfo.TriggerContentUri(MEDIA_URI, 0)) addTriggerContentUri(JobInfo.TriggerContentUri(MEDIA_URI, 0))
context.getSystemService(JobScheduler::class.java).schedule(build())
try {
context.getSystemService(JobScheduler::class.java).schedule(build())
} catch (ignored: Exception) {
}
} }
} }
@ -56,46 +60,45 @@ class NewPhotoFetcher : JobService() {
override fun onStartJob(params: JobParameters): Boolean { override fun onStartJob(params: JobParameters): Boolean {
mRunningParams = params mRunningParams = params
val affectedFolderPaths = HashSet<String>()
if (params.triggeredContentAuthorities != null && params.triggeredContentUris != null) {
val ids = arrayListOf<String>()
for (uri in params.triggeredContentUris!!) {
val path = uri.pathSegments
if (path != null && (path.size == PHOTO_PATH_SEGMENTS.size + 1 || path.size == VIDEO_PATH_SEGMENTS.size + 1)) {
ids.add(path[path.size - 1])
}
}
if (ids.isNotEmpty()) {
val selection = StringBuilder()
for (id in ids) {
if (selection.isNotEmpty()) {
selection.append(" OR ")
}
selection.append("${MediaStore.Images.ImageColumns._ID} = '$id'")
}
var cursor: Cursor? = null
try {
val projection = arrayOf(MediaStore.Images.ImageColumns.DATA)
val uris = arrayListOf(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
uris.forEach {
cursor = contentResolver.query(it, projection, selection.toString(), null, null)
while (cursor!!.moveToNext()) {
val path = cursor!!.getStringValue(MediaStore.Images.ImageColumns.DATA)
affectedFolderPaths.add(path.getParentPath())
addPathToDB(path)
}
}
} catch (ignored: Exception) {
} finally {
cursor?.close()
}
}
}
ensureBackgroundThread { ensureBackgroundThread {
val affectedFolderPaths = HashSet<String>()
if (params.triggeredContentAuthorities != null && params.triggeredContentUris != null) {
val ids = arrayListOf<String>()
for (uri in params.triggeredContentUris!!) {
val path = uri.pathSegments
if (path != null && (path.size == PHOTO_PATH_SEGMENTS.size + 1 || path.size == VIDEO_PATH_SEGMENTS.size + 1)) {
ids.add(path[path.size - 1])
}
}
if (ids.isNotEmpty()) {
val selection = StringBuilder()
for (id in ids) {
if (selection.isNotEmpty()) {
selection.append(" OR ")
}
selection.append("${MediaStore.Images.ImageColumns._ID} = '$id'")
}
var cursor: Cursor? = null
try {
val projection = arrayOf(MediaStore.Images.ImageColumns.DATA)
val uris = arrayListOf(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
uris.forEach {
cursor = contentResolver.query(it, projection, selection.toString(), null, null)
while (cursor!!.moveToNext()) {
val path = cursor!!.getStringValue(MediaStore.Images.ImageColumns.DATA)
affectedFolderPaths.add(path.getParentPath())
addPathToDB(path)
}
}
} catch (ignored: Exception) {
} finally {
cursor?.close()
}
}
}
affectedFolderPaths.forEach { affectedFolderPaths.forEach {
updateDirectoryPath(it) updateDirectoryPath(it)
} }

View File

@ -121,7 +121,7 @@ class MediaSideScroll(context: Context, attrs: AttributeSet) : RelativeLayout(co
return true return true
} }
private fun getCurrentVolume() = activity!!.audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) private fun getCurrentVolume() = activity?.audioManager?.getStreamVolume(AudioManager.STREAM_MUSIC) ?: 0
private fun getCurrentBrightness(): Int { private fun getCurrentBrightness(): Int {
return try { return try {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 680 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 531 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 647 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 620 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 601 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 670 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 688 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 741 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 413 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 867 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 845 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 979 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 320 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 994 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 670 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 373 B

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19,12h-2v3h-3v2h5v-5zM7,9h3L10,7L5,7v5h2L7,9zM21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19.01L3,19.01L3,4.99h18v14.02z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M7.47,21.49C4.2,19.93 1.86,16.76 1.5,13L0,13c0.51,6.16 5.66,11 11.95,11 0.23,0 0.44,-0.02 0.66,-0.03L8.8,20.15l-1.33,1.34zM12.05,0c-0.23,0 -0.44,0.02 -0.66,0.04l3.81,3.81 1.33,-1.33C19.8,4.07 22.14,7.24 22.5,11L24,11c-0.51,-6.16 -5.66,-11 -11.95,-11zM16,14h2L18,8c0,-1.11 -0.9,-2 -2,-2h-6v2h6v6zM8,16L8,4L6,4v2L4,6v2h2v8c0,1.1 0.89,2 2,2h8v2h2v-2h2v-2L8,16z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M4.59,6.89c0.7,-0.71 1.4,-1.35 1.71,-1.22 0.5,0.2 0,1.03 -0.3,1.52 -0.25,0.42 -2.86,3.89 -2.86,6.31 0,1.28 0.48,2.34 1.34,2.98 0.75,0.56 1.74,0.73 2.64,0.46 1.07,-0.31 1.95,-1.4 3.06,-2.77 1.21,-1.49 2.83,-3.44 4.08,-3.44 1.63,0 1.65,1.01 1.76,1.79 -3.78,0.64 -5.38,3.67 -5.38,5.37 0,1.7 1.44,3.09 3.21,3.09 1.63,0 4.29,-1.33 4.69,-6.1L21,14.88v-2.5h-2.47c-0.15,-1.65 -1.09,-4.2 -4.03,-4.2 -2.25,0 -4.18,1.91 -4.94,2.84 -0.58,0.73 -2.06,2.48 -2.29,2.72 -0.25,0.3 -0.68,0.84 -1.11,0.84 -0.45,0 -0.72,-0.83 -0.36,-1.92 0.35,-1.09 1.4,-2.86 1.85,-3.52 0.78,-1.14 1.3,-1.92 1.3,-3.28C8.95,3.69 7.31,3 6.44,3 5.12,3 3.97,4 3.72,4.25c-0.36,0.36 -0.66,0.66 -0.88,0.93l1.75,1.71zM13.88,18.55c-0.31,0 -0.74,-0.26 -0.74,-0.72 0,-0.6 0.73,-2.2 2.87,-2.76 -0.3,2.69 -1.43,3.48 -2.13,3.48z"/>
</vector>

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