57
CHANGELOG.md
|
@ -1,6 +1,63 @@
|
|||
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)*
|
||||
----------------------------
|
||||
|
||||
|
|
|
@ -15,10 +15,11 @@ android {
|
|||
applicationId "com.simplemobiletools.gallery.pro"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 28
|
||||
versionCode 256
|
||||
versionName "6.8.2"
|
||||
versionCode 264
|
||||
versionName "6.9.4"
|
||||
multiDexEnabled true
|
||||
setProperty("archivesBaseName", "gallery")
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
|
@ -61,7 +62,7 @@ android {
|
|||
}
|
||||
|
||||
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 'androidx.multidex:multidex:2.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.caverock:androidsvg-aar:1.3'
|
||||
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 'androidx.room:room-compiler:2.1.0'
|
||||
|
|
|
@ -36,6 +36,14 @@
|
|||
android:name=".activities.MainActivity"
|
||||
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>
|
||||
<action android:name="android.intent.action.PICK"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
|
|
|
@ -25,8 +25,12 @@ import com.bumptech.glide.request.RequestListener
|
|||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.bumptech.glide.request.target.Target
|
||||
import com.simplemobiletools.commons.dialogs.ColorPickerDialog
|
||||
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
|
||||
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.gallery.pro.BuildConfig
|
||||
import com.simplemobiletools.gallery.pro.R
|
||||
|
@ -75,7 +79,7 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
|
|||
private var resizeWidth = 0
|
||||
private var resizeHeight = 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 currCropRotateAction = CROP_ROTATE_ASPECT_RATIO
|
||||
private var currAspectRatio = ASPECT_RATIO_FREE
|
||||
|
@ -90,8 +94,7 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
|
|||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_edit)
|
||||
|
||||
if (config.appSideloadingStatus == SIDELOADING_TRUE) {
|
||||
showSideloadingDialog()
|
||||
if (checkAppSideloading()) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -120,6 +123,7 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
|
|||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_editor, menu)
|
||||
updateMenuItemColors(menu)
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -175,12 +179,12 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
|
|||
setupBottomActions()
|
||||
|
||||
if (config.lastEditorCropAspectRatio == ASPECT_RATIO_OTHER) {
|
||||
if (config.lastEditorCropOtherAspectRatioX == 0) {
|
||||
config.lastEditorCropOtherAspectRatioX = 1
|
||||
if (config.lastEditorCropOtherAspectRatioX == 0f) {
|
||||
config.lastEditorCropOtherAspectRatioX = 1f
|
||||
}
|
||||
|
||||
if (config.lastEditorCropOtherAspectRatioY == 0) {
|
||||
config.lastEditorCropOtherAspectRatioY = 1
|
||||
if (config.lastEditorCropOtherAspectRatioY == 0f) {
|
||||
config.lastEditorCropOtherAspectRatioY = 1f
|
||||
}
|
||||
|
||||
lastOtherAspectRatio = Pair(config.lastEditorCropOtherAspectRatioX, config.lastEditorCropOtherAspectRatioY)
|
||||
|
@ -652,13 +656,13 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
|
|||
setFixedAspectRatio(false)
|
||||
} else {
|
||||
val newAspectRatio = when (aspectRatio) {
|
||||
ASPECT_RATIO_ONE_ONE -> Pair(1, 1)
|
||||
ASPECT_RATIO_FOUR_THREE -> Pair(4, 3)
|
||||
ASPECT_RATIO_SIXTEEN_NINE -> Pair(16, 9)
|
||||
ASPECT_RATIO_ONE_ONE -> Pair(1f, 1f)
|
||||
ASPECT_RATIO_FOUR_THREE -> Pair(4f, 3f)
|
||||
ASPECT_RATIO_SIXTEEN_NINE -> Pair(16f, 9f)
|
||||
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) {
|
||||
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 {
|
||||
ensureBackgroundThread {
|
||||
val file = File(path)
|
||||
|
|
|
@ -31,8 +31,9 @@ class ExcludedFoldersActivity : SimpleActivity(), RefreshRecyclerViewListener {
|
|||
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)
|
||||
updateMenuItemColors(menu)
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
updateMenuItemColors(menu)
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,9 @@ class IncludedFoldersActivity : SimpleActivity(), RefreshRecyclerViewListener {
|
|||
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)
|
||||
updateMenuItemColors(menu)
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package com.simplemobiletools.gallery.pro.activities
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.SearchManager
|
||||
import android.content.ClipData
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
|
@ -12,6 +14,8 @@ import android.view.MenuItem
|
|||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.view.MenuItemCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
|
||||
import com.simplemobiletools.commons.dialogs.CreateNewFolderDialog
|
||||
|
@ -61,6 +65,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
private var mIsPasswordProtectionPending = false
|
||||
private var mWasProtectionHandled = false
|
||||
private var mShouldStopFetching = false
|
||||
private var mIsSearchOpen = false
|
||||
private var mLatestMediaId = 0L
|
||||
private var mLatestMediaDateId = 0L
|
||||
private var mCurrentPathPrefix = "" // used at "Group direct subfolders" for navigation
|
||||
|
@ -68,6 +73,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
private var mLastMediaHandler = Handler()
|
||||
private var mTempShowHiddenHandler = Handler()
|
||||
private var mZoomListener: MyRecyclerView.MyZoomListener? = null
|
||||
private var mSearchMenuItem: MenuItem? = null
|
||||
private var mDirs = ArrayList<Directory>()
|
||||
|
||||
private var mStoredAnimateGifs = true
|
||||
|
@ -145,6 +151,10 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
|
||||
updateWidgets()
|
||||
registerFileUpdateListener()
|
||||
|
||||
directories_switch_searching.setOnClickListener {
|
||||
launchSearchActivity()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
|
@ -192,6 +202,8 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
invalidateOptionsMenu()
|
||||
directories_empty_text_label.setTextColor(config.textColor)
|
||||
directories_empty_text.setTextColor(getAdjustedPrimaryColor())
|
||||
directories_switch_searching.setTextColor(getAdjustedPrimaryColor())
|
||||
directories_switch_searching.underlineText()
|
||||
|
||||
if (mIsPasswordProtectionPending && !mWasProtectionHandled) {
|
||||
handleAppPasswordProtection {
|
||||
|
@ -218,6 +230,8 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
mSearchMenuItem?.collapseActionView()
|
||||
|
||||
if (config.temporarilyShowHidden || config.tempSkipDeleteConfirmation) {
|
||||
mTempShowHiddenHandler.postDelayed({
|
||||
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.hide_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.stop_showing_hidden).isVisible = config.temporarilyShowHidden
|
||||
|
||||
updateMenuItemColors(menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.search -> launchSearchActivity()
|
||||
R.id.sort -> showSortingDialog()
|
||||
R.id.filter -> showFilterMediaDialog()
|
||||
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() {
|
||||
if (isNougatPlus()) {
|
||||
val photoFetcher = NewPhotoFetcher()
|
||||
|
@ -336,7 +390,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
if (config.tempFolderPath.isNotEmpty()) {
|
||||
val newFolder = File(config.tempFolderPath)
|
||||
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)
|
||||
tryDeleteFileDirItem(newFolder.toFileDirItem(), true, true)
|
||||
}
|
||||
|
@ -965,7 +1019,10 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
directories_empty_text_label.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.text = getString(R.string.add_folder)
|
||||
|
||||
|
@ -1017,10 +1074,12 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
}
|
||||
measureRecyclerViewContent(dirsToShow)
|
||||
} else {
|
||||
runOnUiThread {
|
||||
if (textToSearch.isNotEmpty()) {
|
||||
dirsToShow = dirsToShow.filter { it.name.contains(textToSearch, true) }.sortedBy { !it.name.startsWith(textToSearch, true) }.toMutableList() as ArrayList
|
||||
}
|
||||
runOnUiThread {
|
||||
checkPlaceholderVisibility(dirsToShow)
|
||||
|
||||
(directories_grid.adapter as? DirectoryAdapter)?.updateDirs(dirsToShow)
|
||||
measureRecyclerViewContent(dirsToShow)
|
||||
}
|
||||
|
@ -1215,6 +1274,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
|||
add(Release(220, R.string.release_220))
|
||||
add(Release(221, R.string.release_221))
|
||||
add(Release(225, R.string.release_225))
|
||||
add(Release(258, R.string.release_258))
|
||||
checkWhatsNew(this, BuildConfig.VERSION_CODE)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
|
|||
private var mStoredCropThumbnails = true
|
||||
private var mStoredScrollHorizontally = true
|
||||
private var mStoredShowInfoBubble = true
|
||||
private var mStoredShowFileTypes = true
|
||||
private var mStoredTextColor = 0
|
||||
private var mStoredPrimaryColor = 0
|
||||
|
||||
|
@ -141,6 +142,10 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
|
|||
getMedia()
|
||||
}
|
||||
|
||||
if (mStoredShowFileTypes != config.showThumbnailFileTypes) {
|
||||
getMediaAdapter()?.updateShowFileTypes(config.showThumbnailFileTypes)
|
||||
}
|
||||
|
||||
if (mStoredTextColor != config.textColor) {
|
||||
getMediaAdapter()?.updateTextColor(config.textColor)
|
||||
}
|
||||
|
@ -207,7 +212,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
|
|||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_media, menu)
|
||||
|
||||
val isFolderHidden = File(mPath).containsNoMedia()
|
||||
val isFolderHidden = mPath.containsNoMedia()
|
||||
menu.apply {
|
||||
findItem(R.id.group).isVisible = !config.scrollHorizontally
|
||||
|
||||
|
@ -234,6 +239,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
|
|||
}
|
||||
|
||||
setupSearch(menu)
|
||||
updateMenuItemColors(menu)
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -284,6 +290,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
|
|||
mStoredCropThumbnails = cropThumbnails
|
||||
mStoredScrollHorizontally = scrollHorizontally
|
||||
mStoredShowInfoBubble = showInfoBubble
|
||||
mStoredShowFileTypes = showThumbnailFileTypes
|
||||
mStoredTextColor = textColor
|
||||
mStoredPrimaryColor = primaryColor
|
||||
mShowAll = showAll
|
||||
|
@ -381,7 +388,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
|
|||
val fastscroller = if (config.scrollHorizontally) media_horizontal_fastscroller else media_vertical_fastscroller
|
||||
MediaAdapter(this, mMedia.clone() as ArrayList<ThumbnailItem>, this, mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent,
|
||||
mAllowPickingMultiple, mPath, media_grid, fastscroller) {
|
||||
if (it is Medium) {
|
||||
if (it is Medium && !isFinishing) {
|
||||
itemClicked(it.path)
|
||||
}
|
||||
}.apply {
|
||||
|
@ -632,7 +639,10 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
|
|||
|
||||
private fun deleteDBDirectory() {
|
||||
ensureBackgroundThread {
|
||||
try {
|
||||
mDirectoryDao.deleteDirPath(mPath)
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -832,7 +842,9 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
|
|||
} else {
|
||||
val isVideo = path.isVideoFast()
|
||||
if (isVideo) {
|
||||
openPath(path, false)
|
||||
val extras = HashMap<String, Boolean>()
|
||||
extras[SHOW_FAVORITES] = mPath == FAVORITES
|
||||
openPath(path, false, extras)
|
||||
} else {
|
||||
Intent(this, ViewPagerActivity::class.java).apply {
|
||||
putExtra(PATH, path)
|
||||
|
|
|
@ -45,7 +45,7 @@ open class PanoramaPhotoActivity : SimpleActivity() {
|
|||
explore.setOnClickListener {
|
||||
isExploreEnabled = !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) {
|
||||
|
|
|
@ -259,7 +259,7 @@ open class PanoramaVideoActivity : SimpleActivity(), SeekBar.OnSeekBarChangeList
|
|||
explore.setOnClickListener {
|
||||
mIsExploreEnabled = !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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ import com.simplemobiletools.commons.extensions.*
|
|||
import com.simplemobiletools.commons.helpers.IS_FROM_GALLERY
|
||||
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE
|
||||
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.R
|
||||
import com.simplemobiletools.gallery.pro.extensions.*
|
||||
|
@ -41,8 +40,7 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
|
|||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.fragment_holder)
|
||||
|
||||
if (config.appSideloadingStatus == SIDELOADING_TRUE) {
|
||||
showSideloadingDialog()
|
||||
if (checkAppSideloading()) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -231,6 +229,7 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
|
|||
|
||||
private fun sendViewPagerIntent(path: String) {
|
||||
Intent(this, ViewPagerActivity::class.java).apply {
|
||||
putExtra(SHOW_FAVORITES, intent.getBooleanExtra(SHOW_FAVORITES, false))
|
||||
putExtra(IS_VIEW_INTENT, true)
|
||||
putExtra(IS_FROM_GALLERY, mIsFromGallery)
|
||||
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
|
||||
}
|
||||
|
||||
updateMenuItemColors(menu)
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,15 @@ class SearchActivity : SimpleActivity(), MediaOperationsListener {
|
|||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_search, 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
|
||||
}
|
||||
|
||||
|
@ -135,6 +144,11 @@ class SearchActivity : SimpleActivity(), MediaOperationsListener {
|
|||
|
||||
private fun getMediaAdapter() = media_grid.adapter as? MediaAdapter
|
||||
|
||||
private fun toggleFilenameVisibility() {
|
||||
config.displayFileNames = !config.displayFileNames
|
||||
getMediaAdapter()?.updateDisplayFilenames(config.displayFileNames)
|
||||
}
|
||||
|
||||
private fun itemClicked(path: String) {
|
||||
val isVideo = path.isVideoFast()
|
||||
if (isVideo) {
|
||||
|
|
|
@ -10,6 +10,7 @@ import android.os.Bundle
|
|||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
|
||||
import com.simplemobiletools.commons.extensions.checkAppSideloading
|
||||
import com.simplemobiletools.commons.extensions.toast
|
||||
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
|
||||
import com.simplemobiletools.commons.helpers.isNougatPlus
|
||||
|
@ -31,6 +32,10 @@ class SetWallpaperActivity : SimpleActivity(), CropImageView.OnCropImageComplete
|
|||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_set_wallpaper)
|
||||
|
||||
if (checkAppSideloading()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (intent.data == null) {
|
||||
val pickIntent = Intent(applicationContext, MainActivity::class.java)
|
||||
pickIntent.action = Intent.ACTION_PICK
|
||||
|
@ -43,6 +48,20 @@ class SetWallpaperActivity : SimpleActivity(), CropImageView.OnCropImageComplete
|
|||
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) {
|
||||
uri = intent.data
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
isLandscapeRatio = isLandscape
|
||||
setupAspectRatio()
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.simplemobiletools.gallery.pro.activities
|
|||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.Menu
|
||||
import com.simplemobiletools.commons.dialogs.*
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.commons.helpers.*
|
||||
|
@ -63,6 +64,7 @@ class SettingsActivity : SimpleActivity() {
|
|||
setupShowNotch()
|
||||
setupBottomActions()
|
||||
setupThumbnailVideoDuration()
|
||||
setupThumbnailFileTypes()
|
||||
setupShowMediaCount()
|
||||
setupKeepLastModified()
|
||||
setupShowInfoBubble()
|
||||
|
@ -84,6 +86,12 @@ class SettingsActivity : SimpleActivity() {
|
|||
setupSectionColors()
|
||||
setupExportSettings()
|
||||
setupImportSettings()
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
updateMenuItemColors(menu)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
||||
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() {
|
||||
settings_black_background.isChecked = config.blackBackground
|
||||
settings_black_background_holder.setOnClickListener {
|
||||
|
@ -615,9 +631,6 @@ class SettingsActivity : SimpleActivity() {
|
|||
put(FILE_LOADING_PRIORITY, config.fileLoadingPriority)
|
||||
put(AUTOPLAY_VIDEOS, config.autoplayVideos)
|
||||
put(REMEMBER_LAST_VIDEO_POSITION, config.rememberLastVideoPosition)
|
||||
config.getAllLastVideoPositions().forEach {
|
||||
put(it.key, it.value.toString())
|
||||
}
|
||||
put(LOOP_VIDEOS, config.loopVideos)
|
||||
put(OPEN_VIDEOS_ON_SEPARATE_SCREEN, config.openVideosOnSeparateScreen)
|
||||
put(ALLOW_VIDEO_GESTURES, config.allowVideoGestures)
|
||||
|
@ -793,17 +806,13 @@ class SettingsActivity : SimpleActivity() {
|
|||
SLIDESHOW_MOVE_BACKWARDS -> config.slideshowMoveBackwards = value.toBoolean()
|
||||
SLIDESHOW_LOOP -> config.loopSlideshow = value.toBoolean()
|
||||
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_Y -> config.lastEditorCropOtherAspectRatioY = value.toInt()
|
||||
LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_X -> config.lastEditorCropOtherAspectRatioX = value.toString().toFloat()
|
||||
LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_Y -> config.lastEditorCropOtherAspectRatioY = value.toString().toFloat()
|
||||
LAST_EDITOR_DRAW_COLOR -> config.lastEditorDrawColor = value.toInt()
|
||||
LAST_EDITOR_BRUSH_SIZE -> config.lastEditorBrushSize = value.toInt()
|
||||
LAST_CONFLICT_RESOLUTION -> config.lastConflictResolution = value.toInt()
|
||||
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)
|
||||
|
|
|
@ -4,8 +4,6 @@ import android.content.Intent
|
|||
import com.simplemobiletools.commons.activities.BaseSplashActivity
|
||||
|
||||
class SplashActivity : BaseSplashActivity() {
|
||||
override fun getAppPackageName() = packageName
|
||||
|
||||
override fun initActivity() {
|
||||
startActivity(Intent(this, MainActivity::class.java))
|
||||
finish()
|
||||
|
|
|
@ -19,6 +19,7 @@ import android.net.Uri
|
|||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.provider.MediaStore
|
||||
import android.text.Html
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
|
@ -126,6 +127,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
|||
invalidateOptionsMenu()
|
||||
|
||||
supportActionBar?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
supportActionBar?.title = Html.fromHtml("<font color=#FFFFFF'>${mPath.getFilenameFromPath()}</font>")
|
||||
window.statusBarColor = Color.TRANSPARENT
|
||||
}
|
||||
|
||||
|
@ -189,6 +191,8 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
|||
if (visibleBottomActions != 0) {
|
||||
updateBottomActionIcons(currentMedium)
|
||||
}
|
||||
|
||||
updateMenuItemColors(menu, baseColor = Color.BLACK)
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -572,6 +576,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
|||
|
||||
val fileDirItems = arrayListOf(FileDirItem(currPath, currPath.getFilenameFromPath()))
|
||||
tryCopyMoveFilesTo(fileDirItems, isCopyOperation) {
|
||||
fixDateTaken(arrayListOf(currPath), false)
|
||||
config.tempFolderPath = ""
|
||||
if (!isCopyOperation) {
|
||||
refreshViewPager()
|
||||
|
@ -620,12 +625,12 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
|||
private fun getChangeOrientationIcon(): Int {
|
||||
return if (mIsOrientationLocked) {
|
||||
if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
|
||||
R.drawable.ic_orientation_portrait
|
||||
R.drawable.ic_orientation_portrait_vector
|
||||
} else {
|
||||
R.drawable.ic_orientation_landscape
|
||||
R.drawable.ic_orientation_landscape_vector
|
||||
}
|
||||
} else {
|
||||
R.drawable.ic_orientation_auto
|
||||
R.drawable.ic_orientation_auto_vector
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -693,7 +698,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
|||
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() {
|
||||
if (getCurrentMedium() != null) {
|
||||
|
@ -798,10 +803,10 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
|||
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)
|
||||
|
||||
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_rotate.beVisibleIf(config.visibleBottomActions and BOTTOM_ACTION_ROTATE != 0 && getCurrentMedium()?.isImage() == true)
|
||||
|
|
|
@ -145,8 +145,8 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
|
|||
}
|
||||
|
||||
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_unhide).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 { it.doesThisOrParentHaveNoMedia() }
|
||||
}
|
||||
|
||||
private fun checkPinBtnVisibility(menu: Menu, selectedPaths: ArrayList<String>) {
|
||||
|
@ -218,28 +218,23 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
|
|||
}
|
||||
}
|
||||
|
||||
selectedPaths.filter { it != FAVORITES && it != RECYCLE_BIN && (selectedPaths.size == 1 || !activity.config.isFolderProtected(it)) }.forEach {
|
||||
val path = it
|
||||
if (hide) {
|
||||
if (config.wasHideFolderTooltipShown) {
|
||||
activity.handleLockedFolderOpening(path) { success ->
|
||||
if (success) {
|
||||
hideFolder(path)
|
||||
}
|
||||
}
|
||||
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 {
|
||||
val path = it
|
||||
activity.handleLockedFolderOpening(path) { success ->
|
||||
if (success) {
|
||||
hideFolder(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
activity.handleLockedFolderOpening(path) { success ->
|
||||
if (success) {
|
||||
if (path.containsNoMedia()) {
|
||||
activity.removeNoMedia(path) {
|
||||
if (activity.config.shouldShowHidden) {
|
||||
updateFolderNames()
|
||||
|
@ -250,11 +245,27 @@ 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) {
|
||||
if (askConfirmation) {
|
||||
|
@ -308,7 +319,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
|
|||
val affectedPositions = ArrayList<Int>()
|
||||
val includedFolders = activity.config.includedFolders
|
||||
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) {
|
||||
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>
|
||||
activity.tryCopyMoveFilesTo(fileDirItems, isCopyOperation) {
|
||||
activity.fixDateTaken(paths, false)
|
||||
config.tempFolderPath = ""
|
||||
listener?.refreshItems()
|
||||
finishActMode()
|
||||
|
@ -456,7 +468,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
|
|||
activity.getShortcutImage(coverThumbnail, drawable) {
|
||||
val intent = Intent(activity, MediaActivity::class.java)
|
||||
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)
|
||||
|
||||
val shortcut = ShortcutInfo.Builder(activity, path)
|
||||
|
@ -595,7 +607,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
|
|||
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>
|
||||
|
||||
|
@ -669,7 +681,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList<Directo
|
|||
dir_pin.beVisibleIf(pinnedFolders.contains(directory.path))
|
||||
dir_location.beVisibleIf(directory.location != LOCATION_INTERNAL)
|
||||
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)
|
||||
|
|
|
@ -10,8 +10,8 @@ import com.bumptech.glide.Glide
|
|||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
|
||||
import com.simplemobiletools.commons.dialogs.PropertiesDialog
|
||||
import com.simplemobiletools.commons.dialogs.RenameDialog
|
||||
import com.simplemobiletools.commons.dialogs.RenameItemDialog
|
||||
import com.simplemobiletools.commons.dialogs.RenameItemsPatternDialog
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
|
||||
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.extensions.*
|
||||
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.interfaces.MediaOperationsListener
|
||||
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 cropThumbnails = config.cropThumbnails
|
||||
private var displayFilenames = config.displayFileNames
|
||||
private var showFileTypes = config.showThumbnailFileTypes
|
||||
|
||||
init {
|
||||
setupDragListener(true)
|
||||
|
@ -215,7 +218,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
|
|||
}
|
||||
}
|
||||
} else {
|
||||
RenameItemsPatternDialog(activity, getSelectedPaths()) {
|
||||
RenameDialog(activity, getSelectedPaths()) {
|
||||
enableInstantLoad()
|
||||
listener?.refreshItems()
|
||||
finishActMode()
|
||||
|
@ -326,6 +329,7 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
|
|||
config.tempFolderPath = ""
|
||||
activity.applicationContext.rescanFolderMedia(it)
|
||||
activity.applicationContext.rescanFolderMedia(fileDirItems.first().getParentPath())
|
||||
activity.fixDateTaken(paths, false)
|
||||
if (!isCopyOperation) {
|
||||
listener?.refreshItems()
|
||||
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>
|
||||
|
||||
|
@ -431,6 +435,11 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
|
|||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun updateShowFileTypes(showFileTypes: Boolean) {
|
||||
this.showFileTypes = showFileTypes
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
private fun enableInstantLoad() {
|
||||
loadImageInstantly = true
|
||||
delayHandler.postDelayed({
|
||||
|
@ -444,6 +453,18 @@ class MediaAdapter(activity: BaseSimpleActivity, var media: MutableList<Thumbnai
|
|||
val isSelected = selectedKeys.contains(medium.path.hashCode())
|
||||
view.apply {
|
||||
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.text = medium.name
|
||||
medium_name.tag = medium.path
|
||||
|
|
|
@ -9,11 +9,11 @@ import com.simplemobiletools.commons.extensions.value
|
|||
import com.simplemobiletools.gallery.pro.R
|
||||
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 {
|
||||
val view = activity.layoutInflater.inflate(R.layout.dialog_custom_aspect_ratio, null).apply {
|
||||
aspect_ratio_width.setText(defaultCustomAspectRatio?.first?.toString() ?: "")
|
||||
aspect_ratio_height.setText(defaultCustomAspectRatio?.second?.toString() ?: "")
|
||||
aspect_ratio_width.setText(defaultCustomAspectRatio?.first?.toInt()?.toString() ?: "")
|
||||
aspect_ratio_height.setText(defaultCustomAspectRatio?.second?.toInt()?.toString() ?: "")
|
||||
}
|
||||
|
||||
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
|
||||
return if (textValue.isEmpty()) 0 else textValue.toInt()
|
||||
return if (textValue.isEmpty()) 0f else textValue.toFloat()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,44 +6,44 @@ import com.simplemobiletools.commons.extensions.setupDialogStuff
|
|||
import com.simplemobiletools.gallery.pro.R
|
||||
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
|
||||
|
||||
init {
|
||||
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_3_2.setOnClickListener { ratioPicked(Pair(3, 2)) }
|
||||
other_aspect_ratio_4_3.setOnClickListener { ratioPicked(Pair(4, 3)) }
|
||||
other_aspect_ratio_5_3.setOnClickListener { ratioPicked(Pair(5, 3)) }
|
||||
other_aspect_ratio_16_9.setOnClickListener { ratioPicked(Pair(16, 9)) }
|
||||
other_aspect_ratio_19_9.setOnClickListener { ratioPicked(Pair(19, 9)) }
|
||||
other_aspect_ratio_2_1.setOnClickListener { ratioPicked(Pair(2f, 1f)) }
|
||||
other_aspect_ratio_3_2.setOnClickListener { ratioPicked(Pair(3f, 2f)) }
|
||||
other_aspect_ratio_4_3.setOnClickListener { ratioPicked(Pair(4f, 3f)) }
|
||||
other_aspect_ratio_5_3.setOnClickListener { ratioPicked(Pair(5f, 3f)) }
|
||||
other_aspect_ratio_16_9.setOnClickListener { ratioPicked(Pair(16f, 9f)) }
|
||||
other_aspect_ratio_19_9.setOnClickListener { ratioPicked(Pair(19f, 9f)) }
|
||||
other_aspect_ratio_custom.setOnClickListener { customRatioPicked() }
|
||||
|
||||
other_aspect_ratio_1_2.setOnClickListener { ratioPicked(Pair(1, 2)) }
|
||||
other_aspect_ratio_2_3.setOnClickListener { ratioPicked(Pair(2, 3)) }
|
||||
other_aspect_ratio_3_4.setOnClickListener { ratioPicked(Pair(3, 4)) }
|
||||
other_aspect_ratio_3_5.setOnClickListener { ratioPicked(Pair(3, 5)) }
|
||||
other_aspect_ratio_9_16.setOnClickListener { ratioPicked(Pair(9, 16)) }
|
||||
other_aspect_ratio_9_19.setOnClickListener { ratioPicked(Pair(9, 19)) }
|
||||
other_aspect_ratio_1_2.setOnClickListener { ratioPicked(Pair(1f, 2f)) }
|
||||
other_aspect_ratio_2_3.setOnClickListener { ratioPicked(Pair(2f, 3f)) }
|
||||
other_aspect_ratio_3_4.setOnClickListener { ratioPicked(Pair(3f, 4f)) }
|
||||
other_aspect_ratio_3_5.setOnClickListener { ratioPicked(Pair(3f, 5f)) }
|
||||
other_aspect_ratio_9_16.setOnClickListener { ratioPicked(Pair(9f, 16f)) }
|
||||
other_aspect_ratio_9_19.setOnClickListener { ratioPicked(Pair(9f, 19f)) }
|
||||
|
||||
val radio1SelectedItemId = when (lastOtherAspectRatio) {
|
||||
Pair(2, 1) -> other_aspect_ratio_2_1.id
|
||||
Pair(3, 2) -> other_aspect_ratio_3_2.id
|
||||
Pair(4, 3) -> other_aspect_ratio_4_3.id
|
||||
Pair(5, 3) -> other_aspect_ratio_5_3.id
|
||||
Pair(16, 9) -> other_aspect_ratio_16_9.id
|
||||
Pair(19, 9) -> other_aspect_ratio_19_9.id
|
||||
Pair(2f, 1f) -> other_aspect_ratio_2_1.id
|
||||
Pair(3f, 2f) -> other_aspect_ratio_3_2.id
|
||||
Pair(4f, 3f) -> other_aspect_ratio_4_3.id
|
||||
Pair(5f, 3f) -> other_aspect_ratio_5_3.id
|
||||
Pair(16f, 9f) -> other_aspect_ratio_16_9.id
|
||||
Pair(19f, 9f) -> other_aspect_ratio_19_9.id
|
||||
else -> 0
|
||||
}
|
||||
other_aspect_ratio_dialog_radio_1.check(radio1SelectedItemId)
|
||||
|
||||
val radio2SelectedItemId = when (lastOtherAspectRatio) {
|
||||
Pair(1, 2) -> other_aspect_ratio_1_2.id
|
||||
Pair(2, 3) -> other_aspect_ratio_2_3.id
|
||||
Pair(3, 4) -> other_aspect_ratio_3_4.id
|
||||
Pair(3, 5) -> other_aspect_ratio_3_5.id
|
||||
Pair(9, 16) -> other_aspect_ratio_9_16.id
|
||||
Pair(9, 19) -> other_aspect_ratio_9_19.id
|
||||
Pair(1f, 2f) -> other_aspect_ratio_1_2.id
|
||||
Pair(2f, 3f) -> other_aspect_ratio_2_3.id
|
||||
Pair(3f, 4f) -> other_aspect_ratio_3_4.id
|
||||
Pair(3f, 5f) -> other_aspect_ratio_3_5.id
|
||||
Pair(9f, 16f) -> other_aspect_ratio_9_16.id
|
||||
Pair(9f, 19f) -> other_aspect_ratio_9_19.id
|
||||
else -> 0
|
||||
}
|
||||
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)
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ import com.simplemobiletools.gallery.pro.BuildConfig
|
|||
import com.simplemobiletools.gallery.pro.R
|
||||
import com.simplemobiletools.gallery.pro.activities.SimpleActivity
|
||||
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.interfaces.MediumDao
|
||||
import com.squareup.picasso.Picasso
|
||||
|
@ -61,8 +60,8 @@ fun Activity.setAs(path: String) {
|
|||
setAsIntent(path, BuildConfig.APPLICATION_ID)
|
||||
}
|
||||
|
||||
fun Activity.openPath(path: String, forceChooser: Boolean) {
|
||||
openPathIntent(path, forceChooser, BuildConfig.APPLICATION_ID)
|
||||
fun Activity.openPath(path: String, forceChooser: Boolean, extras: HashMap<String, Boolean> = HashMap()) {
|
||||
openPathIntent(path, forceChooser, BuildConfig.APPLICATION_ID, extras = extras)
|
||||
}
|
||||
|
||||
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_15_title, R.string.faq_15_text),
|
||||
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)
|
||||
}
|
||||
|
@ -257,11 +257,15 @@ fun BaseSimpleActivity.restoreRecycleBinPath(path: String, callback: () -> Unit)
|
|||
fun BaseSimpleActivity.restoreRecycleBinPaths(paths: ArrayList<String>, mediumDao: MediumDao = galleryDB.MediumDao(), callback: () -> Unit) {
|
||||
ensureBackgroundThread {
|
||||
val newPaths = ArrayList<String>()
|
||||
paths.forEach {
|
||||
val source = it
|
||||
val destination = it.removePrefix(recycleBinPath)
|
||||
for (source in paths) {
|
||||
val destination = source.removePrefix(recycleBinPath)
|
||||
val lastModified = File(source).lastModified()
|
||||
|
||||
val isShowingSAF = handleSAFDialog(destination) {}
|
||||
if (isShowingSAF) {
|
||||
return@ensureBackgroundThread
|
||||
}
|
||||
|
||||
var inputStream: InputStream? = null
|
||||
var out: OutputStream? = null
|
||||
try {
|
||||
|
|
|
@ -401,6 +401,7 @@ fun Context.rescanFolderMediaSync(path: String) {
|
|||
val newMedia = it
|
||||
val mediumDao = galleryDB.MediumDao()
|
||||
val media = newMedia.filter { it is Medium } as ArrayList<Medium>
|
||||
try {
|
||||
mediumDao.insertAll(media)
|
||||
|
||||
cached.forEach {
|
||||
|
@ -411,6 +412,8 @@ fun Context.rescanFolderMediaSync(path: String) {
|
|||
}
|
||||
}
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
}
|
||||
}.execute()
|
||||
}
|
||||
|
@ -424,7 +427,7 @@ fun Context.storeDirectoryItems(items: ArrayList<Directory>, directoryDao: Direc
|
|||
|
||||
fun Context.checkAppendingHidden(path: String, hidden: String, includedFolders: MutableSet<String>): String {
|
||||
val dirName = getFolderNameFromPath(path)
|
||||
return if (File(path).doesThisOrParentHaveNoMedia() && !path.isThisOrParentIncluded(includedFolders)) {
|
||||
return if (path.doesThisOrParentHaveNoMedia() && !path.isThisOrParentIncluded(includedFolders)) {
|
||||
"$dirName $hidden"
|
||||
} else {
|
||||
dirName
|
||||
|
@ -587,7 +590,7 @@ fun Context.getCachedDirectories(getVideosOnly: Boolean = false, getImagesOnly:
|
|||
|
||||
val hiddenString = resources.getString(R.string.hidden)
|
||||
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"
|
||||
} else {
|
||||
it.name
|
||||
|
@ -620,7 +623,7 @@ fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImag
|
|||
try {
|
||||
val currMedia = mediumDao.getMediaFromPath(it)
|
||||
media.addAll(currMedia)
|
||||
} catch (ignored: IllegalStateException) {
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
package com.simplemobiletools.gallery.pro.extensions
|
||||
|
||||
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.IOException
|
||||
|
||||
|
|
|
@ -251,7 +251,6 @@ class PhotoFragment : ViewPagerFragment() {
|
|||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
|
||||
if (!mWasInit) {
|
||||
return
|
||||
}
|
||||
|
@ -272,6 +271,7 @@ class PhotoFragment : ViewPagerFragment() {
|
|||
loadImage()
|
||||
}
|
||||
|
||||
measureScreen()
|
||||
initExtendedDetails()
|
||||
updateInstantSwitchWidths()
|
||||
}
|
||||
|
@ -461,13 +461,14 @@ class PhotoFragment : ViewPagerFragment() {
|
|||
mIsSubsamplingVisible = true
|
||||
val config = context!!.config
|
||||
val showHighestQuality = config.showHighestQuality
|
||||
val minTileDpi = if (showHighestQuality) -1 else getMinTileDpi()
|
||||
|
||||
val bitmapDecoder = object : DecoderFactory<ImageDecoder> {
|
||||
override fun make() = PicassoDecoder(mMedium.path, Picasso.get(), rotation)
|
||||
override fun make() = MyGlideImageDecoder(rotation)
|
||||
}
|
||||
|
||||
val regionDecoder = object : DecoderFactory<ImageRegionDecoder> {
|
||||
override fun make() = PicassoRegionDecoder(showHighestQuality)
|
||||
override fun make() = PicassoRegionDecoder(showHighestQuality, mScreenWidth, mScreenHeight, minTileDpi)
|
||||
}
|
||||
|
||||
var newOrientation = (rotation + mCurrentRotationDegrees) % 360
|
||||
|
@ -477,7 +478,7 @@ class PhotoFragment : ViewPagerFragment() {
|
|||
|
||||
mView.subsampling_view.apply {
|
||||
setMaxTileSize(if (showHighestQuality) Integer.MAX_VALUE else 4096)
|
||||
setMinimumTileDpi(if (showHighestQuality) -1 else getMinTileDpi())
|
||||
setMinimumTileDpi(minTileDpi)
|
||||
background = ColorDrawable(Color.TRANSPARENT)
|
||||
bitmapDecoderFactory = bitmapDecoder
|
||||
regionDecoderFactory = regionDecoder
|
||||
|
@ -487,6 +488,7 @@ class PhotoFragment : ViewPagerFragment() {
|
|||
isOneToOneZoomEnabled = config.allowOneToOneZoom
|
||||
orientation = newOrientation
|
||||
setImage(mMedium.path)
|
||||
|
||||
onImageEventListener = object : SubsamplingScaleImageView.OnImageEventListener {
|
||||
override fun onReady() {
|
||||
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 device = "${Build.BRAND} ${Build.MODEL}".toLowerCase()
|
||||
return when {
|
||||
WEIRD_DEVICES.contains(device) -> 240
|
||||
averageDpi > 400 -> 280
|
||||
averageDpi > 300 -> 220
|
||||
else -> 160
|
||||
WEIRD_DEVICES.contains(device) -> WEIRD_TILE_DPI
|
||||
averageDpi > 400 -> HIGH_TILE_DPI
|
||||
averageDpi > 300 -> NORMAL_TILE_DPI
|
||||
else -> LOW_TILE_DPI
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,9 +49,12 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
private var mWasVideoStarted = false
|
||||
private var mWasPlayerInited = false
|
||||
private var mWasLastPositionRestored = false
|
||||
private var mPlayOnPrepared = false
|
||||
private var mIsPlayerPrepared = false
|
||||
private var mCurrTime = 0
|
||||
private var mDuration = 0
|
||||
private var mPositionWhenInit = 0
|
||||
private var mPositionAtPause = 0L
|
||||
|
||||
private var mExoPlayer: SimpleExoPlayer? = null
|
||||
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 {
|
||||
instant_prev_item.setOnClickListener { listener?.goToPrevItem() }
|
||||
instant_next_item.setOnClickListener { listener?.goToNextItem() }
|
||||
panorama_outline.setOnClickListener { openPanorama() }
|
||||
video_curr_time.setOnClickListener { skip(false) }
|
||||
video_duration.setOnClickListener { skip(true) }
|
||||
video_holder.setOnClickListener { toggleFullscreen() }
|
||||
video_preview.setOnClickListener { toggleFullscreen() }
|
||||
panorama_outline.setOnClickListener { openPanorama() }
|
||||
video_surface_frame.setOnClickListener { toggleFullscreen() }
|
||||
video_play_outline.setOnClickListener {
|
||||
if (mConfig.openVideosOnSeparateScreen) {
|
||||
launchVideoPlayer()
|
||||
|
@ -108,6 +112,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
mBrightnessSideScroll = video_brightness_controller
|
||||
mVolumeSideScroll = video_volume_controller
|
||||
mTextureView = video_surface
|
||||
mTextureView.surfaceTextureListener = this@VideoFragment
|
||||
|
||||
if (mConfig.allowDownGesture) {
|
||||
video_preview.setOnTouchListener { view, event ->
|
||||
|
@ -158,7 +163,6 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
}
|
||||
|
||||
if (!mIsPanorama) {
|
||||
setupPlayer()
|
||||
if (savedInstanceState != null) {
|
||||
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() {
|
||||
if (!videoEnded()) {
|
||||
if (!videoEnded() && mExoPlayer != null) {
|
||||
mConfig.saveLastVideoPosition(mMedium.path, mExoPlayer!!.currentPosition.toInt() / 1000)
|
||||
}
|
||||
}
|
||||
|
@ -292,6 +281,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
private fun restoreLastVideoSavedPosition() {
|
||||
val pos = mConfig.getLastVideoPosition(mMedium.path)
|
||||
if (pos > 0) {
|
||||
mPositionAtPause = pos * 1000L
|
||||
setPosition(pos)
|
||||
}
|
||||
}
|
||||
|
@ -317,6 +307,13 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
}
|
||||
|
||||
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 uri = if (isContentUri) Uri.parse(mMedium.path) else Uri.fromFile(File(mMedium.path))
|
||||
val dataSpec = DataSpec(uri)
|
||||
|
@ -325,15 +322,19 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
fileDataSource.open(dataSpec)
|
||||
} catch (e: Exception) {
|
||||
activity?.showErrorToast(e)
|
||||
return
|
||||
}
|
||||
|
||||
val factory = DataSource.Factory { fileDataSource }
|
||||
val audioSource = ExtractorMediaSource(fileDataSource.uri, factory, DefaultExtractorsFactory(), null, null)
|
||||
mPlayOnPrepared = true
|
||||
mExoPlayer!!.audioStreamType = C.STREAM_TYPE_MUSIC
|
||||
mExoPlayer!!.prepare(audioSource)
|
||||
|
||||
if (mTextureView.surfaceTexture != null) {
|
||||
mExoPlayer!!.setVideoSurface(Surface(mTextureView.surfaceTexture))
|
||||
}
|
||||
|
||||
private fun initExoPlayerListeners() {
|
||||
mExoPlayer!!.addListener(object : Player.EventListener {
|
||||
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {}
|
||||
|
||||
|
@ -364,7 +365,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
mExoPlayer!!.addVideoListener(object : SimpleExoPlayer.VideoListener {
|
||||
override fun onVideoSizeChanged(width: Int, height: Int, unappliedRotationDegrees: Int, pixelWidthHeightRatio: Float) {
|
||||
mVideoSize.x = width
|
||||
mVideoSize.y = height
|
||||
mVideoSize.y = (height / pixelWidthHeightRatio).toInt()
|
||||
setVideoSize()
|
||||
}
|
||||
|
||||
|
@ -483,10 +484,14 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
}
|
||||
|
||||
private fun skip(forward: Boolean) {
|
||||
if (mExoPlayer == null || mIsPanorama) {
|
||||
if (mIsPanorama) {
|
||||
return
|
||||
} else if (mExoPlayer == null) {
|
||||
playVideo()
|
||||
return
|
||||
}
|
||||
|
||||
mPositionAtPause = 0L
|
||||
val curr = mExoPlayer!!.currentPosition
|
||||
val twoPercents = Math.max((mExoPlayer!!.duration / 50).toInt(), MIN_SKIP_LENGTH)
|
||||
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) {
|
||||
if (mExoPlayer != null && fromUser) {
|
||||
if (fromUser) {
|
||||
if (mExoPlayer != null) {
|
||||
if (!mWasPlayerInited) {
|
||||
mPositionWhenInit = progress
|
||||
}
|
||||
setPosition(progress)
|
||||
}
|
||||
|
||||
if (mExoPlayer == null) {
|
||||
mPositionAtPause = progress * 1000L
|
||||
playVideo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar) {
|
||||
if (mExoPlayer == null)
|
||||
if (mExoPlayer == null) {
|
||||
return
|
||||
}
|
||||
|
||||
mExoPlayer!!.playWhenReady = false
|
||||
mIsDragged = true
|
||||
|
@ -527,26 +540,27 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
if (mIsPlaying) {
|
||||
mExoPlayer!!.playWhenReady = true
|
||||
} else {
|
||||
togglePlayPause()
|
||||
playVideo()
|
||||
}
|
||||
|
||||
mIsDragged = false
|
||||
}
|
||||
|
||||
private fun togglePlayPause() {
|
||||
if (activity == null || !isAdded)
|
||||
if (activity == null || !isAdded) {
|
||||
return
|
||||
}
|
||||
|
||||
mIsPlaying = !mIsPlaying
|
||||
if (mIsPlaying) {
|
||||
playVideo()
|
||||
} else {
|
||||
pauseVideo()
|
||||
} else {
|
||||
playVideo()
|
||||
}
|
||||
}
|
||||
|
||||
fun playVideo() {
|
||||
if (mExoPlayer == null) {
|
||||
initExoPlayer()
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -575,9 +589,11 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
}
|
||||
|
||||
mWasVideoStarted = true
|
||||
if (mIsPlayerPrepared) {
|
||||
mIsPlaying = 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() {
|
||||
|
@ -592,6 +608,8 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
|
||||
mPlayPauseButton.setImageResource(R.drawable.ic_play_outline)
|
||||
activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
mPositionAtPause = mExoPlayer?.currentPosition ?: 0L
|
||||
releaseExoPlayer()
|
||||
}
|
||||
|
||||
private fun videoEnded(): Boolean {
|
||||
|
@ -604,6 +622,10 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
mExoPlayer?.seekTo(seconds * 1000L)
|
||||
mSeekBar.progress = seconds
|
||||
mCurrTimeView.text = seconds.getFormattedDuration()
|
||||
|
||||
if (!mIsPlaying) {
|
||||
mPositionAtPause = mExoPlayer?.currentPosition ?: 0L
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupVideoDuration() {
|
||||
|
@ -627,7 +649,17 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
setPosition(mPositionWhenInit)
|
||||
mPositionWhenInit = 0
|
||||
}
|
||||
|
||||
mIsPlayerPrepared = true
|
||||
if (mPlayOnPrepared && !mIsPlaying) {
|
||||
if (mPositionAtPause != 0L) {
|
||||
mExoPlayer?.seekTo(mPositionAtPause)
|
||||
mPositionAtPause = 0L
|
||||
}
|
||||
playVideo()
|
||||
}
|
||||
mWasPlayerInited = true
|
||||
mPlayOnPrepared = false
|
||||
}
|
||||
|
||||
private fun videoCompleted() {
|
||||
|
@ -657,6 +689,7 @@ class VideoFragment : ViewPagerFragment(), TextureView.SurfaceTextureListener, S
|
|||
}
|
||||
|
||||
private fun releaseExoPlayer() {
|
||||
mIsPlayerPrepared = false
|
||||
mExoPlayer?.stop()
|
||||
ensureBackgroundThread {
|
||||
mExoPlayer?.release()
|
||||
|
|
|
@ -178,6 +178,10 @@ class Config(context: Context) : BaseConfig(context) {
|
|||
get() = prefs.getBoolean(SHOW_THUMBNAIL_VIDEO_DURATION, false)
|
||||
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
|
||||
get() = prefs.getInt(SCREEN_ROTATION, ROTATE_BY_SYSTEM_SETTING)
|
||||
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)
|
||||
set(lastEditorCropAspectRatio) = prefs.edit().putInt(LAST_EDITOR_CROP_ASPECT_RATIO, lastEditorCropAspectRatio).apply()
|
||||
|
||||
var lastEditorCropOtherAspectRatioX: Int
|
||||
get() = prefs.getInt(LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_X, 2)
|
||||
set(lastEditorCropOtherAspectRatioX) = prefs.edit().putInt(LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_X, lastEditorCropOtherAspectRatioX).apply()
|
||||
var lastEditorCropOtherAspectRatioX: Float
|
||||
get() = prefs.getFloat(LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_X, 2f)
|
||||
set(lastEditorCropOtherAspectRatioX) = prefs.edit().putFloat(LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_X, lastEditorCropOtherAspectRatioX).apply()
|
||||
|
||||
var lastEditorCropOtherAspectRatioY: Int
|
||||
get() = prefs.getInt(LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_Y, 1)
|
||||
set(lastEditorCropOtherAspectRatioY) = prefs.edit().putInt(LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_Y, lastEditorCropOtherAspectRatioY).apply()
|
||||
var lastEditorCropOtherAspectRatioY: Float
|
||||
get() = prefs.getFloat(LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_Y, 1f)
|
||||
set(lastEditorCropOtherAspectRatioY) = prefs.edit().putFloat(LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_Y, lastEditorCropOtherAspectRatioY).apply()
|
||||
|
||||
var groupDirectSubfolders: Boolean
|
||||
get() = prefs.getBoolean(GROUP_DIRECT_SUBFOLDERS, false)
|
||||
|
|
|
@ -67,8 +67,8 @@ const val LAST_BIN_CHECK = "last_bin_check"
|
|||
const val SHOW_HIGHEST_QUALITY = "show_highest_quality"
|
||||
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_OTHER_ASPECT_RATIO_X = "last_editor_crop_other_aspect_ratio_x"
|
||||
const val LAST_EDITOR_CROP_OTHER_ASPECT_RATIO_Y = "last_editor_crop_other_aspect_ratio_y"
|
||||
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_2"
|
||||
const val GROUP_DIRECT_SUBFOLDERS = "group_direct_subfolders"
|
||||
const val SHOW_WIDGET_FOLDER_NAME = "show_widget_folder_name"
|
||||
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 FILE_LOADING_PRIORITY = "file_loading_priority"
|
||||
const val SPAM_FOLDERS_CHECKED = "spam_folders_checked"
|
||||
const val SHOW_THUMBNAIL_FILE_TYPES = "show_thumbnail_file_types"
|
||||
|
||||
// slideshow
|
||||
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_FADE = 2
|
||||
|
||||
const val NOMEDIA = ".nomedia"
|
||||
const val FAVORITES = "favorites"
|
||||
const val RECYCLE_BIN = "recycle_bin"
|
||||
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_DRAG = 1
|
||||
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
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.simplemobiletools.gallery.pro.helpers
|
|||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.os.Environment
|
||||
import android.provider.BaseColumns
|
||||
import android.provider.MediaStore
|
||||
import android.text.format.DateFormat
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
|
@ -37,34 +38,56 @@ class MediaFetcher(val context: Context) {
|
|||
}
|
||||
|
||||
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 {
|
||||
val cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
val folders = parseCursor(cursor)
|
||||
|
||||
val priorityFolders = arrayListOf(
|
||||
val folders = getLatestFileFolders()
|
||||
folders.addAll(arrayListOf(
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString(),
|
||||
"${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)}/Camera",
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString()
|
||||
).filter { File(it).exists() }
|
||||
).filter { File(it).exists() })
|
||||
|
||||
folders.sortBy {
|
||||
val folder = it
|
||||
!priorityFolders.any { it.equals(folder, true) }
|
||||
}
|
||||
val filterMedia = context.config.filterMedia
|
||||
val uri = MediaStore.Files.getContentUri("external")
|
||||
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) {
|
||||
context.showErrorToast(e)
|
||||
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 {
|
||||
val query = StringBuilder()
|
||||
query.append("(")
|
||||
|
@ -130,7 +153,7 @@ class MediaFetcher(val context: Context) {
|
|||
return args
|
||||
}
|
||||
|
||||
private fun parseCursor(cursor: Cursor): ArrayList<String> {
|
||||
private fun parseCursor(cursor: Cursor): LinkedHashSet<String> {
|
||||
val foldersToIgnore = arrayListOf("/storage/emulated/legacy")
|
||||
val config = context.config
|
||||
val includedFolders = config.includedFolders
|
||||
|
@ -155,7 +178,7 @@ class MediaFetcher(val context: Context) {
|
|||
val showHidden = config.shouldShowHidden
|
||||
val excludedFolders = config.excludedFolders
|
||||
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) {
|
||||
|
@ -230,7 +253,7 @@ class MediaFetcher(val context: Context) {
|
|||
continue
|
||||
}
|
||||
|
||||
if (checkFileExistence && !file.exists()) {
|
||||
if (checkFileExistence && (!file.exists() || !file.isFile)) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -74,7 +74,11 @@ class MyWidgetProvider : AppWidgetProvider() {
|
|||
}
|
||||
|
||||
setupAppOpenIntent(context, views, R.id.widget_holder, it)
|
||||
|
||||
try {
|
||||
appWidgetManager.updateAppWidget(it.widgetId, views)
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ import android.graphics.*
|
|||
import android.net.Uri
|
||||
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 val decoderLock = Any()
|
||||
|
||||
|
@ -18,10 +18,20 @@ class PicassoRegionDecoder(val showHighestQuality: Boolean) : ImageRegionDecoder
|
|||
|
||||
override fun decodeRegion(rect: Rect, sampleSize: Int): Bitmap {
|
||||
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()
|
||||
options.inSampleSize = sampleSize
|
||||
options.inSampleSize = newSampleSize
|
||||
options.inPreferredConfig = if (showHighestQuality) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
|
||||
val bitmap = decoder!!.decodeRegion(rect, options)
|
||||
|
||||
return bitmap ?: throw RuntimeException("Region decoder returned null bitmap - image format may not be supported")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -44,7 +44,11 @@ class NewPhotoFetcher : JobService() {
|
|||
addTriggerContentUri(JobInfo.TriggerContentUri(photoUri, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS))
|
||||
addTriggerContentUri(JobInfo.TriggerContentUri(videoUri, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS))
|
||||
addTriggerContentUri(JobInfo.TriggerContentUri(MEDIA_URI, 0))
|
||||
|
||||
try {
|
||||
context.getSystemService(JobScheduler::class.java).schedule(build())
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,7 +60,7 @@ class NewPhotoFetcher : JobService() {
|
|||
|
||||
override fun onStartJob(params: JobParameters): Boolean {
|
||||
mRunningParams = params
|
||||
|
||||
ensureBackgroundThread {
|
||||
val affectedFolderPaths = HashSet<String>()
|
||||
if (params.triggeredContentAuthorities != null && params.triggeredContentUris != null) {
|
||||
val ids = arrayListOf<String>()
|
||||
|
@ -95,7 +99,6 @@ class NewPhotoFetcher : JobService() {
|
|||
}
|
||||
}
|
||||
|
||||
ensureBackgroundThread {
|
||||
affectedFolderPaths.forEach {
|
||||
updateDirectoryPath(it)
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ class MediaSideScroll(context: Context, attrs: AttributeSet) : RelativeLayout(co
|
|||
return true
|
||||
}
|
||||
|
||||
private fun getCurrentVolume() = activity!!.audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
|
||||
private fun getCurrentVolume() = activity?.audioManager?.getStreamVolume(AudioManager.STREAM_MUSIC) ?: 0
|
||||
|
||||
private fun getCurrentBrightness(): Int {
|
||||
return try {
|
||||
|
|
Before Width: | Height: | Size: 198 B |
Before Width: | Height: | Size: 680 B |
Before Width: | Height: | Size: 464 B |
Before Width: | Height: | Size: 450 B |
Before Width: | Height: | Size: 531 B |
Before Width: | Height: | Size: 203 B |
Before Width: | Height: | Size: 344 B |
Before Width: | Height: | Size: 140 B |
Before Width: | Height: | Size: 292 B |
Before Width: | Height: | Size: 214 B |
Before Width: | Height: | Size: 647 B |
Before Width: | Height: | Size: 620 B |
Before Width: | Height: | Size: 656 B |
Before Width: | Height: | Size: 301 B |
Before Width: | Height: | Size: 221 B |
Before Width: | Height: | Size: 174 B |
Before Width: | Height: | Size: 812 B |
Before Width: | Height: | Size: 601 B |
Before Width: | Height: | Size: 569 B |
Before Width: | Height: | Size: 670 B |
Before Width: | Height: | Size: 187 B |
Before Width: | Height: | Size: 297 B |
Before Width: | Height: | Size: 92 B |
Before Width: | Height: | Size: 324 B |
Before Width: | Height: | Size: 246 B |
Before Width: | Height: | Size: 733 B |
Before Width: | Height: | Size: 688 B |
Before Width: | Height: | Size: 741 B |
Before Width: | Height: | Size: 413 B |
Before Width: | Height: | Size: 219 B |
Before Width: | Height: | Size: 221 B |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 867 B |
Before Width: | Height: | Size: 845 B |
Before Width: | Height: | Size: 979 B |
Before Width: | Height: | Size: 259 B |
Before Width: | Height: | Size: 442 B |
Before Width: | Height: | Size: 143 B |
Before Width: | Height: | Size: 473 B |
Before Width: | Height: | Size: 320 B |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 509 B |
Before Width: | Height: | Size: 308 B |
Before Width: | Height: | Size: 289 B |
Before Width: | Height: | Size: 994 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 324 B |
Before Width: | Height: | Size: 684 B |
Before Width: | Height: | Size: 110 B |
Before Width: | Height: | Size: 585 B |
Before Width: | Height: | Size: 361 B |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 670 B |
Before Width: | Height: | Size: 373 B |
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|